Merge pull request #7281 from jwangyangls/oidc_step3_onboard_tpl

Add the OIDC onboard page
This commit is contained in:
jwangyangls 2019-04-03 14:11:25 +08:00 committed by GitHub
commit beeb8b53d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 283 additions and 7 deletions

View File

@ -31,7 +31,7 @@ import { ProjectConfigComponent } from './project/project-config/project-config.
import zh from '@angular/common/locales/zh-Hans';
import es from '@angular/common/locales/es';
import localeFr from '@angular/common/locales/fr';
import { DevCenterComponent } from './dev-center/dev-center.component';
import { OidcOnboardModule } from './oidc-onboard/oidc-onboard.module';
registerLocaleData(zh, 'zh-cn');
registerLocaleData(es, 'es-es');
registerLocaleData(localeFr, 'fr-fr');
@ -60,7 +60,8 @@ export function getCurrentLanguage(translateService: TranslateService) {
AccountModule,
HarborRoutingModule,
ConfigurationModule,
DeveloperCenterModule
DeveloperCenterModule,
OidcOnboardModule
],
exports: [
],

View File

@ -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 { OidcGuard } from './shared/route/oidc-guard-active.service';
import { PageNotFoundComponent } from './shared/not-found/not-found.component';
import { HarborShellComponent } from './base/harbor-shell/harbor-shell.component';
@ -51,6 +52,7 @@ import { ProjectRoutingResolver } from './project/project-routing-resolver.servi
import { ListChartsComponent } from './project/helm-chart/list-charts.component';
import { ListChartVersionsComponent } from './project/helm-chart/list-chart-versions/list-chart-versions.component';
import { HelmChartDetailComponent } from './project/helm-chart/helm-chart-detail/chart-detail.component';
import { OidcOnboardComponent } from './oidc-onboard/oidc-onboard.component';
const harborRoutes: Routes = [
{ path: '', redirectTo: 'harbor', pathMatch: 'full' },
@ -59,6 +61,11 @@ const harborRoutes: Routes = [
path: 'devcenter',
component: DevCenterComponent
},
{
path: 'oidc-onboard',
component: OidcOnboardComponent,
canActivate: [OidcGuard, SignInGuard]
},
{
path: 'harbor',
component: HarborShellComponent,

View File

@ -0,0 +1,43 @@
<div class="modal">
<div class="modal-dialog" role="dialog">
<div class="modal-content">
<div class="modal-header">
<button (click)="backHarborPage()" class="close">
<clr-icon shape="close"></clr-icon>
</button>
<h3 class="modal-title oidc-header-text"><span>{{'CONFIG.OIDC.OIDC_SETNAME' | translate}}</span>&nbsp;
</h3>
</div>
<div id="error-message">
<div class="alert alert-danger" role="alert" *ngIf="errorOpen">
<div class="alert-items">
<div class="alert-item static">
<div class="alert-icon-wrapper">
<clr-icon class="alert-icon" size="24" shape="exclamation-circle"></clr-icon>
</div>
<span class="alert-text">{{errorMessage}}</span>
</div>
</div>
<button type="button" class="close" aria-label="Close" (click)="emptyErrorMessage()">
<clr-icon aria-hidden="true" size="16" shape="close"></clr-icon>
</button>
</div>
</div>
<div class="modal-body">
<p class="body-message">{{'CONFIG.OIDC.OIDC_SETNAMECONTENT' | translate}}</p>
</div>
<br />
<div class="username-div">
<label for="oidcUsername" class="required">{{'CONFIG.OIDC.OIDC_USERNAME' | translate}}</label>
<label for="oidcUsername" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right">
<input name="oidcUsername" type="text" [formControl]="oidcUsername" required id="oidcUsername" size="40">
</label>
</div>
<div class="modal-footer">
<button class="btn btn-outline" type="button" (click)="backHarborPage()" id="cancelButton">{{'BUTTON.CANCEL' | translate }}</button>
<button class="btn btn-primary" id="saveButton" (click)="clickSaveBtn()" [disabled]="oidcUsername.invalid"
type="button">{{'BUTTON.SAVE' | translate }}</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
.modal {
background-color: rgb(80, 80, 80);
.body-message {
margin-top: 10px;
}
.modal-header {
.close {
margin-right: 0.2rem
}
}
.username-div {
display: flex;
justify-content: space-between;
width: 80%;
}
input {
width: 300px;
}
}
.oidc-header-text{
color:rgb(94, 94, 94);
}
.close-error {
padding-right:0;
}

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { OidcOnboardComponent } from './oidc-onboard.component';
describe('OidcOnboardComponent', () => {
let component: OidcOnboardComponent;
let fixture: ComponentFixture<OidcOnboardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ OidcOnboardComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OidcOnboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,43 @@
import { Router, ActivatedRoute } from '@angular/router';
import { Component, OnInit } from '@angular/core';
import { OidcOnboardService } from './oidc-onboard.service';
import { FormControl } from '@angular/forms';
import { errorHandler } from "../shared/shared.utils";
import { CommonRoutes } from '../shared/shared.const';
@Component({
selector: 'app-oidc-onboard',
templateUrl: './oidc-onboard.component.html',
styleUrls: ['./oidc-onboard.component.scss']
})
export class OidcOnboardComponent implements OnInit {
url: string;
errorMessage: string = '';
oidcUsername = new FormControl('');
errorOpen: boolean = false;
constructor(
private oidcOnboardService: OidcOnboardService,
private router: Router,
private route: ActivatedRoute,
) { }
ngOnInit() {
this.route.queryParams
.subscribe(params => {
this.oidcUsername.setValue(params["username"] || "");
});
}
clickSaveBtn(): void {
this.oidcOnboardService.oidcSave({ username: this.oidcUsername.value }).subscribe(res => { }
, error => {
this.errorMessage = errorHandler(error);
this.errorOpen = true;
});
}
emptyErrorMessage() {
this.errorOpen = false;
}
backHarborPage() {
this.router.navigate([CommonRoutes.HARBOR_DEFAULT]);
}
}

View File

@ -0,0 +1,29 @@
// Copyright Project Harbor Authors
//
// 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,
// 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.
import { NgModule } from '@angular/core';
import { OidcOnboardComponent } from './oidc-onboard.component';
import { SharedModule } from '../shared/shared.module';
import { OidcOnboardService } from './oidc-onboard.service';
@NgModule({
imports: [SharedModule],
declarations: [
OidcOnboardComponent,
],
providers: [OidcOnboardService],
exports: [
OidcOnboardComponent
]
})
export class OidcOnboardModule { }

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { OidcOnboardService } from './oidc-onboard.service';
describe('OidcOnboardService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: OidcOnboardService = TestBed.get(OidcOnboardService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { Http, URLSearchParams } from '@angular/http';
import { catchError } from 'rxjs/operators';
import { throwError as observableThrowError, Observable } from 'rxjs';
export const logEndpoint = "/c/oidc/onboard";
@Injectable()
export class OidcOnboardService {
constructor(private http: Http) { }
oidcSave(param): Observable<any> {
return this.http.post(logEndpoint, param).pipe(catchError(error => observableThrowError(error)));
}
}

View File

@ -0,0 +1,58 @@
// Copyright Project Harbor Authors
//
// 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,
// 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.
import { Injectable } from '@angular/core';
import {
CanActivate, Router,
ActivatedRouteSnapshot,
RouterStateSnapshot,
CanActivateChild
} from '@angular/router';
import { AppConfigService } from '../../app-config.service';
import { UserPermissionService } from "@harbor/ui";
import { Observable, of } from 'rxjs';
import { CommonRoutes } from '../../shared/shared.const';
@Injectable()
export class OidcGuard implements CanActivate, CanActivateChild {
constructor(private appConfigService: AppConfigService, private router: Router, private userPermission: UserPermissionService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
// If user has logged in, should not login again
return new Observable((observer) => {
// If signout appended
let queryParams = route.queryParams;
this.appConfigService.load()
.subscribe(updatedConfig => {
if (updatedConfig.auth_mode === 'oidc_auth') {
return observer.next(true);
} else {
this.router.navigate([CommonRoutes.HARBOR_DEFAULT]);
return observer.next(false);
}
}
, error => {
// Catch the error
this.router.navigate([CommonRoutes.HARBOR_DEFAULT]);
console.error("Failed to load bootstrap options with error: ", error);
return observer.next(false);
});
});
}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
return this.canActivate(route, state);
}
}

View File

@ -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 { OidcGuard } from "./route/oidc-guard-active.service";
import { LeavingRepositoryRouteDeactivate } from "./route/leaving-repository-deactivate.service";
import { PortValidatorDirective } from "./port.directive";
@ -140,6 +141,7 @@ const uiLibConfig: IServiceConfig = {
SignInGuard,
LeavingRepositoryRouteDeactivate,
MemberGuard,
OidcGuard,
MessageHandlerService,
StatisticHandler
]

View File

@ -697,7 +697,10 @@
"CLIENT_ID": "OIDC Client ID",
"CLIENTSECRET": "OIDC Client Secret",
"SCOPE": "OIDC Scope",
"OIDCSKIPCERTVERIFY": "OIDC Verify Cert"
"OIDCSKIPCERTVERIFY": "OIDC Verify Cert",
"OIDC_SETNAME": "Set OIDC Username",
"OIDC_SETNAMECONTENT": "You must create a Harbor username the first time when authenticating via a third party(OIDC).This will be used within Harbor to be associated with projects, roles, etc.",
"OIDC_USERNAME": "Username"
},
"SCANNING": {
"TRIGGER_SCAN_ALL_SUCCESS": "Trigger scan all successfully!",

View File

@ -696,7 +696,10 @@
"CLIENT_ID": "ID de cliente OIDC",
"CLIENTSECRET": "OIDC Client Secret",
"SCOPE": "OIDC Ámbito",
"OIDCSKIPCERTVERIFY": "OIDC Verify Cert"
"OIDCSKIPCERTVERIFY": "OIDC Verify Cert",
"OIDC_SETNAME": "Set OIDC nombre de usuario",
"OIDC_SETNAMECONTENT": "Usted debe crear un Harbor nombre de usuario la primera vez cuando la autenticación a través de un tercero (OIDC). Esta será usada en Harbor para ser asociados con proyectos, funciones, etc.",
"OIDC_USERNAME": "Usuario"
},
"SCANNING": {
"TRIGGER_SCAN_ALL_SUCCESS": "Trigger scan all successfully!",

View File

@ -661,7 +661,10 @@
"CLIENT_ID": "no d'identification du client OIDC",
"CLIENTSECRET": "OIDC Client Secret",
"SCOPE": "OIDC Scope",
"OIDCSKIPCERTVERIFY": "OIDC vérifier cert"
"OIDCSKIPCERTVERIFY": "OIDC vérifier cert",
"OIDC_SETNAME": "Ensemble OIDC nom d'utilisateur",
"OIDC_SETNAMECONTENT": "vous devez créer un Harbor identifiant la première fois lors de la vérification par une tierce partie (oidc). il sera utilisé au sein de port à être associés aux projets, des rôles, etc.",
"OIDC_USERNAME": "d'utilisateur"
},
"SCANNING": {
"TRIGGER_SCAN_ALL_SUCCESS": "Déclenchement d'analyse globale avec succès !",

View File

@ -690,7 +690,10 @@
"CLIENT_ID": "ID de cliente OIDC",
"CLIENTSECRET": "OIDC Client Secret",
"SCOPE": "Escopo OIDC",
"OIDCSKIPCERTVERIFY": "Verificar certificado OIDC"
"OIDCSKIPCERTVERIFY": "Verificar certificado OIDC",
"OIDC_SETNAME": "Definir o Utilizador OIDC",
"OIDC_SETNAMECONTENT": "Você deve Criar um Nome de usuário do Porto a primeira vez que autenticar através de um terceiro (OIDC). Isto será usado Dentro de Harbor para ser associado a projetos, papéis, etc.",
"OIDC_USERNAME": "Utilizador"
},
"SCANNING": {
"TRIGGER_SCAN_ALL_SUCCESS": "Disparo de análise geral efetuado com sucesso!",

View File

@ -695,7 +695,10 @@
"CLIENT_ID": "OIDC 客户端标识",
"CLIENTSECRET": "OIDC 客户端密码",
"SCOPE": "OIDC scope",
"OIDCSKIPCERTVERIFY": "OIDC 验证证书"
"OIDCSKIPCERTVERIFY": "OIDC 验证证书",
"OIDC_SETNAME": "设置OIDC用户名",
"OIDC_SETNAMECONTENT": "在通过第三方OIDC进行身份验证时您必须第一次创建一个Harbor用户名。这将在端口中用于与项目、角色等关联。",
"OIDC_USERNAME": "用户名"
},
"SCANNING": {
"TRIGGER_SCAN_ALL_SUCCESS": "启动扫描所有镜像任务成功!",