From 45fe51ab424144e5bc10d3c4beaad5f35daefb10 Mon Sep 17 00:00:00 2001 From: Christopher Edwards Date: Tue, 19 Feb 2019 14:49:52 -0500 Subject: [PATCH] [#5] Add username and password authentication Add username and password authentication support using a local variable to the webserver. Update readme with default username/password and how to specify the desired username/password. --- README.md | 4 +++- r/GDEWEB.m | 11 +++++++++-- start.sh | 2 +- webserver/_webreq.m | 15 ++++++++------- webserver/_webrsp.m | 7 +++++++ 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 0007411..d5fca67 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ docker run -itd -p 8089:8080 --name ydbgui yottadb/yottadbgui:latest ``` To use the GUI go to https://localhost:8089 in a web browser. +The default username/password is admin/admin. ## Manual Setup @@ -69,10 +70,11 @@ $ydb_dist/mumps ../r/*.m cd dist export ydb_lct_stdnull=1 export ydb_local_collate=0 # Note: this is the default -$ydb_dist/mumps -run ^GDEWEB 8080 NOSSL +$ydb_dist/mumps -run ^GDEWEB 8080 NOSSL admin:admin ``` 8080 is the port number in which to start the web server and can be adjusted to any port number that is available on your system. +admin:admin is the username:password to use for authentication and can be set to a combination you desire. # Development diff --git a/r/GDEWEB.m b/r/GDEWEB.m index a23e55a..0affc65 100644 --- a/r/GDEWEB.m +++ b/r/GDEWEB.m @@ -18,7 +18,7 @@ ; @example ; d WEB^GDEWEB(9080) ; -WEB(portnum,ssl) +WEB(portnum,ssl,userpass) ; Sanity check env vars to make sure GDE works as intended i (+$ztrnlnm("ydb_local_collate")'=0) w "Local collation environment variable (ydb_local_collate) must be 0" quit i (+$ztrnlnm("ydb_lct_stdnull")'=1) w "Standard null collation environment variable (ydb_lct_stdnull) must be 1" quit @@ -27,9 +27,13 @@ s done=0 f i=1:1:$l($zcmdline," ") d . s args(i)=$p($zcmdline," ",i) + ; port number i $l($g(args(1)))&($g(args(1))=+$g(args(1))) s portnum=args(1) e s portnum="" + ; ssl/tls config i $l($g(args(2))) s ssl=args(2) + ; admin username/password + i $l($g(args(3))) s userpass=args(3) ; ; Get the port number to run on i '$l(portnum) w "No port number specified, or invalid - using default of 8080",! @@ -45,10 +49,13 @@ i ((ssl="nossl")!(ssl="NOSSL")!(ssl=0)) s ssl=0 w "SSL configuration NOT found!",! i 'ssl w "WARNING: Web server started without SSL/TLS",! ; + ; Make sure userpass argument is valid + i $l($g(userpass))&($g(userpass)'[":") w "userpass argument must be in username:password format!",!,$g(userpass),!,"Quitting...",! quit + ; ; Start the web server i $l($t(^%webreq)) d . w "Starting Web Server...",! - . d job^%webreq($g(portnum,8080),$s(ssl:"ydbgui",1:"")) + . d job^%webreq($g(portnum,8080),$s(ssl:"ydbgui",1:""),,$g(userpass)) e d . w "Web server code not found in $zroutines, please make sure $zroutines is set correctly!",! quit diff --git a/start.sh b/start.sh index 39d2a4e..71a8b18 100755 --- a/start.sh +++ b/start.sh @@ -22,7 +22,7 @@ source /opt/yottadb/gui/env # Start the GUI cd /opt/yottadb/gui/dist -/opt/yottadb/current/mumps -run ^GDEWEB 8080 SSL +/opt/yottadb/current/mumps -run ^GDEWEB 8080 SSL admin:admin # Webserver doesn't daemonize, use a fifo to allow bash to capture # signals from docker diff --git a/webserver/_webreq.m b/webserver/_webreq.m index 0d329ee..47d9d70 100644 --- a/webserver/_webreq.m +++ b/webserver/_webreq.m @@ -8,12 +8,13 @@ D job(PORT) QUIT ; -job(PORT,TLSCONFIG,NOGBL) ; Convenience entry point - I $P($SY,",")=47 J start^%webreq(PORT,,$G(TLSCONFIG),$G(NOGBL)):(IN="/dev/null":OUT="vprjreq.mjo":ERR="vprjreq.mje"):5 ; no in and out files please. - E J start^%webreq(PORT,"",$G(TLSCONFIG),$G(NOGBL)) ; Cache can't accept an empty string in the second argument +job(PORT,TLSCONFIG,NOGBL,USERPASS) ; Convenience entry point + I $L($G(USERPASS))&($G(USERPASS)'[":") W "USERPASS argument is invalid, must be in username:password format!" QUIT + I $P($SY,",")=47 J start^%webreq(PORT,,$G(TLSCONFIG),$G(NOGBL),,$G(USERPASS)):(IN="/dev/null":OUT="vprjreq.mjo":ERR="vprjreq.mje"):5 ; no in and out files please. + E J start^%webreq(PORT,"",$G(TLSCONFIG),$G(NOGBL),,$G(USERPASS)) ; Cache can't accept an empty string in the second argument QUIT ; -start(TCPPORT,DEBUG,TLSCONFIG,NOGBL,TRACE) ; set up listening for connections +start(TCPPORT,DEBUG,TLSCONFIG,NOGBL,TRACE,USERPASS) ; set up listening for connections ; I hope TCPPORT needs no explanations. ; ; DEBUG is so that we run our server in the foreground. @@ -62,7 +63,7 @@ D job(PORT) I %WOS="CACHE" D G LOOP . R *X:10 . E QUIT ; Loop back again when listening and nobody on the line - . J CHILD($G(TLSCONFIG)):(:4:TCPIO:TCPIO):10 ; Send off the device to another job for input and output. + . J CHILD($G(TLSCONFIG),$G(NOGBL),$G(TRACE),$G(USERPASS)):(:4:TCPIO:TCPIO):10 ; Send off the device to another job for input and output. . i $ZA\8196#2=1 W *-2 ; job failed to clear bit ; ---- END CACHE CODE ---- ; @@ -86,7 +87,7 @@ D job(PORT) . . U TCPIO:(detach=CHILDSOCK) . . N Q S Q="""" . . N ARG S ARG=Q_"SOCKET:"_CHILDSOCK_Q - . . N J S J="CHILD($G(TLSCONFIG),$G(NOGBL),$G(TRACE)):(input="_ARG_":output="_ARG_")" + . . N J S J="CHILD($G(TLSCONFIG),$G(NOGBL),$G(TRACE),$G(USERPASS)):(input="_ARG_":output="_ARG_")" . . J @J . ; . ; GT.M before 6.1: @@ -138,7 +139,7 @@ D job(PORT) ; HTTPLOG indicates the logging level for this process ; HTTPERR non-zero if there is an error state ; -CHILD(TLSCONFIG,NOGBL,TRACE) ; handle HTTP requests on this connection +CHILD(TLSCONFIG,NOGBL,TRACE,USERPASS) ; handle HTTP requests on this connection CHILDDEBUG ; [Internal] Debugging entry point N %WTCP S %WTCP=$GET(TCPIO,$PRINCIPAL) ; TCP Device N %WOS S %WOS=$S($P($SY,",")=47:"GT.M",$P($SY,",")=50:"MV1",1:"CACHE") ; Get Mumps Virtual Machine diff --git a/webserver/_webrsp.m b/webserver/_webrsp.m index 49db68e..01be911 100644 --- a/webserver/_webrsp.m +++ b/webserver/_webrsp.m @@ -121,8 +121,15 @@ D QSPLIT(HTTPREQ("query"),.HTTPARGS) I $G(HTTPERR) QUIT ; Okay. Do we have a routine to execute? I ROUTINE="" D SETERROR^%webutils(404,"Not Found") QUIT ; + I $l($g(USERPASS)) S AUTHNODE=1 I +$G(AUTHNODE) D ; Web Service has authorization node . ; + . I $d(USERPASS) D QUIT + . . ; First, user must authenticate + . . S HTTPRSP("auth")="Basic realm="""_HTTPREQ("header","host")_"""" ; Send Authentication Header + . . N AUTHEN S AUTHEN=(USERPASS=$$DECODE64^%webutils($P($G(HTTPREQ("header","authorization"))," ",2))) ; Try to authenticate + . . I 'AUTHEN D SETERROR^%webutils(401) QUIT ; Unauthoirzed + . ; . ; If there is no File 200, forget the whole thing. Pretend it didn't happen. . I '$D(^VA(200)) QUIT . ;