Commit 01efaa5e authored by Chris Hines's avatar Chris Hines
Browse files

all sorts of changes

parent 4de33b31
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';
@Injectable({
providedIn: 'root'
})
export class AuthorisationService {
constructor() { }
}
This diff is collapsed.
......@@ -3,6 +3,9 @@ import { RouterModule, Routes } from '@angular/router';
import { LauncherComponent } from './launcher/launcher.component';
import { KeygenComponent } from './keygen/keygen.component';
import { ConnectingComponent } from './connecting/connecting.component';
import { TransferComponent } from './transfer/transfer.component';
import { ShareconnectComponent } from './shareconnect/shareconnect.component';
// import { TokenextractorComponent } from './tokenextractor/tokenextractor.component';
......@@ -13,7 +16,10 @@ const routes: Routes = [
{ path: 'finishlaunch', component: LauncherComponent},
{ path: 'cancellaunch', component: LauncherComponent},
{ path: 'sshauthz_callback', component: KeygenComponent},
{ path: 'connecting', component: ConnectingComponent }
{ path: 'connecting', component: ConnectingComponent },
{ path: 'transfer', component: TransferComponent },
{ path: 'shareconnect', component: ShareconnectComponent }
// { path: 'sshauthz_callback', component: LauncherComponent}
......
.fill-remaining-space {
/* This fills the remaining space, by using flexbox.
Every toolbar row uses a flexbox row layout. */
flex: 1 1 auto;
}
.fill-horizontal-space {
/* This fills the remaining space, by using flexbox.
Every toolbar row uses a flexbox row layout. */
flex: 0 1 auto;
}
<router-outlet class="fill-remaining-space"></router-outlet>
<!-- <app-teserrors></app-teserrors> -->
<!-- <router-outlet class="fill-remaining-space"></router-outlet> -->
<router-outlet></router-outlet>
import { Component } from '@angular/core';
import { TesService } from './tes.service';
import { AuthorisationService} from './authorisation.service';
import { ComputesitesService} from './computesites.service';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import { MatSnackBar } from '@angular/material';
@Component({
selector: 'app-root',
......@@ -12,16 +16,39 @@ export class AppComponent {
private loggedin: Boolean = false;
private errmsg: string='';
public authorised: boolean;
public statusMsg: BehaviorSubject<string>;
private snackBarRef: any;
// private testingAuth: boolean;
constructor(private tesService: TesService, private authService: AuthorisationService) {
constructor(private tesService: TesService,
private authService: AuthorisationService,
private computesitesService: ComputesitesService,
public snackBar: MatSnackBar,) {
};
ngOnInit() {
// this.tesService.testingAuth.subscribe(testingAuth => { this.testingAuth = testingAuth; console.log('testingAuth updated'+this.testingAuth) });
// this.testingAuth = false;
this.statusMsg = new BehaviorSubject<any>('');
this.tesService.setStatusMsg(this.statusMsg);
this.computesitesService.setStatusMsg(this.statusMsg);
this.authService.setStatusMsg(this.statusMsg);
this.statusMsg.subscribe(msg => this.displayMessage(msg));
}
private displayMessage(msg) {
if (msg === null || msg == "") {
console.log('attempting to dismis snackbar');
if (this.snackBarRef != undefined) {
this.snackBarRef.dismiss()
}
} else {
this.snackBarRef = this.snackBar.open(msg,'Dismiss');
}
}
// login() {
// console.log("login");
// this.authService.login()
......
......@@ -17,17 +17,22 @@ import { MatToolbarModule } from '@angular/material';
import { MatDialogModule, MatDialog } from '@angular/material';
import { MatSnackBarModule } from "@angular/material";
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ComputesitesService } from './computesites.service';
import { StrudelappsService } from './strudelapps.service';
import { AuthorisationService } from './authorisation.service';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FileExplorerModule } from './file-explorer/file-explorer.module';
import { TesService} from './tes.service';
import { SubmitAppService } from './submit-app.service';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { JobComponent } from './job/job.component';
// import { SiteselectionComponent } from './siteselection/siteselection.component';
import { TeserrorsComponent } from './teserrors/teserrors.component';
// import { TeserrorsComponent } from './teserrors/teserrors.component';
import { AppRoutingModule } from './/app-routing.module';
import { TokenextractorComponent } from './tokenextractor/tokenextractor.component';
// import { LogindialogComponent } from './logindialog/logindialog.component';
......@@ -39,6 +44,10 @@ import { MatSidenavModule, MatExpansionModule, MatIconModule } from '@angular/ma
import { StrudelapplistComponent } from './strudelapplist/strudelapplist.component';
import { KeygenComponent } from './keygen/keygen.component';
import { ConnectingComponent } from './connecting/connecting.component';
import { TransferComponent } from './transfer/transfer.component';
import { Sv2SideNavComponent } from './sv2-side-nav/sv2-side-nav.component';
import { ShareconnectComponent } from './shareconnect/shareconnect.component';
// import { FileExplorerModule } from './file-explorer/file-explorer.module';
......@@ -50,14 +59,17 @@ import { ConnectingComponent } from './connecting/connecting.component';
JoblistComponent,
JobComponent,
// SiteselectionComponent,
TeserrorsComponent,
// TeserrorsComponent,
TokenextractorComponent,
LogoutdialogComponent,
ModaldialogComponent,
// LaunchdialogComponent,
StrudelapplistComponent,
KeygenComponent,
ConnectingComponent
ConnectingComponent,
TransferComponent,
Sv2SideNavComponent,
ShareconnectComponent
],
imports: [
BrowserModule,
......@@ -80,10 +92,14 @@ import { ConnectingComponent } from './connecting/connecting.component';
MatExpansionModule,
MatIconModule,
MatSnackBarModule,
FileExplorerModule,
FlexLayoutModule,
MatProgressBarModule,
],
entryComponents: [ ModaldialogComponent, LogoutdialogComponent, ],
providers: [ StrudelappsService, ComputesitesService, TesService, MatDialog, AuthorisationService],
providers: [ StrudelappsService, ComputesitesService, TesService, SubmitAppService, MatDialog, AuthorisationService],
bootstrap: [AppComponent]
})
export class AppModule { }
......@@ -4,7 +4,7 @@ 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 {LocationStrategy, Location} from '@angular/common';
// import { keypair } from 'keypair';
import * as keypair from 'keypair';
import * as forge from "node-forge";
......@@ -13,6 +13,8 @@ import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Subject} from 'rxjs/Subject';
import {TesService} from './tes.service';
import { throwError } from 'rxjs';
import { environment } from '../environments/environment';
export class SshauthzServer {}
......@@ -24,26 +26,38 @@ export class AuthorisationService {
// public token: BehaviorSubject<AuthToken>;
public token: AuthToken
public SshAuthzServers: BehaviorSubject<SshAuthzServer[]>;
public readyToNavigate: Subject<Boolean>;
public readyToNavigate: Subject<[Boolean,string]>;
public progress: Subject<string>;
// private keyCert: Subject<KeyCert>;
private backendURI: string;
public statusMsg: BehaviorSubject<string>;
public agentContents: BehaviorSubject<any>;
public keys: KeyCert[];
constructor(private http: HttpClient,
private locationStrategy: LocationStrategy,
private route: ActivatedRoute,
private router: Router,
private tesService: TesService) {
private location: Location) {
console.log('created AuthorisationService');
// this.token = new BehaviorSubject<AuthToken>(new AuthToken('',''));
this.readyToNavigate = new Subject<Boolean>();
this.readyToNavigate.next(false);
this.readyToNavigate = new Subject<[Boolean,string]>();
this.readyToNavigate.next([false,'']);
this.progress = new Subject<string>();
this.progress.next("");
// this.token.subscribe(token => this.getCert(token));
this.route.fragment.subscribe(frag => this.storeToken(frag));
this.SshAuthzServers = new BehaviorSubject<SshAuthzServer[]>([]);
this.backendURI = environment.tesurl;
this.agentContents = new BehaviorSubject(null);
this.keys = [];
this.getSshAuthzServers();
this.keys = [];
}
public setStatusMsg(statusMsg: BehaviorSubject<any>) {
this.statusMsg = statusMsg;
}
getSshAuthzServers() {
......@@ -56,6 +70,7 @@ export class AuthorisationService {
updateSshAuthzServers(resp) {
this.SshAuthzServers.next(<SshAuthzServer[]>resp);
console.log('sshauthzservers set to',this.SshAuthzServers.value);
}
storeToken(frag: string) {
......@@ -109,60 +124,163 @@ export class AuthorisationService {
let data = {'token': token.token, 'pubkey': sshpub, 'signing_url': token.sshauthzservice.sign};
console.log('posting to getcert',this.tesService.Base);
this.http.post<any>(this.tesService.Base+'/getcert',data, options)
.pipe(catchError(this.handleError('getCert',[])))
console.log('posting to getcert',this.backendURI);
this.http.post<any>(this.backendURI+'/getcert',data, options)
// .pipe(catchError(this.handleError([])))
.subscribe(resp => this.makeKeyCert(newkeypair.private, resp, token.sshauthzservice),
error => this.httperrorLogout(error,token.sshauthzservice));
console.log('getcert complete');
}
public getKeys(id?: Identity) {
try{
return JSON.parse(sessionStorage.getItem('keys'));
} catch {
return [];
}
}
makeKeyCert(key: string, resp, sshauthzservice: SshAuthzServer) {
let keyCert = new KeyCert()
keyCert.key = key;
keyCert.cert = resp['cert'];
console.log('in make KeyCert',resp);
console.log('updating keycert',keyCert);
this.tesService.sshAdd(keyCert);
var keys: KeyCert[] = [];
try{
keys = JSON.parse(sessionStorage.getItem('keys'));
} catch {
keys = [];
}
if (keys === null) {
keys = [];
}
keys.push(keyCert);
sessionStorage.setItem('keys',JSON.stringify(keys))
this.sshAdd(keyCert);
let path=localStorage.getItem('path');
console.log('authorisation complete, ready to navigate back to the correct view',path);
// this.tesService.keyCert.next(keyCert);
// As soon as the certificate has been generated, we log back out of the signing server
if (!(sshauthzservice.logout === null)) {
window.open(sshauthzservice.logout);
}
this.readyToNavigate.next(true);
this.readyToNavigate.next([true,path]);
}
public querySshAgentError(error: any) {
this.agentContents.next([]);
if (error.status == 0) {
this.statusMsg.next("A network error occured. Are you connected to the internet?")
}
}
public updateAgentContents() {
this.statusMsg.next("Updating the list of available accounts");
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
var anyvar: any;
this.http.get<any>(this.backendURI+'/sshagent',options)
// .pipe(catchError(this.handleError(anyvar)))
.subscribe(resp => { console.log('sshagent returned',resp); this.agentContents.next(resp); this.statusMsg.next("") },
error => this.querySshAgentError(error));
// .subscribe(resp => this.computeSitesService.updateIdentities(resp),
// error => this.httperror(error))
}
private killAgent() {
this.statusMsg.next("Logging out")
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
var anyvar: any;
this.http.delete<any>(this.backendURI+'/sshagent',options)
.pipe(catchError(this.handleError(anyvar)))
.subscribe(resp => this.updateAgentContents(),
error => this.httperror(error));
}
public logout(): Boolean {
this.killAgent();
return true;
}
public sshAdd(keyCert: KeyCert) {
console.log('in authorisation service sshAdd');
if (keyCert.key == undefined) {
return;
}
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
var anyvar: any;
this.statusMsg.next("Authorising ...")
let data = {'key': keyCert.key, 'cert': keyCert.cert};
this.http.post<any>(this.backendURI+'/sshagent',data,options)
.pipe(catchError(this.handleError(anyvar)))
.subscribe(resp => this.updateAgentContents(),
error => this.httperror(error))
}
public login(authservice: SshAuthzServer) {
let redirect_uri = window.location.origin+this.locationStrategy.getBaseHref()+"sshauthz_callback";
let nonce="asdfzxcv";
console.log(this.location.path());
localStorage.setItem('authservice', JSON.stringify([authservice,nonce]));
localStorage.setItem('path', this.location.path());
console.log('login activated, pathname stored as',window.location.pathname);
if (authservice.scope == null) {
window.location.assign(authservice.authorise+"?response_type=token&redirect_uri="+redirect_uri+"&state="+nonce+"&client_id="+authservice.client_id);
} else {
window.location.assign(authservice.authorise+"?response_type=token&redirect_uri="+redirect_uri+"&state="+nonce+"&client_id="+authservice.client_id+"&scope="+authservice.scope);
}
}
// private handleError(error: HttpErrorResponse) {
// if (error.error instanceof ErrorEvent) {
// console.log('instance of ErrorEvent');
// console.log(error);
// // A client-side or network error occurred. Handle it accordingly.
// return throwError("Hmm, that didn't work. If you're using a local connection, please make sure Strudel-TES is running.");
// } else {
// console.log('NOT an instance of ErrorEvent');
// console.log(error);
// // Not sure if this code works correctly. It should update identities in case the error is
// // that the user isn't allowed to run the job
//
// var re = /identity/gi;
// let searchresult = error.error.message.search(re);
// if (searchresult != -1) {
// // this.getIdentities();
// return throwError('login expired, refreshing');
// }
// return throwError(error.error.message)
// // this.statusMsg.next("There was an error submitting that job. The backend gave me the message: " + error.error.message);
//
// }
private httperror(error: any) {
this.tesService.statusMsg.next(error);
this.statusMsg.next(error);
console.log(error);
}
private httperrorLogout(error: any,sshauthzservice: SshAuthzServer) {
this.tesService.statusMsg.next(error);
this.statusMsg.next(error);
console.log(error);
if (!(sshauthzservice.logout === null)) {
window.open(sshauthzservice.logout);
}
}
private handleError<T> (operation = 'operation', result?: T) {
private handleError<T> (result?: T) {
return (error: any): Observable<T> => {
console.log('in handle error',operation);
console.log(error.status);
console.error(error);
console.log(error)
if (error.status == 500) {
return throwError("The authorisation server encountered and error. Please try again in a few minutes")
return throwError("The backend server encountered and error. Please try again in a few minutes")
}
return throwError(error.message);
// return of(result as T);
......
......@@ -2,5 +2,4 @@ export class BatchInterface {
cancelcmd: string;
submitcmd: string;
statcmd: string;
internalfirewall: boolean;
}
......@@ -6,11 +6,15 @@ export class Computesite {
// submit stat and cancel
name: string; // Human readable name
host: string; // Login host
dtn: string;
dtnport: string;
lscmd: string;
cafingerprint: string; // Certificates contain a CA fingerprint. We use this
// to figure out which compute site a certificate is valid
// for
appCatalog: BehaviorSubject<Strudelapp[]>;
appCatalogUri: string;
internalfirewall: boolean; // Does a firewall exist within the site necessitating an extra level of ssh tunnel
}
......
......@@ -5,6 +5,9 @@ import { HttpClientModule, HttpClient, HttpHeaders, HttpErrorResponse } from '@a
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap } from 'rxjs/operators';
import { Identity } from './identity';
import { TesService } from './tes.service';
import { AuthorisationService} from './authorisation.service';
......@@ -13,24 +16,54 @@ import { catchError, map, tap } from 'rxjs/operators';
})
export class ComputesitesService {
public computesites: BehaviorSubject<Computesite[]>;
public identities: BehaviorSubject<Identity[]>;
public appidentities: BehaviorSubject<Identity[]>;
public ftidentities: BehaviorSubject<Identity[]>;
private statusMsg: BehaviorSubject<any>;
constructor(private http: HttpClient,) {
constructor(private http: HttpClient, private authorisationService: AuthorisationService) {
this.computesites = new BehaviorSubject<Computesite[]>([]);
this.identities = new BehaviorSubject<Identity[]>([]);
this.appidentities = new BehaviorSubject<Identity[]>([]);
this.ftidentities = new BehaviorSubject<Identity[]>([]);
this.computesites.subscribe(computesites => this.getStrudelApps(computesites))
this.getComputeSites();
this.authorisationService.agentContents.subscribe(ac => this.updateIdentities(ac));
}
public setStatusMsg(statusMsg: BehaviorSubject<any>) {
this.statusMsg = statusMsg;
}
getStrudelApps(computesites: Computesite[]) {
for (let s of computesites) {
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: false};
if (s.appCatalogUri !== null) {
this.http.get<Strudelapp[]>(s.appCatalogUri,options)
.pipe(catchError(this.handleError('getStrudelApps')))
.subscribe(resp => this.updateStrudelApps(s.appCatalog,resp));
.subscribe(resp => this.updateStrudelApps(s.appCatalog,resp,s.name));
}
}
}
updateStrudelApps(appCatalog: BehaviorSubject<Strudelapp[]>,apps, sitename) {
var sapps: Strudelapp[];
var localapps: Strudelapp[];
sapps = <Strudelapp[]>apps;
localapps = JSON.parse(localStorage.getItem(sitename+'-apps'))
if (localapps !== null) {
for (let a of localapps) {
sapps.push(a);
}
}
appCatalog.next(sapps);
}
private handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(error);
......@@ -38,9 +71,6 @@ export class ComputesitesService {
};
}
updateStrudelApps(appCatalog: BehaviorSubject<Strudelapp[]>,apps) {
appCatalog.next(<Strudelapp[]>apps);
}
getComputeSites() {