WIP oauth3.issuer.js
This commit is contained in:
parent
460274017b
commit
c2370d9b76
|
@ -0,0 +1,287 @@
|
|||
/* global Promise */
|
||||
;(function (exports) {
|
||||
'use strict';
|
||||
|
||||
OAUTH3.utils.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.urls.resourceOwnerPassword = function (directive, opts) {
|
||||
//
|
||||
// Example Resource Owner Password Request
|
||||
// (generally for 1st party and direct-partner mobile apps, and webapps)
|
||||
//
|
||||
// POST https://example.com/api/org.oauth3.provider/access_token
|
||||
// { "grant_type": "password", "client_id": "<<id>>", "scope": "<<scope>>"
|
||||
// , "username": "<<username>>", "password": "password" }
|
||||
//
|
||||
opts = opts || {};
|
||||
var type = 'access_token';
|
||||
var grantType = 'password';
|
||||
|
||||
if (!opts.password) {
|
||||
if (opts.otp) {
|
||||
// for backwards compat
|
||||
opts.password = opts.otp; // 'otp:' + opts.otpUuid + ':' + opts.otp;
|
||||
}
|
||||
}
|
||||
|
||||
var scope = opts.scope || directive.authn_scope;
|
||||
var clientId = opts.appId || opts.clientId || opts.client_id;
|
||||
var clientAgreeTos = opts.clientAgreeTos || opts.client_agree_tos;
|
||||
var clientUri = opts.clientUri || opts.client_uri || opts.clientUrl || opts.client_url;
|
||||
var args = directive[type];
|
||||
var otpCode = opts.otp || opts.otpCode || opts.otp_code || opts.otpToken || opts.otp_token || undefined;
|
||||
var params = {
|
||||
"grant_type": grantType
|
||||
, "username": opts.username
|
||||
, "password": opts.password || otpCode || undefined
|
||||
, "totp": opts.totp || opts.totpToken || opts.totp_token || undefined
|
||||
, "otp": otpCode
|
||||
, "password_type": otpCode && 'otp'
|
||||
, "otp_code": otpCode
|
||||
, "otp_uuid": opts.otpUuid || opts.otp_uuid || undefined
|
||||
, "user_agent": opts.userAgent || opts.useragent || opts.user_agent || undefined // AJ's Macbook
|
||||
, "jwk": (opts.rememberDevice || opts.remember_device) && opts.jwk || undefined
|
||||
//, "public_key": opts.rememberDevice && opts.publicKey || undefined
|
||||
//, "public_key_type": opts.rememberDevice && opts.publicKeyType || undefined // RSA/ECDSA
|
||||
//, "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 (clientId) {
|
||||
params.clientId = clientId;
|
||||
}
|
||||
if (clientUri) {
|
||||
params.clientUri = clientUri;
|
||||
params.clientAgreeTos = clientAgreeTos;
|
||||
if (!clientAgreeTos) {
|
||||
throw new Error('Developer Error: missing clientAgreeTos uri');
|
||||
}
|
||||
}
|
||||
|
||||
if (scope) {
|
||||
params.scope = core.stringifyscope(scope);
|
||||
}
|
||||
|
||||
if ('GET' === args.method.toUpperCase()) {
|
||||
uri += '?' + core.querystringify(params);
|
||||
} else {
|
||||
body = params;
|
||||
}
|
||||
|
||||
return {
|
||||
url: uri
|
||||
, method: args.method
|
||||
, data: body
|
||||
};
|
||||
};
|
||||
|
||||
OAUTH3.authz = {};
|
||||
OAUTH3.authz.loginMeta = function (directive, opts) {
|
||||
if (opts.mock) {
|
||||
if (opts.mockError) {
|
||||
return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
|
||||
}
|
||||
return OAUTH3.PromiseA.resolve({data: {}});
|
||||
}
|
||||
|
||||
return OAUTH3.request({
|
||||
method: directive.credential_meta.method || 'GET'
|
||||
// TODO lint urls
|
||||
, url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_meta.url)
|
||||
.replace(':type', 'email')
|
||||
.replace(':id', opts.email)
|
||||
});
|
||||
};
|
||||
|
||||
OAUTH3.authz.otp = function (directive, opts) {
|
||||
if (opts.mock) {
|
||||
if (opts.mockError) {
|
||||
return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
|
||||
}
|
||||
return OAUTH3.PromiseA.resolve({data: {uuid: "uuidblah"}});
|
||||
}
|
||||
|
||||
return OAUTH3.request({
|
||||
method: directive.credential_otp.url.method || 'POST'
|
||||
, url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_otp.url)
|
||||
, data: {
|
||||
// TODO replace with signed hosted file
|
||||
client_agree_tos: 'oauth3.org/tos/draft'
|
||||
, client_id: directive.issuer // In this case, the issuer is its own client
|
||||
, client_uri: directive.issuer
|
||||
, request_otp: true
|
||||
, username: opts.email
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
|
||||
var providerUri = directive.issuer;
|
||||
if (opts.mock) {
|
||||
if (opts.mockError) {
|
||||
return OAUTH3.PromiseA.resolve({data: {error_description: "fake error", error: "errorcode", error_uri: "https://blah"}});
|
||||
}
|
||||
|
||||
//core.jwt.encode({header: {alg: 'none'}, payload: {exp: Date.now() / 1000 + 900, sub: 'fakeUserId'}, signature: "fakeSig" })
|
||||
|
||||
return OAUTH3.PromiseA.resolve(OAUTH3.hooks.session.refresh(
|
||||
opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri }
|
||||
|
||||
, { access_token: "eyJhbGciOiJub25lIn0.eyJleHAiOjE0ODc2MTQyMzUuNzg3LCJzdWIiOiJmYWtlVXNlcklkIn0.fakeSig"
|
||||
, refresh_token: "eyJhbGciOiJub25lIn0.eyJleHAiOjE0ODc2MTQyMzUuNzg3LCJzdWIiOiJmYWtlVXNlcklkIn0.fakeSig"
|
||||
, expires_in: "900"
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
//var scope = opts.scope;
|
||||
//var appId = opts.appId;
|
||||
return oauth3.discover(providerUri, opts).then(function (directive) {
|
||||
var prequest = core.urls.resourceOwnerPassword(directive, opts);
|
||||
|
||||
return oauth3.request(prequest).then(function (req) {
|
||||
var data = (req.originalData || req.data);
|
||||
data.provider_uri = providerUri;
|
||||
if (data.error) {
|
||||
return oauth3.PromiseA.reject(oauth3.core.formatError(providerUri, data.error));
|
||||
}
|
||||
return oauth3.hooks.refreshSession(
|
||||
opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri }
|
||||
, data
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) {
|
||||
console.info('redirectWithToken scopes');
|
||||
console.log(scopes);
|
||||
|
||||
scopes.new = scopes.new || [];
|
||||
|
||||
if ('token' === clientParams.response_type) {
|
||||
// get token and redirect client-side
|
||||
return OAUTH3.requests.grants(providerUri, {
|
||||
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) {
|
||||
console.info('generate token results');
|
||||
console.info(results);
|
||||
|
||||
OAUTH3.redirect(clientParams, scopes, results);
|
||||
});
|
||||
}
|
||||
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");
|
||||
}
|
||||
};
|
||||
OAUTH3.requests = {};
|
||||
OAUTH3.requests.accounts = {};
|
||||
OAUTH3.requests.accounts.update = function (directive, session, opts) {
|
||||
var dir = directive.update_account || {
|
||||
method: 'POST'
|
||||
, url: 'https://' + directive.provider_url + '/api/org.oauth3.provider/accounts/:accountId'
|
||||
, bearer: 'Bearer'
|
||||
};
|
||||
var url = dir.url
|
||||
.replace(/:accountId/, opts.accountId)
|
||||
;
|
||||
|
||||
return OAUTH3.request({
|
||||
method: dir.method || 'POST'
|
||||
, url: url
|
||||
, headers: {
|
||||
'Authorization': (dir.bearer || 'Bearer') + ' ' + session.accessToken
|
||||
}
|
||||
, json: {
|
||||
name: opts.name
|
||||
, comment: opts.comment
|
||||
, displayName: opts.displayName
|
||||
, priority: opts.priority
|
||||
}
|
||||
});
|
||||
};
|
||||
OAUTH3.requests.accounts.create = function (directive, session, account) {
|
||||
var dir = directive.create_account || {
|
||||
method: 'POST'
|
||||
, url: 'https://' + directive.issuer + '/api/org.oauth3.provider/accounts'
|
||||
, bearer: 'Bearer'
|
||||
};
|
||||
var data = {
|
||||
// TODO fix the server to just use one scheme
|
||||
// account = { nick, self: { comment, username } }
|
||||
// account = { name, comment, display_name, priority }
|
||||
account: {
|
||||
nick: account.display_name
|
||||
, name: account.name
|
||||
, comment: account.comment
|
||||
, display_name: account.display_name
|
||||
, priority: account.priority
|
||||
, self: {
|
||||
nick: account.display_name
|
||||
, name: account.name
|
||||
, comment: account.comment
|
||||
, display_name: account.display_name
|
||||
, priority: account.priority
|
||||
}
|
||||
}
|
||||
, logins: [
|
||||
{
|
||||
token: session.access_token
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return OAUTH3.request({
|
||||
method: dir.method || 'POST'
|
||||
, url: dir.url
|
||||
, session: session
|
||||
, data: data
|
||||
});
|
||||
};
|
||||
|
||||
}('undefined' !== typeof exports ? exports : window));
|
Loading…
Reference in New Issue