From b13e95b8eeba6de7abfada6135461431a3311242 Mon Sep 17 00:00:00 2001 From: Bartosz Sekula Date: Mon, 26 Aug 2024 12:00:22 -0400 Subject: [PATCH] AAE-18154 Fix redirect post logout uri (#10122) --- .../lib/auth/oidc/auth-config.service.spec.ts | 82 ++++++++++++------- .../src/lib/auth/oidc/auth-config.service.ts | 21 +++-- 2 files changed, 66 insertions(+), 37 deletions(-) diff --git a/lib/core/src/lib/auth/oidc/auth-config.service.spec.ts b/lib/core/src/lib/auth/oidc/auth-config.service.spec.ts index 9e9992c239..fc80d4948f 100644 --- a/lib/core/src/lib/auth/oidc/auth-config.service.spec.ts +++ b/lib/core/src/lib/auth/oidc/auth-config.service.spec.ts @@ -37,11 +37,7 @@ describe('AuthConfigService', () => { redirectSilentIframeUri: 'http://localhost:3000/assets/silent-refresh.html', redirectUri: '/', redirectUriLogout: '#/logout', - publicUrls: [ - '**/preview/s/*', - '**/settings', - '**/logout' - ] + publicUrls: ['**/preview/s/*', '**/settings', '**/logout'] }; const mockAuthConfigSubfolderRedirectUri: OauthConfigModel = { @@ -54,11 +50,7 @@ describe('AuthConfigService', () => { redirectSilentIframeUri: 'http://localhost:3000/subfolder/assets/silent-refresh.html', redirectUri: '/subfolder', redirectUriLogout: '#/logout', - publicUrls: [ - '**/preview/s/*', - '**/settings', - '**/logout' - ] + publicUrls: ['**/preview/s/*', '**/settings', '**/logout'] }; const mockAuthConfigSubfolder2RedirectUri: OauthConfigModel = { @@ -71,11 +63,7 @@ describe('AuthConfigService', () => { redirectSilentIframeUri: 'http://localhost:3000/subfolder2/assets/silent-refresh.html', redirectUri: '/subfolder2', redirectUriLogout: '#/logout', - publicUrls: [ - '**/preview/s/*', - '**/settings', - '**/logout' - ] + publicUrls: ['**/preview/s/*', '**/settings', '**/logout'] }; const mockAuthConfigSlashRedirectUri: OauthConfigModel = { @@ -88,11 +76,7 @@ describe('AuthConfigService', () => { redirectSilentIframeUri: 'http://localhost:3000/assets/silent-refresh.html', redirectUri: '/', redirectUriLogout: '#/logout', - publicUrls: [ - '**/preview/s/*', - '**/settings', - '**/logout' - ] + publicUrls: ['**/preview/s/*', '**/settings', '**/logout'] }; const mockAuthConfigCodeFlow = { @@ -106,19 +90,13 @@ describe('AuthConfigService', () => { redirectSilentIframeUri: 'http://localhost:3000/assets/silent-refresh.html', redirectUri: '/', redirectUriLogout: '#/logout', - publicUrls: [ - '**/preview/s/*', - '**/settings', - '**/logout' - ] + publicUrls: ['**/preview/s/*', '**/settings', '**/logout'] }; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], - providers: [ - { provide: AUTH_MODULE_CONFIG, useValue: { useHash: true } } - ] + providers: [{ provide: AUTH_MODULE_CONFIG, useValue: { useHash: true } }] }); service = TestBed.inject(AuthConfigService); spyOn(service, 'getLocationOrigin').and.returnValue('http://localhost:3000'); @@ -195,4 +173,52 @@ describe('AuthConfigService', () => { expect(service.loadAppConfig().silentRefreshRedirectUri).toBe(expectedUri); }); }); + + describe('postLogoutRedirectUri', () => { + const getConfig = (config: Partial): OauthConfigModel => { + const defaultConfig = { + host: 'http://localhost:3000/auth/realms/alfresco', + clientId: 'fakeClientId', + scope: 'openid profile email', + secret: '', + implicitFlow: true, + silentLogin: true, + redirectSilentIframeUri: 'http://localhost:3000/assets/silent-refresh.html', + redirectUri: '/', + redirectUriLogout: '/', + publicUrls: ['**/preview/s/*', '**/settings', '**/logout'] + }; + + return { + ...defaultConfig, + ...config + }; + }; + it('should return proper postLogoutRedirectUri when the redirectUriLogout is "/"', () => { + const testConfig = getConfig({ + redirectUriLogout: '/' + }); + + spyOnProperty(appConfigService, 'oauth2').and.returnValue(testConfig); + expect(service.loadAppConfig().postLogoutRedirectUri).toBe('http://localhost:3000/'); + }); + + it('should return proper postLogoutRedirectUri when the redirectUriLogout is empty', () => { + const testConfig = getConfig({ + redirectUriLogout: undefined + }); + + spyOnProperty(appConfigService, 'oauth2').and.returnValue(testConfig); + expect(service.loadAppConfig().postLogoutRedirectUri).toBe('http://localhost:3000/'); + }); + + it('should return proper postLogoutRedirectUri when the redirectUriLogout starts with slash', () => { + const testConfig = getConfig({ + redirectUriLogout: '/asd' + }); + + spyOnProperty(appConfigService, 'oauth2').and.returnValue(testConfig); + expect(service.loadAppConfig().postLogoutRedirectUri).toBe('http://localhost:3000/asd'); + }); + }); }); diff --git a/lib/core/src/lib/auth/oidc/auth-config.service.ts b/lib/core/src/lib/auth/oidc/auth-config.service.ts index bdc32c43c6..37fc9ae7cf 100644 --- a/lib/core/src/lib/auth/oidc/auth-config.service.ts +++ b/lib/core/src/lib/auth/oidc/auth-config.service.ts @@ -35,10 +35,7 @@ export function authConfigFactory(authConfigService: AuthConfigService): Promise providedIn: 'root' }) export class AuthConfigService { - constructor( - private appConfigService: AppConfigService, - @Inject(AUTH_MODULE_CONFIG) private readonly authModuleConfig: AuthModuleConfig - ) {} + constructor(private appConfigService: AppConfigService, @Inject(AUTH_MODULE_CONFIG) private readonly authModuleConfig: AuthModuleConfig) {} private _authConfig!: AuthConfig; get authConfig(): AuthConfig { @@ -62,7 +59,7 @@ export class AuthConfigService { nonceStateSeparator: '~', redirectUri, silentRefreshRedirectUri: oauth2.redirectSilentIframeUri, - postLogoutRedirectUri: `${origin}/${oauth2.redirectUriLogout}`, + postLogoutRedirectUri: this.generatePostLogoutUri(origin, oauth2.redirectUriLogout), clientId: oauth2.clientId, scope: oauth2.scope, dummyClientSecret: oauth2.secret || '', @@ -84,11 +81,10 @@ export class AuthConfigService { return oauth2.redirectUri; } - const locationOrigin = oauth2.redirectUri && oauth2.redirectUri !== '/' ? this.getLocationOrigin() + '' + oauth2.redirectUri : this.getLocationOrigin(); + const locationOrigin = + oauth2.redirectUri && oauth2.redirectUri !== '/' ? this.getLocationOrigin() + '' + oauth2.redirectUri : this.getLocationOrigin(); - const redirectUri = useHash - ? `${locationOrigin}/#/${viewUrl}` - : `${locationOrigin}/${viewUrl}`; + const redirectUri = useHash ? `${locationOrigin}/#/${viewUrl}` : `${locationOrigin}/${viewUrl}`; // handle issue from the OIDC library with hashStrategy and implicitFlow, with would append &state to the url with would lead to error // `cannot match any routes`, and displaying the wildcard ** error page @@ -98,4 +94,11 @@ export class AuthConfigService { private getLocationOrigin() { return window.location.origin; } + + private generatePostLogoutUri(hostUri: string = '', redirectUriLogout: string = ''): string { + const hostUriWithoutSlash = hostUri.endsWith('/') ? hostUri.substring(0, hostUri.length - 1) : hostUri; + const redirectUriLogoutWithoutSlash = redirectUriLogout.startsWith('/') ? redirectUriLogout.substring(1) : redirectUriLogout; + + return `${hostUriWithoutSlash}/${redirectUriLogoutWithoutSlash}`; + } }