From 537a501b491388b86977e9e0fee9cc5fec1c9e92 Mon Sep 17 00:00:00 2001 From: Yogi_Wang Date: Mon, 9 Sep 2019 14:00:50 +0800 Subject: [PATCH] Add page routing permission to prevent refresh from entering the error page Signed-off-by: Yogi_Wang --- src/portal/src/app/harbor-routing.module.ts | 106 ++++++++++++++---- .../project-detail.component.ts | 1 + ...ember-permission-guard-activate.service.ts | 56 +++++++++ src/portal/src/app/shared/shared.module.ts | 6 +- 4 files changed, 147 insertions(+), 22 deletions(-) create mode 100644 src/portal/src/app/shared/route/member-permission-guard-activate.service.ts diff --git a/src/portal/src/app/harbor-routing.module.ts b/src/portal/src/app/harbor-routing.module.ts index 662b51fe90..df41803927 100644 --- a/src/portal/src/app/harbor-routing.module.ts +++ b/src/portal/src/app/harbor-routing.module.ts @@ -1,13 +1,13 @@ // Copyright Project Harbor Authors // -// Licensed under the Apache License, Version 2.0 (the "License"); +// Licensed under the Apache License, Version 2.0 (the 'License'); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, +// distributed under the License is distributed on an 'AS IS' BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -18,6 +18,7 @@ import { SystemAdminGuard } from './shared/route/system-admin-activate.service'; import { AuthCheckGuard } from './shared/route/auth-user-activate.service'; import { SignInGuard } from './shared/route/sign-in-guard-activate.service'; import { MemberGuard } from './shared/route/member-guard-activate.service'; +import { MemberPermissionGuard } from './shared/route/member-permission-guard-activate.service'; import { OidcGuard } from './shared/route/oidc-guard-active.service'; import { PageNotFoundComponent } from './shared/not-found/not-found.component'; @@ -50,7 +51,7 @@ import { ProjectDetailComponent } from './project/project-detail/project-detail. import { MemberComponent } from './project/member/member.component'; import { RobotAccountComponent } from './project/robot-account/robot-account.component'; import { WebhookComponent } from './project/webhook/webhook.component'; -import { ProjectLabelComponent } from "./project/project-label/project-label.component"; +import { ProjectLabelComponent } from './project/project-label/project-label.component'; import { ProjectConfigComponent } from './project/project-config/project-config.component'; import { ProjectRoutingResolver } from './project/project-routing-resolver.service'; import { ListChartsComponent } from './project/helm-chart/list-charts.component'; @@ -59,8 +60,8 @@ import { HelmChartDetailComponent } from './project/helm-chart/helm-chart-detail import { OidcOnboardComponent } from './oidc-onboard/oidc-onboard.component'; import { LicenseComponent } from './license/license.component'; import { SummaryComponent } from './project/summary/summary.component'; -import { TagRetentionComponent } from "./project/tag-retention/tag-retention.component"; - +import { TagRetentionComponent } from './project/tag-retention/tag-retention.component'; +import { USERSTATICPERMISSION } from '@harbor/ui'; const harborRoutes: Routes = [ { path: '', redirectTo: 'harbor', pathMatch: 'full' }, @@ -81,7 +82,7 @@ const harborRoutes: Routes = [ { path: 'harbor/sign-in', component: SignInComponent, - canActivate: [ SignInGuard] + canActivate: [SignInGuard] }, { path: 'harbor', @@ -117,13 +118,13 @@ const harborRoutes: Routes = [ path: 'replications', component: TotalReplicationPageComponent, canActivate: [SystemAdminGuard], - canActivateChild: [SystemAdminGuard], + canActivateChild: [SystemAdminGuard] }, { path: 'replications/:id/:tasks', component: ReplicationTasksPageComponent, canActivate: [SystemAdminGuard], - canActivateChild: [SystemAdminGuard], + canActivateChild: [SystemAdminGuard] }, { path: 'tags/:id/:repo', @@ -148,7 +149,7 @@ const harborRoutes: Routes = [ canActivate: [MemberGuard], resolve: { projectResolver: ProjectRoutingResolver - }, + } }, { path: 'projects/:id/helm-charts/:chart/versions', @@ -156,7 +157,7 @@ const harborRoutes: Routes = [ canActivate: [MemberGuard], resolve: { projectResolver: ProjectRoutingResolver - }, + } }, { path: 'projects/:id/helm-charts/:chart/versions/:version', @@ -164,60 +165,127 @@ const harborRoutes: Routes = [ canActivate: [MemberGuard], resolve: { projectResolver: ProjectRoutingResolver - }, + } }, { path: 'projects/:id', component: ProjectDetailComponent, canActivate: [MemberGuard], + canActivateChild: [MemberPermissionGuard], resolve: { projectResolver: ProjectRoutingResolver }, children: [ { path: 'summary', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.PROJECT.KEY, + action: USERSTATICPERMISSION.PROJECT.VALUE.READ + } + }, component: SummaryComponent }, { path: 'repositories', - component: RepositoryPageComponent + data: { + permissionParam: { + resource: USERSTATICPERMISSION.REPOSITORY.KEY, + action: USERSTATICPERMISSION.REPOSITORY.VALUE.LIST + } + }, + component: RepositoryPageComponent, }, { path: 'helm-charts', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.HELM_CHART.KEY, + action: USERSTATICPERMISSION.HELM_CHART.VALUE.LIST + } + }, component: ListChartsComponent }, { path: 'repositories/:repo/tags', - component: TagRepositoryComponent, + data: { + permissionParam: { + resource: USERSTATICPERMISSION.REPOSITORY.KEY, + action: USERSTATICPERMISSION.REPOSITORY.VALUE.LIST + } + }, + component: TagRepositoryComponent }, { path: 'members', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.MEMBER.KEY, + action: USERSTATICPERMISSION.MEMBER.VALUE.LIST + } + }, component: MemberComponent }, { path: 'logs', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.LOG.KEY, + action: USERSTATICPERMISSION.LOG.VALUE.LIST + } + }, component: AuditLogComponent }, { path: 'labels', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.LABEL.KEY, + action: USERSTATICPERMISSION.LABEL.VALUE.CREATE + } + }, component: ProjectLabelComponent }, { path: 'configs', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.CONFIGURATION.KEY, + action: USERSTATICPERMISSION.CONFIGURATION.VALUE.READ + } + }, component: ProjectConfigComponent }, { path: 'robot-account', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.ROBOT.KEY, + action: USERSTATICPERMISSION.ROBOT.VALUE.LIST + } + }, component: RobotAccountComponent }, { path: 'tag-retention', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.TAG_RETENTION.KEY, + action: USERSTATICPERMISSION.TAG_RETENTION.VALUE.READ + } + }, component: TagRetentionComponent }, { path: 'webhook', + data: { + permissionParam: { + resource: USERSTATICPERMISSION.WEBHOOK.KEY, + action: USERSTATICPERMISSION.WEBHOOK.VALUE.LIST + } + }, component: WebhookComponent - }, + } ] }, { @@ -239,19 +307,17 @@ const harborRoutes: Routes = [ path: 'registry', component: DestinationPageComponent, canActivate: [SystemAdminGuard], - canActivateChild: [SystemAdminGuard], + canActivateChild: [SystemAdminGuard] } ] }, - { path: "**", component: PageNotFoundComponent } + { path: '**', component: PageNotFoundComponent } ]; @NgModule({ imports: [ - RouterModule.forRoot(harborRoutes, {onSameUrlNavigation: 'reload'}) + RouterModule.forRoot(harborRoutes, { onSameUrlNavigation: 'reload' }) ], exports: [RouterModule] }) -export class HarborRoutingModule { - -} +export class HarborRoutingModule {} diff --git a/src/portal/src/app/project/project-detail/project-detail.component.ts b/src/portal/src/app/project/project-detail/project-detail.component.ts index 8fdc749c53..edffad952e 100644 --- a/src/portal/src/app/project/project-detail/project-detail.component.ts +++ b/src/portal/src/app/project/project-detail/project-detail.component.ts @@ -89,6 +89,7 @@ export class ProjectDetailComponent implements OnInit { USERSTATICPERMISSION.TAG_RETENTION.KEY, USERSTATICPERMISSION.TAG_RETENTION.VALUE.READ)); permissionsList.push(this.userPermissionService.getPermission(projectId, USERSTATICPERMISSION.WEBHOOK.KEY, USERSTATICPERMISSION.WEBHOOK.VALUE.LIST)); + forkJoin(...permissionsList).subscribe(Rules => { [this.hasProjectReadPermission, this.hasLogListPermission, this.hasConfigurationListPermission, this.hasMemberListPermission , this.hasLabelListPermission, this.hasRepositoryListPermission, this.hasHelmChartsListPermission, this.hasRobotListPermission diff --git a/src/portal/src/app/shared/route/member-permission-guard-activate.service.ts b/src/portal/src/app/shared/route/member-permission-guard-activate.service.ts new file mode 100644 index 0000000000..3717b1b5ed --- /dev/null +++ b/src/portal/src/app/shared/route/member-permission-guard-activate.service.ts @@ -0,0 +1,56 @@ +import { Injectable } from "@angular/core"; +import { + CanActivate, + Router, + ActivatedRouteSnapshot, + RouterStateSnapshot, + CanActivateChild, +} from "@angular/router"; +import { + UserPrivilegeServeItem, + UserPermissionService, + ErrorHandler, + CommonRoutes +} from "@harbor/ui"; +import { Observable } from "rxjs"; + +@Injectable() +export class MemberPermissionGuard implements CanActivate, CanActivateChild { + constructor( + private router: Router, + private errorHandler: ErrorHandler, + private userPermission: UserPermissionService + ) {} + + canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable | boolean { + const projectId = route.parent.params["id"]; + const permission = route.data.permissionParam as UserPrivilegeServeItem; + return new Observable(observer => { + this.userPermission + .getPermission(projectId, permission.resource, permission.action) + .subscribe( + permissionRouter => { + if (!permissionRouter) { + this.router.navigate([CommonRoutes.HARBOR_DEFAULT]); + } + observer.next(permissionRouter); + }, + error => { + this.router.navigate([CommonRoutes.HARBOR_DEFAULT]); + observer.next(false); + this.errorHandler.error(error); + } + ); + }); + } + + canActivateChild( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable | boolean { + return this.canActivate(route, state); + } +} diff --git a/src/portal/src/app/shared/shared.module.ts b/src/portal/src/app/shared/shared.module.ts index 9cb09394e6..20f25d2f50 100644 --- a/src/portal/src/app/shared/shared.module.ts +++ b/src/portal/src/app/shared/shared.module.ts @@ -14,7 +14,7 @@ import { NgModule } from "@angular/core"; import { RouterModule } from "@angular/router"; import { TranslateModule } from "@ngx-translate/core"; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { CookieService } from "ngx-cookie"; import { IServiceConfig, @@ -33,6 +33,7 @@ import { AuthCheckGuard } from "./route/auth-user-activate.service"; import { SignInGuard } from "./route/sign-in-guard-activate.service"; import { SystemAdminGuard } from "./route/system-admin-activate.service"; import { MemberGuard } from "./route/member-guard-activate.service"; +import { MemberPermissionGuard } from "./route/member-permission-guard-activate.service"; import { OidcGuard } from "./route/oidc-guard-active.service"; import { LeavingRepositoryRouteDeactivate } from "./route/leaving-repository-deactivate.service"; @@ -52,7 +53,7 @@ import { GaugeComponent } from "./gauge/gauge.component"; import { ConfirmationDialogComponent } from "./confirmation-dialog/confirmation-dialog.component"; import { ConfirmationDialogService } from "./confirmation-dialog/confirmation-dialog.service"; import { MessageHandlerService } from "./message-handler/message-handler.service"; -import { ListChartVersionRoComponent } from './list-chart-version-ro/list-chart-version-ro.component'; +import { ListChartVersionRoComponent } from "./list-chart-version-ro/list-chart-version-ro.component"; const uiLibConfig: IServiceConfig = { enablei18Support: true, @@ -141,6 +142,7 @@ const uiLibConfig: IServiceConfig = { SignInGuard, LeavingRepositoryRouteDeactivate, MemberGuard, + MemberPermissionGuard, OidcGuard, MessageHandlerService, StatisticHandler