Commit f8714215 authored by Lukas Burgey's avatar Lukas Burgey

Add components

parent 7524c8ac
...@@ -41,3 +41,5 @@ yarn-error.log ...@@ -41,3 +41,5 @@ yarn-error.log
# System Files # System Files
.DS_Store .DS_Store
Thumbs.db Thumbs.db
deploy
{ {
"name": "fum", "name": "fum-webpage",
"version": "0.0.0", "version": "0.1.0",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
...@@ -12,42 +12,43 @@ ...@@ -12,42 +12,43 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^4.4.6", "@angular/animations": "^5.0.1",
"@angular/cdk": "^2.0.0-beta.12", "@angular/cdk": "^5.0.0-rc0",
"@angular/common": "^4.2.4", "@angular/cli": "^1.5.3",
"@angular/compiler": "^4.2.4", "@angular/common": "^5.0.0",
"@angular/core": "^4.2.4", "@angular/compiler": "^5.0.0",
"@angular/forms": "^4.2.4", "@angular/core": "^5.0.0",
"@angular/http": "^4.2.4", "@angular/forms": "^5.0.0",
"@angular/material": "^2.0.0-beta.12", "@angular/http": "^5.0.0",
"@angular/platform-browser": "^4.2.4", "@angular/material": "^5.0.0-rc0",
"@angular/platform-browser-dynamic": "^4.2.4", "@angular/platform-browser": "^5.0.0",
"@angular/router": "^4.2.4", "@angular/platform-browser-dynamic": "^5.0.0",
"angular-auth-oidc-client": "^2.0.0", "@angular/router": "^5.0.0",
"core-js": "^2.4.1", "core-js": "^2.4.1",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"rxjs": "^5.4.2", "ngx-cookie-service": "^1.0.9",
"rxjs": "^5.5.2",
"typescript": "^2.4.2",
"zone.js": "^0.8.14" "zone.js": "^0.8.14"
}, },
"devDependencies": { "devDependencies": {
"@angular/cli": "1.3.2", "@angular/cli": "^1.5.4",
"@angular/compiler-cli": "^4.2.4", "@angular/compiler-cli": "^5.0.0",
"@angular/language-service": "^4.2.4", "@angular/language-service": "^5.0.0",
"@types/jasmine": "~2.5.53", "@types/jasmine": "~2.8.2",
"@types/jasminewd2": "~2.0.2", "@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60", "@types/node": "~8.0.53",
"codelyzer": "~3.1.1", "jasmine-core": "~2.8.0",
"jasmine-core": "~2.6.2", "jasmine-spec-reporter": "~4.2.1",
"jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0", "karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1", "karma-chrome-launcher": "~2.2.0",
"karma-cli": "~1.0.1", "karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1", "karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0", "karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2", "karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2", "protractor": "~5.2.0",
"ts-node": "~3.2.0", "ts-node": "~3.3.0",
"tslint": "~5.3.2", "tslint": "~5.8.0",
"typescript": "~2.3.3" "typescript": "^2.4.2"
} }
} }
<div style="text-align: center"> <mat-toolbar color="primary">
<h3>Federated User Management</h3> <span>Federated User Management</span>
<span class="toolbar-spacer"></span>
<app-login></app-login>
</mat-toolbar>
<div class="outer">
<div class="inner">
<router-outlet></router-outlet>
</div>
</div> </div>
<router-outlet></router-outlet>
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
...@@ -7,4 +6,5 @@ import { Subscription } from 'rxjs/Subscription'; ...@@ -7,4 +6,5 @@ import { Subscription } from 'rxjs/Subscription';
styleUrls: ['./app.component.css'] styleUrls: ['./app.component.css']
}) })
export class AppComponent { export class AppComponent {
constructor() { }
} }
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { JsonPipe } from '@angular/common';
import { HttpModule } from '@angular/http'; import { HttpModule } from '@angular/http';
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
import { AuthModule, OidcSecurityService, OpenIDImplicitFlowConfiguration } from 'angular-auth-oidc-client';
import { MatButtonModule } from '@angular/material'; import { MatButtonModule } from '@angular/material';
import { MatToolbarModule } from '@angular/material';
import { MatTableModule } from '@angular/material/table';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatIconModule } from '@angular/material/icon';
import { MatDialogModule } from '@angular/material/dialog';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatSelectModule} from '@angular/material/select';
import {MatInputModule} from '@angular/material/input';
import { CookieService } from 'ngx-cookie-service';
import { AuthGuard } from './auth.guard'; import { UserService } from './user.service';
import { SnackBarService } from './snackbar.service';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { MgmtComponent } from './mgmt/mgmt.component'; import { MgmtComponent } from './mgmt/mgmt.component';
import { LoginComponent } from './login/login.component'; import { LoginComponent } from './login/login.component';
import { ProfileComponent } from './profile/profile.component';
import { ServiceComponent } from './service/service.component';
import { SshKeysComponent } from './ssh-keys/ssh-keys.component';
const routes = [ const routes = [
{ {
path: '', path: '',
component: LoginComponent, component: MgmtComponent,
},
{
path: 'oidcredirect',
redirectTo: '/mgmt',
}, },
{ {
path: 'mgmt', path: '*',
component: MgmtComponent, redirectTo: '/',
}, },
]; ];
...@@ -34,45 +46,48 @@ const routes = [ ...@@ -34,45 +46,48 @@ const routes = [
AppComponent, AppComponent,
MgmtComponent, MgmtComponent,
LoginComponent, LoginComponent,
ProfileComponent,
ServiceComponent,
SshKeysComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
BrowserAnimationsModule, BrowserAnimationsModule,
FormsModule,
HttpModule, HttpModule,
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'csrftoken',
headerName: 'HTTP_X_CSRFTOKEN',
}),
RouterModule.forRoot( RouterModule.forRoot(
routes, routes,
), ),
AuthModule.forRoot(),
MatButtonModule, MatButtonModule,
MatToolbarModule,
MatTableModule,
MatSnackBarModule,
MatExpansionModule,
MatIconModule,
MatDialogModule,
MatFormFieldModule,
MatSelectModule,
MatInputModule,
], ],
providers: [ providers: [
AuthGuard, CookieService,
UserService,
SnackBarService,
JsonPipe,
],
bootstrap: [AppComponent],
entryComponents: [
ProfileComponent,
SshKeysComponent,
], ],
bootstrap: [AppComponent]
}) })
export class AppModule { export class AppModule {
constructor(public oidcSecurityService: OidcSecurityService) { constructor() {
const openIDImplicitFlowConfiguration = new OpenIDImplicitFlowConfiguration();
openIDImplicitFlowConfiguration.stsServer = 'https://iam-test.indigo-datacloud.eu';
openIDImplicitFlowConfiguration.redirect_url = 'http://localhost:4200/oidcredirect';
openIDImplicitFlowConfiguration.client_id = '46b352da-b75f-4375-b56b-5b0565fa9cf3';
openIDImplicitFlowConfiguration.response_type = 'id_token token';
openIDImplicitFlowConfiguration.scope = 'openid email profile';
openIDImplicitFlowConfiguration.post_logout_redirect_uri =
'http://localhost:44311/Unauthorized';
openIDImplicitFlowConfiguration.start_checksession = false;
openIDImplicitFlowConfiguration.silent_renew = true;
openIDImplicitFlowConfiguration.silent_renew_offset_in_seconds = 0;
openIDImplicitFlowConfiguration.post_login_route = '/mgmt';
openIDImplicitFlowConfiguration.forbidden_route = '/Forbidden';
openIDImplicitFlowConfiguration.unauthorized_route = '/Unauthorized';
openIDImplicitFlowConfiguration.auto_userinfo = true;
openIDImplicitFlowConfiguration.log_console_warning_active = true;
openIDImplicitFlowConfiguration.log_console_debug_active = true;
openIDImplicitFlowConfiguration.max_id_token_iat_offset_allowed_in_seconds = 10;
openIDImplicitFlowConfiguration.override_well_known_configuration = false;
this.oidcSecurityService.setupModule(openIDImplicitFlowConfiguration);
} }
} }
import { TestBed, async, inject } from '@angular/core/testing';
import { AuthGuard } from './auth.guard';
describe('AuthGuard', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AuthGuard]
});
});
it('should ...', inject([AuthGuard], (guard: AuthGuard) => {
expect(guard).toBeTruthy();
}));
});
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { OidcSecurityService } from 'angular-auth-oidc-client';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(public oidcSecurityService: OidcSecurityService) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.oidcSecurityService.getIsAuthorized();
}
}
<div style="text-align: center"> <span *ngIf="userService.loggedIn ? false : true">
<button mat-raised-button (click)="login()">OIDC Login</button> <button mat-raised-button color="accent" (click)="userService.login()">Login</button>
</div> </span>
<span *ngIf="userService.loggedIn">
<button mat-button mat-icon-button (click)="openSshKeys()">
<mat-icon>vpn_key</mat-icon>
</button>
<button mat-button (click)="openProfile()">
{{ userService.user?.username }}
</button>
<button mat-raised-button color="accent" (click)="userService.logout()">Logout</button>
</span>
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component } from '@angular/core';
import { Subscription } from 'rxjs/Subscription'; import { MatDialog } from '@angular/material/dialog';
import { OidcSecurityService } from 'angular-auth-oidc-client';
import { ProfileComponent } from '../profile/profile.component';
import { SshKeysComponent } from '../ssh-keys/ssh-keys.component';
import { UserService } from '../user.service';
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
templateUrl: './login.component.html', templateUrl: './login.component.html',
styleUrls: ['./login.component.css'] styleUrls: ['./login.component.css']
}) })
export class LoginComponent implements OnInit, OnDestroy { export class LoginComponent {
private profileDialog;
constructor(public oidcSecurityService: OidcSecurityService) {
if (this.oidcSecurityService.moduleSetup) {
this.doCallbackLogicIfRequired();
} else {
this.oidcSecurityService.onModuleSetup.subscribe(() => {
this.doCallbackLogicIfRequired();
});
}
}
ngOnInit() {
}
ngOnDestroy(): void {
this.oidcSecurityService.onModuleSetup.unsubscribe();
}
login() { constructor(
this.oidcSecurityService.authorize(); public userService: UserService,
} public dialog: MatDialog,
) { }
logout() { public openProfile() {
this.oidcSecurityService.logoff(); this.profileDialog = this.dialog.open(
} ProfileComponent,
{
width: '80%',
}
);
}
private doCallbackLogicIfRequired() { public openSshKeys() {
if (window.location.hash) { this.profileDialog = this.dialog.open(
this.oidcSecurityService.authorizedCallback(); SshKeysComponent,
} {
} width: '80%',
}
);
}
} }
<div *ngIf="isAuthorized"> <div *ngIf="userService.loggedIn">
You are authorized <h4>Services</h4>
</div> <div *ngIf="userService.state.services.length > 0">
<div *ngIf="!isAuthorized"> <mat-accordion>
You are not authorized <app-service *ngFor="let service of userService.state.services"
[serviceData]="service"></app-service>
</mat-accordion>
</div>
<p *ngIf="userService.state.services?.length == 0">
You have no available services.<br/>
This is due services requiring users to be member of a certain group.
</p>
</div> </div>
{{ userData }} <!--
{{ oidcSecurityService.getToken() }} <div style="margin-top: 100px">
{{ userService.state | json }}
</div>
<div style="margin-top: 100px">
{{ userService.user | json }}
</div>
-->
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import {OidcSecurityService } from 'angular-auth-oidc-client'; import { UserService } from '../user.service';
@Component({ @Component({
selector: 'app-mgmt', selector: 'app-mgmt',
...@@ -8,27 +9,12 @@ import {OidcSecurityService } from 'angular-auth-oidc-client'; ...@@ -8,27 +9,12 @@ import {OidcSecurityService } from 'angular-auth-oidc-client';
styleUrls: ['./mgmt.component.css'] styleUrls: ['./mgmt.component.css']
}) })
export class MgmtComponent implements OnInit { export class MgmtComponent implements OnInit {
isAuthorized: boolean;
userData: any;
constructor(public oidcSecurityService: OidcSecurityService) { constructor(
this.isAuthorized = false; public userService: UserService
this.userData = null; ) {
} }
ngOnInit() { ngOnInit() {
this.oidcSecurityService.getIsAuthorized().subscribe(
(isAuthorized: boolean) => {
console.log(JSON.stringify(isAuthorized));
this.isAuthorized = isAuthorized;
}
);
this.oidcSecurityService.getUserData().subscribe(
(userData: any) => {
console.log(JSON.stringify(userData));
this.userData = userData;
}
);
} }
} }
<div>
<mat-table [dataSource]="userService.userInfoData">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let element">{{ element.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef>Info</mat-header-cell>
<mat-cell *matCellDef="let element">{{ element.info }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="columns"></mat-header-row>
<mat-row *matRowDef="let row; columns: columns;"></mat-row>
</mat-table>
</div>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProfileComponent } from './profile.component';
describe('ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture<ProfileComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ProfileComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { MatTableDataSource } from '@angular/material';
import { UserService } from '../user.service';
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
columns = ['name', 'info'];
constructor(
public userService: UserService,
) { }
ngOnInit() {
}
}
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>{{ serviceData.name }}</mat-panel-title>
<mat-panel-description>{{ serviceData.description }}</mat-panel-description>
</mat-expansion-panel-header>
<p>
<mat-icon style="vertical-align: middle; padding-right: 35px;">storage</mat-icon>
Provided by: {{ serviceData.site.name }}
</p>
<span>
<mat-icon style="vertical-align: middle; padding-right: 35px;">lock outline</mat-icon>
</span>
Needs membership of one of the following groups:
<ul>
<li *ngFor="let group of serviceData.groups">
{{ group.name }}
</li>
</ul>
<mat-action-row>
<span style="padding-right: 20px;">
<mat-form-field>
<mat-select placeholder="SSH Public Key" [(ngModel)]="sshKeyName">
<mat-option *ngFor="let key of userService.user.ssh_keys" [value]="key.name">
{{ key.name }}
</mat-option>
</mat-select>
</mat-form-field>
</span>
<button mat-raised-button color="primary" [disabled]="requestDisabled()" (click)="request()">Request deployment</button>
</mat-action-row>
</mat-expansion-panel>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ServiceComponent } from './service.component';
describe('ServiceComponent', () => {
let component: ServiceComponent;
let fixture: ComponentFixture<ServiceComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ServiceComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ServiceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, Input } from '@angular/core';
import { SnackBarService } from '../snackbar.service';
import { UserService } from '../user.service';
@Component({
selector: 'app-service',
templateUrl: './service.component.html',
styleUrls: ['./service.component.css']
})
export class ServiceComponent implements OnInit {
@Input() serviceData: any;
sshKeyName = '';
constructor(
public userService: UserService,
public snackBar: SnackBarService,
) {
}
ngOnInit() {
}
public request() {
this.snackBar.open('Requesting with key ' + this.sshKeyName);
}
public requestDisabled(): boolean {
return this.sshKeyName === '';
}
}
import { Injectable } from '@angular/core';
import { MatSnackBar, MatSnackBarConfig } from '@angular/material';
@Injectable()
export class SnackBarService {
config = new MatSnackBarConfig()
constructor(
public snackBar: MatSnackBar,
) {
this.config.duration = 3000;
}
public open(message: string) {
return this.snackBar.open(message, '', this.config);
}
}
<div style="margin-bottom: 25px;">
<mat-table *ngIf="userService.user.ssh_keys" [dataSource]="userService.sshKeyData">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let element">{{ element.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="key">
<mat-header-cell *matHeaderCellDef>Key</mat-header-cell>
<mat-cell *matCellDef="let element">{{ element.key }}</mat-cell>
</ng-container>
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let element">
<button mat-icon-button (click)="deleteKey(element.name)"><mat-icon>delete_forever</mat-icon></button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="columns"></mat-header-row>
<mat-row *matRowDef="let row; columns: columns;"></mat-row>
</mat-table>
<p *ngIf="!userService.user.ssh_keys">
You have no keys uploaded yet.
</p>
</div>
<div *ngIf="!upload">
<button mat-icon-button (click)="upload = true"><mat-icon>add</mat-icon></button>
</div>
<div *ngIf="upload" class="form-container">
<form (ngSubmit)="uploadKey()" #sshKeyForm="ngForm">
<mat-form-field>
<input matInput placeholder="Name" required [(ngModel)]="newKeyName" name="name">
</mat-form-field>
<mat-form-field>
<textarea matInput placeholder="Key" required [(ngModel)]="newKeyKey" name="key"></textarea>
</mat-form-field>
<button mat-raised-button color="primary" type="submit" [disabled]="!sshKeyForm.form.valid">Submit</button>
</form>
</div>