diff --git a/demo-shell/src/app/app.routes.ts b/demo-shell/src/app/app.routes.ts index 659820096a..dddb772de6 100644 --- a/demo-shell/src/app/app.routes.ts +++ b/demo-shell/src/app/app.routes.ts @@ -106,6 +106,11 @@ export const appRoutes: Routes = [ component: AppLayoutComponent, canActivate: [AuthGuard], children: [ + { + path: '', + redirectTo: `/home`, + pathMatch: 'full' + }, { path: 'breadcrumb', canActivate: [AuthGuardEcm], diff --git a/lib/core/services/auth-guard-base.ts b/lib/core/services/auth-guard-base.ts index af3e4d688d..07c6a2805f 100644 --- a/lib/core/services/auth-guard-base.ts +++ b/lib/core/services/auth-guard-base.ts @@ -61,25 +61,11 @@ export abstract class AuthGuardBase implements CanActivate, CanActivateChild { state: RouterStateSnapshot ): Observable | Promise | boolean | UrlTree { - const redirectFragment = this.storageService.getItem('loginFragment'); - - if (this.authenticationService.isLoggedIn() || this.withCredentials) { - - if (redirectFragment && this.getLoginRoute() !== redirectFragment) { - this.storageService.removeItem('loginFragment'); - this.redirectToUrl(redirectFragment); - } - - return true; + if (this.authenticationService.isLoggedIn() && this.authenticationService.isOauth() && this.isLoginFragmentPresent()) { + return this.redirectSSOSuccessURL(); } - const checkLogin = this.checkLogin(route, state.url); - - if (!checkLogin) { - this.dialog.closeAll(); - } - - return checkLogin; + return this.checkLogin(route, state.url); } canActivateChild( @@ -89,31 +75,44 @@ export abstract class AuthGuardBase implements CanActivate, CanActivateChild { return this.canActivate(route, state); } - protected redirectToUrl(url: string) { - let urlToRedirect; + protected async redirectSSOSuccessURL(): Promise { + const redirectFragment = this.storageService.getItem('loginFragment'); - this.dialog.closeAll(); - - if (!this.authenticationService.isLoggedIn()) { - const pathToLogin = `/${this.getLoginRoute()}`; - - if (!this.authenticationService.isOauth()) { - this.authenticationService.setRedirect({ - provider: this.getProvider(), - url - }); - - urlToRedirect = `${pathToLogin}?redirectUrl=${url}`; - this.router.navigateByUrl(urlToRedirect); - } else if (this.getOauthConfig().silentLogin && !this.authenticationService.isPublicUrl()) { - this.authenticationService.ssoImplicitLogin(); - } else { - urlToRedirect = pathToLogin; - this.router.navigateByUrl(urlToRedirect); - } - } else { - this.router.navigateByUrl(url); + if (redirectFragment && this.getLoginRoute() !== redirectFragment) { + this.storageService.removeItem('loginFragment'); + return this.navigate(redirectFragment); } + + return true; + } + + protected async isLoginFragmentPresent(): Promise { + return !!this.storageService.getItem('loginFragment'); + } + + protected async redirectToUrl(url: string): Promise { + let urlToRedirect = `/${this.getLoginRoute()}`; + + if (!this.authenticationService.isOauth()) { + this.authenticationService.setRedirect({ + provider: this.getProvider(), + url + }); + + urlToRedirect = `${urlToRedirect}?redirectUrl=${url}`; + return this.navigate(urlToRedirect); + } else if (this.getOauthConfig().silentLogin && !this.authenticationService.isPublicUrl()) { + this.authenticationService.ssoImplicitLogin(); + } else { + return this.navigate(urlToRedirect); + } + + return false; + } + + protected navigate(url: string): Promise { + this.dialog.closeAll(); + return this.router.navigateByUrl(url); } protected getOauthConfig(): OauthConfigModel { diff --git a/lib/core/services/auth-guard-bpm.service.spec.ts b/lib/core/services/auth-guard-bpm.service.spec.ts index f0b860653a..e9d69e5c67 100644 --- a/lib/core/services/auth-guard-bpm.service.spec.ts +++ b/lib/core/services/auth-guard-bpm.service.spec.ts @@ -51,7 +51,7 @@ describe('AuthGuardService BPM', () => { appConfigService.config.oauth2 = {}; }); - it('should redirect url if the alfresco js api is NOT logged in and isOAuth with silentLogin', async(() => { + it('should redirect url if the alfresco js api is NOT logged in and isOAuth with silentLogin', async(async () => { spyOn(router, 'navigateByUrl').and.stub(); spyOn(authService, 'isBpmLoggedIn').and.returnValue(false); spyOn(authService, 'isOauth').and.returnValue(true); @@ -68,66 +68,66 @@ describe('AuthGuardService BPM', () => { provider: 'BPM' }; - const route: RouterStateSnapshot = {url : 'abc'}; + const route: RouterStateSnapshot = { url: 'abc' }; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); expect(authService.ssoImplicitLogin).toHaveBeenCalledTimes(1); })); - it('if the alfresco js api is logged in should canActivate be true', async(() => { + it('if the alfresco js api is logged in should canActivate be true', async(async () => { spyOn(authService, 'isBpmLoggedIn').and.returnValue(true); - const route: RouterStateSnapshot = {url : 'some-url'}; + const route: RouterStateSnapshot = { url: 'some-url' }; - expect(authGuard.canActivate(null, route)).toBeTruthy(); + expect(await authGuard.canActivate(null, route)).toBeTruthy(); })); - it('if the alfresco js api is configured with withCredentials true should canActivate be true', async(() => { + it('if the alfresco js api is configured with withCredentials true should canActivate be true', async(async () => { spyOn(authService, 'isBpmLoggedIn').and.returnValue(true); appConfigService.config.auth.withCredentials = true; - const route: RouterStateSnapshot = {url : 'some-url'}; + const route: RouterStateSnapshot = { url: 'some-url' }; - expect(authGuard.canActivate(null, route)).toBeTruthy(); + expect(await authGuard.canActivate(null, route)).toBeTruthy(); })); - it('if the alfresco js api is NOT logged in should canActivate be false', async(() => { + it('if the alfresco js api is NOT logged in should canActivate be false', async(async () => { spyOn(authService, 'isBpmLoggedIn').and.returnValue(false); spyOn(router, 'navigateByUrl').and.stub(); const route: RouterStateSnapshot = { url: 'some-url' }; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); })); - it('if the alfresco js api is NOT logged in should trigger a redirect event', async(() => { + it('if the alfresco js api is NOT logged in should trigger a redirect event', async(async () => { appConfigService.config.loginRoute = 'login'; spyOn(router, 'navigateByUrl'); spyOn(authService, 'isBpmLoggedIn').and.returnValue(false); - const route: RouterStateSnapshot = {url : 'some-url'}; + const route: RouterStateSnapshot = { url: 'some-url' }; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); expect(router.navigateByUrl).toHaveBeenCalledWith('/login?redirectUrl=some-url'); })); - it('should redirect url if the alfresco js api is NOT logged in and isOAuthWithoutSilentLogin', async(() => { + it('should redirect url if the alfresco js api is NOT logged in and isOAuthWithoutSilentLogin', async(async () => { spyOn(router, 'navigateByUrl').and.stub(); spyOn(authService, 'isBpmLoggedIn').and.returnValue(false); spyOn(authService, 'isOauth').and.returnValue(true); appConfigService.config.oauth2.silentLogin = false; - const route: RouterStateSnapshot = {url : 'some-url'}; + const route: RouterStateSnapshot = { url: 'some-url' }; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); expect(router.navigateByUrl).toHaveBeenCalled(); })); - it('should redirect url if NOT logged in and isOAuth but no silentLogin configured', async(() => { + it('should redirect url if NOT logged in and isOAuth but no silentLogin configured', async(async () => { spyOn(router, 'navigateByUrl').and.stub(); spyOn(authService, 'isBpmLoggedIn').and.returnValue(false); spyOn(authService, 'isOauth').and.returnValue(true); appConfigService.config.oauth2.silentLogin = undefined; - const route: RouterStateSnapshot = {url : 'some-url'}; + const route: RouterStateSnapshot = { url: 'some-url' }; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); expect(router.navigateByUrl).toHaveBeenCalled(); })); diff --git a/lib/core/services/auth-guard-bpm.service.ts b/lib/core/services/auth-guard-bpm.service.ts index efab51fe5d..7c9434290c 100644 --- a/lib/core/services/auth-guard-bpm.service.ts +++ b/lib/core/services/auth-guard-bpm.service.ts @@ -36,11 +36,10 @@ export class AuthGuardBpm extends AuthGuardBase { super(authenticationService, router, appConfigService, dialog, storageService); } - checkLogin(_: ActivatedRouteSnapshot, redirectUrl: string): boolean { + async checkLogin(_: ActivatedRouteSnapshot, redirectUrl: string): Promise { if (this.authenticationService.isBpmLoggedIn() || this.withCredentials) { return true; } - this.redirectToUrl(redirectUrl); - return false; + return this.redirectToUrl(redirectUrl); } } diff --git a/lib/core/services/auth-guard-ecm.service.spec.ts b/lib/core/services/auth-guard-ecm.service.spec.ts index 21f00a0a23..c42bba9b36 100644 --- a/lib/core/services/auth-guard-ecm.service.spec.ts +++ b/lib/core/services/auth-guard-ecm.service.spec.ts @@ -51,53 +51,53 @@ describe('AuthGuardService ECM', () => { appConfigService.config.oauth2 = {}; }); - it('if the alfresco js api is logged in should canActivate be true', async(() => { + it('if the alfresco js api is logged in should canActivate be true', async(async() => { spyOn(authService, 'isEcmLoggedIn').and.returnValue(true); const route: RouterStateSnapshot = {url : 'some-url'}; - expect(authGuard.canActivate(null, route)).toBeTruthy(); + expect(await authGuard.canActivate(null, route)).toBeTruthy(); })); - it('if the alfresco js api is configured with withCredentials true should canActivate be true', async(() => { + it('if the alfresco js api is configured with withCredentials true should canActivate be true', async(async() => { spyOn(authService, 'isBpmLoggedIn').and.returnValue(true); appConfigService.config.auth.withCredentials = true; const route: RouterStateSnapshot = {url : 'some-url'}; - expect(authGuard.canActivate(null, route)).toBeTruthy(); + expect(await authGuard.canActivate(null, route)).toBeTruthy(); })); - it('if the alfresco js api is NOT logged in should canActivate be false', async(() => { + it('if the alfresco js api is NOT logged in should canActivate be false', async(async() => { spyOn(authService, 'isEcmLoggedIn').and.returnValue(false); spyOn(router, 'navigateByUrl').and.stub(); const route: RouterStateSnapshot = { url: 'some-url' }; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); })); - it('if the alfresco js api is NOT logged in should trigger a redirect event', async(() => { + it('if the alfresco js api is NOT logged in should trigger a redirect event', async(async() => { appConfigService.config.loginRoute = 'login'; spyOn(router, 'navigateByUrl'); spyOn(authService, 'isEcmLoggedIn').and.returnValue(false); const route: RouterStateSnapshot = {url : 'some-url'}; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); expect(router.navigateByUrl).toHaveBeenCalledWith('/login?redirectUrl=some-url'); })); - it('should redirect url if the alfresco js api is NOT logged in and isOAuthWithoutSilentLogin', async(() => { + it('should redirect url if the alfresco js api is NOT logged in and isOAuthWithoutSilentLogin', async(async() => { spyOn(router, 'navigateByUrl').and.stub(); spyOn(authService, 'isEcmLoggedIn').and.returnValue(false); spyOn(authService, 'isOauth').and.returnValue(true); appConfigService.config.oauth2.silentLogin = false; const route: RouterStateSnapshot = {url : 'some-url'}; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); expect(router.navigateByUrl).toHaveBeenCalled(); })); - it('should redirect url if the alfresco js api is NOT logged in and isOAuth with silentLogin', async(() => { + it('should redirect url if the alfresco js api is NOT logged in and isOAuth with silentLogin', async(async() => { spyOn(authService, 'isEcmLoggedIn').and.returnValue(false); spyOn(authService, 'isOauth').and.returnValue(true); spyOn(authService, 'isPublicUrl').and.returnValue(false); @@ -114,18 +114,18 @@ describe('AuthGuardService ECM', () => { const route: RouterStateSnapshot = {url : 'abc'}; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); expect(authService.ssoImplicitLogin).toHaveBeenCalledTimes(1); })); - it('should not redirect url if NOT logged in and isOAuth but no silentLogin configured', async(() => { + it('should not redirect url if NOT logged in and isOAuth but no silentLogin configured', async(async() => { spyOn(router, 'navigateByUrl').and.stub(); spyOn(authService, 'isEcmLoggedIn').and.returnValue(false); spyOn(authService, 'isOauth').and.returnValue(true); appConfigService.config.oauth2.silentLogin = undefined; const route: RouterStateSnapshot = {url : 'some-url'}; - expect(authGuard.canActivate(null, route)).toBeFalsy(); + expect(await authGuard.canActivate(null, route)).toBeFalsy(); expect(router.navigateByUrl).toHaveBeenCalled(); })); diff --git a/lib/core/services/auth-guard-ecm.service.ts b/lib/core/services/auth-guard-ecm.service.ts index abcf098e6c..4957f85757 100644 --- a/lib/core/services/auth-guard-ecm.service.ts +++ b/lib/core/services/auth-guard-ecm.service.ts @@ -38,13 +38,11 @@ export class AuthGuardEcm extends AuthGuardBase { super(authenticationService, router, appConfigService, dialog, storageService); } - checkLogin(_: ActivatedRouteSnapshot, redirectUrl: string): boolean { + async checkLogin(_: ActivatedRouteSnapshot, redirectUrl: string): Promise { if (this.authenticationService.isEcmLoggedIn() || this.withCredentials) { return true; } - this.redirectToUrl(redirectUrl); - - return false; + return this.redirectToUrl(redirectUrl); } } diff --git a/lib/core/services/auth-guard-sso-role.service.spec.ts b/lib/core/services/auth-guard-sso-role.service.spec.ts index 0b12d667e1..fd0fd5b294 100644 --- a/lib/core/services/auth-guard-sso-role.service.spec.ts +++ b/lib/core/services/auth-guard-sso-role.service.spec.ts @@ -44,27 +44,27 @@ describe('Auth Guard SSO role service', () => { routerService = TestBed.inject(Router); }); - it('Should canActivate be true if the Role is present int the JWT token', async(() => { + it('Should canActivate be true if the Role is present int the JWT token', async(async () => { spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); spyOn(jwtHelperService, 'decodeToken').and.returnValue({ 'realm_access': { roles: ['role1'] } }); const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); router.data = { 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(router)).toBeTruthy(); + expect(await authGuard.canActivate(router)).toBeTruthy(); })); - it('Should canActivate be false if the Role is not present int the JWT token', async(() => { + it('Should canActivate be false if the Role is not present int the JWT token', async(async () => { spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); spyOn(jwtHelperService, 'decodeToken').and.returnValue({ 'realm_access': { roles: ['role3'] } }); const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); router.data = { 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(router)).toBeFalsy(); + expect(await authGuard.canActivate(router)).toBeFalsy(); })); - it('Should not redirect if canActivate is', async(() => { + it('Should not redirect if canActivate is', async(async () => { spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); spyOn(jwtHelperService, 'decodeToken').and.returnValue({ 'realm_access': { roles: ['role1'] } }); spyOn(routerService, 'navigate').and.stub(); @@ -72,29 +72,29 @@ describe('Auth Guard SSO role service', () => { const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); router.data = { 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(router)).toBeTruthy(); + expect(await authGuard.canActivate(router)).toBeTruthy(); expect(routerService.navigate).not.toHaveBeenCalled(); })); - it('Should canActivate return false if the data Role to check is empty', async(() => { + it('Should canActivate return false if the data Role to check is empty', async(async () => { spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); spyOn(jwtHelperService, 'decodeToken').and.returnValue({ 'realm_access': { roles: ['role1', 'role3'] } }); const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); - expect(authGuard.canActivate(router)).toBeFalsy(); + expect(await authGuard.canActivate(router)).toBeFalsy(); })); - it('Should canActivate return false if the realm_access is not present', async(() => { + it('Should canActivate return false if the realm_access is not present', async(async () => { spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); spyOn(jwtHelperService, 'decodeToken').and.returnValue({}); const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); - expect(authGuard.canActivate(router)).toBeFalsy(); + expect(await authGuard.canActivate(router)).toBeFalsy(); })); - it('Should redirect to the redirectURL if canActivate is false and redirectUrl is in data', async(() => { + it('Should redirect to the redirectURL if canActivate is false and redirectUrl is in data', async(async () => { spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); spyOn(jwtHelperService, 'decodeToken').and.returnValue({}); spyOn(routerService, 'navigate').and.stub(); @@ -102,11 +102,11 @@ describe('Auth Guard SSO role service', () => { const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); router.data = { 'roles': ['role1', 'role2'], 'redirectUrl': 'no-role-url' }; - expect(authGuard.canActivate(router)).toBeFalsy(); + expect(await authGuard.canActivate(router)).toBeFalsy(); expect(routerService.navigate).toHaveBeenCalledWith(['/no-role-url']); })); - it('Should not redirect if canActivate is false and redirectUrl is not in data', async(() => { + it('Should not redirect if canActivate is false and redirectUrl is not in data', async(async () => { spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); spyOn(jwtHelperService, 'decodeToken').and.returnValue({}); spyOn(routerService, 'navigate').and.stub(); @@ -114,11 +114,11 @@ describe('Auth Guard SSO role service', () => { const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); router.data = { 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(router)).toBeFalsy(); + expect(await authGuard.canActivate(router)).toBeFalsy(); expect(routerService.navigate).not.toHaveBeenCalled(); })); - it('Should canActivate be false hasRealm is true and hasClientRole is false', () => { + it('Should canActivate be false hasRealm is true and hasClientRole is false', async () => { const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); spyOn(jwtHelperService, 'hasRealmRoles').and.returnValue(true); spyOn(jwtHelperService, 'hasRealmRolesForClientRole').and.returnValue(false); @@ -126,10 +126,10 @@ describe('Auth Guard SSO role service', () => { route.params = { appName: 'fakeapp' }; route.data = { 'clientRoles': ['appName'], 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(route)).toBeFalsy(); + expect(await authGuard.canActivate(route)).toBeFalsy(); }); - it('Should canActivate be false if hasRealm is false and hasClientRole is true', () => { + it('Should canActivate be false if hasRealm is false and hasClientRole is true', async () => { const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); spyOn(jwtHelperService, 'hasRealmRoles').and.returnValue(false); spyOn(jwtHelperService, 'hasRealmRolesForClientRole').and.returnValue(true); @@ -137,10 +137,10 @@ describe('Auth Guard SSO role service', () => { route.params = { appName: 'fakeapp' }; route.data = { 'clientRoles': ['fakeapp'], 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(route)).toBeFalsy(); + expect(await authGuard.canActivate(route)).toBeFalsy(); }); - it('Should canActivate be true if both Real Role and Client Role are present int the JWT token', () => { + it('Should canActivate be true if both Real Role and Client Role are present int the JWT token', async () => { const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); @@ -152,10 +152,10 @@ describe('Auth Guard SSO role service', () => { route.params = { appName: 'fakeapp' }; route.data = { 'clientRoles': ['appName'], 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(route)).toBeTruthy(); + expect(await authGuard.canActivate(route)).toBeTruthy(); }); - it('Should canActivate be false if the Client Role is not present int the JWT token with the correct role', () => { + it('Should canActivate be false if the Client Role is not present int the JWT token with the correct role', async () => { const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot(); spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token'); @@ -167,10 +167,10 @@ describe('Auth Guard SSO role service', () => { route.params = { appName: 'fakeapp' }; route.data = { 'clientRoles': ['appName'], 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(route)).toBeFalsy(); + expect(await authGuard.canActivate(route)).toBeFalsy(); }); - it('Should canActivate be false hasRealm is true and hasClientRole is false', () => { + it('Should canActivate be false hasRealm is true and hasClientRole is false', async () => { const materialDialog = TestBed.inject(MatDialog); spyOn(materialDialog, 'closeAll'); @@ -182,7 +182,7 @@ describe('Auth Guard SSO role service', () => { route.params = { appName: 'fakeapp' }; route.data = { 'clientRoles': ['appName'], 'roles': ['role1', 'role2'] }; - expect(authGuard.canActivate(route)).toBeFalsy(); + expect(await authGuard.canActivate(route)).toBeFalsy(); expect(materialDialog.closeAll).toHaveBeenCalled(); }); }); diff --git a/lib/core/services/auth-guard.service.ts b/lib/core/services/auth-guard.service.ts index 92d02384e3..21879c8831 100644 --- a/lib/core/services/auth-guard.service.ts +++ b/lib/core/services/auth-guard.service.ts @@ -61,7 +61,7 @@ export class AuthGuard extends AuthGuardBase { private ticketChangeRedirect(event: StorageEvent) { if (!event.newValue) { - this.redirectToUrl(this.router.url); + this.navigate(this.router.url); } else { window.location.reload(); } @@ -69,9 +69,9 @@ export class AuthGuard extends AuthGuardBase { async checkLogin(_: ActivatedRouteSnapshot, redirectUrl: string): Promise { if (this.authenticationService.isLoggedIn() || this.withCredentials) { + return true; } - this.redirectToUrl( redirectUrl); - return false; + return this.redirectToUrl( redirectUrl); } }