Skip to content

Commit

Permalink
security : protect access to the resource editor
Browse files Browse the repository at this point in the history
Add guard for any resources to disallow access to the editor based on user permissions API.
Add a basic error page management

* Without this fix, user can access to a resources editor but cannot apply any changes (backend return 403 - forbidden).
* With this fix, user without required privileges cannot access to the resource editor.
* Closes rero/rero-ils#575

Co-Authored-by: Renaud Michotte <renaud.michotte@gmail.com>
  • Loading branch information
zannkukai committed Apr 2, 2020
1 parent febaf66 commit 161c648
Show file tree
Hide file tree
Showing 17 changed files with 180 additions and 37 deletions.
7 changes: 5 additions & 2 deletions projects/admin/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ import { RemoteAutocompleteInputTypeComponent } from './record/editor/remote-aut
import { ItemAvailabilityComponent } from './record/item-availability/item-availability.component';
import { AppConfigService } from './service/app-config.service';
import { TranslateLoader } from './translate/loader/translate-loader';
import { ErrorPageComponent } from './error/error-page/error-page.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -170,7 +171,8 @@ import { TranslateLoader } from './translate/loader/translate-loader';
FrontpageBoardComponent,
RelatedResourceComponent,
ResourceComponent,
ItemRequestComponent
ItemRequestComponent,
ErrorPageComponent
],
imports: [
AppRoutingModule,
Expand Down Expand Up @@ -256,7 +258,8 @@ import { TranslateLoader } from './translate/loader/translate-loader';
BudgetsBriefViewComponent,
BudgetDetailViewComponent,
OrganisationDetailViewComponent,
ItemRequestComponent
ItemRequestComponent,
ErrorPageComponent
],
bootstrap: [AppComponent]
})
Expand Down
70 changes: 70 additions & 0 deletions projects/admin/src/app/error/error-page/error-page.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { ActivatedRoute } from '@angular/router';
import { Component, OnInit } from '@angular/core';
import { map } from 'rxjs/operators';
import { marker } from '@biesbjerg/ngx-translate-extract-marker';

export function _(str) {
return marker(str);
}

@Component({
selector: 'admin-error-page',
template: `
<div class="alert alert-{{ messages[statusCode].level || 'danger' }}">
<h1 class="alert-heading mb-4">{{ statusCode }} - {{ messages[statusCode].title }}</h1>
<pre *ngFor="let text of messages[statusCode].description || []">{{ text }}</pre>
<hr>
<p>For any information please contact system administrator</p>
</div>
`
})

export class ErrorPageComponent implements OnInit {

/** the status code to display. By default 404 : Page not found */
statusCode = 404;
/** All messages ablt to be managed by this component. Availables for each error are :
* - title : the error title
* - description : A human readable description of this error as Array<string>. Each array
* element will be a separate line.
* - level: the boostrap alert look-and-feel level to use for the error. 'danger' by default.
*/
messages = {
401: {
title: _('Unauthorized'),
description: [_('Access denied due to invalid credentials.')],
level: 'warning'
},
403: {
title: _('Forbidden access'),
description: [_('You don\'t have permission to access this page.')],
level: 'warning'
},
404: {
title: _('Page not found'),
description: [_('Woops. Looks like this page doesn\'t exists')]
},
418: {
title: _('I\'m a teapot'),
description: [
_('The requested entity body is short and stout'),
_('Tip me over and pour me out')
],
level: 'success'
},
500: {
title: _('Internal server error'),
desctiption: [_('Oops, Something went wrong !')]
}
};

constructor(private _route: ActivatedRoute) { }

ngOnInit() {
this._route.params.pipe(
map(params => params.status_code || 404), // check for status_code parameter from ActivatedRoute
map(code => /^\d+$/.test(code) ? parseInt(code, 10) : 404), // try to parse status code to integer
map(code => code in this.messages ? code : 404) // check if http code definition exists
).subscribe(code => this.statusCode = code );
}
}
46 changes: 46 additions & 0 deletions projects/admin/src/app/guard/can-update.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
CanActivate,
ActivatedRouteSnapshot,
Router,
RouterStateSnapshot,
UrlTree,
NavigationError
} from '@angular/router';
import { Injectable } from '@angular/core';
import {Observable, throwError} from 'rxjs';
import { RecordPermission, RecordPermissionService } from '../service/record-permission.service';
import { ToastrService } from 'ngx-toastr';
import { TranslateService } from '@ngx-translate/core';


@Injectable({
providedIn: 'root'
})
export class CanUpdateGuard implements CanActivate {

constructor(
private _permissionService: RecordPermissionService,
private _toastrService: ToastrService,
private _translateService: TranslateService,
private _router: Router) {
}

/**
* Check if the current logged user can update a resource
* @param next - ActivatedRouteSnapshot
* @param state - RouterStateSnapshot
*/
canActivate(next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

this._permissionService.getPermission(next.params.type, next.params.pid).subscribe(
(permission: RecordPermission) => {
if (!permission.update.can) {
this._router.navigate(['/errors/403']);
}
}
);
return true;
}

}
5 changes: 3 additions & 2 deletions projects/admin/src/app/routes/acquisition-accounts-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { RouteInterface, EditorComponent, extractIdOnRef } from '@rero/ng-core';
import { BaseRoute } from './Base-route';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { RouteInterface, EditorComponent, extractIdOnRef } from '@rero/ng-core';
import { of } from 'rxjs';

export class AcquisitionAccountsRoute extends BaseRoute implements RouteInterface {
Expand All @@ -31,7 +32,7 @@ export class AcquisitionAccountsRoute extends BaseRoute implements RouteInterfac
return {
matcher: (url: any) => this.routeMatcher(url, this.name),
children: [
{ path: 'edit/:pid', component: EditorComponent },
{ path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: EditorComponent }
],
data: {
Expand Down
11 changes: 6 additions & 5 deletions projects/admin/src/app/routes/acquisition-order-lines-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { DetailComponent, EditorComponent, extractIdOnRef, RecordService, RouteInterface} from '@rero/ng-core';
import { BaseRoute } from './Base-route';
import { FormlyFieldConfig } from '@ngx-formly/core';
import { JSONSchema7 } from 'json-schema';
import {
AcquisitionOrderLineDetailViewComponent
} from '../record/detail-view/acquisition-order-line-detail-view/acquisition-order-line-detail-view.component';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { BaseRoute } from './Base-route';
import { DetailComponent, EditorComponent, extractIdOnRef, RecordService, RouteInterface} from '@rero/ng-core';
import { FormlyFieldConfig } from '@ngx-formly/core';
import { JSONSchema7 } from 'json-schema';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';

Expand All @@ -41,7 +42,7 @@ export class AcquisitionOrderLinesRoute extends BaseRoute implements RouteInterf
matcher: (url: any) => this.routeMatcher(url, this.name),
children: [
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: EditorComponent },
{ path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: EditorComponent }
],
data: {
Expand Down
9 changes: 5 additions & 4 deletions projects/admin/src/app/routes/acquisition-orders-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { BaseRoute } from './Base-route';
import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core';
import { formatDate } from '@angular/common';
import { AcquisitionOrderBriefViewComponent } from '../record/brief-view/acquisition-order-brief-view.component';
import {
AcquisitionOrderDetailViewComponent
} from '../record/detail-view/acquisition-order-detail-view/acquisition-order-detail-view.component';
import { BaseRoute } from './Base-route';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core';
import { formatDate } from '@angular/common';

export class AcquisitionOrdersRoute extends BaseRoute implements RouteInterface {

Expand All @@ -40,7 +41,7 @@ export class AcquisitionOrdersRoute extends BaseRoute implements RouteInterface
children: [
{ path: '', component: RecordSearchComponent },
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: EditorComponent },
{ path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: EditorComponent }
],
data: {
Expand Down
6 changes: 4 additions & 2 deletions projects/admin/src/app/routes/budgets-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core';
import { BaseRoute } from './Base-route';
import { BudgetsBriefViewComponent } from '../record/brief-view/budgets-brief-view.component';
import { BudgetDetailViewComponent } from '../record/detail-view/budget-detail-view/budget-detail-view.component';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core';


export class BudgetsRoute extends BaseRoute implements RouteInterface {

Expand All @@ -37,7 +39,7 @@ export class BudgetsRoute extends BaseRoute implements RouteInterface {
children: [
{ path: '', component: RecordSearchComponent },
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: EditorComponent },
{ path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: EditorComponent }
],
data: {
Expand Down
5 changes: 3 additions & 2 deletions projects/admin/src/app/routes/circulation-policies-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { BaseRoute } from './Base-route';
import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { CirculationPolicyComponent } from '../record/custom-editor/circulation-settings/circulation-policy/circulation-policy.component';
import { CircPoliciesBriefViewComponent } from '../record/brief-view/circ-policies-brief-view.component';
import { CircPolicyDetailViewComponent } from '../record/detail-view/circ-policy-detail-view/circ-policy-detail-view.component';
import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core';

export class CirculationPoliciesRoute extends BaseRoute implements RouteInterface {

Expand All @@ -38,7 +39,7 @@ export class CirculationPoliciesRoute extends BaseRoute implements RouteInterfac
children: [
{ path: '', component: RecordSearchComponent },
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: CirculationPolicyComponent },
{ path: 'edit/:pid', component: CirculationPolicyComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: CirculationPolicyComponent }
],
data: {
Expand Down
10 changes: 6 additions & 4 deletions projects/admin/src/app/routes/documents-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core';
import { DocumentEditorComponent } from '../record/custom-editor/document-editor/document-editor.component';

import { BaseRoute } from './Base-route';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { DocumentsBriefViewComponent } from '../record/brief-view/documents-brief-view/documents-brief-view.component';
import { DocumentDetailViewComponent } from '../record/detail-view/document-detail-view/document-detail-view.component';
import { BaseRoute } from './Base-route';
import { DocumentEditorComponent } from '../record/custom-editor/document-editor/document-editor.component';
import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core';

export class DocumentsRoute extends BaseRoute implements RouteInterface {

Expand All @@ -38,7 +40,7 @@ export class DocumentsRoute extends BaseRoute implements RouteInterface {
children: [
{ path: '', component: RecordSearchComponent },
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: DocumentEditorComponent },
{ path: 'edit/:pid', component: DocumentEditorComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: DocumentEditorComponent }
],
data: {
Expand Down
8 changes: 5 additions & 3 deletions projects/admin/src/app/routes/item-types-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core';
import { BaseRoute } from './Base-route';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { ItemTypesBriefViewComponent } from '../record/brief-view/item-types-brief-view.component';
import { ItemTypeDetailViewComponent } from '../record/detail-view/item-type-detail-view.component';
import { BaseRoute } from './Base-route';
import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core';


export class ItemTypesRoute extends BaseRoute implements RouteInterface {

Expand All @@ -37,7 +39,7 @@ export class ItemTypesRoute extends BaseRoute implements RouteInterface {
children: [
{ path: '', component: RecordSearchComponent },
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: EditorComponent },
{ path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: EditorComponent }
],
data: {
Expand Down
9 changes: 6 additions & 3 deletions projects/admin/src/app/routes/libraries-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core';
import { BaseRoute } from './Base-route';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { DetailComponent, RecordSearchComponent, RouteInterface } from '@rero/ng-core';
import { LibraryComponent } from '../record/custom-editor/libraries/library.component';
import { LibrariesBriefViewComponent } from '../record/brief-view/libraries-brief-view/libraries-brief-view.component';
import { LibraryDetailViewComponent } from '../record/detail-view/library-detail-view/library-detail-view.component';
import { BaseRoute } from './Base-route';



export class LibrariesRoute extends BaseRoute implements RouteInterface {

Expand All @@ -38,7 +41,7 @@ export class LibrariesRoute extends BaseRoute implements RouteInterface {
children: [
{ path: '', component: RecordSearchComponent },
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: LibraryComponent },
{ path: 'edit/:pid', component: LibraryComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: LibraryComponent }
],
data: {
Expand Down
5 changes: 3 additions & 2 deletions projects/admin/src/app/routes/locations-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { BaseRoute } from './Base-route';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { RouteInterface, DetailComponent, EditorComponent } from '@rero/ng-core';
import { LocationDetailViewComponent } from '../record/detail-view/location-detail-view/location-detail-view.component';

Expand All @@ -32,10 +33,10 @@ export class LocationsRoute extends BaseRoute implements RouteInterface {
*/
getConfiguration() {
return {
matcher: (url: any) => this.routeMatcher(url, 'locations'),
matcher: (url: any) => this.routeMatcher(url, this.name),
children: [
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: EditorComponent },
{ path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] },
{ path: 'new', component: EditorComponent }
],
data: {
Expand Down
5 changes: 3 additions & 2 deletions projects/admin/src/app/routes/organisations-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { RouteInterface, DetailComponent, EditorComponent } from '@rero/ng-core';
import { BaseRoute } from './Base-route';
import { CanUpdateGuard } from '../guard/can-update.guard';
import { OrganisationDetailViewComponent } from '../record/detail-view/organisation-detail-view/organisation-detail-view.component';
import { RouteInterface, DetailComponent, EditorComponent } from '@rero/ng-core';

export class OrganisationsRoute extends BaseRoute implements RouteInterface {

Expand All @@ -32,7 +33,7 @@ export class OrganisationsRoute extends BaseRoute implements RouteInterface {
matcher: (url: any) => this.routeMatcher(url, this.name),
children: [
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: EditorComponent }
{ path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }
],
data: {
linkPrefix: 'records',
Expand Down
Loading

0 comments on commit 161c648

Please sign in to comment.