From d13728dd3d6b6554f8518cb1778babea56100a9a Mon Sep 17 00:00:00 2001 From: John Shaver Date: Mon, 20 Nov 2017 08:26:52 -0800 Subject: [PATCH] Initial scope discover. Needs testing and renaming. --- oauth3.core.js | 78 +++++++++++++++++------------------- well-known/oauth3/index.html | 40 ++++++++++++++++-- 2 files changed, 74 insertions(+), 44 deletions(-) diff --git a/oauth3.core.js b/oauth3.core.js index d5f9ade..ea2611e 100644 --- a/oauth3.core.js +++ b/oauth3.core.js @@ -294,10 +294,6 @@ } } , urls: { - scope: function (directives, opts) { - var uri = directives.grants.url; - uri.replace("/:sub", ); - } , discover: function (providerUri, opts) { if (!providerUri) { throw new Error("cannot discover without providerUri"); @@ -307,25 +303,27 @@ } var clientId = OAUTH3.url.normalize(opts.client_id || opts.client_uri); providerUri = OAUTH3.url.normalize(providerUri); + var discoverFile = opts.discoverFile || "directives.json"; var params = { - action: 'directives' + action: 'directives' //TODO: change this to not be directive specific. Is it even used? , state: opts.state || OAUTH3.utils.randomState() , redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html#/') , response_type: 'rpc' + , discoverFile: opts.discoveFile || "directives.json" , _method: 'GET' , _pathname: '.well-known/oauth3/directives.json' , debug: opts.debug || undefined }; - var result = { + var toRequest = { url: providerUri + '/.well-known/oauth3/#/?' + OAUTH3.query.stringify(params) , state: params.state , method: 'GET' , query: params }; - return result; + return toRequest; } , implicitGrant: function (directive, opts) { // @@ -534,6 +532,14 @@ return OAUTH3.PromiseA.resolve(OAUTH3._hooks.directives.clear()); } } + , scopes: { + get: function(providerUri) { + //TODO: retrieve cached scopes + } + , set: function(providerUri, scopes) { + //TODO: cache scopes + } + } , session: { refresh: function (oldSession, newSession) { var providerUri = oldSession.provider_uri; @@ -662,37 +668,18 @@ } } } - , discoverGrants: function (providerUri, opts) { + , discoverScopes: function (providerUri, opts) { if (!providerUri) { - throw new Error('oauth3.discoverGrants(providerUri, opts) received providerUri as :', providerUri); + throw new Error('oauth3.discoverScopes(providerUri, opts) received providerUri as :', providerUri); } var opts = opts || {}; - var err; - if(!opts.sub && (!opts.token || !opts.token.sub)) { - err = new Error('We need a sub in order to discover grants for.'); - err.code = 'E_NO_SUB'; - throw err; - } - if(! + opts.discoverFile = "scopes.json"; + //TODO: add caching - console.warn(!opts.scopes) { - var firstDo; - - if (directives && directives.issuer) { - firstDo = OAUTH3.PromiseA.resolve(directives); - } else { - firstDo = this.discover(providerUri, opts); - } - - return firstDo.then(function(directives) { - var grantPromises = []; - - - - return OAUTH3._disoverHelper(providerUri, "grants", opts); - }).then(function() { + return OAUTH3._discoverHelper(providerUri, opts).then(function(scopes) { + return scopes; }); } @@ -706,7 +693,7 @@ return directives; } - return OAUTH3._discoverHelper(providerUri, "directives", opts).then(function (directives) { + return OAUTH3._discoverHelper(providerUri, opts).then(function (directives) { directives.azp = directives.azp || OAUTH3.url.normalize(providerUri); directives.issuer = directives.issuer || OAUTH3.url.normalize(providerUri); directives.api = OAUTH3.url.normalize((directives.api||':hostname').replace(/:hostname/, OAUTH3.uri.normalize(directives.issuer) || OAUTH3.uri.normalize(providerUri))); @@ -715,8 +702,9 @@ }); }); } - , _discoverHelper: function(providerUri, type, opts) { - return OAUTH3._browser.discover(providerUri, type, opts); + , _discoverHelper: function(providerUri, opts) { + opts.discoverFile = "directives.json"; + return OAUTH3._browser.discover(providerUri, opts); } , request: function (preq, opts) { function fetch() { @@ -897,17 +885,24 @@ , _browser: { window: 'undefined' !== typeof window ? window : null // TODO we don't need to include this if we're using jQuery or angular - , discover: function(providerUri, type, opts) { + , discover: function(providerUri, opts) { opts = opts || {}; providerUri = OAUTH3.url.normalize(providerUri); + // If no discoverFile was specified, who knows what they want, but + // this function used to only support directives.json, so it's worth + // a shot. + var discoverFile = opts.discoverFile || "directives.json"; + if (OAUTH3.uri.normalize(providerUri).replace(/\/.*/, '') === OAUTH3.uri.normalize(OAUTH3._browser.window.location.hostname)) { - console.warn("It looks like you're a provider checking for your own directive," + console.warn("It looks like you're a provider trying to discover on yourself," + " so we we're just gonna use" - + " OAUTH3.request({ method: 'GET', url: '.well-known/oauth3/directive.json' })"); + + " OAUTH3.request({ method: 'GET', url: " + + "'/.well-known/oauth3/" + discoverFile + "' })"); + return OAUTH3.request({ method: 'GET' - , url: OAUTH3.url.normalize(providerUri) + '/.well-known/oauth3/directives.json' + , url: OAUTH3.url.normalize(providerUri) + '/.well-known/oauth3/' + discoverFile }).then(function (resp) { return resp.data; }); @@ -926,6 +921,7 @@ , broker: opts.broker , state: opts._state || undefined , debug: opts.debug + , discoverFile: opts.discoverFile } ); opts._state = discReq.state; @@ -957,9 +953,9 @@ } // TODO params should have response_type indicating json, binary, etc - var directives = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.result || params.directives)); + var result = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.result || params.directives)); // caller will call OAUTH3.hooks.directives.set(providerUri, directives); - return directives; + return result; }); } , request: function (preq, _sys) { diff --git a/well-known/oauth3/index.html b/well-known/oauth3/index.html index 9c415e5..b31b6b9 100644 --- a/well-known/oauth3/index.html +++ b/well-known/oauth3/index.html @@ -30,11 +30,44 @@ console.log(prefix, 'params:'); console.log(params); - OAUTH3.request({ url: 'directives.json' }).then(function (resp) { + var fileWhiteList = [ + "directives.json" + , "scopes.json" ]; + + //Serving arbitrary files/paths is probably not a good idea. + //Let's make sure this is something we want to serve. + if(fileWhiteList.indexOf(params.discoverFile) === -1) { + //Nope! + var redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({ + state: params.state + , error: "No access to requested file: " + params.discoverFile + , error_code: "E_ACCESS_DENIED" + , debug: params.debug || undefined + }); + + console.error(prefix, "Requested file is not listed as a discoverable file:" + , fileWhiteList); + console.log("Redirecting with error: ", redirect) + + if (!params.debug) { + window.location = redirect; + } else { + // yes, we're violating the security lint with purpose + document.body.innerHTML += window.location.host + window.location.pathname + + '

You\'ve passed the \'debug\' parameter so we\'re pausing' + + ' to let you look at logs or whatever it is that you intended to do.' + + '

The requested file was not a discoverable file (see console for details).' + + '

Continue with error redirect: ' + redirect + ''; + } + return; + } + + OAUTH3.request({ url: params.discoverfile }).then(function (resp) { var urlsafe64 = OAUTH3._base64.encodeUrlSafe(JSON.stringify(resp.data, null, 0)); var redirect; + var returnParams; - console.log(prefix, 'directives'); + console.log(prefix, 'file contents'); console.log(resp); console.log(prefix, 'base64'); @@ -48,7 +81,8 @@ console.log(prefix, 'params.redirect_uri:', params.redirect_uri); redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({ state: params.state - , directives: urlsafe64 + , directives: urlsafe64 //kept for now, probably should remove this. + , result: urlsafe64 , debug: params.debug || undefined })