@@ -24,6 +24,7 @@ const DUMMY_WELL_KNOWN_DOCUMENT = {
2424 introspection_endpoint :
2525 'https://identity-server.test/realms/main/protocol/openid-connect/token/introspect' ,
2626} ;
27+ const DUMMY_MALICIOUS_URL = 'https://malicious.test/realms/main' ;
2728
2829describe ( 'AuthWellKnownDataService' , ( ) => {
2930 let service : AuthWellKnownDataService ;
@@ -174,7 +175,10 @@ describe('AuthWellKnownDataService', () => {
174175
175176 describe ( 'getWellKnownEndPointsForConfig' , ( ) => {
176177 it ( 'calling internal getWellKnownDocument and maps' , waitForAsync ( ( ) => {
177- spyOn ( dataService , 'get' ) . and . returnValue ( of ( { jwks_uri : 'jwks_uri' } ) ) ;
178+ spyOn ( dataService , 'get' ) . and . returnValue ( of ( {
179+ issuer : 'localhost' ,
180+ jwks_uri : 'jwks_uri'
181+ } ) ) ;
178182
179183 const spy = spyOn (
180184 service as any ,
@@ -184,12 +188,13 @@ describe('AuthWellKnownDataService', () => {
184188 service
185189 . getWellKnownEndPointsForConfig ( {
186190 configId : 'configId1' ,
187- authWellknownEndpointUrl : 'any-url ' ,
191+ authWellknownEndpointUrl : 'localhost ' ,
188192 } )
189193 . subscribe ( ( result ) => {
190194 expect ( spy ) . toHaveBeenCalled ( ) ;
191195 expect ( ( result as any ) . jwks_uri ) . toBeUndefined ( ) ;
192196 expect ( result . jwksUri ) . toBe ( 'jwks_uri' ) ;
197+ expect ( result . issuer ) . toBe ( 'localhost' ) ;
193198 } ) ;
194199 } ) ) ;
195200
@@ -214,19 +219,103 @@ describe('AuthWellKnownDataService', () => {
214219 it ( 'should merge the mapped endpoints with the provided endpoints' , waitForAsync ( ( ) => {
215220 spyOn ( dataService , 'get' ) . and . returnValue ( of ( DUMMY_WELL_KNOWN_DOCUMENT ) ) ;
216221
222+ const expected : AuthWellKnownEndpoints = {
223+ endSessionEndpoint : 'config-endSessionEndpoint' ,
224+ revocationEndpoint : 'config-revocationEndpoint' ,
225+ jwksUri : DUMMY_WELL_KNOWN_DOCUMENT . jwks_uri
226+ } ;
227+
228+ service
229+ . getWellKnownEndPointsForConfig ( {
230+ configId : 'configId1' ,
231+ authWellknownEndpointUrl : DUMMY_WELL_KNOWN_DOCUMENT . issuer ,
232+ authWellknownEndpoints : {
233+ endSessionEndpoint : 'config-endSessionEndpoint' ,
234+ revocationEndpoint : 'config-revocationEndpoint' ,
235+ } ,
236+ } )
237+ . subscribe ( ( result ) => {
238+ expect ( result ) . toEqual ( jasmine . objectContaining ( expected ) ) ;
239+ } ) ;
240+ } ) ) ;
241+
242+ it ( 'throws error and logs if well known issuer does not match authwellknownUrl' , waitForAsync ( ( ) => {
243+ const loggerSpy = spyOn ( loggerService , 'logError' ) ;
244+ const maliciousWellKnown = {
245+ ...DUMMY_WELL_KNOWN_DOCUMENT ,
246+ issuer : DUMMY_MALICIOUS_URL
247+ } ;
248+
249+ spyOn ( dataService , 'get' ) . and . returnValue (
250+ createRetriableStream (
251+ of ( maliciousWellKnown )
252+ )
253+ ) ;
254+
255+ const config = {
256+ configId : 'configId1' ,
257+ authWellknownEndpointUrl : DUMMY_WELL_KNOWN_DOCUMENT . issuer ,
258+ } ;
259+
260+ service . getWellKnownEndPointsForConfig ( config ) . subscribe ( {
261+ next : ( result ) => {
262+ fail ( `Retrieval was supposed to fail. Well known endpoints returned : ${ JSON . stringify ( result ) } ` ) ;
263+ } ,
264+ error : ( error ) => {
265+ expect ( loggerSpy ) . toHaveBeenCalledOnceWith (
266+ config ,
267+ `Issuer mismatch. Well known issuer ${ DUMMY_MALICIOUS_URL } does not match configured well known url ${ DUMMY_WELL_KNOWN_DOCUMENT . issuer } `
268+ ) ;
269+ expect ( error . message ) . toEqual ( `Issuer mismatch. Well known issuer ${ DUMMY_MALICIOUS_URL } does not match configured well known url ${ DUMMY_WELL_KNOWN_DOCUMENT . issuer } ` ) ;
270+ }
271+ } ) ;
272+ } ) ) ;
273+
274+ it ( 'should not throws error and logs if well known issuer has a trailing slash compared to authwellknownUrl ' , waitForAsync ( ( ) => {
275+ const trailingSlashIssuerWellKnown = {
276+ ...DUMMY_WELL_KNOWN_DOCUMENT ,
277+ issuer : DUMMY_WELL_KNOWN_DOCUMENT . issuer + "/"
278+ } ;
279+
280+ spyOn ( dataService , 'get' ) . and . returnValue ( of ( trailingSlashIssuerWellKnown ) ) ;
281+
282+ const expected : AuthWellKnownEndpoints = {
283+ issuer : DUMMY_WELL_KNOWN_DOCUMENT . issuer + "/" ,
284+ } ;
285+
286+ service
287+ . getWellKnownEndPointsForConfig ( {
288+ configId : 'configId1' ,
289+ authWellknownEndpointUrl : DUMMY_WELL_KNOWN_DOCUMENT . issuer
290+ } )
291+ . subscribe ( ( result ) => {
292+ expect ( result ) . toEqual ( jasmine . objectContaining ( expected ) ) ;
293+ } ) ;
294+ } ) ) ;
295+
296+ it ( 'should merge the mapped endpoints with the provided endpoints and ignore issuer/authwellknownUrl mismatch' , waitForAsync ( ( ) => {
297+ const maliciousWellKnown = {
298+ ...DUMMY_WELL_KNOWN_DOCUMENT ,
299+ issuer : DUMMY_MALICIOUS_URL
300+ } ;
301+
302+ spyOn ( dataService , 'get' ) . and . returnValue ( of ( maliciousWellKnown ) ) ;
303+
217304 const expected : AuthWellKnownEndpoints = {
218305 endSessionEndpoint : 'config-endSessionEndpoint' ,
219306 revocationEndpoint : 'config-revocationEndpoint' ,
220307 jwksUri : DUMMY_WELL_KNOWN_DOCUMENT . jwks_uri ,
308+ issuer : DUMMY_WELL_KNOWN_DOCUMENT . issuer ,
221309 } ;
222310
223311 service
224312 . getWellKnownEndPointsForConfig ( {
225313 configId : 'configId1' ,
226- authWellknownEndpointUrl : 'any-url' ,
314+ authWellknownEndpointUrl : DUMMY_WELL_KNOWN_DOCUMENT . issuer ,
227315 authWellknownEndpoints : {
228316 endSessionEndpoint : 'config-endSessionEndpoint' ,
229317 revocationEndpoint : 'config-revocationEndpoint' ,
318+ issuer : DUMMY_WELL_KNOWN_DOCUMENT . issuer
230319 } ,
231320 } )
232321 . subscribe ( ( result ) => {
0 commit comments