From 48e0a3e1aaa32ebf495348a66d13d6b3d1870ce3 Mon Sep 17 00:00:00 2001
From: Chris Hines <chris.hines@monash.edu>
Date: Wed, 6 May 2020 16:20:23 +1000
Subject: [PATCH]  support apps that require a form post to log in (as opposed
 to a token in the query params)

---
 src/app/browser-window.service.ts             | 43 ++++++++++++++++---
 .../launch-dialog/launch-dialog.component.ts  |  3 +-
 src/app/strudelapp.ts                         |  1 +
 src/app/tes.service.ts                        |  6 +--
 4 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/src/app/browser-window.service.ts b/src/app/browser-window.service.ts
index 10b2d86..157c46e 100644
--- a/src/app/browser-window.service.ts
+++ b/src/app/browser-window.service.ts
@@ -10,7 +10,7 @@ import { Injectable } from '@angular/core';
 import { Job } from './job';
 import { AppAction, Strudelapp, StrudelappInstance } from './strudelapp';
 import {BackendSelectionService} from './backend-selection.service';
-import {repeat, take, takeUntil, filter, catchError} from 'rxjs/operators';
+import {repeat, take, takeUntil, filter, catchError, map, tap} from 'rxjs/operators';
 import {timer, interval, Subject, BehaviorSubject, of} from 'rxjs';
 import { ModaldialogComponent } from './modaldialog/modaldialog.component';
 import { MatDialog, MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material';
@@ -55,22 +55,55 @@ export class BrowserWindowService {
    }
  }
 
- public openAppWindow( job: Job, url: any, basicAuth: boolean, action: AppAction ) {
+ public openAppWindow( job: Job, url: any, basicAuth: boolean, action: AppAction, appinst: any ) {
      var re = /^https:\/\/([a-z0-9\.-]+)\/?/;
      let twshost = this.twsproxy.replace(re,"$1");
      let windowloc = url.replace(/\{twsproxy\}/g,this.twsproxy).replace(/twshost/g,twshost);
      var authwindow = null;
    
      if (basicAuth) {
-       let authwindowloc = windowloc.replace(/^https:\/\//,'https://'+job.appinst.username+':'+job.appinst.password+'@');
+       let authwindowloc = windowloc.replace(/^https:\/\//,'https://'+appinst.username+':'+appinst.password+'@');
        authwindow = window.open(authwindowloc);
        this.authdone$.pipe(take(1)).subscribe( () => { authwindow.close() ; this.finishAppWindow(windowloc,job,action) });
        interval(500).pipe(takeUntil(this.authdone$),filter((v) => this.windowLoaded(authwindow, authwindowloc))).subscribe( () => this.authdone$.next(true));
-     } else {
-       this.finishAppWindow(windowloc,job, action);
+       return
+     } 
+     if (action.postData !== undefined && action.postData !== null) {
+       let params = {}
+       for (let k in action.postData) {
+         params[k] = action.postData[k].replace(/\{password\}/g,appinst.password).replace(/\{username\}/g,appinst.username);
+       }
+       this.openWindowWithPostRequest(windowloc,params);
+       return
      }
+
+
+     this.finishAppWindow(windowloc,job, action);
  }
 
+
+  public openWindowWithPostRequest(url: string, params: any) {
+  var winName='MyWindow';
+  var form = document.createElement("form");
+  form.setAttribute("method", "post");
+  form.setAttribute("action", url);
+  form.setAttribute("target",winName);
+  for (var i in params) {
+    if (params.hasOwnProperty(i)) {
+      var input = document.createElement('input');
+      input.type = 'hidden';
+      input.name = i;
+      input.value = params[i];
+      form.appendChild(input);
+    }
+  }
+  document.body.appendChild(form);
+  window.open('', winName);
+  form.target = winName;
+  form.submit();
+  document.body.removeChild(form);
+}
+
   public logUsage() {
     var app: any;
     this.openapps.forEach( (app,index) => {
diff --git a/src/app/launch-dialog/launch-dialog.component.ts b/src/app/launch-dialog/launch-dialog.component.ts
index 2fd67d4..f186c31 100644
--- a/src/app/launch-dialog/launch-dialog.component.ts
+++ b/src/app/launch-dialog/launch-dialog.component.ts
@@ -59,7 +59,7 @@ export class LaunchDialogComponent implements OnInit {
     this.height=0;
     this.submitcmd.subscribe(() => this.canILaunch());
     this.appData.subscribe(() => this.canILaunch());
-    this.tesService.openWindow$.subscribe((v) => {  this.browserWindowService.openAppWindow(v.job,v.url,v.usebasicauth,v.action)})
+    this.tesService.openWindow$.subscribe((v) => {  this.browserWindowService.openAppWindow(v.job,v.url,v.usebasicauth,v.action,v.appinst)})
     this.browserWindowService.cancelJob$.subscribe((v) => this.tesService.cancel(v))
 
   }
@@ -159,6 +159,7 @@ export class LaunchDialogComponent implements OnInit {
     newaction.paramscmd = action.paramscmd.replace(/\{submitcmd\}/,submitcmd);
     newaction.notunnel = action.notunnel;
     newaction.client = action.client;
+    newaction.postData = action.postData;
     this.tesService.connect(job,newaction);
   }
 
diff --git a/src/app/strudelapp.ts b/src/app/strudelapp.ts
index eab5c2f..7b8c863 100644
--- a/src/app/strudelapp.ts
+++ b/src/app/strudelapp.ts
@@ -4,6 +4,7 @@ export class AppAction {
   notunnel: boolean = false;
   client: {cmd: string[], redir: string, usebasicauth: boolean};
   states: string[]; // list of stats such as 'RUNNING' in which the action is valid. null||undefined if its always valid
+  postData: string; // if you need to post to the url to authenticate use this
 }
 export class Strudelapp {
   url: string; // A url used to retrieve extra config options. May be null
diff --git a/src/app/tes.service.ts b/src/app/tes.service.ts
index 4afcc8c..02d0690 100644
--- a/src/app/tes.service.ts
+++ b/src/app/tes.service.ts
@@ -297,14 +297,14 @@ private addUserHealth(identity,resp) {
        (data,tunnelresp) => { data[1]['localport'] = (<any> tunnelresp)['localport'] ; return data}), // we don't care about data from the tunnel as long as it was successful.`
      tap((_) => job.connectionState=3),
      switchMap(([apiserver,appinst]) => this.getAppUrl(job,appinst,action,<APIServer>apiserver),
-       ([apiserver,appinst],url) => {return [apiserver,url]}),
+       ([apiserver,appinst],url) => {return [apiserver,appinst,url]}),
      tap((_) => job.connectionState=4),
-   ).subscribe(([apiserver,url]) => { if (url !== null) {
+   ).subscribe(([apiserver,appinst,url]) => { if (url !== null) {
                                           this.openWindow$.next( {'job':job, 
                                                 'url': <string> url, 
                                                 'usebasicauth':action.client.usebasicauth,
                                                 'apiserver':apiserver,
-                                            'action':action});
+                                            'action':action,'appinst':appinst});
                                       }
                                     job.connectionState=0},
      (err) => { job.connectionState = 0; this.handleError(err)})
-- 
GitLab