Commit 82a5b259 authored by Chris Hines's avatar Chris Hines
Browse files

move code deailing with generating a new cert into a separate service (away...

move code deailing with generating a new cert into a separate service (away from TES which deals with creating tunnels and running commands)
parent 101d7444
import { Component } from '@angular/core';
import { TesService } from './tes.service';
import { AuthorisationService} from './authorisation.service';
@Component({
selector: 'app-root',
......@@ -13,7 +14,7 @@ export class AppComponent {
public authorised: boolean;
// private testingAuth: boolean;
constructor(private tesService: TesService,) {
constructor(private tesService: TesService, private authService: AuthorisationService) {
};
ngOnInit() {
......@@ -21,13 +22,13 @@ export class AppComponent {
// this.testingAuth = false;
}
login() {
console.log("login");
this.tesService.login()
}
logout() {
console.log("logout");
this.tesService.logout();
}
// login() {
// console.log("login");
// this.authService.login()
// }
//
// logout() {
// console.log("logout");
// this.tesService.logout();
// }
}
import { TestBed, inject } from '@angular/core/testing';
import { AuthorisationService } from './authorisation.service';
describe('AuthorisationService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AuthorisationService]
});
});
it('should be created', inject([AuthorisationService], (service: AuthorisationService) => {
expect(service).toBeTruthy();
}));
});
import { Injectable } from '@angular/core';
import { HttpClientModule, HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap } from 'rxjs/operators';
import { ActivatedRoute, Router } from '@angular/router';
import {LocationStrategy} from '@angular/common';
// import { keypair } from 'keypair';
import * as keypair from 'keypair';
import * as forge from "node-forge";
import { Identity, AuthToken, KeyCert, AuthService } from './identity';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Subject} from 'rxjs/Subject';
import {TesService} from './tes.service';
@Injectable({
providedIn: 'root'
})
export class AuthorisationService {
private token: Subject<AuthToken>;
// private keyCert: Subject<KeyCert>;
constructor(private http: HttpClient,
private locationStrategy: LocationStrategy,
private route: ActivatedRoute,
private router: Router,
private tesService: TesService) {
this.token = new Subject<AuthToken>();
this.token.subscribe(token => this.getCert(token));
this.route.fragment.subscribe(frag => this.storeToken(frag));
}
storeToken(frag: string) {
if (frag === undefined || frag == null) {
return;
}
let tokenmatch = null;
let statematch = null;
if (!(frag === undefined) && !(frag == null)) {
tokenmatch = frag.match(/access_token\=([\S\s]*?)[&|$]/);
statematch = frag.match(/state\=([\S\s]*?)[&|$]/);
}
if (tokenmatch == null || statematch == null) {
return;
}
let accesstoken = tokenmatch[1];
let state = statematch[1];
this.router.navigate(['/']);
//Verify that the state matched the nonce we used when initiating login
let tuple = JSON.parse(localStorage.getItem('authservice'));
if (tuple[1] != state) {
return
}
this.token.next(new AuthToken(tokenmatch[1],tuple[0]));
// TODO fire off a query to the auth service to get the associated sites
}
getCert(token: AuthToken) {
console.log('in getCert');
if (token.token === undefined || token.token === '' || token.token == null) {
console.log('no authtoken available, we wont be able to generate a cert');
console.log(token);
return
}
console.log("Generating key matter");
let starttime = new Date();
let newkeypair = keypair();
let publicKey = forge.pki.publicKeyFromPem(newkeypair.public);
let sshpub = forge.ssh.publicKeyToOpenSSH(publicKey, 'sv2@monash.edu');
let endtime = new Date();
console.log("generating new keys took", endtime.valueOf() - starttime.valueOf())
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
let data = {'token': token.token, 'pubkey': sshpub, 'signing_url': token.authservice.sign};
console.log('posting to getcert',this.tesService.Base);
this.http.post<any>(this.tesService.Base+'/getcert',data, options)
.pipe(catchError(this.handleError('getCert',[])))
.subscribe(resp => this.makeKeyCert(newkeypair.private, resp, token.authservice))
console.log('getcert complete');
}
makeKeyCert(key: string, resp, authservice: AuthService) {
let keyCert = new KeyCert()
keyCert.key = key;
keyCert.cert = resp['cert'];
keyCert.authservice = authservice;
console.log('updating keycert',keyCert);
this.tesService.keyCert.next(keyCert);
}
public login() {
let redirect_uri = window.location.origin+this.locationStrategy.getBaseHref()+"sshauthz_callback";
let nonce="asdfzxcv";
let authservice = new AuthService();
authservice.base = "https://autht.massive.org.au/hpcid/";
authservice.authorise = authservice.base + 'oauth/authorize';
authservice.sign = authservice.base + 'api/v1/sign_key';
authservice.client_id = "86c06039-e589-4b39-9d1f-9eca431be18f";
localStorage.setItem('authservice', JSON.stringify([authservice,nonce]));
window.location.assign(authservice.authorise+"?response_type=token&redirect_uri="+redirect_uri+"&state="+nonce+"&client_id="+authservice.client_id);
}
private httperror(error: any) {
console.log(error);
}
private handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.log('in handle error',operation);
console.log(error.status);
console.error(error);
return of(result as T);
};
}
}
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material';
import { TesService } from '../tes.service';
import {AuthorisationService} from '../authorisation.service';
......@@ -14,14 +15,15 @@ export class LogindialogComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<LogindialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private tesService: TesService) {
private tesService: TesService,
private authService: AuthorisationService ) {
}
ngOnInit() {
}
onLogin() {
this.tesService.login();
this.authService.login();
}
onCancel() {
this.dialogRef.close();
......
......@@ -6,7 +6,6 @@ import { catchError, map, tap } from 'rxjs/operators';
import { Job } from './job';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Subject} from 'rxjs/Subject';
import { Strudelapp } from './strudelapp';
import { Computesite } from './computesite';
import { Identity, AuthToken, KeyCert, AuthService } from './identity';
......@@ -16,95 +15,57 @@ import { StrudelappsService } from './strudelapps.service';
import { timer } from 'rxjs/observable/timer';
import { repeat } from 'rxjs/operators';
import {LocationStrategy} from '@angular/common';
// import { keypair } from 'keypair';
import * as keypair from 'keypair';
import * as forge from "node-forge";
import { ActivatedRoute, Router } from '@angular/router';
// import keypair = require('keypair');
// import forge = require('node-forge');
@Injectable({
providedIn: 'root',
})
export class TesService {
// private Base='http://localhost:5000'
private Base='https://vm-118-138-240-255.erc.monash.edu.au/tes'
// public authorised: BehaviorSubject<boolean>;
// public tesSelected: BehaviorSubject<boolean>;
public Base='https://vm-118-138-240-255.erc.monash.edu.au/tes'
public statusMsg: BehaviorSubject<any>;
public jobs: any[];
public busy: BehaviorSubject<boolean> ;
// public testingAuth: BehaviorSubject<boolean>;
public joblist: BehaviorSubject<{ [id: string ]: Job[]}>;
private timerSubscription: any;
private token: Subject<AuthToken>;
private keyCert: Subject<KeyCert>;
private signing_endpoint: string;
private sshauthzbase: string;
private sshauthz: string;
private client_id: string;
private keypair: any;
private ssh: any;
private sshcert: any;
public keyCert: Subject<KeyCert>;
public identities: BehaviorSubject<Identity[]>;
private batchinterface: {[id: string] : BatchInterface};
constructor(private http: HttpClient,
private locationStrategy: LocationStrategy,
private route: ActivatedRoute,
private router: Router,
private computesite: ComputesitesService,
private strudelappsService: StrudelappsService) {
this.statusMsg = new BehaviorSubject<any>('');
this.busy = new BehaviorSubject<boolean>(false);
this.joblist = new BehaviorSubject<{[id: string]: Job[]}>({});
this.timerSubscription = null;
this.token = new Subject<AuthToken>();
this.keyCert = new Subject<KeyCert>();
this.identities= new BehaviorSubject<Identity[]>([]);
this.route.fragment.subscribe(frag => this.storeToken(frag));
this.token.subscribe(token => this.getCert(token));
this.keyCert.subscribe(keyCert => this.sshAdd(keyCert));
this.batchinterface = {};
this.getIdentities();
}
updateJoblist(resp, identity: Identity) {
let joblist = <Job[]>resp;
let alljobs = this.joblist.value;
let i = 0;
for (let j of joblist) {
j.app = this.strudelappsService.getApp(j.name);
j.identity = identity;
}
alljobs[identity.repr()] = joblist;
this.joblist.next(alljobs);
this.statusMsg.next(null);
}
submitted(resp: any ) {
this.busy.next(false);
this.statusMsg.next('Updating job list');
this.getJobs();
}
buildParams(app: Strudelapp, identity: Identity, batchinterface: BatchInterface): string {
private buildParams(app: Strudelapp, identity: Identity, batchinterface: BatchInterface): string {
let params = new URLSearchParams();
let appstr = JSON.stringify(app);
params.set('app',appstr);
let interfacestr = JSON.stringify(batchinterface);
params.set('interface',interfacestr);
let identitystr = JSON.stringify(identity);
params.set('identity',identitystr);
params.set('app',JSON.stringify(app));
params.set('interface',JSON.stringify(batchinterface));
params.set('identity',JSON.stringify(identity));
return params.toString();
}
updateJoblist(resp, identity: Identity) {
let joblist = <Job[]>resp;
let alljobs = this.joblist.value;
let i = 0;
for (let j of joblist) {
j.app = this.strudelappsService.getApp(j.name);
j.identity = identity;
}
alljobs[identity.repr()] = joblist;
this.joblist.next(alljobs);
this.statusMsg.next(null);
}
getJobs() {
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
......@@ -134,16 +95,28 @@ private batchinterface: {[id: string] : BatchInterface};
.pipe(catchError(this.handleError('getJobs',[])))
.subscribe(resp => this.updateJoblist(resp,identity));
}
}
private startPolling() {
this.statusMsg.next(null);
if (!(this.timerSubscription === null)) {
this.timerSubscription.unsubscribe()
}
this.timerSubscription = timer(5000).pipe(repeat()).subscribe(() => this.getJobs());
this.getJobs();
}
private stopPolling() {
if (!(this.timerSubscription === null)) {
this.timerSubscription.unsubscribe()
}
}
getconfig(app: Strudelapp, identity: Identity): Observable<any> {
public getconfig(app: Strudelapp, identity: Identity): Observable<any> {
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
return this.http.get<any>(identity.site.url+'getconfig/'+app.name,options)
.pipe(catchError(this.handleError('getconfig',[])))
}
submit(app: Strudelapp, identity: Identity, batchinterface: BatchInterface) {
......@@ -157,6 +130,12 @@ private batchinterface: {[id: string] : BatchInterface};
.subscribe(resp => this.busy.next(false));
}
submitted(resp: any ) {
this.busy.next(false);
this.statusMsg.next('Updating job list');
this.getJobs();
}
cancel(job: Job) {
console.log("In tes cancel");
let headers = new HttpHeaders();
......@@ -183,80 +162,7 @@ private batchinterface: {[id: string] : BatchInterface};
this.busy.next(false);
}
storeToken(frag: string) {
if (frag === undefined || frag == null) {
return;
}
let tokenmatch = null;
let statematch = null;
if (!(frag === undefined) && !(frag == null)) {
tokenmatch = frag.match(/access_token\=([\S\s]*?)[&|$]/);
statematch = frag.match(/state\=([\S\s]*?)[&|$]/);
}
if (tokenmatch == null || statematch == null) {
return;
}
let accesstoken = tokenmatch[1];
let state = statematch[1];
this.router.navigate(['/']);
//Verify that the state matched the nonce we used when initiating login
let tuple = JSON.parse(localStorage.getItem('authservice'));
if (tuple[1] != state) {
return
}
this.token.next(new AuthToken(tokenmatch[1],tuple[0]));
// TODO fire off a query to the auth service to get the associated sites
}
getCert(token: AuthToken) {
console.log('in getCert');
if (token.token === undefined || token.token === '' || token.token == null) {
console.log('no authtoken available, we wont be able to generate a cert');
console.log(token);
return
}
console.log("Generating key matter");
let starttime = new Date();
let newkeypair = keypair();
let publicKey = forge.pki.publicKeyFromPem(newkeypair.public);
let sshpub = forge.ssh.publicKeyToOpenSSH(publicKey, 'sv2@monash.edu');
let endtime = new Date();
console.log("generating new keys took", endtime.valueOf() - starttime.valueOf())
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
let data = {'token': token.token, 'pubkey': sshpub, 'signing_url': token.authservice.sign};
this.busy.next(true);
this.statusMsg.next("Generating Certificates ...")
console.log('posting to getcert',this.Base);
this.http.post<any>(this.Base+'/getcert',data, options)
.pipe(catchError(this.handleError('getCert',[])))
.subscribe(resp => this.makeKeyCert(newkeypair.private, resp, token.authservice))
console.log('getcert complete');
}
makeKeyCert(key: string, resp, authservice: AuthService) {
let keyCert = new KeyCert()
keyCert.key = key;
keyCert.cert = resp['cert'];
keyCert.authservice = authservice;
console.log('updating keycert',keyCert);
this.keyCert.next(keyCert);
}
private sshAdd(keyCert: KeyCert) {
console.log('in sshAdd');
if (keyCert.key == undefined) {
return;
}
......@@ -265,13 +171,10 @@ private sshAdd(keyCert: KeyCert) {
this.statusMsg.next("Authorising ...")
let data = {'key': keyCert.key, 'cert': keyCert.cert};
console.log('adding key',data);
this.http.post<any>(this.Base+'/sshagent',data,options)
.pipe(catchError(this.handleError('storeCert',[])))
.subscribe(resp => this.getIdentities(),
error => this.httperror(error));
console.log('sshAdd complete');
}
private getIdentities() {
......@@ -282,12 +185,10 @@ private getIdentities() {
this.http.get<any>(this.Base+'/sshagent',options)
.pipe(catchError(this.handleError('getIdentities',[])))
.subscribe(resp => this.updateIdentities(resp));
console.log('getIdentities complete');
}
private killAgent() {
this.statusMsg.next("Updating the list of available accounts")
this
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
this.http.delete<any>(this.Base+'/sshagent',options)
......@@ -298,11 +199,8 @@ private killAgent() {
private updateIdentities(resp) {
//TODO Each cert as the signing CA parameter. Use this to find the compute sites
// rather than just assuming sites[0]
console.log('attempting to update our local list of identities');
let certcontents = resp;
console.log(certcontents);
let identities = [];
console.log('identities updated');
let sites = this.computesite.getComputeSites();
let idsShort = []
for (let i in certcontents) {
......@@ -311,52 +209,17 @@ private updateIdentities(resp) {
this.identities.next(identities);
if (identities.length == 0) {
this.statusMsg.next(null);
console.log('local identities, none available');
return;
}
console.log('local identities updated');
this.startPolling();
}
private startPolling() {
console.log('in start polling');
this.statusMsg.next(null);
if (!(this.timerSubscription === null)) {
console.log('unsubscribing timer');
this.timerSubscription.unsubscribe()
}
console.log('creating timer to poll for jobs');
// this.timerSubscription = timer(100,5000).subscribe(() => this.getJobs());
this.timerSubscription = timer(5000).pipe(repeat()).subscribe(() => this.getJobs());
this.getJobs();
console.log('start polling complete');
}
public login() {
let redirect_uri = window.location.origin+this.locationStrategy.getBaseHref()+"sshauthz_callback";
let nonce="asdfzxcv";
let authservice = new AuthService();
authservice.base = "https://autht.massive.org.au/hpcid/";
authservice.authorise = authservice.base + 'oauth/authorize';
authservice.sign = authservice.base + 'api/v1/sign_key';
authservice.client_id = "86c06039-e589-4b39-9d1f-9eca431be18f";
localStorage.setItem('authservice', JSON.stringify([authservice,nonce]));
window.location.assign(authservice.authorise+"?response_type=token&redirect_uri="+redirect_uri+"&state="+nonce+"&client_id="+authservice.client_id);
}
public logout(): Boolean {
this.token = null;
this.sshcert = null;
this.statusMsg.next(null);
this.killAgent();
// if (!(this.timerSubscription === null)) {
// this.timerSubscription.unsubscribe()
// }
return true;
}
public getstatusMsgSubject(): BehaviorSubject<any> {
return this.statusMsg;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment