diff --git a/src/nginx.conf b/src/nginx.conf index bb68ece..1b62034 100644 --- a/src/nginx.conf +++ b/src/nginx.conf @@ -4,7 +4,7 @@ load_module modules/ngx_http_js_module.so; user nginx; worker_processes auto; -error_log /var/log/nginx/error.log notice; +error_log /var/log/nginx/error.log info; pid /var/run/nginx.pid; @@ -21,7 +21,7 @@ http { js_import pep.js; # added to bind enforce function - js_set $authorization pep.enforce; + js_set $authorization pep.enforce_legacy; # added to create cache for tokens and auth calls proxy_cache_path /var/cache/nginx/pep keys_zone=token_responses:1m max_size=2m; diff --git a/src/nginx.default.conf.template b/src/nginx.default.conf.template index b1cee84..a407ffb 100644 --- a/src/nginx.default.conf.template +++ b/src/nginx.default.conf.template @@ -10,7 +10,7 @@ js_var $auth_token; js_var $account_record; js_var $pep_credentials; -# proxy_cache_path /tmp levels=1:2 keys_zone=social_cache:10m max_size=10g inactive=60m use_temp_path=off; +proxy_cache_path /tmp levels=1:2 keys_zone=social_cache:10m max_size=10g inactive=60m use_temp_path=off; server { @@ -31,9 +31,22 @@ server { location / { proxy_read_timeout 300; proxy_send_timeout 300; - js_content pep.enforce; + js_content pep.enforce_legacy; } + location /gcube_user_info { + internal; + gunzip on; + proxy_method GET; + proxy_http_version 1.1; + proxy_set_header gcube-token "$auth_token"; + proxy_pass https://api.d4science.org/rest/2/people/profile; + + proxy_cache social_cache; + proxy_cache_key $auth_token; + } + + # internal location that redirects to backend will only be called from PEP JS code when all checks are passed location /_backend { internal; diff --git a/src/pep.js b/src/pep.js index fc1ed0f..d65d96f 100644 --- a/src/pep.js +++ b/src/pep.js @@ -1,9 +1,9 @@ -export default { enforce }; +export default { enforce_legacy }; import defaultExport from './config.js'; function log(c, s){ - c.request.error(s) + c.request.log(s) } var _debug = defaultExport["debug"] @@ -28,6 +28,57 @@ function enforce(r) { wkf.run(wkf.build(context), context) } + + +function enforce_legacy(r) { + + var context = { + request: r + } + + var allowedcontexts = [defaultExport["accounting"]["scope"]] + + log(context, "Inside NJS enforce for " + r.method + " @ " + r.headersIn.host + "/" + r.uri) + + const token = getGCubeToken(context) + if(token != null){ + debug(context, "[PEP] token is " + token) + exportVariable(context, "auth_token", token) + context.request.subrequest("/gcube_user_info") + .then(reply=>{ + if (reply.status === 200) { + debug(context, "[Social Service] got response " + reply.responseBody) + var response = JSON.parse(reply.responseBody); + if(allowedcontexts.indexOf(response.result.context) === -1){ + debug(context, "[PEP] Unathorized context " + response.result.context) + throw new Error("Unauthorized") + } + return response + } else { + debug(context, "[Social Service] failed " + reply.status + ":" + reply.responseBody) + throw new Error("Unauthorized") + } + }).then(userinfo => { + debug(context, "[Social Service] username is " + userinfo.result.username) + context.userinfo = userinfo + context.record = buildAccountingRecord(context) + return context.request.subrequest("/_backend", { method : context.request.method, args : context.request.args, headers : context.request.headersIn}) + }).then(reply=>{ + debug(context, "[{{ sobigdata_ontotagme_service_name }}] response status: " + reply.status) + closeAccountingRecord(context.record, (reply.status === 200 || reply.status === 201 || reply.status === 204)) + context.request.subrequest("/_accounting", { detached : true, body : JSON.stringify([context.record]) }) + r.return(reply.status, reply.responseBody) + }).catch(e => { log(context, "Error .... " + njs.dump(e)); context.request.return(e.message === "Unauthorized" ? 403 : 500)} ) + + return + } + + r.return(401, "Authorization required") +} + + + + // ######## WORKFLOW FUNCTIONS ############### var wkf = { @@ -64,7 +115,7 @@ var wkf = { }, run : (actions, context) => { - context.request.error("Starting workflow with " + njs.dump(actions)) + context.request.log("Starting workflow with " + njs.dump(actions)) var w = actions.reduce( (acc, f) => { return acc.then(typeof(f) === "function" ? f : wkf[f]) }, Promise.resolve().then(()=>context) @@ -89,6 +140,16 @@ var wkf = { send_accounting : sendAccountingRecord } +function getGCubeToken(context){ + if (context.request.args["gcube-token"]) { + return context.request["gcube-token"]; + } else if (context.request.headersIn['gcube-token']) { + return context.request.headersIn['gcube-token']; + } + return null; +} + + function getTokenField(context, f){ return context.authn.verified_token[f] } @@ -122,6 +183,7 @@ function checkAuthentication(context){ function parseAuthentication(context){ context.request.log("Inside parseAuthentication") + context.request.log(JSON.stringify(context.request.args, null, 2)) var incomingauth = context.request.headersIn["Authorization"] if(!incomingauth) throw new Error("Authentication required"); @@ -343,7 +405,7 @@ function computeProtection(context){ context.authz = {} context.authz.host = getHost(context.config, context.request.headersIn.host) if(context.authz.host !== null){ - log(context, "Host found:" + context.authz.host) + log(context, "Host found: " + njs.dump(context.authz.host)) context.authz.pip = context.authz.host.pip ? context.authz.host.pip : []; context.authz.pdp = context.authz.host.pdp ? context.authz.host.pdp : umaCall; var pathandmethod = getPath(context.authz.host, context.request.uri, context.request.method);