@sassoftware/viya-serverjs 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +24 -10
- package/.env.server +6 -4
- package/Dockerfile +6 -6
- package/README.md +37 -69
- package/lib/handlers/setCookies.js +0 -1
- package/lib/iService.js +24 -16
- package/lib/index.js +6 -13
- package/lib/plugins/SASauth.js +4 -2
- package/lib/plugins/appCookie.js +0 -1
- package/lib/plugins/setDefaultRoutes.js +10 -1
- package/lib/plugins/setupUserRoutes.js +2 -0
- package/mcpServer.js +364 -0
- package/package.json +3 -2
- package/public/help.html +1 -1
- package/public/index.html +7 -1
- package/server.js +8 -4
- package/src/handlers/setCookies.js +0 -1
- package/src/iService.js +26 -11
- package/src/index.js +8 -12
- package/src/plugins/SASauth.js +6 -2
- package/src/plugins/appCookie.js +0 -1
- package/src/plugins/setDefaultRoutes.js +7 -2
- package/src/plugins/setupUserRoutes.js +3 -6
- package/.env.proxy +0 -32
- package/tls/viyatls.sh +0 -3
package/.env
CHANGED
|
@@ -1,24 +1,38 @@
|
|
|
1
1
|
APPHOST=localhost
|
|
2
2
|
# APPENTRY=index.html
|
|
3
3
|
APPLOC=./public
|
|
4
|
-
# VIYA_SERVER=
|
|
5
|
-
|
|
4
|
+
# VIYA_SERVER=your viya server
|
|
5
|
+
|
|
6
6
|
APPPORT=8080
|
|
7
|
-
APPNAME=
|
|
8
|
-
AUTHFLOW=
|
|
9
|
-
CLIENTID=
|
|
7
|
+
APPNAME=mcpapp
|
|
8
|
+
AUTHFLOW=code
|
|
9
|
+
CLIENTID=mcpapp
|
|
10
10
|
CLIENTSECRET=jellico
|
|
11
|
+
|
|
11
12
|
REDIRECT=
|
|
12
13
|
# APPDIR=./appDir
|
|
13
14
|
HTTPS=true
|
|
14
|
-
VIYA_SERVER=https://viya-00m2kebi2b.engage.sas.com
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Most modern browsers do not accept self-signed certs from localhost
|
|
19
|
+
# Options:
|
|
20
|
+
|
|
21
|
+
# 1. provide signed certificates for localhost
|
|
22
|
+
# 2. Use libraries like mkcert to create temporary trusted certs for localhost
|
|
23
|
+
# 3. Use the app server as a proxy to the Viya server to avoid CORS issues.
|
|
24
|
+
# This requires that the app redirect all Viya API calls to the app server proxy endpoint
|
|
25
|
+
# Users of restaf can simply set the APPENV_PROXY env to TRUE to enable this behavior
|
|
26
|
+
# 4. set USETOKEN to TRUE and use the token in the APPENV object to make the calls
|
|
27
|
+
// either use the proper ssl/tsl certs or use the "proxy" method
|
|
28
|
+
// to avoid CORS issues with self-signed certs
|
|
17
29
|
// so run all apps thru the proxy and call Viya from there
|
|
30
|
+
APPENV_PROXY=false
|
|
31
|
+
|
|
18
32
|
|
|
19
|
-
APPENV_PROXYSERVER=
|
|
20
|
-
USETOKEN=
|
|
21
|
-
SHOWENV=
|
|
33
|
+
# APPENV_PROXYSERVER=true
|
|
34
|
+
# USETOKEN=true
|
|
35
|
+
SHOWENV=true
|
|
22
36
|
|
|
23
37
|
APPENV_XYZ=AA
|
|
24
38
|
APPENV_BAD=
|
package/.env.server
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
APPHOST=localhost
|
|
2
2
|
APPENTRY=index.html
|
|
3
3
|
APPLOC=./public
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
# viya-server set preset
|
|
5
|
+
# VIYA_SERVER=
|
|
6
|
+
APPENV_PROXYSERVER=https://localhost:8080/viyaapp/proxy
|
|
7
|
+
|
|
6
8
|
APPPORT=8080
|
|
7
|
-
APPNAME=
|
|
9
|
+
APPNAME=viyaapp
|
|
8
10
|
AUTHFLOW=server
|
|
9
|
-
CLIENTID=
|
|
11
|
+
CLIENTID=viyaapp
|
|
10
12
|
CLIENTSECRET=jellico
|
|
11
13
|
REDIRECT=/new
|
|
12
14
|
# APPDIR=./appDir
|
package/Dockerfile
CHANGED
|
@@ -11,6 +11,7 @@ ENV APPHOST=0.0.0.0
|
|
|
11
11
|
ENV PORT=8080
|
|
12
12
|
EXPOSE 8080
|
|
13
13
|
ENV HTTPS=true
|
|
14
|
+
ENV VIYA_SERVER=
|
|
14
15
|
# ENV APPSERVERLEVEL=v2
|
|
15
16
|
#######################################################################
|
|
16
17
|
# You can override these(but in container leave APPHOST as shown below)
|
|
@@ -20,20 +21,19 @@ ENV HTTPS=true
|
|
|
20
21
|
# ENV APPPORT=8080
|
|
21
22
|
|
|
22
23
|
ENV APPNAME=viyaapp
|
|
23
|
-
|
|
24
|
+
ENV AUTHFLOW=server
|
|
24
25
|
ENV CLIENTID=viyaapp
|
|
25
|
-
ENV CLIENTSECRET=
|
|
26
|
+
ENV CLIENTSECRET=
|
|
26
27
|
# ENV HAPIDEBUG=NO
|
|
27
28
|
# ENV LOGLEVEL=info
|
|
28
29
|
# ENV USETOKEN=YES
|
|
29
30
|
|
|
31
|
+
# specify ssl/tls cert and key in a folder
|
|
32
|
+
# example below
|
|
33
|
+
ENV SSLCERT=c:/Users/kumar/.tls
|
|
30
34
|
#sample setup for creating a temporary cert and key
|
|
31
35
|
ENV TLS_CREATE="C:US,ST:NC,L:Cary,O:SAS Institute,OU:STO,CN:localhost"
|
|
32
36
|
|
|
33
|
-
# You can specify your own cet and key
|
|
34
|
-
# ENV TLS_CRT=./tls/tls.crt
|
|
35
|
-
# ENV TLS_KEY=./tls/tls.key
|
|
36
|
-
|
|
37
37
|
# Samesite specification
|
|
38
38
|
ENV SAMESITE=None,secure
|
|
39
39
|
|
package/README.md
CHANGED
|
@@ -1,99 +1,67 @@
|
|
|
1
|
-
# `Application
|
|
1
|
+
# `Application server for use with SAS Viya`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
viya-serverjs is a app server designed to support user written SAS Viya applications. The applications can be written using any framework.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Key features:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
1. Handles authentication
|
|
8
|
+
2. Extendable with additional end points
|
|
8
9
|
|
|
9
10
|
## Usage
|
|
10
11
|
|
|
11
|
-
Specify it as a dependency in your package.json just as you do with other dependencies
|
|
12
|
-
|
|
13
12
|
Use npx command to start the server
|
|
14
13
|
|
|
15
14
|
```sh
|
|
16
|
-
npx @sassoftware/
|
|
15
|
+
npx @sassoftware/viya-serverjs
|
|
17
16
|
```
|
|
18
17
|
|
|
19
18
|
## `Basic configuration`
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
2. The defaults can be overriden using environment variables.
|
|
20
|
+
Configure the server using a .env file
|
|
23
21
|
|
|
24
22
|
### `Sample env file`
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
>[Note] Sample values shown below. See Advanced section for other ways to configure the server
|
|
27
25
|
|
|
28
26
|
```env
|
|
29
|
-
VIYA_SERVER=<your viya server>
|
|
30
|
-
APPHOST=localhost < can also be dns name of your server. ex: viyaiscool.unx.sas.com>
|
|
31
|
-
APPPORT=5000 <any port of your choice>
|
|
32
|
-
APPNAME=viyaapp
|
|
33
|
-
|
|
34
|
-
CLIENTID=viyaapp
|
|
35
|
-
CLIENTSECRET=secret
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### `Sample Dockerfile`
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
ENV APPHOST=0.0.0.0
|
|
28
|
+
# Base setup
|
|
29
|
+
# With the configuration below the app server url will be
|
|
30
|
+
# https://localhost:8080/viyaapp
|
|
31
|
+
#
|
|
32
|
+
APPHOST=localhost
|
|
33
|
+
APPPORT=8080
|
|
34
|
+
HTTPS=true
|
|
35
|
+
APPNAME=viyaapp
|
|
49
36
|
|
|
50
|
-
|
|
37
|
+
# Most modern browsers will reject self-signed certs from localhost
|
|
38
|
+
# And SAS Viya might also refuse connection.
|
|
39
|
+
# Supply your own SSL/TLS values in a folder. All files in this folder will be used.
|
|
40
|
+
# Options:
|
|
41
|
+
# 1. provide signed certificates for localhost
|
|
42
|
+
# 2. Use libraries like mkcert to create temporary trusted certs for localhost
|
|
43
|
+
# 3. For other options see the Advanced Section
|
|
44
|
+
SSLCERT=./tls
|
|
51
45
|
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
# APPENTRY - the main entry of the application
|
|
55
|
-
ENV APPLOC=./public
|
|
56
|
-
ENV APPENTRY=index.html
|
|
57
|
-
# if your app takes advantage of appenv.js to pass configuration to the web application
|
|
58
|
-
# ENV APPENV=appenv.js
|
|
46
|
+
# AUTHENTICATION
|
|
47
|
+
VIYA_SERVER=<viya servrer url>
|
|
59
48
|
|
|
60
|
-
#
|
|
61
|
-
ENV TLS_CREATE="C:US,ST:NC,L:Cary,O:yourcompany,OU:STO,CN:localhost"
|
|
62
|
-
ENV SAMESITE=None,secure
|
|
49
|
+
# By default it uses authorization_code flow
|
|
63
50
|
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
CLIENTID=<clientid>
|
|
52
|
+
CLIENTSECRET=<clientSecret if present>
|
|
53
|
+
AUTHFLOW=code|pkce
|
|
66
54
|
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
##########################
|
|
56
|
+
# Read the Advanced Section in the README before turning on these options
|
|
57
|
+
#
|
|
58
|
+
APPENV_PROXY=false
|
|
59
|
+
USETOKEN=false
|
|
69
60
|
|
|
70
|
-
|
|
61
|
+
APPENV_A=somevalue
|
|
62
|
+
APPENV_B=somevalue
|
|
71
63
|
|
|
72
64
|
```
|
|
73
65
|
|
|
74
|
-
### `Running with SSL enabled -- Recommended`
|
|
75
|
-
|
|
76
|
-
This is the recommended setting. This will also make browsers like Chrome run with the SAMESITE settings set to Default - your users will thank you.
|
|
77
|
-
|
|
78
|
-
Make sure you specify the VIYA_SERVER with a protocol of https.
|
|
79
66
|
|
|
80
|
-
### `TLS certificates`
|
|
81
67
|
|
|
82
|
-
- Option 1: Let server create a temporary unsigned certificate
|
|
83
|
-
|
|
84
|
-
```env
|
|
85
|
-
ENV TLS_CREATE=C:US,ST:NC,L:Cary,O:YourCompany,OU:yourgroup,CN:localhost
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
- Option 2: Provide your own key and certificate key
|
|
89
|
-
|
|
90
|
-
```env
|
|
91
|
-
ENV TLS_KEY=../certs/self/key.pem
|
|
92
|
-
ENV TLS_CERT=../certs/self/certificate.pem
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
- Option 3: Provide key and certificate as a pfx file
|
|
96
|
-
|
|
97
|
-
```env
|
|
98
|
-
ENV TLS_PFX=../certs/sascert/sascert2.pfx
|
|
99
|
-
```
|
package/lib/iService.js
CHANGED
|
@@ -181,6 +181,7 @@ function iService(userRouteTable, useDefault, asset, allAppEnv, serverMode, user
|
|
|
181
181
|
},
|
|
182
182
|
});
|
|
183
183
|
*/
|
|
184
|
+
//
|
|
184
185
|
// setup authentication related plugins
|
|
185
186
|
options = {
|
|
186
187
|
serverMode: serverMode,
|
|
@@ -193,6 +194,7 @@ function iService(userRouteTable, useDefault, asset, allAppEnv, serverMode, user
|
|
|
193
194
|
redirect: process.env.REDIRECT,
|
|
194
195
|
clientId: process.env.CLIENTID,
|
|
195
196
|
clientSecret: process.env.CLIENTSECRET,
|
|
197
|
+
pkce: allAppEnv.LOGONPAYLOAD.pkce,
|
|
196
198
|
redirectTo: "/".concat(process.env.APPNAME, "/logon"),
|
|
197
199
|
allAppEnv: allAppEnv,
|
|
198
200
|
useHapiCookie: true,
|
|
@@ -320,22 +322,8 @@ function _getCertificates() {
|
|
|
320
322
|
_context2.n = 1;
|
|
321
323
|
break;
|
|
322
324
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
options = {};
|
|
326
|
-
options.key = fs.readFileSync("".concat(tlsdir, "/key.pem"), {
|
|
327
|
-
encoding: 'utf8'
|
|
328
|
-
});
|
|
329
|
-
options.cert = fs.readFileSync("".concat(tlsdir, "/crt.pem"), {
|
|
330
|
-
encoding: 'utf8'
|
|
331
|
-
});
|
|
332
|
-
if (fs.existsSync("".concat(tlsdir, "/ca.pem")) === true) {
|
|
333
|
-
options.ca = fs.readFileSync("".concat(tlsdir, "/ca.pem"), {
|
|
334
|
-
encoding: 'utf8'
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
options.rejectUnauthorized = true;
|
|
338
|
-
}
|
|
325
|
+
options = readTLS(tlsdir);
|
|
326
|
+
options.rejectUnauthorized = true;
|
|
339
327
|
_context2.n = 3;
|
|
340
328
|
break;
|
|
341
329
|
case 1:
|
|
@@ -352,6 +340,26 @@ function _getCertificates() {
|
|
|
352
340
|
}));
|
|
353
341
|
return _getCertificates.apply(this, arguments);
|
|
354
342
|
}
|
|
343
|
+
function readTLS(tlsdir) {
|
|
344
|
+
console.log("[Note] Using TLS dir: " + tlsdir);
|
|
345
|
+
if (fs.existsSync(tlsdir) === false) {
|
|
346
|
+
console.log("[Warning] Specified TLS dir does not exist: " + tlsdir);
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
var listOfFiles = fs.readdirSync(tlsdir);
|
|
350
|
+
console.log("[Note] TLS/SSL files found: " + listOfFiles);
|
|
351
|
+
var options = {};
|
|
352
|
+
for (var i = 0; i < listOfFiles.length; i++) {
|
|
353
|
+
var fname = listOfFiles[i];
|
|
354
|
+
var name = tlsdir + '/' + listOfFiles[i];
|
|
355
|
+
var key = fname.split('.')[0];
|
|
356
|
+
options[key] = fs.readFileSync(name, {
|
|
357
|
+
encoding: 'utf8'
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
console.log('TLS FILES', Object.keys(options));
|
|
361
|
+
return options;
|
|
362
|
+
}
|
|
355
363
|
function getTls() {
|
|
356
364
|
return _getTls.apply(this, arguments);
|
|
357
365
|
}
|
package/lib/index.js
CHANGED
|
@@ -29,7 +29,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default":
|
|
|
29
29
|
var debug = require("debug")("startup");
|
|
30
30
|
module.exports = function core(uTable, useDefault, serverMode, customize, swaggerfcn) {
|
|
31
31
|
var argv = (0, _yargs["default"])((0, _helpers.hideBin)(process.argv)).argv;
|
|
32
|
-
var env = argv.env == null ?
|
|
32
|
+
var env = argv.env == null ? '.env' : argv.env;
|
|
33
33
|
var appenv = argv.appenv == null ? null : argv.appenv;
|
|
34
34
|
var docker = argv.docker == null ? null : argv.docker;
|
|
35
35
|
//process.env.SERVERMODE = serverMode !== null ? "api" : "app";
|
|
@@ -95,20 +95,11 @@ function getAllEnv(userData) {
|
|
|
95
95
|
console.log('Note: setting host to null');
|
|
96
96
|
host = null;
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
/*
|
|
100
|
-
if (process.env.AUTHTYPE != null) {
|
|
101
|
-
process.env.AUTHFLOW = process.env.AUTHTYPE;
|
|
102
|
-
}
|
|
103
|
-
*/
|
|
104
|
-
|
|
105
98
|
var authflow = trimit("AUTHFLOW");
|
|
106
|
-
|
|
99
|
+
var pkce = authflow === "pkce" ? true : false;
|
|
100
|
+
if (authflow === "authorization_code" || authflow === "code" || authflow === "server" || authflow === "null" || authflow === "pkce") {
|
|
107
101
|
authflow = "server";
|
|
108
102
|
}
|
|
109
|
-
if (authflow === null) {
|
|
110
|
-
host = null;
|
|
111
|
-
}
|
|
112
103
|
if (host === null) {
|
|
113
104
|
authflow = null;
|
|
114
105
|
console.log('Note: setting authflow to null');
|
|
@@ -119,7 +110,7 @@ function getAllEnv(userData) {
|
|
|
119
110
|
var clientID = trimit("CLIENTID");
|
|
120
111
|
|
|
121
112
|
// eslint-disable-next-line no-unused-vars
|
|
122
|
-
|
|
113
|
+
//let clientSecret = trimit("CLIENTSECRET");
|
|
123
114
|
var keepAlive = trimit("KEEPALIVE");
|
|
124
115
|
var appName = trimit("APPNAME");
|
|
125
116
|
var ns = trimit("NAMESPACE");
|
|
@@ -130,6 +121,7 @@ function getAllEnv(userData) {
|
|
|
130
121
|
host: host,
|
|
131
122
|
clientID: clientID,
|
|
132
123
|
appName: appName,
|
|
124
|
+
pkce: pkce,
|
|
133
125
|
keepAlive: null,
|
|
134
126
|
useToken: process.env.USETOKEN,
|
|
135
127
|
ns: ns,
|
|
@@ -186,6 +178,7 @@ function getAllEnv(userData) {
|
|
|
186
178
|
}
|
|
187
179
|
}
|
|
188
180
|
}
|
|
181
|
+
userData.APPNAME = l.appName;
|
|
189
182
|
env = {
|
|
190
183
|
LOGONPAYLOAD: l,
|
|
191
184
|
APPENV: userData
|
package/lib/plugins/SASauth.js
CHANGED
|
@@ -79,11 +79,13 @@ function _iSASauth() {
|
|
|
79
79
|
provider: provider,
|
|
80
80
|
password: uuid.v4(),
|
|
81
81
|
clientId: options.clientId,
|
|
82
|
-
clientSecret: options.clientSecret,
|
|
82
|
+
clientSecret: options.clientSecret == null ? '' : options.clientSecret,
|
|
83
83
|
// isSameSite : options.isSameSite,
|
|
84
84
|
isSecure: options.isSecure
|
|
85
85
|
};
|
|
86
|
-
|
|
86
|
+
if (options.pkce === true) {
|
|
87
|
+
bellAuthOptions.pkce = 'S256';
|
|
88
|
+
}
|
|
87
89
|
debug('belloptions', bellAuthOptions);
|
|
88
90
|
server.log('SASAuth', bellAuthOptions);
|
|
89
91
|
_context2.n = 1;
|
package/lib/plugins/appCookie.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
4
4
|
var _handlers = require("../handlers");
|
|
5
|
+
var _setContext = _interopRequireDefault(require("./setContext"));
|
|
6
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
5
7
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
6
8
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
7
9
|
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
@@ -43,7 +45,7 @@ module.exports = function setDefaultRoutes(server, options) {
|
|
|
43
45
|
strategy: "sas"
|
|
44
46
|
};
|
|
45
47
|
}
|
|
46
|
-
var getAppb = _handlers.getApp.bind(null, process.env.USETOKEN === "
|
|
48
|
+
var getAppb = _handlers.getApp.bind(null, process.env.USETOKEN != null && process.env.USETOKEN.toUpperCase() === "TRUE" ? options : null);
|
|
47
49
|
console.log("Default strategy", authDefault);
|
|
48
50
|
console.log("Logon strategy", authLogon);
|
|
49
51
|
options.authDefault = authDefault;
|
|
@@ -271,6 +273,13 @@ module.exports = function setDefaultRoutes(server, options) {
|
|
|
271
273
|
};
|
|
272
274
|
debug(pr);
|
|
273
275
|
defaultTable.push(pr);
|
|
276
|
+
// now set pre for all default routes
|
|
277
|
+
defaultTable.forEach(function (r) {
|
|
278
|
+
r.options.pre = [{
|
|
279
|
+
method: _setContext["default"],
|
|
280
|
+
assign: 'context'
|
|
281
|
+
}];
|
|
282
|
+
});
|
|
274
283
|
var routeTables = uTable !== null ? defaultTable.concat(uTable) : defaultTable;
|
|
275
284
|
server.route(routeTables);
|
|
276
285
|
};
|
|
@@ -51,11 +51,13 @@ function setupUserRoutes(u, options) {
|
|
|
51
51
|
assign: 'context'
|
|
52
52
|
}]);
|
|
53
53
|
}
|
|
54
|
+
console.log(rx.options.pre);
|
|
54
55
|
if (rx.options.auth === true) {
|
|
55
56
|
rx.options.auth = options.authDefault;
|
|
56
57
|
} else if (rx.options.auth === 'logon') {
|
|
57
58
|
rx.options.auth = options.authLogon;
|
|
58
59
|
}
|
|
60
|
+
console.log('route auth', rx.options.auth);
|
|
59
61
|
return rx;
|
|
60
62
|
});
|
|
61
63
|
return routes;
|
package/mcpServer.js
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
let core = require('./lib/index.js');
|
|
6
|
+
debugger;
|
|
7
|
+
core(getCustomHandler, true, 'app', null);
|
|
8
|
+
|
|
9
|
+
function getCustomHandler() {
|
|
10
|
+
let appName = `/${process.env.APPNAME}`; /* does not have to be this - your choice */
|
|
11
|
+
debugger;
|
|
12
|
+
let routes = [
|
|
13
|
+
{
|
|
14
|
+
method: ["GET"],
|
|
15
|
+
path: "/help",
|
|
16
|
+
options: {
|
|
17
|
+
files: {
|
|
18
|
+
relativeTo: "./public",
|
|
19
|
+
},
|
|
20
|
+
handler: async (req, h) => {
|
|
21
|
+
debugger;
|
|
22
|
+
let hf = 'help.html';
|
|
23
|
+
return h.file(hf);
|
|
24
|
+
},
|
|
25
|
+
auth: false,
|
|
26
|
+
description: "Help",
|
|
27
|
+
notes: "Help",
|
|
28
|
+
tags: ["app"],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
method: ["GET"],
|
|
33
|
+
path: `${appName}/new`,
|
|
34
|
+
options: {
|
|
35
|
+
files: {
|
|
36
|
+
relativeTo: "./public",
|
|
37
|
+
},
|
|
38
|
+
handler: async (req, h) => {
|
|
39
|
+
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>in new');
|
|
40
|
+
return h.file('index.html');
|
|
41
|
+
},
|
|
42
|
+
// auth: 'logon',
|
|
43
|
+
description: "Create new application",
|
|
44
|
+
notes: "Index file created from env data",
|
|
45
|
+
tags: ["app"],
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
];
|
|
50
|
+
return routes;
|
|
51
|
+
}
|
|
52
|
+
function customize(key, options) {
|
|
53
|
+
let info = {
|
|
54
|
+
swaggerOptions: {
|
|
55
|
+
info: {
|
|
56
|
+
title: "Test API",
|
|
57
|
+
version: "0.0.1",
|
|
58
|
+
description: "This document was auto-generated at run time",
|
|
59
|
+
},
|
|
60
|
+
documentationPage: true,
|
|
61
|
+
documentationPath: `/${process.env.APPNAME}/documentation`,
|
|
62
|
+
swaggerUI: true,
|
|
63
|
+
swaggerUIPath: `/${process.env.APPNAME}/swaggerui`,
|
|
64
|
+
schemes: ["https", "http"],
|
|
65
|
+
cors: true,
|
|
66
|
+
auth: options.authDefault,
|
|
67
|
+
},
|
|
68
|
+
APPENV: {
|
|
69
|
+
x: 1,
|
|
70
|
+
y: 2,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
let r = info[key];
|
|
74
|
+
return r == null ? {} : r;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getIndex() {
|
|
78
|
+
|
|
79
|
+
let template = `
|
|
80
|
+
<html lang="en">
|
|
81
|
+
<head>
|
|
82
|
+
<meta charset="UTF-8" />
|
|
83
|
+
|
|
84
|
+
<script
|
|
85
|
+
crossorigin
|
|
86
|
+
src="https://unpkg.com/react@16/umd/react.production.min.js"
|
|
87
|
+
></script>
|
|
88
|
+
<script
|
|
89
|
+
crossorigin
|
|
90
|
+
src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"
|
|
91
|
+
></script>
|
|
92
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
|
|
93
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.min.js"></script>
|
|
94
|
+
<script src="https://unpkg.com/@sassoftware/restaf@5.2.4/dist/restaf.js"></script>
|
|
95
|
+
<script src="https://unpkg.com/@sassoftware/restaflib@5.2.4/dist/restaflib.js"></script>
|
|
96
|
+
|
|
97
|
+
<style>
|
|
98
|
+
.container {
|
|
99
|
+
display: flex;
|
|
100
|
+
flex-direction: column;
|
|
101
|
+
flex-wrap: nowrap;
|
|
102
|
+
min-height: 800px;
|
|
103
|
+
}
|
|
104
|
+
.elabel {
|
|
105
|
+
display: inline-block;
|
|
106
|
+
|
|
107
|
+
clear: left;
|
|
108
|
+
width: 250px;
|
|
109
|
+
text-align: right;
|
|
110
|
+
}
|
|
111
|
+
.einput {
|
|
112
|
+
display: inline-block;
|
|
113
|
+
}
|
|
114
|
+
.div1 {
|
|
115
|
+
border: 1px solid black;
|
|
116
|
+
background: lightskyblue;
|
|
117
|
+
}
|
|
118
|
+
.div2 {
|
|
119
|
+
border: 1px solid black;
|
|
120
|
+
background: lightskyblue;
|
|
121
|
+
height: 200px;
|
|
122
|
+
}
|
|
123
|
+
</style>
|
|
124
|
+
|
|
125
|
+
<script>
|
|
126
|
+
let LOGONPAYLOAD = {
|
|
127
|
+
host: "${process.env.VIYA_SERVER}",
|
|
128
|
+
authType: "server",
|
|
129
|
+
appName: "${process.env.APPNAME}",
|
|
130
|
+
};
|
|
131
|
+
</script>
|
|
132
|
+
|
|
133
|
+
<script>
|
|
134
|
+
debugger;
|
|
135
|
+
let store = restaf.initStore({
|
|
136
|
+
casProxy: true});
|
|
137
|
+
debugger; console.log(store.config);
|
|
138
|
+
|
|
139
|
+
let session = null;
|
|
140
|
+
let servers = null;
|
|
141
|
+
let services = null;
|
|
142
|
+
let files = null;
|
|
143
|
+
let reports = null;
|
|
144
|
+
let compute = null;
|
|
145
|
+
|
|
146
|
+
function setup() {
|
|
147
|
+
debugger;
|
|
148
|
+
document.getElementById('output').innerHTML = '...initializing';
|
|
149
|
+
|
|
150
|
+
initSession()
|
|
151
|
+
.then(r => {
|
|
152
|
+
document.getElementById('output').innerHTML = 'ready';
|
|
153
|
+
keepAlive();
|
|
154
|
+
})
|
|
155
|
+
.catch(e => {
|
|
156
|
+
|
|
157
|
+
console.log(e);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
async function initSession() {
|
|
163
|
+
|
|
164
|
+
console.log(LOGONPAYLOAD);
|
|
165
|
+
debugger;
|
|
166
|
+
let msg = await store.logon(LOGONPAYLOAD);
|
|
167
|
+
console.log(msg);
|
|
168
|
+
|
|
169
|
+
// let { identities } = await store.addServices('identities');
|
|
170
|
+
let name = 'user';
|
|
171
|
+
// if (identities.links('currentUser') != null) {
|
|
172
|
+
// let c = await store.apiCall(identities.links('currentUser'));
|
|
173
|
+
// name = c.items('id');
|
|
174
|
+
// }
|
|
175
|
+
console.log(name);
|
|
176
|
+
debugger;
|
|
177
|
+
/*
|
|
178
|
+
services = await store.addServices(
|
|
179
|
+
'files', 'compute', 'casManagement'
|
|
180
|
+
);
|
|
181
|
+
console.log(services.casManagement.links().toJS())
|
|
182
|
+
*/
|
|
183
|
+
debugger;
|
|
184
|
+
return 'done';
|
|
185
|
+
}
|
|
186
|
+
function runit(type) {
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
document.getElementById('output').innerHTML = '...running';
|
|
190
|
+
let testcase;
|
|
191
|
+
switch (type) {
|
|
192
|
+
case 'files': {
|
|
193
|
+
testcase = SASfileService;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case 'compute': {
|
|
197
|
+
testcase = dsCompute;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
case 'cas': {
|
|
201
|
+
testcase = runCas;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
case 'spre': {
|
|
206
|
+
testcase= spre;
|
|
207
|
+
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
default: {
|
|
211
|
+
testcase = SASfileService;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
testcase(store)
|
|
217
|
+
.then(r => {
|
|
218
|
+
document.getElementById(
|
|
219
|
+
'output'
|
|
220
|
+
).innerHTML = JSON.stringify(r, null, 4);
|
|
221
|
+
})
|
|
222
|
+
.catch(err => {
|
|
223
|
+
|
|
224
|
+
document.getElementById(
|
|
225
|
+
'output'
|
|
226
|
+
).innerHTML = JSON.stringify(err, null, 4);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
async function noaction() {
|
|
230
|
+
r = {msg: 'redirects completed'};
|
|
231
|
+
return r;
|
|
232
|
+
}
|
|
233
|
+
async function spre(store) {
|
|
234
|
+
let p = {
|
|
235
|
+
method: 'GET',
|
|
236
|
+
url : 'http://localhost:3000/api/test',
|
|
237
|
+
withCredentials: true
|
|
238
|
+
}
|
|
239
|
+
let r = await store.request(p);
|
|
240
|
+
return r.data;
|
|
241
|
+
}
|
|
242
|
+
async function runCas(store) {
|
|
243
|
+
|
|
244
|
+
let {casManagement} = await store.addServices('casManagement');
|
|
245
|
+
let servers = await store.apiCall(
|
|
246
|
+
casManagement.links('servers')
|
|
247
|
+
);
|
|
248
|
+
let serverName = servers.itemsList(0);
|
|
249
|
+
let session = await store.apiCall(
|
|
250
|
+
servers.itemsCmd(serverName, 'createSession')
|
|
251
|
+
);
|
|
252
|
+
let payload = {
|
|
253
|
+
action: 'builtins.echo',
|
|
254
|
+
data: { code: { x: 1 } }
|
|
255
|
+
};
|
|
256
|
+
console.log(JSON.stringify(session.links("execute"), null, 4));
|
|
257
|
+
let r = await store.runAction(session, payload);
|
|
258
|
+
console.log('echo completed');
|
|
259
|
+
await store.apiCall(session.links('delete'));
|
|
260
|
+
return r.items();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async function SASfileService(store) {
|
|
264
|
+
debugger;
|
|
265
|
+
let content;
|
|
266
|
+
try {
|
|
267
|
+
debugger;
|
|
268
|
+
let {files} = await store.addServices('files');
|
|
269
|
+
debugger;
|
|
270
|
+
console.log(JSON.stringify(files.links(), null, 4));
|
|
271
|
+
//console.log('items - should be an array of files(empty array is ok)')
|
|
272
|
+
// console.log(files.items().toJS());
|
|
273
|
+
let payload = {
|
|
274
|
+
data: { x: 1, y: 'This was saved earlier in the step' },
|
|
275
|
+
headers: { 'content-type': 'application/json' }
|
|
276
|
+
};
|
|
277
|
+
let createCmd = files.links('create');
|
|
278
|
+
let newFile = await store.apiCall(createCmd, payload);
|
|
279
|
+
debugger;
|
|
280
|
+
console.log(JSON.stringify(newFile.links('content'), null, 4));
|
|
281
|
+
content = await store.apiCall(newFile.links('content'));
|
|
282
|
+
|
|
283
|
+
} catch(err) {
|
|
284
|
+
console.log(JSON.stringify(err, null, 4));
|
|
285
|
+
debugger;
|
|
286
|
+
}
|
|
287
|
+
console.log(content);
|
|
288
|
+
return content.items();
|
|
289
|
+
}
|
|
290
|
+
async function dsCompute(store) {
|
|
291
|
+
let log = null;
|
|
292
|
+
debugger;
|
|
293
|
+
let {compute} = await store.addServices('compute');
|
|
294
|
+
let servers = await store.apiCall(compute.links('servers'));
|
|
295
|
+
|
|
296
|
+
let contexts = await store.apiCall(compute.links('contexts'));
|
|
297
|
+
|
|
298
|
+
// lookup the name of the first context and then use it to get the associated createSession restafLink
|
|
299
|
+
let createSession = contexts.itemsCmd(
|
|
300
|
+
contexts.itemsList(0),
|
|
301
|
+
'createSession'
|
|
302
|
+
);
|
|
303
|
+
let session = await store.apiCall(createSession);
|
|
304
|
+
|
|
305
|
+
// Now run a simple data step in that session
|
|
306
|
+
let payload = {
|
|
307
|
+
data: {
|
|
308
|
+
code: ["data _null_; do i = 1 to 100; x=1; end; run; "]
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// Now execute the data step and wait for completion
|
|
313
|
+
let job = await store.apiCall(
|
|
314
|
+
session.links('execute'),
|
|
315
|
+
payload
|
|
316
|
+
);
|
|
317
|
+
let status = await store.jobState(job, null, 5, 2);
|
|
318
|
+
|
|
319
|
+
if (status.data === 'running') {
|
|
320
|
+
throw "ERROR: Job did not complete in allotted time";
|
|
321
|
+
} else {
|
|
322
|
+
switch (status.data) {
|
|
323
|
+
case 'warning':
|
|
324
|
+
console.log("Warning: check your log for warnings");
|
|
325
|
+
break;
|
|
326
|
+
case 'error':
|
|
327
|
+
throw "Please correct errors and rerun program";
|
|
328
|
+
default:
|
|
329
|
+
log = await store.apiCall(status.job.links('log'));
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return log === null ? status : log.items();
|
|
334
|
+
}
|
|
335
|
+
</script>
|
|
336
|
+
</head>
|
|
337
|
+
<body onload="setup()">
|
|
338
|
+
<h1 id="head">Hi</h1>
|
|
339
|
+
<div>
|
|
340
|
+
|
|
341
|
+
<button onclick="runit('files')">
|
|
342
|
+
Press to make a call to file service
|
|
343
|
+
</button>
|
|
344
|
+
<br />
|
|
345
|
+
<br />
|
|
346
|
+
<button onclick="runit('compute')">
|
|
347
|
+
Press to make a call compute service
|
|
348
|
+
</button>
|
|
349
|
+
<br />
|
|
350
|
+
<br />
|
|
351
|
+
<button onclick="runit('cas')">
|
|
352
|
+
Press to make a call to cas echo
|
|
353
|
+
</button>
|
|
354
|
+
<br />
|
|
355
|
+
<br />
|
|
356
|
+
|
|
357
|
+
<div>
|
|
358
|
+
<pre id="output"></pre>
|
|
359
|
+
</div>
|
|
360
|
+
</body>
|
|
361
|
+
</html>
|
|
362
|
+
`;
|
|
363
|
+
return template;
|
|
364
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sassoftware/viya-serverjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Easy to use app server for SAS Viya applications",
|
|
5
5
|
"author": "Deva Kumaraswamy <deva.kumar@sas.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "./lib/index.js",
|
|
8
8
|
"bin": {
|
|
9
|
-
"@sassoftware/viya-
|
|
9
|
+
"@sassoftware/viya-serverjs": "cli.js"
|
|
10
10
|
},
|
|
11
11
|
"keywords": [
|
|
12
12
|
"restaf",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"test": "node cli --env=./.env --docker=./Dockerfile",
|
|
33
33
|
"submit": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 APPENTRY=simplesubmit.html node cli --env=./.env --docker=./Dockerfile",
|
|
34
34
|
"server": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 node server.js --env=./.env.server --docker=./Dockerfile",
|
|
35
|
+
"server2": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 node server.js --env=./.env --docker=./Dockerfile",
|
|
35
36
|
"debug": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 node --inspect-brk server.js --env=./.env.server --docker=./Dockerfile",
|
|
36
37
|
"proxy": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 node cli --env=./.env.proxy --docker=./Dockerfile",
|
|
37
38
|
"pub": "npm publish --tag dev --access public",
|
package/public/help.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<h1>
|
|
1
|
+
<h1> Hello</h1>
|
package/public/index.html
CHANGED
|
@@ -66,10 +66,16 @@
|
|
|
66
66
|
<script>
|
|
67
67
|
debugger;
|
|
68
68
|
console.log(JSON.stringify(APPENV, null, 4));
|
|
69
|
+
let proxyServer = null;
|
|
70
|
+
if (APPENV.PROXY.toUpperCase() === 'TRUE') {
|
|
71
|
+
proxyServer = `${window.location.protocol}//${window.location.host}/${LOGONPAYLOAD.appName}/proxy`;
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
console.log('Proxy Server = ' + proxyServer);
|
|
69
75
|
let store = restaf.initStore({
|
|
70
76
|
casProxy: true,
|
|
71
77
|
options: {
|
|
72
|
-
proxyServer:
|
|
78
|
+
proxyServer: proxyServer,
|
|
73
79
|
httpOptions: null
|
|
74
80
|
}
|
|
75
81
|
});
|
package/server.js
CHANGED
|
@@ -22,7 +22,7 @@ function getCustomHandler() {
|
|
|
22
22
|
let hf = 'help.html';
|
|
23
23
|
return h.file(hf);
|
|
24
24
|
},
|
|
25
|
-
auth:
|
|
25
|
+
auth: true,
|
|
26
26
|
description: "Help",
|
|
27
27
|
notes: "Help",
|
|
28
28
|
tags: ["app"],
|
|
@@ -30,21 +30,25 @@ function getCustomHandler() {
|
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
method: ["GET"],
|
|
33
|
-
path:
|
|
33
|
+
path: `/mcp`,
|
|
34
34
|
options: {
|
|
35
35
|
files: {
|
|
36
36
|
relativeTo: "./public",
|
|
37
37
|
},
|
|
38
38
|
handler: async (req, h) => {
|
|
39
|
-
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>in
|
|
39
|
+
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>in mcp');
|
|
40
|
+
console.log(req.auth.credentials);
|
|
41
|
+
debugger;
|
|
42
|
+
console.log(req.context);
|
|
40
43
|
return h.file('index.html');
|
|
41
44
|
},
|
|
42
|
-
|
|
45
|
+
auth: 'logon',
|
|
43
46
|
description: "Create new application",
|
|
44
47
|
notes: "Index file created from env data",
|
|
45
48
|
tags: ["app"],
|
|
46
49
|
},
|
|
47
50
|
}
|
|
51
|
+
|
|
48
52
|
];
|
|
49
53
|
return routes;
|
|
50
54
|
}
|
|
@@ -8,7 +8,6 @@ let debug = require('debug')('setcookies');
|
|
|
8
8
|
async function setCookies (req, h, options) {
|
|
9
9
|
debugger;
|
|
10
10
|
let credentials = req.auth.credentials;
|
|
11
|
-
console.log('setcookies credentials', credentials);
|
|
12
11
|
debug('setcookie', credentials);
|
|
13
12
|
|
|
14
13
|
if (credentials != null && req.auth.error != null) {
|
package/src/iService.js
CHANGED
|
@@ -152,6 +152,7 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
|
|
|
152
152
|
});
|
|
153
153
|
*/
|
|
154
154
|
|
|
155
|
+
//
|
|
155
156
|
// setup authentication related plugins
|
|
156
157
|
|
|
157
158
|
let options = {
|
|
@@ -165,6 +166,7 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
|
|
|
165
166
|
redirect : process.env.REDIRECT,
|
|
166
167
|
clientId : process.env.CLIENTID,
|
|
167
168
|
clientSecret : process.env.CLIENTSECRET,
|
|
169
|
+
pkce : allAppEnv.LOGONPAYLOAD.pkce,
|
|
168
170
|
redirectTo : `/${process.env.APPNAME}/logon`,
|
|
169
171
|
allAppEnv : allAppEnv,
|
|
170
172
|
useHapiCookie : true,
|
|
@@ -176,7 +178,7 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
|
|
|
176
178
|
userInfo : userInfo,
|
|
177
179
|
https : process.env.HTTPS,
|
|
178
180
|
authDefault : false, /* set later in setDefaultRoutes */
|
|
179
|
-
|
|
181
|
+
authLogon : false /* set later in setDefaultRoutes */
|
|
180
182
|
|
|
181
183
|
};
|
|
182
184
|
|
|
@@ -263,16 +265,8 @@ async function getCertificates () {
|
|
|
263
265
|
let options = null;
|
|
264
266
|
let tlsdir = process.env.SSLCERT;
|
|
265
267
|
if (tlsdir != null && tlsdir.trim().length > 0) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
options = {};
|
|
269
|
-
options.key = fs.readFileSync(`${tlsdir}/key.pem`, { encoding: 'utf8' });
|
|
270
|
-
options.cert = fs.readFileSync(`${tlsdir}/crt.pem`, { encoding: 'utf8' });
|
|
271
|
-
if (fs.existsSync(`${tlsdir}/ca.pem`) === true) {
|
|
272
|
-
options.ca = fs.readFileSync(`${tlsdir}/ca.pem`, { encoding: 'utf8' });
|
|
273
|
-
}
|
|
274
|
-
options.rejectUnauthorized= true;
|
|
275
|
-
}
|
|
268
|
+
options = readTLS(tlsdir);
|
|
269
|
+
options.rejectUnauthorized= true;
|
|
276
270
|
} else {
|
|
277
271
|
console.log('No SSL certificates found, generating self-signed certificates');
|
|
278
272
|
options = await getTls();
|
|
@@ -281,6 +275,27 @@ async function getCertificates () {
|
|
|
281
275
|
return options;
|
|
282
276
|
}
|
|
283
277
|
|
|
278
|
+
function readTLS (tlsdir) {
|
|
279
|
+
console.log("[Note] Using TLS dir: " + tlsdir);
|
|
280
|
+
if (fs.existsSync(tlsdir) === false) {
|
|
281
|
+
console.log("[Warning] Specified TLS dir does not exist: " + tlsdir);
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let listOfFiles = fs.readdirSync(tlsdir);
|
|
286
|
+
console.log("[Note] TLS/SSL files found: " + listOfFiles);
|
|
287
|
+
let options = {};
|
|
288
|
+
for(let i=0; i < listOfFiles.length; i++) {
|
|
289
|
+
let fname = listOfFiles[i];
|
|
290
|
+
let name = tlsdir + '/' + listOfFiles[i];
|
|
291
|
+
let key = fname.split('.')[0];
|
|
292
|
+
options[key] = fs.readFileSync(name, { encoding: 'utf8' });
|
|
293
|
+
}
|
|
294
|
+
console.log('TLS FILES', Object.keys(options));
|
|
295
|
+
return options;
|
|
296
|
+
|
|
297
|
+
}
|
|
298
|
+
|
|
284
299
|
async function getTls () {
|
|
285
300
|
let options = {
|
|
286
301
|
keySize : 2048,
|
package/src/index.js
CHANGED
|
@@ -33,7 +33,7 @@ module.exports = function core(
|
|
|
33
33
|
swaggerfcn
|
|
34
34
|
) {
|
|
35
35
|
let argv = yargs(hideBin(process.argv)).argv;
|
|
36
|
-
let env = argv.env == null ?
|
|
36
|
+
let env = argv.env == null ? '.env' : argv.env;
|
|
37
37
|
let appenv = argv.appenv == null ? null : argv.appenv;
|
|
38
38
|
let docker = argv.docker == null ? null : argv.docker;
|
|
39
39
|
//process.env.SERVERMODE = serverMode !== null ? "api" : "app";
|
|
@@ -124,20 +124,15 @@ function getAllEnv(userData) {
|
|
|
124
124
|
host = null;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
/*
|
|
128
|
-
if (process.env.AUTHTYPE != null) {
|
|
129
|
-
process.env.AUTHFLOW = process.env.AUTHTYPE;
|
|
130
|
-
}
|
|
131
|
-
*/
|
|
132
127
|
|
|
133
128
|
let authflow = trimit("AUTHFLOW");
|
|
134
|
-
|
|
129
|
+
let pkce = (authflow === "pkce") ? true : false;
|
|
130
|
+
if (authflow === "authorization_code" || authflow === "code" || authflow === "server" ||
|
|
131
|
+
authflow === "null" || authflow === "pkce") {
|
|
135
132
|
authflow = "server";
|
|
133
|
+
|
|
136
134
|
}
|
|
137
135
|
|
|
138
|
-
if (authflow === null) {
|
|
139
|
-
host = null;
|
|
140
|
-
}
|
|
141
136
|
|
|
142
137
|
if (host === null) {
|
|
143
138
|
authflow = null;
|
|
@@ -151,7 +146,7 @@ function getAllEnv(userData) {
|
|
|
151
146
|
let clientID = trimit("CLIENTID");
|
|
152
147
|
|
|
153
148
|
// eslint-disable-next-line no-unused-vars
|
|
154
|
-
let clientSecret = trimit("CLIENTSECRET");
|
|
149
|
+
//let clientSecret = trimit("CLIENTSECRET");
|
|
155
150
|
let keepAlive = trimit("KEEPALIVE");
|
|
156
151
|
let appName = trimit("APPNAME");
|
|
157
152
|
let ns = trimit("NAMESPACE");
|
|
@@ -164,6 +159,7 @@ function getAllEnv(userData) {
|
|
|
164
159
|
host: host,
|
|
165
160
|
clientID: clientID,
|
|
166
161
|
appName: appName,
|
|
162
|
+
pkce: pkce,
|
|
167
163
|
|
|
168
164
|
keepAlive: null,
|
|
169
165
|
useToken: process.env.USETOKEN,
|
|
@@ -230,7 +226,7 @@ for (let key in process.env) {
|
|
|
230
226
|
}
|
|
231
227
|
}
|
|
232
228
|
}
|
|
233
|
-
|
|
229
|
+
userData.APPNAME = l.appName;
|
|
234
230
|
env = {
|
|
235
231
|
LOGONPAYLOAD: l,
|
|
236
232
|
APPENV: userData,
|
package/src/plugins/SASauth.js
CHANGED
|
@@ -65,11 +65,15 @@ async function iSASauth (server, options) {
|
|
|
65
65
|
provider : provider,
|
|
66
66
|
password : uuid.v4(),
|
|
67
67
|
clientId : options.clientId,
|
|
68
|
-
clientSecret: options.clientSecret,
|
|
68
|
+
clientSecret: (options.clientSecret == null) ? '' : options.clientSecret,
|
|
69
69
|
// isSameSite : options.isSameSite,
|
|
70
70
|
isSecure : options.isSecure
|
|
71
71
|
};
|
|
72
|
-
|
|
72
|
+
|
|
73
|
+
if (options.pkce === true) {
|
|
74
|
+
bellAuthOptions.pkce = 'S256';
|
|
75
|
+
}
|
|
76
|
+
|
|
73
77
|
debug('belloptions', bellAuthOptions);
|
|
74
78
|
server.log('SASAuth',bellAuthOptions);
|
|
75
79
|
await server.register(bell);
|
package/src/plugins/appCookie.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
|
|
19
20
|
import {
|
|
20
21
|
getApp,
|
|
21
22
|
getApp2,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
reactDev,
|
|
30
31
|
proxyMapUri,
|
|
31
32
|
} from "../handlers";
|
|
33
|
+
import setContext from './setContext';
|
|
32
34
|
let debug = require("debug")("routes");
|
|
33
35
|
module.exports = function setDefaultRoutes(server, options) {
|
|
34
36
|
debug("setDefaultRoutes");
|
|
@@ -51,7 +53,7 @@ module.exports = function setDefaultRoutes(server, options) {
|
|
|
51
53
|
}
|
|
52
54
|
let getAppb = getApp.bind(
|
|
53
55
|
null,
|
|
54
|
-
process.env.USETOKEN === "
|
|
56
|
+
(process.env.USETOKEN != null && process.env.USETOKEN.toUpperCase() === "TRUE") ? options : null
|
|
55
57
|
);
|
|
56
58
|
|
|
57
59
|
console.log("Default strategy", authDefault);
|
|
@@ -249,7 +251,10 @@ module.exports = function setDefaultRoutes(server, options) {
|
|
|
249
251
|
};
|
|
250
252
|
debug(pr);
|
|
251
253
|
defaultTable.push(pr);
|
|
252
|
-
|
|
254
|
+
// now set pre for all default routes
|
|
255
|
+
defaultTable.forEach((r) => {
|
|
256
|
+
r.options.pre = [{method: setContext, assign: 'context'}];
|
|
257
|
+
});
|
|
253
258
|
let routeTables =
|
|
254
259
|
uTable !== null ? defaultTable.concat(uTable) : defaultTable;
|
|
255
260
|
server.route(routeTables);
|
|
@@ -25,22 +25,19 @@ function setupUserRoutes (u, options) {
|
|
|
25
25
|
let ux = (typeof u === 'function') ? u() : u;
|
|
26
26
|
let routes = ux.map(rx => {
|
|
27
27
|
//let rx = {...r};
|
|
28
|
-
|
|
29
|
-
if (rx.config != null) {
|
|
30
|
-
rx.options = {...rx.config};
|
|
31
|
-
delete rx.config;
|
|
32
|
-
}
|
|
28
|
+
|
|
33
29
|
if (rx.options.pre == null) {
|
|
34
30
|
rx.options.pre = [{method: setContext, assign: 'context'}];
|
|
35
31
|
} else{
|
|
36
32
|
rx.options.pre.push([{method: setContext, assign: 'context'}]);
|
|
37
33
|
}
|
|
34
|
+
console.log(rx.options.pre);
|
|
38
35
|
if (rx.options.auth === true) {
|
|
39
36
|
rx.options.auth = options.authDefault;
|
|
40
37
|
} else if (rx.options.auth === 'logon') {
|
|
41
38
|
rx.options.auth = options.authLogon;
|
|
42
39
|
}
|
|
43
|
-
|
|
40
|
+
console.log('route auth', rx.options.auth);
|
|
44
41
|
return rx;
|
|
45
42
|
});
|
|
46
43
|
return routes;
|
package/.env.proxy
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
APPHOST=localhost
|
|
2
|
-
# APPENTRY=index.html
|
|
3
|
-
APPENTRY=indexProxy.html
|
|
4
|
-
APPLOC=./public
|
|
5
|
-
VIYA_SERVER=
|
|
6
|
-
APPENV_PROXYSERVER=https://localhost:8080/appBuilder/proxy
|
|
7
|
-
|
|
8
|
-
APPPORT=8080
|
|
9
|
-
APPNAME=appBuilder
|
|
10
|
-
AUTHFLOW=server
|
|
11
|
-
CLIENTID=appbuilder
|
|
12
|
-
CLIENTSECRET=jellico
|
|
13
|
-
REDIRECT=
|
|
14
|
-
|
|
15
|
-
# APPDIR=./appDir
|
|
16
|
-
# HTTPS=true
|
|
17
|
-
USELOGON=YES
|
|
18
|
-
|
|
19
|
-
USETOKEN=YES
|
|
20
|
-
# SHOWENV=YES
|
|
21
|
-
# APPENV=
|
|
22
|
-
APPENV_XYZ=AA
|
|
23
|
-
APPENV_BAD=
|
|
24
|
-
|
|
25
|
-
# APPENV_PUPID=NSHOST=https://sas-logon-app.viya.svc.cluster.local
|
|
26
|
-
|
|
27
|
-
# NAMESPACE=viya
|
|
28
|
-
# TLS_CERT=./certs/tls.crt
|
|
29
|
-
# TLS_KEY=./certs/tls.key
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
package/tls/viyatls.sh
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
kubectl cp $(kubectl get pod | grep "sas-consul-server-0" | awk -F" " '{print $1}'):security/ca.crt ./ca.crt
|
|
2
|
-
kubectl cp $(kubectl get pod | grep "sas-consul-server-0" | awk -F" " '{print $1}'):security/tls.crt ./tls.crt
|
|
3
|
-
kubectl cp $(kubectl get pod | grep "sas-consul-server-0" | awk -F" " '{print $1}'):security/tls.key ./tls.key
|