merge master to v1
This commit is contained in:
commit
9962c72e60
|
@ -38,10 +38,10 @@
|
||||||
|
|
||||||
// Modified from http://stackoverflow.com/a/7826782
|
// Modified from http://stackoverflow.com/a/7826782
|
||||||
core.queryparse = function (search) {
|
core.queryparse = 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
var args = search.split('&');
|
var args = search.split('&');
|
||||||
var argsParsed = {};
|
var argsParsed = {};
|
||||||
|
@ -53,15 +53,15 @@
|
||||||
|
|
||||||
if (-1 === arg.indexOf('=')) {
|
if (-1 === arg.indexOf('=')) {
|
||||||
|
|
||||||
argsParsed[decodeURIComponent(arg).trim()] = true;
|
argsParsed[decodeURIComponent(arg).trim()] = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
kvp = arg.split('=');
|
kvp = arg.split('=');
|
||||||
key = decodeURIComponent(kvp[0]).trim();
|
key = decodeURIComponent(kvp[0]).trim();
|
||||||
value = decodeURIComponent(kvp[1]).trim();
|
value = decodeURIComponent(kvp[1]).trim();
|
||||||
argsParsed[key] = value;
|
argsParsed[key] = value;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,58 @@
|
||||||
return providerUri + '/.well-known/oauth3/directives.html#' + core.querystringify(params);
|
return providerUri + '/.well-known/oauth3/directives.html#' + core.querystringify(params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// these might not really belong in core... not sure
|
||||||
|
// there should be node.js- and browser-specific versions probably
|
||||||
|
core.utils = {
|
||||||
|
urlSafeBase64ToBase64: function (b64) {
|
||||||
|
// URL-safe Base64 to Base64
|
||||||
|
b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
|
||||||
|
b64 = (b64 + '===').slice(0, b64.length + (b64.length % 4));
|
||||||
|
return b64;
|
||||||
|
}
|
||||||
|
, base64ToUrlSafeBase64: function (b64) {
|
||||||
|
// Base64 to URL-safe Base64
|
||||||
|
b64 = b64.replace(/\+/g, '-').replace(/\//g, '_');
|
||||||
|
b64 = b64.replace(/=+/g, '');
|
||||||
|
return b64;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
core.jwt = {
|
||||||
|
// decode only (no verification)
|
||||||
|
decode: function (str) {
|
||||||
|
|
||||||
|
// 'abc.qrs.xyz'
|
||||||
|
// [ 'abc', 'qrs', 'xyz' ]
|
||||||
|
// [ {}, {}, 'foo' ]
|
||||||
|
// { header: {}, payload: {}, signature: }
|
||||||
|
var parts = str.split(/\./g);
|
||||||
|
var jsons = parts.slice(0, 2).map(function (b64) {
|
||||||
|
var atob = exports.atob || require('atob');
|
||||||
|
return atob(core.utils.urlSafeBase64ToBase64(b64));
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
header: JSON.parse(jsons[0])
|
||||||
|
, payload: JSON.parse(jsons[1])
|
||||||
|
, signature: parts[2] // should remain url-safe base64
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
core.authorizationCode = function (/*directive, scope, redirectUri, clientId*/) {
|
core.authorizationCode = function (/*directive, scope, redirectUri, clientId*/) {
|
||||||
//
|
//
|
||||||
// Example Authorization Code Request
|
// Example Authorization Code Request
|
||||||
|
@ -191,7 +243,7 @@
|
||||||
|
|
||||||
var redirectUri = opts.redirectUri;
|
var redirectUri = opts.redirectUri;
|
||||||
var scope = opts.scope || directive.authn_scope;
|
var scope = opts.scope || directive.authn_scope;
|
||||||
var clientId = opts.appId;
|
var clientId = opts.appId || opts.clientId;
|
||||||
var args = directive[type];
|
var args = directive[type];
|
||||||
var uri = args.url;
|
var uri = args.url;
|
||||||
var state = Math.random().toString().replace(/^0\./, '');
|
var state = Math.random().toString().replace(/^0\./, '');
|
||||||
|
@ -297,7 +349,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
var scope = opts.scope || directive.authn_scope;
|
var scope = opts.scope || directive.authn_scope;
|
||||||
var clientId = opts.appId;
|
var clientId = opts.appId || opts.clientId;
|
||||||
var clientAgreeTos = opts.clientAgreeTos;
|
var clientAgreeTos = opts.clientAgreeTos;
|
||||||
var clientUri = opts.clientUri;
|
var clientUri = opts.clientUri;
|
||||||
var args = directive[type];
|
var args = directive[type];
|
||||||
|
|
104
oauth3.js
104
oauth3.js
|
@ -81,14 +81,95 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
oauth3.provideRequest = function (request, opts) {
|
oauth3._recaseRequest = function (recase, req) {
|
||||||
|
// convert JavaScript camelCase to oauth3/ruby snake_case
|
||||||
|
if (req.data && 'object' === typeof req.data) {
|
||||||
|
req.originalData = req.data;
|
||||||
|
req.data = recase.snakeCopy(req.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return req;
|
||||||
|
};
|
||||||
|
oauth3._recaseResponse = function (recase, resp) {
|
||||||
|
// convert oauth3/ruby snake_case to JavaScript camelCase
|
||||||
|
if (resp.data && 'object' === typeof resp.data) {
|
||||||
|
resp.originalData = resp.data;
|
||||||
|
resp.data = recase.camelCopy(resp.data);
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
};
|
||||||
|
oauth3._lintRequest = function (preq, opts) {
|
||||||
|
var providerUri;
|
||||||
|
var fresh;
|
||||||
|
|
||||||
|
console.log('[os] request meta opts', opts);
|
||||||
|
|
||||||
|
// check that the JWT is not expired
|
||||||
|
// TODO check that this request applies to the aud and azp
|
||||||
|
if (!(preq.session && preq.session.accessToken)) {
|
||||||
|
console.log('[os] no session/accessTokenData');
|
||||||
|
return oauth3.PromiseA.resolve(preq);
|
||||||
|
}
|
||||||
|
|
||||||
|
preq.headers = preq.headers || {};
|
||||||
|
preq.headers.Authorization = 'Bearer ' + preq.session.accessToken;
|
||||||
|
|
||||||
|
if (!preq.session._accessTokenData) {
|
||||||
|
console.log('[os] no _accessTokenData');
|
||||||
|
preq.session._accessTokenData = core.jwt.decode(preq.session.accessToken).payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preq.url.match(preq.session._accessTokenData.aud)) {
|
||||||
|
console.log("[os] doesn't match audience", preq.session._accessTokenData.aud);
|
||||||
|
return oauth3.PromiseA.resolve(preq);
|
||||||
|
}
|
||||||
|
|
||||||
|
fresh = (Date.now() / 1000) >= (parseInt(preq.session._accessTokenData.exp) || 0);
|
||||||
|
if (!fresh) {
|
||||||
|
console.log("[os] isn't fresh", preq.session._accessTokenData.exp);
|
||||||
|
return oauth3.PromiseA.resolve(preq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preq.session.refreshToken) {
|
||||||
|
console.log("[os] cann't refresh", preq.session);
|
||||||
|
return oauth3.PromiseA.resolve(preq);
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.refreshToken = preq.session.refreshToken;
|
||||||
|
console.log('[oauth3.js] refreshToken attempt');
|
||||||
|
|
||||||
|
// TODO include directive?
|
||||||
|
providerUri = preq.session.providerUri || preq.session._accessTokenData.iss;
|
||||||
|
//opts.
|
||||||
|
return oauth3.refreshToken(providerUri, opts).then(function (res) {
|
||||||
|
console.log('[oauth3.js] refreshToken result:', res);
|
||||||
|
|
||||||
|
if (!res.data.accessToken) {
|
||||||
|
return preq;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO fire session update event
|
||||||
|
res.data.providerUri = preq.session.providerUri;
|
||||||
|
preq.session = res.data;
|
||||||
|
preq.headers.Authorization = 'Bearer ' + preq.session.accessToken;
|
||||||
|
return preq;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
oauth3.provideRequest = function (rawRequest, opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
var Recase = exports.Recase || require('recase');
|
var Recase = exports.Recase || require('recase');
|
||||||
// TODO make insensitive to providing exceptions
|
// TODO make insensitive to providing exceptions
|
||||||
var recase = Recase.create({ exceptions: {} });
|
var recase = Recase.create({ exceptions: {} });
|
||||||
|
|
||||||
|
function lintAndRequest(preq) {
|
||||||
|
return oauth3._lintRequest(preq, opts).then(function (preq) {
|
||||||
|
return rawRequest(preq);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (opts.rawCase) {
|
if (opts.rawCase) {
|
||||||
oauth3.request = request;
|
oauth3.request = lintAndRequest;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,23 +179,12 @@
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
if (opts.rawCase) {
|
if (opts.rawCase) {
|
||||||
return request(req);
|
return lintAndRequest(req, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert JavaScript camelCase to oauth3 snake_case
|
req = oauth3._recaseRequest(recase, req);
|
||||||
if (req.data && 'object' === typeof req.data) {
|
return lintAndRequest(req, opts).then(function (res) {
|
||||||
req.originalData = req.data;
|
return oauth3._recaseResponse(recase, res);
|
||||||
req.data = recase.snakeCopy(req.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log('[F] [oauth3 req.url]', req.url);
|
|
||||||
return request(req).then(function (resp) {
|
|
||||||
// convert oauth3 snake_case to JavaScript camelCase
|
|
||||||
if (resp.data && 'object' === typeof resp.data) {
|
|
||||||
resp.originalData = resp.data;
|
|
||||||
resp.data = recase.camelCopy(resp.data);
|
|
||||||
}
|
|
||||||
return resp;
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue