changed how grants are saved and how tokens are created for other clients

This commit is contained in:
tigerbot 2017-07-26 18:15:09 -06:00
parent 1ca6f0a324
commit 28dbf9ab23
2 changed files with 105 additions and 44 deletions

View File

@ -78,7 +78,7 @@
, uri: {
normalize: function (uri) {
if ('string' !== typeof uri) {
console.error((new Error('stack')).stack);
throw new Error("attempted to normalize non-string URI: "+JSON.stringify(uri));
}
// tested with
// example.com
@ -94,7 +94,7 @@
, url: {
normalize: function (url) {
if ('string' !== typeof url) {
console.error((new Error('stack')).stack);
throw new Error("attempted to normalize non-string URL: "+JSON.stringify(url));
}
// tested with
// example.com

View File

@ -102,8 +102,6 @@ OAUTH3.urls.resourceOwnerPassword = function (directive, opts) {
// , "username": "<<username>>", "password": "password" }
//
opts = opts || {};
var type = 'access_token';
var grantType = 'password';
if (!opts.password) {
if (opts.otp) {
@ -112,16 +110,13 @@ OAUTH3.urls.resourceOwnerPassword = function (directive, opts) {
}
}
var scope = opts.scope || directive.authn_scope;
var clientAgreeTos = 'oauth3.org/tos/draft'; // opts.clientAgreeTos || opts.client_agree_tos;
var clientUri = opts.client_uri;
var args = directive[type];
var args = directive.access_token;
var otpCode = opts.otp || opts.otpCode || opts.otp_code || opts.otpToken || opts.otp_token || undefined;
// TODO require user agent
var params = {
client_id: opts.client_id || opts.client_uri
, client_uri: opts.client_uri
, grant_type: grantType
, grant_type: 'password'
, username: opts.username
, password: opts.password || otpCode || undefined
, totp: opts.totp || opts.totpToken || opts.totp_token || undefined
@ -136,23 +131,21 @@ OAUTH3.urls.resourceOwnerPassword = function (directive, opts) {
//, "jwt": opts.jwt // TODO sign a proof with a previously loaded public_key
, debug: opts.debug || undefined
};
var uri = args.url;
var body;
if (opts.totp) {
params.totp = opts.totp;
}
if (clientUri) {
params.clientAgreeTos = clientAgreeTos;
if (!clientAgreeTos) {
if (opts.client_uri) {
params.clientAgreeTos = 'oauth3.org/tos/draft'; // opts.clientAgreeTos || opts.client_agree_tos;
if (!params.clientAgreeTos) {
throw new Error('Developer Error: missing clientAgreeTos uri');
}
}
var scope = opts.scope || directive.authn_scope;
if (scope) {
params.scope = OAUTH3.scope.stringify(scope);
}
var uri = args.url;
var body;
if ('GET' === args.method.toUpperCase()) {
uri += '?' + OAUTH3.query.stringify(params);
} else {
@ -168,6 +161,10 @@ OAUTH3.urls.resourceOwnerPassword = function (directive, opts) {
OAUTH3.urls.grants = function (directive, opts) {
// directive = { issuer, authorization_decision }
// opts = { response_type, scopes{ granted, requested, pending, accepted } }
var grantsDir = directive.grants;
if (!grantsDir) {
throw new Error("provider doesn't support grants");
}
if (!opts) {
throw new Error("You must supply a directive and an options object.");
@ -183,15 +180,18 @@ OAUTH3.urls.grants = function (directive, opts) {
}
if (!opts.method) {
console.warn("You should supply options.method as either 'GET', or 'POST'");
opts.method = 'GET';
opts.method = grantsDir.method || 'GET';
}
if ('POST' === opts.method) {
if ('string' !== typeof opts.scope) {
throw new Error("You must supply options.scope as a comma-delimited string of scopes");
}
if ('string' !== typeof opts.sub) {
console.log("provide 'sub' to urls.grants to specify the PPID for the client");
}
}
var url = OAUTH3.url.resolve(directive.api, directive.grants.url)
var url = OAUTH3.url.resolve(directive.api, grantsDir.url)
.replace(/(:azp|:client_id)/g, OAUTH3.uri.normalize(opts.client_id || opts.client_uri))
.replace(/(:sub|:account_id)/g, opts.session.token.sub || 'ISSUER:GRANT:TOKEN_SUB:UNDEFINED')
;
@ -200,13 +200,13 @@ OAUTH3.urls.grants = function (directive, opts) {
, client_uri: opts.client_uri
, referrer: opts.referrer
, scope: opts.scope
, sub: opts.sub
};
var body;
if ('GET' === opts.method) {
url += '?' + OAUTH3.query.stringify(data);
}
else {
} else {
body = data;
}
@ -217,6 +217,50 @@ OAUTH3.urls.grants = function (directive, opts) {
, session: opts.session
};
};
OAUTH3.urls.clientToken = function (directive, opts) {
var tokenDir = directive.access_token;
if (!tokenDir) {
throw new Error("provider doesn't support getting access tokens");
}
if (!opts) {
throw new Error("You must supply a directive and an options object.");
}
if (!(opts.azp || opts.client_id)) {
throw new Error("You must supply options.client_id.");
}
if (!opts.session) {
throw new Error("You must supply options.session.");
}
if (!opts.method) {
opts.method = tokenDir.method || 'POST';
}
var params = {
grant_type: 'issuer_token'
, client_id: opts.azp || opts.client_id
, azp: opts.azp || opts.client_id
, aud: opts.aud
, exp: opts.exp
, refresh_token: opts.refresh_token
, refresh_exp: opts.refresh_exp
};
var url = OAUTH3.url.resolve(directive.api, tokenDir.url);
var body;
if ('GET' === opts.method) {
url += '?' + OAUTH3.query.stringify(params);
} else {
body = params;
}
return {
method: opts.method
, url: url
, data: body
, session: opts.session
};
};
OAUTH3.authn = {};
OAUTH3.authn.loginMeta = function (directive, opts) {
@ -340,34 +384,51 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s
if (!OAUTH3.url.checkRedirect(clientParams.client_uri, clientParams)) {
return;
}
if ('token' !== clientParams.response_type) {
var message;
if ('code' === clientParams.response_type) {
message = "Authorization Code Redirect NOT IMPLEMENTED";
} else {
message = "Authorization response type '"+clientParams.response_type+"' not supported";
}
window.alert(message);
throw new Error(message);
}
scopes.new = scopes.new || [];
if ('token' === clientParams.response_type) {
// get token and redirect client-side
return OAUTH3.authz.grants(providerUri, {
method: 'POST'
var prom;
if (scopes.new) {
prom = OAUTH3.authz.grants(providerUri, {
session: session
, method: 'POST'
, client_id: clientParams.client_uri
, client_uri: clientParams.client_uri
, scope: scopes.granted.concat(scopes.new).join(',')
, response_type: clientParams.response_type
, referrer: clientParams.referrer
, session: session
, debug: clientParams.debug
}).then(function (results) {
// TODO limit refresh token to an expirable token
// TODO inform client not to persist token
OAUTH3.url.redirect(clientParams, scopes, results);
, scope: scopes.accepted.concat(scopes.new).join(',')
});
} else {
prom = OAUTH3.PromiseA.resolve();
}
else if ('code' === clientParams.response_type) {
// get token and redirect server-side
// (requires insecure form post as per spec)
//OAUTH3.requests.authorizationDecision();
window.alert("Authorization Code Redirect NOT IMPLEMENTED");
throw new Error("Authorization Code Redirect NOT IMPLEMENTED");
}
return prom.then(function () {
return OAUTH3.discover(providerUri, { client_id: providerUri, debug: clientParams.debug });
}).then(function (directive) {
return OAUTH3.request(OAUTH3.urls.clientToken(directive, {
method: 'POST'
, session: session
, referrer: clientParams.referrer
, response_type: clientParams.response_type
, client_id: clientParams.client_uri
, azp: clientParams.client_uri
, aud: clientParams.aud
, exp: clientParams.exp
, refresh_token: clientParams.refresh_token
, refresh_exp: clientParams.refresh_exp
, debug: clientParams.debug
}));
}).then(function (results) {
// TODO limit refresh token to an expirable token
// TODO inform client not to persist token
OAUTH3.url.redirect(clientParams, scopes, results.originalData || results.data);
});
};
OAUTH3.requests = {};