clean up, clean up, everybody everywhere
This commit is contained in:
parent
bb6bcd826e
commit
c2b6a91716
|
@ -3,22 +3,22 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var OAUTH3 = exports.OAUTH3 = {
|
var OAUTH3 = exports.OAUTH3 = {
|
||||||
utils: {
|
clientUri: function (location) {
|
||||||
clientUri: function (location) {
|
return OAUTH3.utils.uri.normalize(location.host + location.pathname);
|
||||||
return OAUTH3.utils.uri.normalize(location.host + location.pathname);
|
}
|
||||||
|
, error: {
|
||||||
|
parse: function (providerUri, params) {
|
||||||
|
var err = new Error(params.error_description || params.error.message || "Unknown error with provider '" + providerUri + "'");
|
||||||
|
err.uri = params.error_uri || params.error.uri;
|
||||||
|
err.code = params.error.code || params.error;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
, _error: {
|
}
|
||||||
parse: function (providerUri, params) {
|
, _base64: {
|
||||||
var err = new Error(params.error_description || params.error.message || "Unknown error with provider '" + providerUri + "'");
|
atob: function (base64) {
|
||||||
err.uri = params.error_uri || params.error.uri;
|
|
||||||
err.code = params.error.code || params.error;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
, atob: function (base64) {
|
|
||||||
return (exports.atob || require('atob'))(base64);
|
return (exports.atob || require('atob'))(base64);
|
||||||
}
|
}
|
||||||
, _urlSafeBase64ToBase64: function (b64) {
|
, decodeUrlSafe: function (b64) {
|
||||||
// URL-safe Base64 to Base64
|
// URL-safe Base64 to Base64
|
||||||
// https://en.wikipedia.org/wiki/Base64
|
// https://en.wikipedia.org/wiki/Base64
|
||||||
// https://gist.github.com/catwell/3046205
|
// https://gist.github.com/catwell/3046205
|
||||||
|
@ -26,105 +26,105 @@
|
||||||
if (2 === mod) { b64 += '=='; }
|
if (2 === mod) { b64 += '=='; }
|
||||||
if (3 === mod) { b64 += '='; }
|
if (3 === mod) { b64 += '='; }
|
||||||
b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
|
b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
|
||||||
return b64;
|
return OAUTH3._base64.atob(b64);
|
||||||
}
|
}
|
||||||
, uri: {
|
}
|
||||||
normalize: function (uri) {
|
, uri: {
|
||||||
if ('string' !== typeof uri) {
|
normalize: function (uri) {
|
||||||
console.error((new Error('stack')).stack);
|
if ('string' !== typeof uri) {
|
||||||
}
|
console.error((new Error('stack')).stack);
|
||||||
// tested with
|
|
||||||
// example.com
|
|
||||||
// example.com/
|
|
||||||
// http://example.com
|
|
||||||
// https://example.com/
|
|
||||||
return uri
|
|
||||||
.replace(/^(https?:\/\/)?/i, '')
|
|
||||||
.replace(/\/?$/, '')
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
// tested with
|
||||||
|
// example.com
|
||||||
|
// example.com/
|
||||||
|
// http://example.com
|
||||||
|
// https://example.com/
|
||||||
|
return uri
|
||||||
|
.replace(/^(https?:\/\/)?/i, '')
|
||||||
|
.replace(/\/?$/, '')
|
||||||
|
;
|
||||||
}
|
}
|
||||||
, url: {
|
}
|
||||||
normalize: function (url) {
|
, url: {
|
||||||
if ('string' !== typeof url) {
|
normalize: function (url) {
|
||||||
console.error((new Error('stack')).stack);
|
if ('string' !== typeof url) {
|
||||||
}
|
console.error((new Error('stack')).stack);
|
||||||
// tested with
|
|
||||||
// example.com
|
|
||||||
// example.com/
|
|
||||||
// http://example.com
|
|
||||||
// https://example.com/
|
|
||||||
return url
|
|
||||||
.replace(/^(https?:\/\/)?/i, 'https://')
|
|
||||||
.replace(/\/?$/, '')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
, resolve: function (base, next) {
|
|
||||||
if (/^https:\/\//i.test(next)) {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
return this.normalize(base) + '/' + this._normalizePath(next);
|
|
||||||
}
|
|
||||||
, _normalizePath: function (path) {
|
|
||||||
return path.replace(/^\//, '').replace(/\/$/, '');
|
|
||||||
}
|
}
|
||||||
|
// tested with
|
||||||
|
// example.com
|
||||||
|
// example.com/
|
||||||
|
// http://example.com
|
||||||
|
// https://example.com/
|
||||||
|
return url
|
||||||
|
.replace(/^(https?:\/\/)?/i, 'https://')
|
||||||
|
.replace(/\/?$/, '')
|
||||||
|
;
|
||||||
}
|
}
|
||||||
, query: {
|
, resolve: function (base, next) {
|
||||||
stringify: function (params) {
|
if (/^https:\/\//i.test(next)) {
|
||||||
var qs = [];
|
return next;
|
||||||
|
}
|
||||||
|
return this.normalize(base) + '/' + this._normalizePath(next);
|
||||||
|
}
|
||||||
|
, _normalizePath: function (path) {
|
||||||
|
return path.replace(/^\//, '').replace(/\/$/, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, query: {
|
||||||
|
stringify: function (params) {
|
||||||
|
var qs = [];
|
||||||
|
|
||||||
Object.keys(params).forEach(function (key) {
|
Object.keys(params).forEach(function (key) {
|
||||||
// TODO nullify instead?
|
// TODO nullify instead?
|
||||||
if ('undefined' === typeof params[key]) {
|
if ('undefined' === typeof params[key]) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if ('scope' === key) {
|
|
||||||
params[key] = OAUTH3.utils.scope.stringify(params[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
qs.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
|
|
||||||
});
|
|
||||||
|
|
||||||
return qs.join('&');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
, scope: {
|
|
||||||
stringify: function (scope) {
|
|
||||||
if (Array.isArray(scope)) {
|
|
||||||
scope = scope.join(' ');
|
|
||||||
}
|
}
|
||||||
return scope;
|
|
||||||
}
|
if ('scope' === key) {
|
||||||
|
params[key] = OAUTH3.utils.scope.stringify(params[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
qs.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
|
||||||
|
});
|
||||||
|
|
||||||
|
return qs.join('&');
|
||||||
}
|
}
|
||||||
, randomState: function () {
|
}
|
||||||
// TODO put in different file for browser vs node
|
, scope: {
|
||||||
try {
|
stringify: function (scope) {
|
||||||
return Array.prototype.slice.call(
|
if (Array.isArray(scope)) {
|
||||||
window.crypto.getRandomValues(new Uint8Array(16))
|
scope = scope.join(' ');
|
||||||
).map(function (ch) { return (ch).toString(16); }).join('');
|
|
||||||
} catch(e) {
|
|
||||||
return OAUTH3.utils._insecureRandomState();
|
|
||||||
}
|
}
|
||||||
|
return scope;
|
||||||
}
|
}
|
||||||
, _insecureRandomState: function () {
|
}
|
||||||
var i;
|
, randomState: function () {
|
||||||
var ch;
|
// TODO put in different file for browser vs node
|
||||||
var str;
|
try {
|
||||||
// TODO use fisher-yates on 0..255 and select [0] 16 times
|
return Array.prototype.slice.call(
|
||||||
// [security] https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d#.5qx0bf95a
|
window.crypto.getRandomValues(new Uint8Array(16))
|
||||||
// https://github.com/v8/v8/blob/b0e4dce6091a8777bda80d962df76525dc6c5ea9/src/js/math.js#L135-L144
|
).map(function (ch) { return (ch).toString(16); }).join('');
|
||||||
// Note: newer versions of v8 do not have this bug, but other engines may still
|
} catch(e) {
|
||||||
console.warn('[security] crypto.getRandomValues() failed, falling back to Math.random()');
|
return OAUTH3.utils._insecureRandomState();
|
||||||
str = '';
|
|
||||||
for (i = 0; i < 32; i += 1) {
|
|
||||||
ch = Math.round(Math.random() * 255).toString(16);
|
|
||||||
if (ch.length < 2) { ch = '0' + ch; }
|
|
||||||
str += ch;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
, _insecureRandomState: function () {
|
||||||
|
var i;
|
||||||
|
var ch;
|
||||||
|
var str;
|
||||||
|
// TODO use fisher-yates on 0..255 and select [0] 16 times
|
||||||
|
// [security] https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d#.5qx0bf95a
|
||||||
|
// https://github.com/v8/v8/blob/b0e4dce6091a8777bda80d962df76525dc6c5ea9/src/js/math.js#L135-L144
|
||||||
|
// Note: newer versions of v8 do not have this bug, but other engines may still
|
||||||
|
console.warn('[security] crypto.getRandomValues() failed, falling back to Math.random()');
|
||||||
|
str = '';
|
||||||
|
for (i = 0; i < 32; i += 1) {
|
||||||
|
ch = Math.round(Math.random() * 255).toString(16);
|
||||||
|
if (ch.length < 2) { ch = '0' + ch; }
|
||||||
|
str += ch;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
, jwt: {
|
, jwt: {
|
||||||
// decode only (no verification)
|
// decode only (no verification)
|
||||||
decode: function (str) {
|
decode: function (str) {
|
||||||
|
@ -135,9 +135,8 @@
|
||||||
// { header: {}, payload: {}, signature: '' }
|
// { header: {}, payload: {}, signature: '' }
|
||||||
var parts = str.split(/\./g);
|
var parts = str.split(/\./g);
|
||||||
var jsons = parts.slice(0, 2).map(function (urlsafe64) {
|
var jsons = parts.slice(0, 2).map(function (urlsafe64) {
|
||||||
var atob = exports.atob || require('atob');
|
var b64 = OAUTH3._base64.decodeUrlSafe(urlsafe64);
|
||||||
var b64 = OAUTH3.utils._urlSafeBase64ToBase64(urlsafe64);
|
return b64;
|
||||||
return atob(b64);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -161,22 +160,6 @@
|
||||||
|
|
||||||
return 'stale';
|
return 'stale';
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
// encode-only (no signature)
|
|
||||||
, encode: function (parts) {
|
|
||||||
parts.header = parts.header || { alg: 'none', typ: 'jwt' };
|
|
||||||
parts.signature = parts.signature || '';
|
|
||||||
|
|
||||||
var btoa = exports.btoa || require('btoa');
|
|
||||||
var result = [
|
|
||||||
core.utils.base64ToUrlSafeBase64(btoa(JSON.stringify(parts.header, null)))
|
|
||||||
, core.utils.base64ToUrlSafeBase64(btoa(JSON.stringify(parts.payload, null)))
|
|
||||||
, parts.signature // should already be url-safe base64
|
|
||||||
].join('.');
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
, urls: {
|
, urls: {
|
||||||
discover: function (providerUri, opts) {
|
discover: function (providerUri, opts) {
|
||||||
|
@ -727,7 +710,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO params should have response_type indicating json, binary, etc
|
// TODO params should have response_type indicating json, binary, etc
|
||||||
var directives = JSON.parse(OAUTH3.utils.atob(OAUTH3.utils._urlSafeBase64ToBase64(params.result || params.directives)));
|
var directives = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.result || params.directives));
|
||||||
// caller will call OAUTH3.hooks.directives._set(providerUri, directives);
|
// caller will call OAUTH3.hooks.directives._set(providerUri, directives);
|
||||||
return directives;
|
return directives;
|
||||||
});
|
});
|
||||||
|
@ -917,7 +900,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
OAUTH3.utils._formatError = OAUTH3.utils._error.parse;
|
OAUTH3.login = OAUTH3.implicitGrant;
|
||||||
|
|
||||||
|
// TODO get rid of these
|
||||||
|
OAUTH3.utils = {
|
||||||
|
clientUri: OAUTH3.clientUri
|
||||||
|
, query: OAUTH3.query
|
||||||
|
, scope: OAUTH3.scope
|
||||||
|
, uri: OAUTH3.uri
|
||||||
|
, url: OAUTH3.url
|
||||||
|
, _error: OAUTH3.error
|
||||||
|
, _formatError: OAUTH3.error
|
||||||
|
, _urlSafeBase64ToBase64: OAUTH3._urlSafeBase64ToBase64
|
||||||
|
, randomState: OAUTH3.randomState
|
||||||
|
, _insecureRandomState: OAUTH3._insecureRandomState
|
||||||
|
};
|
||||||
|
|
||||||
if ('undefined' !== typeof Promise) {
|
if ('undefined' !== typeof Promise) {
|
||||||
OAUTH3.PromiseA = Promise;
|
OAUTH3.PromiseA = Promise;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
/* global Promise */
|
|
||||||
;(function (exports) {
|
;(function (exports) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
OAUTH3.utils.query.parse = function (search) {
|
var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.implicit.js').OAUTH3;
|
||||||
|
|
||||||
|
OAUTH3.query.parse = function (search) {
|
||||||
// parse a query or a hash
|
// parse a query or a hash
|
||||||
if (-1 !== ['#', '?'].indexOf(search[0])) {
|
if (-1 !== ['#', '?'].indexOf(search[0])) {
|
||||||
search = search.substring(1);
|
search = search.substring(1);
|
||||||
|
@ -32,19 +33,19 @@ OAUTH3.utils.query.parse = function (search) {
|
||||||
}
|
}
|
||||||
return argsParsed;
|
return argsParsed;
|
||||||
};
|
};
|
||||||
OAUTH3.utils.scope.parse = function (scope) {
|
OAUTH3.scope.parse = function (scope) {
|
||||||
return (scope||'').split(/[, ]/g);
|
return (scope||'').split(/[, ]/g);
|
||||||
};
|
};
|
||||||
OAUTH3.utils.url.parse = function (url) {
|
OAUTH3.url.parse = function (url) {
|
||||||
// TODO browser
|
// TODO browser
|
||||||
// Node should replace this
|
// Node should replace this
|
||||||
var parser = document.createElement('a');
|
var parser = document.createElement('a');
|
||||||
parser.href = url;
|
parser.href = url;
|
||||||
return parser;
|
return parser;
|
||||||
};
|
};
|
||||||
OAUTH3.utils.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) {
|
OAUTH3.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) {
|
||||||
var src = OAUTH3.utils.url.parse(referrerUrl);
|
var src = OAUTH3.url.parse(referrerUrl);
|
||||||
var dst = OAUTH3.utils.url.parse(redirectUrl);
|
var dst = OAUTH3.url.parse(redirectUrl);
|
||||||
|
|
||||||
// TODO how should we handle subdomains?
|
// TODO how should we handle subdomains?
|
||||||
// It should be safe for api.example.com to redirect to example.com
|
// It should be safe for api.example.com to redirect to example.com
|
||||||
|
@ -55,11 +56,11 @@ OAUTH3.utils.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) {
|
||||||
// api.example.com.evil.com SHOULD NOT match example.com
|
// api.example.com.evil.com SHOULD NOT match example.com
|
||||||
return dst.hostname === src.hostname;
|
return dst.hostname === src.hostname;
|
||||||
};
|
};
|
||||||
OAUTH3.utils.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");
|
||||||
|
|
||||||
var clientUrl = OAUTH3.utils.url.normalize(client.url);
|
var clientUrl = OAUTH3.url.normalize(client.url);
|
||||||
var redirectUrl = OAUTH3.utils.url.normalize(query.redirect_uri);
|
var redirectUrl = OAUTH3.url.normalize(query.redirect_uri);
|
||||||
|
|
||||||
// General rule:
|
// General rule:
|
||||||
// I can callback to a shorter domain (fewer subs) or a shorter path (on the same domain)
|
// I can callback to a shorter domain (fewer subs) or a shorter path (on the same domain)
|
||||||
|
@ -67,13 +68,13 @@ OAUTH3.utils.url.checkRedirect = function (client, query) {
|
||||||
|
|
||||||
|
|
||||||
// We can callback to an explicitly listed domain (TODO and path)
|
// We can callback to an explicitly listed domain (TODO and path)
|
||||||
if (OAUTH3.utils.url._isRedirectHostSafe(clientUrl, redirectUrl)) {
|
if (OAUTH3.url._isRedirectHostSafe(clientUrl, redirectUrl)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
OAUTH3.utils.url.redirect = function (clientParams, grants, tokenOrError) {
|
OAUTH3.url.redirect = function (clientParams, grants, tokenOrError) {
|
||||||
// TODO OAUTH3.redirect(clientParams, grants, tokenOrError)
|
// TODO OAUTH3.redirect(clientParams, grants, tokenOrError)
|
||||||
// TODO check redirect safeness right here with grants.client.urls
|
// TODO check redirect safeness right here with grants.client.urls
|
||||||
// TODO check for '#' and '?'. If none, issue warning and use '?' (for backwards compat)
|
// TODO check for '#' and '?'. If none, issue warning and use '?' (for backwards compat)
|
||||||
|
@ -93,7 +94,7 @@ OAUTH3.utils.url.redirect = function (clientParams, grants, tokenOrError) {
|
||||||
authz.error_description = tokenOrError.error.message || tokenOrError.error_description;
|
authz.error_description = tokenOrError.error.message || tokenOrError.error_description;
|
||||||
authz.error_uri = tokenOrError.error.uri || tokenOrError.error_uri;
|
authz.error_uri = tokenOrError.error.uri || tokenOrError.error_uri;
|
||||||
}
|
}
|
||||||
var redirect = clientParams.redirect_uri + '#' + window.OAUTH3.utils.query.stringify(authz);
|
var redirect = clientParams.redirect_uri + '#' + window.OAUTH3.query.stringify(authz);
|
||||||
|
|
||||||
if (clientParams.debug) {
|
if (clientParams.debug) {
|
||||||
console.info('final redirect_uri:', redirect);
|
console.info('final redirect_uri:', redirect);
|
||||||
|
@ -164,11 +165,11 @@ OAUTH3.urls.resourceOwnerPassword = function (directive, opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope) {
|
if (scope) {
|
||||||
params.scope = OAUTH3.utils.scope.stringify(scope);
|
params.scope = OAUTH3.scope.stringify(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('GET' === args.method.toUpperCase()) {
|
if ('GET' === args.method.toUpperCase()) {
|
||||||
uri += '?' + OAUTH3.utils.query.stringify(params);
|
uri += '?' + OAUTH3.query.stringify(params);
|
||||||
} else {
|
} else {
|
||||||
body = params;
|
body = params;
|
||||||
}
|
}
|
||||||
|
@ -207,8 +208,8 @@ OAUTH3.urls.grants = function (directive, opts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = OAUTH3.utils.url.resolve(directive.issuer, directive.grants.url)
|
var url = OAUTH3.url.resolve(directive.issuer, directive.grants.url)
|
||||||
.replace(/(:azp|:client_id)/g, OAUTH3.utils.uri.normalize(opts.client_id || opts.client_uri))
|
.replace(/(:azp|:client_id)/g, OAUTH3.uri.normalize(opts.client_id || opts.client_uri))
|
||||||
.replace(/(:sub|:account_id)/g, opts.session.token.sub)
|
.replace(/(:sub|:account_id)/g, opts.session.token.sub)
|
||||||
;
|
;
|
||||||
var data = {
|
var data = {
|
||||||
|
@ -222,7 +223,7 @@ OAUTH3.urls.grants = function (directive, opts) {
|
||||||
var body;
|
var body;
|
||||||
|
|
||||||
if ('GET' === opts.method) {
|
if ('GET' === opts.method) {
|
||||||
url += '?' + OAUTH3.utils.query.stringify(data);
|
url += '?' + OAUTH3.query.stringify(data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
body = data;
|
body = data;
|
||||||
|
@ -237,9 +238,7 @@ OAUTH3.urls.grants = function (directive, opts) {
|
||||||
};
|
};
|
||||||
|
|
||||||
OAUTH3.authn = {};
|
OAUTH3.authn = {};
|
||||||
|
OAUTH3.authn.loginMeta = OAUTH3.authz.loginMeta = function (directive, opts) {
|
||||||
OAUTH3.authz = {};
|
|
||||||
OAUTH3.authz.loginMeta = function (directive, opts) {
|
|
||||||
if (opts.mock) {
|
if (opts.mock) {
|
||||||
if (opts.mockError) {
|
if (opts.mockError) {
|
||||||
return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
|
return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
|
||||||
|
@ -250,13 +249,12 @@ OAUTH3.authz.loginMeta = function (directive, opts) {
|
||||||
return OAUTH3.request({
|
return OAUTH3.request({
|
||||||
method: directive.credential_meta.method || 'GET'
|
method: directive.credential_meta.method || 'GET'
|
||||||
// TODO lint urls
|
// TODO lint urls
|
||||||
, url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_meta.url)
|
, url: OAUTH3.url.resolve(directive.issuer, directive.credential_meta.url)
|
||||||
.replace(':type', 'email')
|
.replace(':type', 'email')
|
||||||
.replace(':id', opts.email)
|
.replace(':id', opts.email)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
OAUTH3.authn.otp = OAUTH3.authz.otp = function (directive, opts) {
|
||||||
OAUTH3.authz.otp = function (directive, opts) {
|
|
||||||
if (opts.mock) {
|
if (opts.mock) {
|
||||||
if (opts.mockError) {
|
if (opts.mockError) {
|
||||||
return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
|
return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
|
||||||
|
@ -266,7 +264,7 @@ OAUTH3.authz.otp = function (directive, opts) {
|
||||||
|
|
||||||
return OAUTH3.request({
|
return OAUTH3.request({
|
||||||
method: directive.credential_otp.url.method || 'POST'
|
method: directive.credential_otp.url.method || 'POST'
|
||||||
, url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_otp.url)
|
, url: OAUTH3.url.resolve(directive.issuer, directive.credential_otp.url)
|
||||||
, data: {
|
, data: {
|
||||||
// TODO replace with signed hosted file
|
// TODO replace with signed hosted file
|
||||||
client_agree_tos: 'oauth3.org/tos/draft'
|
client_agree_tos: 'oauth3.org/tos/draft'
|
||||||
|
@ -277,8 +275,7 @@ OAUTH3.authz.otp = function (directive, opts) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
OAUTH3.authn.resourceOwnerPassword = OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
|
||||||
OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
|
|
||||||
console.log('ginger bread man');
|
console.log('ginger bread man');
|
||||||
var providerUri = directive.issuer;
|
var providerUri = directive.issuer;
|
||||||
|
|
||||||
|
@ -291,7 +288,7 @@ OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
|
||||||
var data = req.data;
|
var data = req.data;
|
||||||
data.provider_uri = providerUri;
|
data.provider_uri = providerUri;
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
return oauth3.PromiseA.reject(OAUTH3.utils._error.parse(providerUri, data.error));
|
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, data.error));
|
||||||
}
|
}
|
||||||
return OAUTH3.hooks.refreshSession(
|
return OAUTH3.hooks.refreshSession(
|
||||||
opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri }
|
opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri }
|
||||||
|
@ -300,6 +297,8 @@ OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OAUTH3.authz = {};
|
||||||
OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
|
OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
|
||||||
if (clientParams.mock) {
|
if (clientParams.mock) {
|
||||||
return {
|
return {
|
||||||
|
@ -312,7 +311,7 @@ OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
|
||||||
|
|
||||||
// OAuth3.requests.grants(providerUri, {}); // return list of grants
|
// OAuth3.requests.grants(providerUri, {}); // return list of grants
|
||||||
// OAuth3.checkGrants(providerUri, {}); //
|
// OAuth3.checkGrants(providerUri, {}); //
|
||||||
var clientUri = OAUTH3.utils.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 || '';
|
||||||
var clientObj = clientParams;
|
var clientObj = clientParams;
|
||||||
|
|
||||||
|
@ -348,14 +347,14 @@ OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
|
||||||
// it doesn't matter who the referrer is as long as the destination
|
// it doesn't matter who the referrer is as long as the destination
|
||||||
// is an authorized destination for the client in question
|
// is an authorized destination for the client in question
|
||||||
// (though it may not hurt to pass the referrer's info on to the client)
|
// (though it may not hurt to pass the referrer's info on to the client)
|
||||||
if (!OAUTH3.utils.url.checkRedirect(grantResults.client, clientObj)) {
|
if (!OAUTH3.url.checkRedirect(grantResults.client, clientObj)) {
|
||||||
callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK'
|
callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK'
|
||||||
+ '?redirect_uri=' + clientObj.redirect_uri
|
+ '?redirect_uri=' + clientObj.redirect_uri
|
||||||
+ '&allowed_urls=' + grantResults.client.url
|
+ '&allowed_urls=' + grantResults.client.url
|
||||||
+ '&client_id=' + clientUri
|
+ '&client_id=' + clientUri
|
||||||
+ '&referrer_uri=' + OAUTH3.utils.uri.normalize(window.document.referrer)
|
+ '&referrer_uri=' + OAUTH3.uri.normalize(window.document.referrer)
|
||||||
;
|
;
|
||||||
if (opts.debug) {
|
if (clientParams.debug) {
|
||||||
console.log('grantResults Redirect Attack');
|
console.log('grantResults Redirect Attack');
|
||||||
console.log(grantResults);
|
console.log(grantResults);
|
||||||
console.log(clientObj);
|
console.log(clientObj);
|
||||||
|
@ -424,21 +423,21 @@ OAUTH3.authz.grants = function (providerUri, opts) {
|
||||||
var grants = grantsResult.originalData || grantsResult.data;
|
var grants = grantsResult.originalData || grantsResult.data;
|
||||||
// TODO
|
// TODO
|
||||||
if (grants.error) {
|
if (grants.error) {
|
||||||
return oauth3.PromiseA.reject(oauth3.utils._formatError(grants.error));
|
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(grants.error));
|
||||||
}
|
}
|
||||||
|
|
||||||
console.warn('requests.grants', grants);
|
console.warn('requests.grants', grants);
|
||||||
|
|
||||||
oauth3.hooks.setGrants(opts.client_id + '-client', grants.client);
|
OAUTH3.hooks.grants.set(opts.client_id + '-client', grants.client);
|
||||||
grants.grants.forEach(function (grant) {
|
grants.grants.forEach(function (grant) {
|
||||||
var clientId = grant.client_id || grant.oauth_client_id || grant.oauthClientId;
|
var clientId = grant.client_id || grant.oauth_client_id || grant.oauthClientId;
|
||||||
// TODO should save as an array
|
// TODO should save as an array
|
||||||
oauth3.hooks.setGrants(clientId, [ grant ]);
|
OAUTH3.hooks.grants.set(clientId, [ grant ]);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
client: oauth3.hooks.getGrants(opts.client_id + '-client')
|
client: OAUTH3.hooks.grants.get(opts.client_id + '-client')
|
||||||
, grants: oauth3.hooks.getGrants(opts.client_id) || []
|
, grants: OAUTH3.hooks.grants.get(opts.client_id) || []
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -464,7 +463,7 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s
|
||||||
console.info('generate token results');
|
console.info('generate token results');
|
||||||
console.info(results);
|
console.info(results);
|
||||||
|
|
||||||
OAUTH3.utils.url.redirect(clientParams, scopes, results);
|
OAUTH3.url.redirect(clientParams, scopes, results);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if ('code' === clientParams.response_type) {
|
else if ('code' === clientParams.response_type) {
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
/* global Promise */
|
|
||||||
;(function (exports) {
|
;(function (exports) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
OAUTH3.utils._base64ToUrlSafeBase64 = function (b64) {
|
var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.implicit.js').OAUTH3;
|
||||||
|
|
||||||
|
OAUTH3._base64.btoa = exports.btoa || require('btoa');
|
||||||
|
OAUTH3._base64.encodeUrlSafe = function (b64) {
|
||||||
// Base64 to URL-safe Base64
|
// Base64 to URL-safe Base64
|
||||||
b64 = b64.replace(/\+/g, '-').replace(/\//g, '_');
|
b64 = b64.replace(/\+/g, '-').replace(/\//g, '_');
|
||||||
b64 = b64.replace(/=+/g, '');
|
b64 = b64.replace(/=+/g, '');
|
||||||
return b64;
|
return OAUTH3._base64.btoa(b64);
|
||||||
};
|
};
|
||||||
|
|
||||||
OAUTH3.jwt.encode = function (parts) {
|
OAUTH3.jwt.encode = function (parts) {
|
||||||
parts.header = parts.header || { alg: 'none', typ: 'jwt' };
|
parts.header = parts.header || { alg: 'none', typ: 'jwt' };
|
||||||
parts.signature = parts.signature || '';
|
parts.signature = parts.signature || '';
|
||||||
|
|
||||||
var btoa = exports.btoa || require('btoa');
|
|
||||||
var result = [
|
var result = [
|
||||||
OAUTH3.utils._base64ToUrlSafeBase64(btoa(JSON.stringify(parts.header, null)))
|
OAUTH3._base64.encodeUrlSafe(JSON.stringify(parts.header, null))
|
||||||
, OAUTH3.utils._base64ToUrlSafeBase64(btoa(JSON.stringify(parts.payload, null)))
|
, OAUTH3._base64.encodeUrlSafe(JSON.stringify(parts.payload, null))
|
||||||
, parts.signature // should already be url-safe base64
|
, parts.signature // should already be url-safe base64
|
||||||
].join('.');
|
].join('.');
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue