updated how grants are retrieved
This commit is contained in:
parent
c38554a9dd
commit
1ca6f0a324
|
@ -168,9 +168,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, scope: {
|
, scope: {
|
||||||
stringify: function (scope) {
|
parse: function (scope) {
|
||||||
|
return (scope||'').split(/[+, ]+/g);
|
||||||
|
}
|
||||||
|
, stringify: function (scope) {
|
||||||
if (Array.isArray(scope)) {
|
if (Array.isArray(scope)) {
|
||||||
scope = scope.join(' ');
|
scope = scope.join(',');
|
||||||
}
|
}
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
213
oauth3.issuer.js
213
oauth3.issuer.js
|
@ -3,39 +3,6 @@
|
||||||
|
|
||||||
var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.core.js').OAUTH3;
|
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) {
|
OAUTH3.url.parse = function (url) {
|
||||||
// TODO browser
|
// TODO browser
|
||||||
// Node should replace this
|
// Node should replace this
|
||||||
|
@ -58,8 +25,16 @@ OAUTH3.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) {
|
||||||
};
|
};
|
||||||
OAUTH3.url.checkRedirect = function (client, query) {
|
OAUTH3.url.checkRedirect = function (client, query) {
|
||||||
console.warn("[security] URL path checking not yet implemented");
|
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);
|
var redirectUrl = OAUTH3.url.normalize(query.redirect_uri);
|
||||||
|
|
||||||
// General rule:
|
// General rule:
|
||||||
|
@ -72,6 +47,18 @@ OAUTH3.url.checkRedirect = function (client, query) {
|
||||||
return true;
|
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;
|
return false;
|
||||||
};
|
};
|
||||||
OAUTH3.url.redirect = function (clientParams, grants, tokenOrError) {
|
OAUTH3.url.redirect = function (clientParams, grants, tokenOrError) {
|
||||||
|
@ -195,14 +182,12 @@ OAUTH3.urls.grants = function (directive, opts) {
|
||||||
console.warn("You should supply options.referrer");
|
console.warn("You should supply options.referrer");
|
||||||
}
|
}
|
||||||
if (!opts.method) {
|
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 ('POST' === opts.method) {
|
||||||
if ('string' !== typeof opts.scope) {
|
if ('string' !== typeof opts.scope) {
|
||||||
console.warn("You should supply options.scope as a space-delimited string of scopes");
|
throw new Error("You must supply options.scope as a comma-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'");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,12 +199,10 @@ OAUTH3.urls.grants = function (directive, opts) {
|
||||||
client_id: opts.client_id
|
client_id: opts.client_id
|
||||||
, client_uri: opts.client_uri
|
, client_uri: opts.client_uri
|
||||||
, referrer: opts.referrer
|
, referrer: opts.referrer
|
||||||
, response_type: opts.response_type
|
|
||||||
, scope: opts.scope
|
, scope: opts.scope
|
||||||
, tenant_id: opts.tenant_id
|
|
||||||
};
|
};
|
||||||
var body;
|
|
||||||
|
|
||||||
|
var body;
|
||||||
if ('GET' === opts.method) {
|
if ('GET' === opts.method) {
|
||||||
url += '?' + OAUTH3.query.stringify(data);
|
url += '?' + OAUTH3.query.stringify(data);
|
||||||
}
|
}
|
||||||
|
@ -290,14 +273,13 @@ OAUTH3.authn.resourceOwnerPassword = function (directive, opts) {
|
||||||
|
|
||||||
OAUTH3.authz = {};
|
OAUTH3.authz = {};
|
||||||
OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
|
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 clientUri = OAUTH3.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer);
|
||||||
var scope = clientParams.scope || '';
|
var scope = clientParams.scope || 'oauth3_authn';
|
||||||
var clientObj = clientParams;
|
if ('oauth3_authn' === scope) {
|
||||||
|
// implicit ppid grant is automatic
|
||||||
if (!scope) {
|
console.warn('[security] fix scope checking on backend so that we can do automatic grants');
|
||||||
scope = 'oauth3_authn';
|
// TODO check user preference if implicit ppid grant is allowed
|
||||||
|
//return generateToken(session, clientObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OAUTH3.authz.grants(providerUri, {
|
return OAUTH3.authz.grants(providerUri, {
|
||||||
|
@ -305,74 +287,30 @@ OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
|
||||||
, client_id: clientUri
|
, client_id: clientUri
|
||||||
, client_uri: clientUri
|
, client_uri: clientUri
|
||||||
, session: session
|
, session: session
|
||||||
}).then(function (grantResults) {
|
}).then(function (results) {
|
||||||
var grants;
|
return results.grants;
|
||||||
var grantedScopes;
|
}, function (err) {
|
||||||
var grantedScopesMap;
|
if (!/no .*grants .*found/i.test(err.message)) {
|
||||||
var pendingScopes;
|
console.error(err);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
return [];
|
||||||
if ('oauth3_authn' === scope) {
|
}).then(function (granted) {
|
||||||
// implicit ppid grant is automatic
|
var requested = OAUTH3.scope.parse(scope);
|
||||||
console.warn('[security] fix scope checking on backend so that we can do automatic grants');
|
var accepted = [];
|
||||||
// TODO check user preference if implicit ppid grant is allowed
|
var pending = [];
|
||||||
//return generateToken(session, clientObj);
|
requested.forEach(function (scp) {
|
||||||
}
|
if (granted.indexOf(scp) < 0) {
|
||||||
|
pending.push(scp);
|
||||||
grants = (grantResults).grants.filter(function (grant) {
|
} else {
|
||||||
if (clientUri === (grant.azp || grant.oauth_client_id || grant.oauthClientId)) {
|
accepted.push(scp);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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 {
|
return {
|
||||||
pending: pendingScopes // not yet accepted
|
requested: requested // all requested, now
|
||||||
, granted: grantedScopes // all granted, ever
|
, granted: granted // all granted, ever
|
||||||
, requested: scopes // all requested, now
|
, accepted: accepted // intersection of granted (ever) and requested (now)
|
||||||
, accepted: acceptedScopes // granted (ever) and requested (now)
|
, pending: pending // not yet accepted
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -381,34 +319,27 @@ OAUTH3.authz.grants = function (providerUri, opts) {
|
||||||
client_id: providerUri
|
client_id: providerUri
|
||||||
, debug: opts.debug
|
, debug: opts.debug
|
||||||
}).then(function (directive) {
|
}).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) {
|
OAUTH3.hooks.grants.set(grants.sub+'/'+grants.azp, grants.scope);
|
||||||
if ('POST' === opts.method) {
|
return {
|
||||||
// TODO this is clientToken
|
client: grants.azp
|
||||||
return grantsResult.originalData || grantsResult.data;
|
, grants: OAUTH3.scope.parse(grants.scope)
|
||||||
}
|
};
|
||||||
|
|
||||||
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.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) {
|
OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) {
|
||||||
|
if (!OAUTH3.url.checkRedirect(clientParams.client_uri, clientParams)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
scopes.new = scopes.new || [];
|
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 limit refresh token to an expirable token
|
||||||
// TODO inform client not to persist 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);
|
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");
|
throw new Error("Authorization Code Redirect NOT IMPLEMENTED");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
OAUTH3.requests = {};
|
OAUTH3.requests = {};
|
||||||
OAUTH3.requests.accounts = {};
|
OAUTH3.requests.accounts = {};
|
||||||
OAUTH3.requests.accounts.update = function (directive, session, opts) {
|
OAUTH3.requests.accounts.update = function (directive, session, opts) {
|
||||||
|
|
Loading…
Reference in New Issue