diff --git a/docs/core/services/auth-guard-sso-role.service.md b/docs/core/services/auth-guard-sso-role.service.md
index e58dfea256..f2768b9eb2 100644
--- a/docs/core/services/auth-guard-sso-role.service.md
+++ b/docs/core/services/auth-guard-sso-role.service.md
@@ -24,14 +24,14 @@ const appRoutes: Routes = [
path: 'examplepath',
component: ExampleComponent,
canActivate: [ AuthGuardSsoRoleService ],
- data: { roles: ['USER_ROLE1', 'USER_ROLE2']}
+ data: { roles: ['USER_ROLE1', 'USER_ROLE2'], excludedRoles: ['USER_ROLE3']}
},
...
]
```
-If the user now clicks on a link or button that follows this route, they will be not able to access this content if they do not have the Realms roles.
-
**Note**: An additional role ALFRESCO_ADMINISTRATORS can be used in the roles array, which will result in checking whether the logged in user has Content Admin capabilities or not, as this role is not part of the JWT token it will call a Content API to determine it.
+If the user now clicks on a link or button that follows this route, they will be not able to access this content if they do not have the Realms roles. Additionally, the user will not be able to access the resource when they have a role that is part of the excludedRoles array.
+
**Notes**: An additional role ALFRESCO_ADMINISTRATORS can be used in the roles array, which will result in checking whether the logged in user has Content Admin capabilities or not, as this role is not part of the JWT token it will call a Content API to determine it.
Client role Example
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 49d48d35dc..c1c2f78610 100644
--- a/lib/core/services/auth-guard-sso-role.service.spec.ts
+++ b/lib/core/services/auth-guard-sso-role.service.spec.ts
@@ -225,4 +225,38 @@ describe('Auth Guard SSO role service', () => {
expect(getCurrentPersonSpy).not.toHaveBeenCalled();
});
});
+
+ describe('Excluded Roles', () => {
+ it('Should canActivate be false when the user has one of the excluded roles', async () => {
+ spyOn(peopleContentService, 'getCurrentPerson').and.returnValue(of(getFakeUserWithContentAdminCapability()));
+ 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': ['ALFRESCO_ADMINISTRATORS'], 'excludedRoles': ['role1'] };
+
+ expect(await authGuard.canActivate(router)).toBeFalsy();
+ });
+
+ it('Should canActivate be true when the user has none of the excluded roles', async () => {
+ spyOn(jwtHelperService, 'getAccessToken').and.returnValue('my-access_token');
+ spyOn(jwtHelperService, 'decodeToken').and.returnValue({ 'realm_access': { roles: ['role2'] } });
+
+ const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
+ router.data = { 'roles': ['role1', 'role2'], 'excludedRoles': ['role3'] };
+
+ expect(await authGuard.canActivate(router)).toBeTruthy();
+ });
+
+ it('Should canActivate be false when the user is a content admin and the ALFRESCO_ADMINISTRATORS role is excluded', async () => {
+ spyOn(peopleContentService, 'getCurrentPerson').and.returnValue(of(getFakeUserWithContentAdminCapability()));
+ 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'], 'excludedRoles': ['ALFRESCO_ADMINISTRATORS'] };
+
+ expect(await authGuard.canActivate(router)).toBeFalsy();
+ });
+ });
});
diff --git a/lib/core/services/auth-guard-sso-role.service.ts b/lib/core/services/auth-guard-sso-role.service.ts
index 60c1087b0c..605c087463 100644
--- a/lib/core/services/auth-guard-sso-role.service.ts
+++ b/lib/core/services/auth-guard-sso-role.service.ts
@@ -39,8 +39,9 @@ export class AuthGuardSsoRoleService implements CanActivate {
if (route.data) {
if (route.data['roles']) {
const rolesToCheck: string[] = route.data['roles'];
- const isContentAdmin = rolesToCheck.includes(ContentGroups.ALFRESCO_ADMINISTRATORS) ? await this.peopleContentService.isContentAdmin() : false;
- hasRealmRole = this.jwtHelperService.hasRealmRoles(rolesToCheck) || isContentAdmin;
+ const excludedRoles = route.data['excludedRoles'] || [];
+ const isContentAdmin = rolesToCheck.includes(ContentGroups.ALFRESCO_ADMINISTRATORS) || excludedRoles.includes(ContentGroups.ALFRESCO_ADMINISTRATORS) ? await this.peopleContentService.isContentAdmin() : false;
+ hasRealmRole = excludedRoles.length ? this.checkAccessWithExcludedRoles(rolesToCheck, excludedRoles, isContentAdmin) : this.hasRoles(rolesToCheck, isContentAdmin);
}
if (route.data['clientRoles']) {
@@ -62,4 +63,12 @@ export class AuthGuardSsoRoleService implements CanActivate {
return hasRole;
}
+
+ private checkAccessWithExcludedRoles(rolesToCheck: string[], excludedRoles: string[], isContentAdmin: boolean): boolean {
+ return this.hasRoles(rolesToCheck, isContentAdmin) && !this.hasRoles(excludedRoles, isContentAdmin);
+ }
+
+ private hasRoles(rolesToCheck: string[], isContentAdmin: boolean): boolean {
+ return rolesToCheck.includes(ContentGroups.ALFRESCO_ADMINISTRATORS) ? this.jwtHelperService.hasRealmRoles(rolesToCheck) || isContentAdmin : this.jwtHelperService.hasRealmRoles(rolesToCheck);
+ }
}