mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
71429: Unauthorized page fixes
This commit is contained in:
@@ -245,7 +245,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}));
|
||||
this.canImpersonate$ = this.epersonService.getActiveEPerson().pipe(
|
||||
switchMap((eperson) => this.authorizationService.isAuthenticated(FeatureID.LoginOnBehalfOf, hasValue(eperson) ? eperson.self : undefined))
|
||||
switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.LoginOnBehalfOf, hasValue(eperson) ? eperson.self : undefined))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@@ -360,7 +360,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
||||
* Create menu sections dependent on whether or not the current user is a site administrator
|
||||
*/
|
||||
createSiteAdministratorMenuSections() {
|
||||
this.authorizationService.isAuthenticated(FeatureID.AdministratorOf).subscribe((authorized) => {
|
||||
this.authorizationService.isAuthorized(FeatureID.AdministratorOf).subscribe((authorized) => {
|
||||
const menuList = [
|
||||
/* Access Control */
|
||||
{
|
||||
|
@@ -64,6 +64,12 @@ export function getDSOPath(dso: DSpaceObject): string {
|
||||
}
|
||||
}
|
||||
|
||||
const UNAUTHORIZED_PATH = 'unauthorized';
|
||||
|
||||
export function getUnauthorizedPath() {
|
||||
return `/${UNAUTHORIZED_PATH}`;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot([
|
||||
@@ -100,7 +106,7 @@ export function getDSOPath(dso: DSpaceObject): string {
|
||||
path: PROFILE_MODULE_PATH,
|
||||
loadChildren: './profile-page/profile-page.module#ProfilePageModule', canActivate: [AuthenticatedGuard]
|
||||
},
|
||||
{ path: '401', component: UnauthorizedComponent },
|
||||
{ path: UNAUTHORIZED_PATH, component: UnauthorizedComponent },
|
||||
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent },
|
||||
],
|
||||
{
|
||||
|
@@ -51,13 +51,13 @@ describe('AuthorizationDataService', () => {
|
||||
const objectUrl = 'fake-object-url';
|
||||
const ePersonUuid = 'fake-eperson-uuid';
|
||||
|
||||
function createExpected(objectUrl: string, ePersonUuid?: string, featureId?: FeatureID): FindListOptions {
|
||||
const searchParams = [new RequestParam('uri', objectUrl)];
|
||||
if (hasValue(featureId)) {
|
||||
searchParams.push(new RequestParam('feature', featureId));
|
||||
function createExpected(providedObjectUrl: string, providedEPersonUuid?: string, providedFeatureId?: FeatureID): FindListOptions {
|
||||
const searchParams = [new RequestParam('uri', providedObjectUrl)];
|
||||
if (hasValue(providedFeatureId)) {
|
||||
searchParams.push(new RequestParam('feature', providedFeatureId));
|
||||
}
|
||||
if (hasValue(ePersonUuid)) {
|
||||
searchParams.push(new RequestParam('eperson', ePersonUuid));
|
||||
if (hasValue(providedEPersonUuid)) {
|
||||
searchParams.push(new RequestParam('eperson', providedEPersonUuid));
|
||||
}
|
||||
return Object.assign(new FindListOptions(), { searchParams });
|
||||
}
|
||||
@@ -114,7 +114,7 @@ describe('AuthorizationDataService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAuthenticated', () => {
|
||||
describe('isAuthorized', () => {
|
||||
const validPayload = [
|
||||
Object.assign(new Authorization())
|
||||
]
|
||||
@@ -126,7 +126,7 @@ describe('AuthorizationDataService', () => {
|
||||
});
|
||||
|
||||
it('should return false', (done) => {
|
||||
service.isAuthenticated().subscribe((result) => {
|
||||
service.isAuthorized().subscribe((result) => {
|
||||
expect(result).toEqual(false);
|
||||
done();
|
||||
});
|
||||
@@ -139,7 +139,7 @@ describe('AuthorizationDataService', () => {
|
||||
});
|
||||
|
||||
it('should return false', (done) => {
|
||||
service.isAuthenticated().subscribe((result) => {
|
||||
service.isAuthorized().subscribe((result) => {
|
||||
expect(result).toEqual(false);
|
||||
done();
|
||||
});
|
||||
@@ -152,7 +152,7 @@ describe('AuthorizationDataService', () => {
|
||||
});
|
||||
|
||||
it('should return true', (done) => {
|
||||
service.isAuthenticated().subscribe((result) => {
|
||||
service.isAuthorized().subscribe((result) => {
|
||||
expect(result).toEqual(true);
|
||||
done();
|
||||
});
|
||||
|
@@ -60,7 +60,7 @@ export class AuthorizationDataService extends DataService<Authorization> {
|
||||
* If not provided, the UUID of the currently authenticated {@link EPerson} will be used.
|
||||
* @param featureId ID of the {@link Feature} to check {@link Authorization} for
|
||||
*/
|
||||
isAuthenticated(featureId?: FeatureID, objectUrl?: string, ePersonUuid?: string): Observable<boolean> {
|
||||
isAuthorized(featureId?: FeatureID, objectUrl?: string, ePersonUuid?: string): Observable<boolean> {
|
||||
return this.searchByObject(featureId, objectUrl, ePersonUuid).pipe(
|
||||
map((authorizationRD) => (authorizationRD.statusCode !== 401 && hasValue(authorizationRD.payload) && isNotEmpty(authorizationRD.payload.page)))
|
||||
);
|
||||
|
@@ -2,6 +2,7 @@ import { FeatureAuthorizationGuard } from './feature-authorization.guard';
|
||||
import { AuthorizationDataService } from '../authorization-data.service';
|
||||
import { FeatureID } from '../feature-id';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
/**
|
||||
* Test implementation of abstract class FeatureAuthorizationGuard
|
||||
@@ -9,10 +10,11 @@ import { of as observableOf } from 'rxjs';
|
||||
*/
|
||||
class FeatureAuthorizationGuardImpl extends FeatureAuthorizationGuard {
|
||||
constructor(protected authorizationService: AuthorizationDataService,
|
||||
protected router: Router,
|
||||
protected featureId: FeatureID,
|
||||
protected objectUrl: string,
|
||||
protected ePersonUuid: string) {
|
||||
super(authorizationService);
|
||||
super(authorizationService, router);
|
||||
}
|
||||
|
||||
getFeatureID(): FeatureID {
|
||||
@@ -31,6 +33,7 @@ class FeatureAuthorizationGuardImpl extends FeatureAuthorizationGuard {
|
||||
describe('FeatureAuthorizationGuard', () => {
|
||||
let guard: FeatureAuthorizationGuard;
|
||||
let authorizationService: AuthorizationDataService;
|
||||
let router: Router;
|
||||
|
||||
let featureId: FeatureID;
|
||||
let objectUrl: string;
|
||||
@@ -44,7 +47,10 @@ describe('FeatureAuthorizationGuard', () => {
|
||||
authorizationService = jasmine.createSpyObj('authorizationService', {
|
||||
isAuthenticated: observableOf(true)
|
||||
});
|
||||
guard = new FeatureAuthorizationGuardImpl(authorizationService, featureId, objectUrl, ePersonUuid);
|
||||
router = jasmine.createSpyObj('router', {
|
||||
navigateByUrl: {}
|
||||
});
|
||||
guard = new FeatureAuthorizationGuardImpl(authorizationService, router, featureId, objectUrl, ePersonUuid);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -54,14 +60,7 @@ describe('FeatureAuthorizationGuard', () => {
|
||||
describe('canActivate', () => {
|
||||
it('should call authorizationService.isAuthenticated with the appropriate arguments', () => {
|
||||
guard.canActivate(undefined, undefined).subscribe();
|
||||
expect(authorizationService.isAuthenticated).toHaveBeenCalledWith(featureId, objectUrl, ePersonUuid);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canLoad', () => {
|
||||
it('should call authorizationService.isAuthenticated with the appropriate arguments', () => {
|
||||
guard.canLoad(undefined, undefined).subscribe();
|
||||
expect(authorizationService.isAuthenticated).toHaveBeenCalledWith(featureId, objectUrl, ePersonUuid);
|
||||
expect(authorizationService.isAuthorized).toHaveBeenCalledWith(featureId, objectUrl, ePersonUuid);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,23 +1,21 @@
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
CanActivate,
|
||||
CanLoad,
|
||||
Route,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
UrlSegment
|
||||
UrlTree
|
||||
} from '@angular/router';
|
||||
import { AuthorizationDataService } from '../authorization-data.service';
|
||||
import { FeatureID } from '../feature-id';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { redirectToUnauthorizedOnFalse } from '../../../shared/operators';
|
||||
import { returnUnauthorizedUrlTreeOnFalse } from '../../../shared/operators';
|
||||
|
||||
/**
|
||||
* Abstract Guard for preventing unauthorized activating and loading of routes when a user
|
||||
* doesn't have authorized rights on a specific feature and/or object.
|
||||
* Override the desired getters in the parent class for checking specific authorization on a feature and/or object.
|
||||
*/
|
||||
export abstract class FeatureAuthorizationGuard implements CanActivate, CanLoad {
|
||||
export abstract class FeatureAuthorizationGuard implements CanActivate {
|
||||
constructor(protected authorizationService: AuthorizationDataService,
|
||||
protected router: Router) {
|
||||
}
|
||||
@@ -26,16 +24,8 @@ export abstract class FeatureAuthorizationGuard implements CanActivate, CanLoad
|
||||
* 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
|
||||
*/
|
||||
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
||||
return this.authorizationService.isAuthenticated(this.getFeatureID(), this.getObjectUrl(), this.getEPersonUuid()).pipe(redirectToUnauthorizedOnFalse(this.router));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> {
|
||||
return this.authorizationService.isAuthenticated(this.getFeatureID(), this.getObjectUrl(), this.getEPersonUuid()).pipe(redirectToUnauthorizedOnFalse(this.router));
|
||||
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
|
||||
return this.authorizationService.isAuthorized(this.getFeatureID(), this.getObjectUrl(), this.getEPersonUuid()).pipe(returnUnauthorizedUrlTreeOnFalse(this.router));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Router } from '@angular/router';
|
||||
import { Router, UrlTree } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, find, flatMap, map, take, tap } from 'rxjs/operators';
|
||||
import { hasValue, hasValueOperator, isNotEmpty } from '../../shared/empty.util';
|
||||
@@ -11,6 +11,7 @@ import { RequestEntry } from '../data/request.reducer';
|
||||
import { RequestService } from '../data/request.service';
|
||||
import { BrowseDefinition } from './browse-definition.model';
|
||||
import { DSpaceObject } from './dspace-object.model';
|
||||
import { getUnauthorizedPath } from '../../app-routing.module';
|
||||
|
||||
/**
|
||||
* This file contains custom RxJS operators that can be used in multiple places
|
||||
@@ -181,16 +182,14 @@ export const redirectToPageNotFoundOn404 = (router: Router) =>
|
||||
}));
|
||||
|
||||
/**
|
||||
* Operator that redirects the user to the unauthorized page when the boolean received is false
|
||||
* Operator that returns a UrlTree to the unauthorized page when the boolean received is false
|
||||
* @param router
|
||||
*/
|
||||
export const redirectToUnauthorizedOnFalse = (router: Router) =>
|
||||
(source: Observable<boolean>): Observable<boolean> =>
|
||||
export const returnUnauthorizedUrlTreeOnFalse = (router: Router) =>
|
||||
(source: Observable<boolean>): Observable<boolean | UrlTree> =>
|
||||
source.pipe(
|
||||
tap((authorized: boolean) => {
|
||||
if (!authorized) {
|
||||
router.navigateByUrl('/401', { skipLocationChange: true });
|
||||
}
|
||||
map((authorized: boolean) => {
|
||||
return authorized ? authorized : router.parseUrl(getUnauthorizedPath())
|
||||
}));
|
||||
|
||||
export const getFinishedRemoteData = () =>
|
||||
|
Reference in New Issue
Block a user