updated how grants are retrieved

This commit is contained in:
tigerbot 2017-07-26 16:27:03 -06:00
parent c38554a9dd
commit 1ca6f0a324
2 changed files with 73 additions and 147 deletions

View File

@ -168,9 +168,12 @@
}
}
, scope: {
stringify: function (scope) {
parse: function (scope) {
return (scope||'').split(/[+, ]+/g);
}
, stringify: function (scope) {
if (Array.isArray(scope)) {
scope = scope.join(' ');
scope = scope.join(',');
}
return scope;
}

View File

@ -3,39 +3,6 @@
var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.core.js').OAUTH3;
OAUTH3.query.parse = function (search) {
// parse a query or a hash
if (-1 !== ['#', '?'].indexOf(search[0])) {
search = search.substring(1);
}
// Solve for case of search within hash
// example: #/authorization_dialog/?state=...&redirect_uri=...
var queryIndex = search.indexOf('?');
if (-1 !== queryIndex) {
search = search.substr(queryIndex + 1);
}
var args = search.split('&');
var argsParsed = {};
var i, arg, kvp, key, value;
for (i = 0; i < args.length; i += 1) {
arg = args[i];
if (-1 === arg.indexOf('=')) {
argsParsed[decodeURIComponent(arg).trim()] = true;
}
else {
kvp = arg.split('=');
key = decodeURIComponent(kvp[0]).trim();
value = decodeURIComponent(kvp[1]).trim();
argsParsed[key] = value;
}
}
return argsParsed;
};
OAUTH3.scope.parse = function (scope) {
return (scope||'').split(/[, ]/g);
};
OAUTH3.url.parse = function (url) {
// TODO browser
// Node should replace this
@ -58,8 +25,16 @@ OAUTH3.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) {
};
OAUTH3.url.checkRedirect = function (client, query) {
console.warn("[security] URL path checking not yet implemented");
if (!query) {
query = client;
client = query.client_uri;
}
client = client.url || client;
var clientUrl = OAUTH3.url.normalize(client.url);
// it doesn't matter who the referrer is as long as the destination
// is an authorized destination for the client in question
// (though it may not hurt to pass the referrer's info on to the client)
var clientUrl = OAUTH3.url.normalize(client);
var redirectUrl = OAUTH3.url.normalize(query.redirect_uri);
// General rule:
@ -72,6 +47,18 @@ OAUTH3.url.checkRedirect = function (client, query) {
return true;
}
var callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK?'+OAUTH3.query.stringify({
'redirect_uri': redirectUrl
, 'allowed_urls': clientUrl
, 'client_id': client
, 'referrer_uri': OAUTH3.uri.normalize(window.document.referrer)
});
if (query.debug) {
console.log('Redirect Attack');
console.log(query);
window.alert("DEBUG MODE checkRedirect error encountered. Check the console.");
}
location.href = callbackUrl;
return false;
};
OAUTH3.url.redirect = function (clientParams, grants, tokenOrError) {
@ -195,14 +182,12 @@ OAUTH3.urls.grants = function (directive, opts) {
console.warn("You should supply options.referrer");
}
if (!opts.method) {
console.warn("You must supply options.method as either 'GET', or 'POST'");
console.warn("You should supply options.method as either 'GET', or 'POST'");
opts.method = 'GET';
}
if ('POST' === opts.method) {
if ('string' !== typeof opts.scope) {
console.warn("You should supply options.scope as a space-delimited string of scopes");
}
if (-1 === ['token', 'code'].indexOf(opts.response_type)) {
throw new Error("You must supply options.response_type as 'token' or 'code'");
throw new Error("You must supply options.scope as a comma-delimited string of scopes");
}
}
@ -214,12 +199,10 @@ OAUTH3.urls.grants = function (directive, opts) {
client_id: opts.client_id
, client_uri: opts.client_uri
, referrer: opts.referrer
, response_type: opts.response_type
, scope: opts.scope
, tenant_id: opts.tenant_id
};
var body;
var body;
if ('GET' === opts.method) {
url += '?' + OAUTH3.query.stringify(data);
}
@ -290,14 +273,13 @@ OAUTH3.authn.resourceOwnerPassword = function (directive, opts) {
OAUTH3.authz = {};
OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
// OAuth3.requests.grants(providerUri, {}); // return list of grants
// OAuth3.checkGrants(providerUri, {}); //
var clientUri = OAUTH3.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer);
var scope = clientParams.scope || '';
var clientObj = clientParams;
if (!scope) {
scope = 'oauth3_authn';
var scope = clientParams.scope || 'oauth3_authn';
if ('oauth3_authn' === scope) {
// implicit ppid grant is automatic
console.warn('[security] fix scope checking on backend so that we can do automatic grants');
// TODO check user preference if implicit ppid grant is allowed
//return generateToken(session, clientObj);
}
return OAUTH3.authz.grants(providerUri, {
@ -305,74 +287,30 @@ OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
, client_id: clientUri
, client_uri: clientUri
, session: session
}).then(function (grantResults) {
var grants;
var grantedScopes;
var grantedScopesMap;
var pendingScopes;
var acceptedScopes;
var scopes = scope.split(/[+, ]/g);
var callbackUrl;
// it doesn't matter who the referrer is as long as the destination
// is an authorized destination for the client in question
// (though it may not hurt to pass the referrer's info on to the client)
if (!OAUTH3.url.checkRedirect(grantResults.client, clientObj)) {
callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK'
+ '?redirect_uri=' + clientObj.redirect_uri
+ '&allowed_urls=' + grantResults.client.url
+ '&client_id=' + clientUri
+ '&referrer_uri=' + OAUTH3.uri.normalize(window.document.referrer)
;
if (clientParams.debug) {
console.log('grantResults Redirect Attack');
console.log(grantResults);
console.log(clientObj);
window.alert("DEBUG MODE checkRedirect error encountered. Check the console.");
}
location.href = callbackUrl;
return;
}).then(function (results) {
return results.grants;
}, function (err) {
if (!/no .*grants .*found/i.test(err.message)) {
console.error(err);
}
if ('oauth3_authn' === scope) {
// implicit ppid grant is automatic
console.warn('[security] fix scope checking on backend so that we can do automatic grants');
// TODO check user preference if implicit ppid grant is allowed
//return generateToken(session, clientObj);
}
grants = (grantResults).grants.filter(function (grant) {
if (clientUri === (grant.azp || grant.oauth_client_id || grant.oauthClientId)) {
return true;
return [];
}).then(function (granted) {
var requested = OAUTH3.scope.parse(scope);
var accepted = [];
var pending = [];
requested.forEach(function (scp) {
if (granted.indexOf(scp) < 0) {
pending.push(scp);
} else {
accepted.push(scp);
}
});
grantedScopesMap = {};
acceptedScopes = [];
pendingScopes = scopes.filter(function (requestedScope) {
return grants.every(function (grant) {
if (!grant.scope) {
grant.scope = 'oauth3_authn';
}
var gscopes = grant.scope.split(/[+, ]/g);
gscopes.forEach(function (s) { grantedScopesMap[s] = true; });
if (-1 !== gscopes.indexOf(requestedScope)) {
// already accepted in the past
acceptedScopes.push(requestedScope);
}
else {
// true, is pending
return true;
}
});
});
grantedScopes = Object.keys(grantedScopesMap);
return {
pending: pendingScopes // not yet accepted
, granted: grantedScopes // all granted, ever
, requested: scopes // all requested, now
, accepted: acceptedScopes // granted (ever) and requested (now)
requested: requested // all requested, now
, granted: granted // all granted, ever
, accepted: accepted // intersection of granted (ever) and requested (now)
, pending: pending // not yet accepted
};
});
};
@ -381,34 +319,27 @@ OAUTH3.authz.grants = function (providerUri, opts) {
client_id: providerUri
, debug: opts.debug
}).then(function (directive) {
return OAUTH3.request(OAUTH3.urls.grants(directive, opts), opts);
}).then(function (grantsResult) {
var grants = grantsResult.originalData || grantsResult.data;
if (grants.error) {
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, grants));
}
if ('POST' === opts.method) {
return grants;
}
return OAUTH3.request(OAUTH3.urls.grants(directive, opts), opts).then(function (grantsResult) {
if ('POST' === opts.method) {
// TODO this is clientToken
return grantsResult.originalData || grantsResult.data;
}
var grants = grantsResult.originalData || grantsResult.data;
// TODO
if (grants.error) {
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, grants));
}
OAUTH3.hooks.grants.set(opts.client_id + '-client', grants.client);
grants.grants.forEach(function (grant) {
var clientId = grant.client_id || grant.oauth_client_id || grant.oauthClientId;
// TODO should save as an array
OAUTH3.hooks.grants.set(clientId, [ grant ]);
});
return {
client: OAUTH3.hooks.grants.get(opts.client_id + '-client')
, grants: OAUTH3.hooks.grants.get(opts.client_id) || []
};
});
OAUTH3.hooks.grants.set(grants.sub+'/'+grants.azp, grants.scope);
return {
client: grants.azp
, grants: OAUTH3.scope.parse(grants.scope)
};
});
};
OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) {
if (!OAUTH3.url.checkRedirect(clientParams.client_uri, clientParams)) {
return;
}
scopes.new = scopes.new || [];
@ -427,15 +358,6 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s
// TODO limit refresh token to an expirable token
// TODO inform client not to persist token
/*
if (clientParams.dnsTxt) {
Object.keys(results).forEach(function (key) {
if (/refresh/.test(key)) {
results[key] = undefined;
}
});
}
*/
OAUTH3.url.redirect(clientParams, scopes, results);
});
}
@ -447,6 +369,7 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s
throw new Error("Authorization Code Redirect NOT IMPLEMENTED");
}
};
OAUTH3.requests = {};
OAUTH3.requests.accounts = {};
OAUTH3.requests.accounts.update = function (directive, session, opts) {