mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-15 14:03:06 +00:00
71764: DsoPageAdministratorGuard
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { DsoPageAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-administrator.guard';
|
||||||
|
import { Collection } from '../core/shared/collection.model';
|
||||||
|
import { CollectionPageResolver } from './collection-page.resolver';
|
||||||
|
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* Guard for preventing unauthorized access to certain {@link Collection} pages requiring administrator rights
|
||||||
|
*/
|
||||||
|
export class CollectionPageAdministratorGuard extends DsoPageAdministratorGuard<Collection> {
|
||||||
|
constructor(protected resolver: CollectionPageResolver,
|
||||||
|
protected authorizationService: AuthorizationDataService,
|
||||||
|
protected router: Router) {
|
||||||
|
super(resolver, authorizationService, router);
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,7 @@ import { CollectionBreadcrumbResolver } from '../core/breadcrumbs/collection-bre
|
|||||||
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
||||||
import { LinkService } from '../core/cache/builders/link.service';
|
import { LinkService } from '../core/cache/builders/link.service';
|
||||||
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||||
|
import { CollectionPageAdministratorGuard } from './collection-page-administrator.guard';
|
||||||
|
|
||||||
export const COLLECTION_PARENT_PARAMETER = 'parent';
|
export const COLLECTION_PARENT_PARAMETER = 'parent';
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ const ITEMTEMPLATE_PATH = 'itemtemplate';
|
|||||||
{
|
{
|
||||||
path: COLLECTION_EDIT_PATH,
|
path: COLLECTION_EDIT_PATH,
|
||||||
loadChildren: './edit-collection-page/edit-collection-page.module#EditCollectionPageModule',
|
loadChildren: './edit-collection-page/edit-collection-page.module#EditCollectionPageModule',
|
||||||
canActivate: [AuthenticatedGuard]
|
canActivate: [CollectionPageAdministratorGuard]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'delete',
|
path: 'delete',
|
||||||
@@ -93,7 +94,8 @@ const ITEMTEMPLATE_PATH = 'itemtemplate';
|
|||||||
CollectionBreadcrumbResolver,
|
CollectionBreadcrumbResolver,
|
||||||
DSOBreadcrumbsService,
|
DSOBreadcrumbsService,
|
||||||
LinkService,
|
LinkService,
|
||||||
CreateCollectionPageGuard
|
CreateCollectionPageGuard,
|
||||||
|
CollectionPageAdministratorGuard
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CollectionPageRoutingModule {
|
export class CollectionPageRoutingModule {
|
||||||
|
@@ -0,0 +1,20 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { DsoPageAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-administrator.guard';
|
||||||
|
import { Community } from '../core/shared/community.model';
|
||||||
|
import { CommunityPageResolver } from './community-page.resolver';
|
||||||
|
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* Guard for preventing unauthorized access to certain {@link Community} pages requiring administrator rights
|
||||||
|
*/
|
||||||
|
export class CommunityPageAdministratorGuard extends DsoPageAdministratorGuard<Community> {
|
||||||
|
constructor(protected resolver: CommunityPageResolver,
|
||||||
|
protected authorizationService: AuthorizationDataService,
|
||||||
|
protected router: Router) {
|
||||||
|
super(resolver, authorizationService, router);
|
||||||
|
}
|
||||||
|
}
|
@@ -12,6 +12,7 @@ import { getCommunityModulePath } from '../app-routing.module';
|
|||||||
import { CommunityBreadcrumbResolver } from '../core/breadcrumbs/community-breadcrumb.resolver';
|
import { CommunityBreadcrumbResolver } from '../core/breadcrumbs/community-breadcrumb.resolver';
|
||||||
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
||||||
import { LinkService } from '../core/cache/builders/link.service';
|
import { LinkService } from '../core/cache/builders/link.service';
|
||||||
|
import { CommunityPageAdministratorGuard } from './community-page-administrator.guard';
|
||||||
|
|
||||||
export const COMMUNITY_PARENT_PARAMETER = 'parent';
|
export const COMMUNITY_PARENT_PARAMETER = 'parent';
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ const COMMUNITY_EDIT_PATH = 'edit';
|
|||||||
{
|
{
|
||||||
path: COMMUNITY_EDIT_PATH,
|
path: COMMUNITY_EDIT_PATH,
|
||||||
loadChildren: './edit-community-page/edit-community-page.module#EditCommunityPageModule',
|
loadChildren: './edit-community-page/edit-community-page.module#EditCommunityPageModule',
|
||||||
canActivate: [AuthenticatedGuard]
|
canActivate: [CommunityPageAdministratorGuard]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'delete',
|
path: 'delete',
|
||||||
@@ -71,7 +72,8 @@ const COMMUNITY_EDIT_PATH = 'edit';
|
|||||||
CommunityBreadcrumbResolver,
|
CommunityBreadcrumbResolver,
|
||||||
DSOBreadcrumbsService,
|
DSOBreadcrumbsService,
|
||||||
LinkService,
|
LinkService,
|
||||||
CreateCommunityPageGuard
|
CreateCommunityPageGuard,
|
||||||
|
CommunityPageAdministratorGuard
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CommunityPageRoutingModule {
|
export class CommunityPageRoutingModule {
|
||||||
|
20
src/app/+item-page/item-page-administrator.guard.ts
Normal file
20
src/app/+item-page/item-page-administrator.guard.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { DsoPageAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-administrator.guard';
|
||||||
|
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||||
|
import { ItemPageResolver } from './item-page.resolver';
|
||||||
|
import { Item } from '../core/shared/item.model';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* Guard for preventing unauthorized access to certain {@link Item} pages requiring administrator rights
|
||||||
|
*/
|
||||||
|
export class ItemPageAdministratorGuard extends DsoPageAdministratorGuard<Item> {
|
||||||
|
constructor(protected resolver: ItemPageResolver,
|
||||||
|
protected authorizationService: AuthorizationDataService,
|
||||||
|
protected router: Router) {
|
||||||
|
super(resolver, authorizationService, router);
|
||||||
|
}
|
||||||
|
}
|
@@ -11,6 +11,7 @@ import { ItemBreadcrumbResolver } from '../core/breadcrumbs/item-breadcrumb.reso
|
|||||||
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
||||||
import { LinkService } from '../core/cache/builders/link.service';
|
import { LinkService } from '../core/cache/builders/link.service';
|
||||||
import { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.component';
|
import { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.component';
|
||||||
|
import { ItemPageAdministratorGuard } from './item-page-administrator.guard';
|
||||||
|
|
||||||
export function getItemPageRoute(itemId: string) {
|
export function getItemPageRoute(itemId: string) {
|
||||||
return new URLCombiner(getItemModulePath(), itemId).toString();
|
return new URLCombiner(getItemModulePath(), itemId).toString();
|
||||||
@@ -46,7 +47,7 @@ const UPLOAD_BITSTREAM_PATH = 'bitstreams/new';
|
|||||||
{
|
{
|
||||||
path: ITEM_EDIT_PATH,
|
path: ITEM_EDIT_PATH,
|
||||||
loadChildren: './edit-item-page/edit-item-page.module#EditItemPageModule',
|
loadChildren: './edit-item-page/edit-item-page.module#EditItemPageModule',
|
||||||
canActivate: [AuthenticatedGuard]
|
canActivate: [ItemPageAdministratorGuard]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: UPLOAD_BITSTREAM_PATH,
|
path: UPLOAD_BITSTREAM_PATH,
|
||||||
@@ -61,7 +62,8 @@ const UPLOAD_BITSTREAM_PATH = 'bitstreams/new';
|
|||||||
ItemPageResolver,
|
ItemPageResolver,
|
||||||
ItemBreadcrumbResolver,
|
ItemBreadcrumbResolver,
|
||||||
DSOBreadcrumbsService,
|
DSOBreadcrumbsService,
|
||||||
LinkService
|
LinkService,
|
||||||
|
ItemPageAdministratorGuard
|
||||||
]
|
]
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@@ -0,0 +1,56 @@
|
|||||||
|
import { DsoPageAdministratorGuard } from './dso-page-administrator.guard';
|
||||||
|
import { AuthorizationDataService } from '../authorization-data.service';
|
||||||
|
import { Resolve, Router } from '@angular/router';
|
||||||
|
import { RemoteData } from '../../remote-data';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
|
||||||
|
import { DSpaceObject } from '../../../shared/dspace-object.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test implementation of abstract class DsoPageAdministratorGuard
|
||||||
|
*/
|
||||||
|
class DsoPageAdministratorGuardImpl extends DsoPageAdministratorGuard<any> {
|
||||||
|
constructor(protected resolver: Resolve<RemoteData<any>>,
|
||||||
|
protected authorizationService: AuthorizationDataService,
|
||||||
|
protected router: Router) {
|
||||||
|
super(resolver, authorizationService, router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('DsoPageAdministratorGuard', () => {
|
||||||
|
let guard: DsoPageAdministratorGuard<any>;
|
||||||
|
let authorizationService: AuthorizationDataService;
|
||||||
|
let router: Router;
|
||||||
|
let resolver: Resolve<RemoteData<any>>;
|
||||||
|
let object: DSpaceObject;
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
object = {
|
||||||
|
self: 'test-selflink'
|
||||||
|
} as DSpaceObject;
|
||||||
|
|
||||||
|
authorizationService = jasmine.createSpyObj('authorizationService', {
|
||||||
|
isAuthorized: observableOf(true)
|
||||||
|
});
|
||||||
|
router = jasmine.createSpyObj('router', {
|
||||||
|
parseUrl: {}
|
||||||
|
});
|
||||||
|
resolver = jasmine.createSpyObj('resolver', {
|
||||||
|
resolve: createSuccessfulRemoteDataObject$(object)
|
||||||
|
});
|
||||||
|
guard = new DsoPageAdministratorGuardImpl(resolver, authorizationService, router);
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getObjectUrl', () => {
|
||||||
|
it('should return the resolved object\'s selflink', (done) => {
|
||||||
|
guard.getObjectUrl(undefined, undefined).subscribe((selflink) => {
|
||||||
|
expect(selflink).toEqual(object.self);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,39 @@
|
|||||||
|
import { FeatureAuthorizationGuard } from './feature-authorization.guard';
|
||||||
|
import { AuthorizationDataService } from '../authorization-data.service';
|
||||||
|
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { DSpaceObject } from '../../../shared/dspace-object.model';
|
||||||
|
import { FeatureID } from '../feature-id';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { RemoteData } from '../../remote-data';
|
||||||
|
import { getAllSucceededRemoteDataPayload } from '../../../shared/operators';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Guard for preventing unauthorized access to {@link DSpaceObject} pages that require administrator rights
|
||||||
|
* This guard utilizes a resolver to retrieve the relevant object to check authorizations for
|
||||||
|
*/
|
||||||
|
export abstract class DsoPageAdministratorGuard<T extends DSpaceObject> extends FeatureAuthorizationGuard {
|
||||||
|
constructor(protected resolver: Resolve<RemoteData<T>>,
|
||||||
|
protected authorizationService: AuthorizationDataService,
|
||||||
|
protected router: Router) {
|
||||||
|
super(authorizationService, router);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check administrator authorization rights
|
||||||
|
*/
|
||||||
|
getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
|
||||||
|
return observableOf(FeatureID.AdministratorOf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check authorization rights for the object resolved using the provided resolver
|
||||||
|
*/
|
||||||
|
getObjectUrl(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<string> {
|
||||||
|
return (this.resolver.resolve(route, state) as Observable<RemoteData<T>>).pipe(
|
||||||
|
getAllSucceededRemoteDataPayload(),
|
||||||
|
map((dso) => dso.self)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -2,7 +2,8 @@ import { FeatureAuthorizationGuard } from './feature-authorization.guard';
|
|||||||
import { AuthorizationDataService } from '../authorization-data.service';
|
import { AuthorizationDataService } from '../authorization-data.service';
|
||||||
import { FeatureID } from '../feature-id';
|
import { FeatureID } from '../feature-id';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { Router } from '@angular/router';
|
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test implementation of abstract class FeatureAuthorizationGuard
|
* Test implementation of abstract class FeatureAuthorizationGuard
|
||||||
@@ -17,16 +18,16 @@ class FeatureAuthorizationGuardImpl extends FeatureAuthorizationGuard {
|
|||||||
super(authorizationService, router);
|
super(authorizationService, router);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeatureID(): FeatureID {
|
getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
|
||||||
return this.featureId;
|
return observableOf(this.featureId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getObjectUrl(): string {
|
getObjectUrl(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<string> {
|
||||||
return this.objectUrl;
|
return observableOf(this.objectUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
getEPersonUuid(): string {
|
getEPersonUuid(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<string> {
|
||||||
return this.ePersonUuid;
|
return observableOf(this.ePersonUuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,6 +9,8 @@ import { AuthorizationDataService } from '../authorization-data.service';
|
|||||||
import { FeatureID } from '../feature-id';
|
import { FeatureID } from '../feature-id';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { returnUnauthorizedUrlTreeOnFalse } from '../../../shared/operators';
|
import { returnUnauthorizedUrlTreeOnFalse } from '../../../shared/operators';
|
||||||
|
import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
|
||||||
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract Guard for preventing unauthorized activating and loading of routes when a user
|
* Abstract Guard for preventing unauthorized activating and loading of routes when a user
|
||||||
@@ -24,29 +26,32 @@ export abstract class FeatureAuthorizationGuard implements CanActivate {
|
|||||||
* True when user has authorization rights for the feature and object provided
|
* True when user has authorization rights for the feature and object provided
|
||||||
* Redirect the user to the unauthorized page when he/she's not authorized for the given feature
|
* Redirect the user to the unauthorized page when he/she's not authorized for the given feature
|
||||||
*/
|
*/
|
||||||
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
|
||||||
return this.authorizationService.isAuthorized(this.getFeatureID(), this.getObjectUrl(), this.getEPersonUuid()).pipe(returnUnauthorizedUrlTreeOnFalse(this.router));
|
return observableCombineLatest(this.getFeatureID(route, state), this.getObjectUrl(route, state), this.getEPersonUuid(route, state)).pipe(
|
||||||
|
switchMap(([featureID, objectUrl, ePersonUuid]) => this.authorizationService.isAuthorized(featureID, objectUrl, ePersonUuid)),
|
||||||
|
returnUnauthorizedUrlTreeOnFalse(this.router)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of feature to check authorization for
|
* The type of feature to check authorization for
|
||||||
* Override this method to define a feature
|
* Override this method to define a feature
|
||||||
*/
|
*/
|
||||||
abstract getFeatureID(): FeatureID;
|
abstract getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URL of the object to check if the user has authorized rights for
|
* The URL of the object to check if the user has authorized rights for
|
||||||
* Override this method to define an object URL. If not provided, the {@link Site}'s URL will be used
|
* Override this method to define an object URL. If not provided, the {@link Site}'s URL will be used
|
||||||
*/
|
*/
|
||||||
getObjectUrl(): string {
|
getObjectUrl(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<string> {
|
||||||
return undefined;
|
return observableOf(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The UUID of the user to check authorization rights for
|
* The UUID of the user to check authorization rights for
|
||||||
* Override this method to define an {@link EPerson} UUID. If not provided, the authenticated user's UUID will be used.
|
* Override this method to define an {@link EPerson} UUID. If not provided, the authenticated user's UUID will be used.
|
||||||
*/
|
*/
|
||||||
getEPersonUuid(): string {
|
getEPersonUuid(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<string> {
|
||||||
return undefined;
|
return observableOf(undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,9 @@ import { Injectable } from '@angular/core';
|
|||||||
import { FeatureAuthorizationGuard } from './feature-authorization.guard';
|
import { FeatureAuthorizationGuard } from './feature-authorization.guard';
|
||||||
import { FeatureID } from '../feature-id';
|
import { FeatureID } from '../feature-id';
|
||||||
import { AuthorizationDataService } from '../authorization-data.service';
|
import { AuthorizationDataService } from '../authorization-data.service';
|
||||||
import { Router } from '@angular/router';
|
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent unauthorized activating and loading of routes when the current authenticated user doesn't have administrator
|
* Prevent unauthorized activating and loading of routes when the current authenticated user doesn't have administrator
|
||||||
@@ -19,7 +21,7 @@ export class SiteAdministratorGuard extends FeatureAuthorizationGuard {
|
|||||||
/**
|
/**
|
||||||
* Check administrator authorization rights
|
* Check administrator authorization rights
|
||||||
*/
|
*/
|
||||||
getFeatureID(): FeatureID {
|
getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
|
||||||
return FeatureID.AdministratorOf;
|
return observableOf(FeatureID.AdministratorOf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user