Compare commits

..

40 Commits

Author SHA1 Message Date
AJ ONeal 291bfd6a79 retrieve signing key 2018-07-06 08:12:13 +00:00
AJ ONeal def91fb60d fix url for validating token 2018-07-06 07:51:39 +00:00
AJ ONeal 738573a79c typo fix _providerUri => providerUri 2018-07-06 05:56:01 +00:00
AJ ONeal 58f245f90c typo auth => oauth3 2018-07-06 05:48:25 +00:00
AJ ONeal c5735f402c add symlinks for back-compat 2018-07-06 04:55:52 +00:00
AJ ONeal db43f09ce2 .well-known => _apis 2018-07-06 04:55:34 +00:00
AJ ONeal e7ffe06d9d .well-known => _apis 2018-07-06 00:45:58 +00:00
AJ ONeal 3d9d7b00d7 update links 2018-04-23 22:10:10 +00:00
AJ ONeal cf5c106f64 correct logout 2017-11-29 05:30:22 +00:00
AJ ONeal f4b3dbd495 Merge branch 'v1.2-next' of git.oauth3.org:OAuth3/oauth3.js into v1.2-next 2017-11-29 05:13:53 +00:00
AJ ONeal 6f6d07e670 add navigator.auth api 2017-11-29 05:13:49 +00:00
AJ ONeal 23db17a31e accept scope as array, use scope as delimited string 2017-11-29 04:17:43 +00:00
AJ ONeal d87645d135 oauth3_authn -> authn@oauth3.org 2017-11-29 02:12:39 +00:00
AJ ONeal 989dbfb150 Merge branch 'v1.2-next' of git.oauth3.org:OAuth3/oauth3.js into v1.2-next 2017-11-29 02:09:39 +00:00
AJ ONeal 36fe8e2a80 default scope changed to authn@oauth3.org 2017-11-29 02:09:19 +00:00
AJ ONeal ff6d9665e2 default broker is new.oauth3.org 2017-11-29 02:09:00 +00:00
AJ ONeal 2587d03860 fix trailing slash 2017-11-28 02:26:31 +00:00
AJ ONeal f14f42404e Merge branch 'v1.2' into v1.2-next 2017-11-28 01:25:00 +00:00
AJ ONeal 0aa85baf6d Merge branch 'v1.2-next' of git.oauth3.org:OAuth3/oauth3.js into v1.2-next 2017-11-25 09:11:01 +00:00
AJ ONeal 39c0c775ed get issuer via rpc 2017-11-25 09:10:54 +00:00
AJ ONeal 2bfc752ea1 Merge branch 'rpc' into v1.2-next 2017-11-25 08:59:15 +00:00
AJ ONeal d7c4d0ff13 demagicstringify 2017-11-25 08:58:58 +00:00
AJ ONeal 18170e94f4 Merge remote-tracking branch 'origin/rpc' into v1.2-next 2017-11-25 08:39:37 +00:00
AJ ONeal ff76a4116e Merge branch 'rpc' into v1.2-next 2017-11-25 08:32:39 +00:00
AJ ONeal c9c45ebe4e fix syntax error 2017-11-25 08:32:13 +00:00
AJ ONeal d84b7bd6ea Merge branch 'rpc' into v1.2-next 2017-11-25 08:28:46 +00:00
AJ ONeal e78999d4a1 default broker is self 2017-11-25 08:28:27 +00:00
AJ ONeal 687391e56b Merge branch 'rpc' into v1.2-next 2017-11-25 08:21:45 +00:00
AJ ONeal 6a131f6650 add broker 2017-11-25 08:21:17 +00:00
AJ ONeal 9f48a44958 merge rpc 2017-11-25 08:15:44 +00:00
AJ ONeal be9e8852b8 WIP respond to RPC 2017-11-25 08:09:57 +00:00
AJ ONeal d015e66f17 WIP request rpc 2017-11-25 07:46:37 +00:00
AJ ONeal 77c64df163 Merge branch 'discover-pixel' into v1.2-next 2017-11-24 01:28:23 +00:00
AJ ONeal e27af15485 Merge branch 'no-timeout' into v1.2-next 2017-11-24 01:00:20 +00:00
AJ ONeal c59e23d114 Merge branch 'no-timeout' of OAuth3/oauth3.js into v1.2 2017-11-24 01:00:06 +00:00
AJ ONeal 9298776620 ws 2017-11-24 00:50:26 +00:00
AJ ONeal 2c0b757c13 no timeout 2017-11-24 00:49:35 +00:00
John Shaver bc82bb6f1b Moved scopes to well-known dir. 2017-11-20 08:59:23 -08:00
John Shaver d13728dd3d Initial scope discover. Needs testing and renaming. 2017-11-20 08:26:52 -08:00
John Shaver 1e459ce186 WIP started trying some things with scope discovery. 2017-11-15 21:39:10 -08:00
14 changed files with 433 additions and 156 deletions

View File

@ -1 +1 @@
well-known
_apis

View File

@ -5,7 +5,7 @@ oauth3.js
| [issuer.html](https://git.oauth3.org/OAuth3/issuer.html)
| [issuer.rest.walnut.js](https://git.oauth3.org/OAuth3/issuer.rest.walnut.js)
| [issuer.srv](https://git.oauth3.org/OAuth3/issuer.srv)
| Sponsored by [Daplie](https://daplie.com)
| Sponsored by [ppl](https://ppl.family)
The world's smallest, fastest, and most secure OAuth3 (and OAuth2) JavaScript implementation
(Yes! works in browsers and node.js with no extra dependencies or bloat and no hacks!)
@ -29,8 +29,7 @@ If you have no idea what you're doing
4. Download [oauth3.js-v1.zip](https://git.oauth3.org/OAuth3/oauth3.js/repository/archive.zip?ref=v1)
5. Double-click to unzip the folder.
6. Copy the file `oauth3.core.js` into the folder `example.com/assets/oauth3.org/`
7. Copy the folder `well-known` into the folder `example.com/`
8. Rename the folder `well-known` to `.well-known` (when you do this, it become invisible, that's okay)
7. Copy the folder `_apis` into the folder `example.com/`
9. Add `<script src="assets/oauth3.org/oauth3.core.js"></script>` to your `index.html`
9. Add `<script src="app.js"></script>` to your `index.html`
10. Create files in `example.com` called `app.js` and `index.html` and put this in it:
@ -59,13 +58,13 @@ If you have no idea what you're doing
`app.js`:
```js
var OAUTH3 = window.OAUTH3;
var auth = OAUTH3.create(window.location); // use window.location to set Client URI (your app's id)
var oauth3 = OAUTH3.create(window.location); // use window.location to set Client URI (your app's id)
// this is any OAuth3-compatible provider, such as oauth3.org
// in v1.1.0 we'll add backwards compatibility for facebook.com, google.com, etc
//
function onChangeProvider(_providerUri) {
function onChangeProvider(providerUri) {
// example https://oauth3.org
return oauth3.setIdentityProvider(providerUri);
}
@ -87,11 +86,13 @@ function onClickLogin() {
console.info('Secure PPID (aka subject):', session.token.sub);
return oauth3.request({
url: 'https://oauth3.org/api/issuer@oauth3.org/inspect'
url: 'https://api.oauth3.org/api/issuer@oauth3.org/jwks/:sub/:kid'
.replace(/:sub/g, session.token.sub)
.replace(/:kid/g, session.token.kid || session.token.iss)
, session: session
}).then(function (resp) {
console.info("Inspect Token:");
console.info("Signing Public Key JWK:");
console.log(resp.data);
});
@ -144,13 +145,13 @@ it might look like this:
example.com
├── .well-known (hidden)
│   └── oauth3
├── _apis
│   └── oauth3.org
│   ├── callback.html
│   ├── directives.json
│   └── index.html
├── assets
│   └── org.oauth3
│   └── oauth3.org
│   └── oauth3.core.js
@ -171,17 +172,17 @@ Installation (if you know what you're doing)
pushd /path/to/your/web/app
# clone the project as assets/org.oauth3
# clone the project as assets/oauth3.org
mkdir -p assets
git clone git@git.daplie.com:OAuth3/oauth3.js.git assets/org.oauth3
pushd assets/org.oauth3
git clone git@git.oauth3.org:OAuth3/oauth3.js.git assets/oauth3.org
pushd assets/oauth3.org
git checkout v1
popd
# symlink `.well-known/oauth3` to `assets/org.oauth3/.well-known/oauth3`
mkdir -p .well-known
ln -sf ../assets/org.oauth3/.well-known/oauth3 .well-known/oauth3
# symlink `_apis/oauth3.org` to `assets/oauth3.org/_apis/oauth3.org`
mkdir -p _apis
ln -sf ../assets/oauth3.org/_apis/oauth3 _apis/oauth3.org
```
**Advanced Installation with `bower`**
@ -191,17 +192,17 @@ ln -sf ../assets/org.oauth3/.well-known/oauth3 .well-known/oauth3
bower install oauth3
# create a `.well-known` folder and an `assets` folder
mkdir -p .well-known assets
# create a `_apis` folder and an `assets` folder
mkdir -p _apis assets
# symlink `.well-known/oauth3` to `bower_components/oauth3/.well-known/oauth3`
ln -sf ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3
# symlink `_apis/oauth3.org` to `bower_components/oauth3.org/_apis/oauth3.org`
ln -sf ../bower_components/oauth3.org/_apis/oauth3.org _apis/oauth3.org
# symlink `assets/org.oauth3` to `bower_components/oauth3`
ln -sf ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3
ln -sf ../bower_components/oauth3 assets/org.oauth3
# symlink `assets/oauth3.org` to `bower_components/oauth3.org`
ln -sf ../bower_components/oauth3.org/_apis/oauth3.org _apis/oauth3.org
ln -sf ../bower_components/oauth3.org assets/oauth3.org
```
Usage
@ -210,7 +211,7 @@ Usage
Update your HTML to include the the following script tag:
```html
<script src="assets/org.oauth3/oauth3.core.js"></script>
<script src="assets/oauth3.org/oauth3.core.js"></script>
```
You can create a very simple demo application like this:
@ -289,7 +290,7 @@ You're all set. Nothing else is needed.
We've created an `Oauth3` service just for you:
```html
<script src="assets/org.oauth3/oauth3.ng.js"></script>
<script src="assets/oauth3.org/oauth3.ng.js"></script>
```
```js
@ -322,7 +323,7 @@ promise = oauth3.init(opts); // set and fetch your own si
// promises your site's config // opts = { location, session, issuer, audience }
promise = oauth3.setIdentityProvider(url); // changes the Identity Provider URI (the site you're logging into),
// promises the provider's config // gets the config for that site (from their .well-known/oauth3),
// promises the provider's config // gets the config for that site (from their _apis/oauth3.org),
// and caches it in internal state as the default
promise = oauth3.setResourceProvider(url); // changes the Resource Provider URI (the site you're getting stuff from)
@ -339,12 +340,11 @@ promise = oauth3.request({ url, method, data }); // make an (authorized) arbi
// (contacts, photos, whatever)
promise = oauth3.api(apiname, opts); // make an (authorized) well-known api call to an audience
// See https://labs.daplie.com/docs/ for API schemas
// Ex: oauth3.api('dns.list', { sld: 'daplie', tld: 'com' });
// Ex: oauth3.api('dns.list', { sld: 'example', tld: 'com' });
// TODO
api = await oauth3.package(audience, schemaname); // make an (authorized) well-known api call to an audience
// Ex: api = await oauth3.package('domains.daplie.com', 'dns@oauth3.org');
// Ex: api = await oauth3.package('domains.example.com', 'dns@oauth3.org');
// api.list({ sld: 'mydomain', tld: 'com' });
@ -353,6 +353,10 @@ promise = oauth3.logout(); // opens logout window for t
oauth3.session(); // returns the current session, if any
```
<!-- TODO
Track down the old https://labs.daplie.com/docs/ for API schemas
--
Real API
----------
@ -494,5 +498,5 @@ can be very ugly and confusing and we definitely need to allow relative paths.
A potential work-around would be to assume all paths are relative (eliminate #4 instead)
and have the path always key off of the base URL - if oauth3 directives are to be found at
https://example.com/username/.well-known/oauth3/directives.json then /api/whatever would refer
https://example.com/username/_apis/oauth3.org/index.json then /api/whatever would refer
to https://example.com/username/api/whatever.

View File

Before

Width:  |  Height:  |  Size: 43 B

After

Width:  |  Height:  |  Size: 43 B

View File

Before

Width:  |  Height:  |  Size: 43 B

After

Width:  |  Height:  |  Size: 43 B

140
_apis/oauth3/index.html Normal file
View File

@ -0,0 +1,140 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color: #ffcccc;
}
</style>
</head>
<body>
OAuth3 RPC
<script src="../../assets/oauth3.org/oauth3.core.js"></script>
<script>
;(function () {
'use strict';
// Taken from oauth3.core.js
// TODO what about search within hash?
var prefix = "(" + window.location.hostname + ") [.well-known/oauth3/]";
var params = OAUTH3.query.parse(window.location.hash || window.location.search);
var urlsafe64;
var redirect;
var err;
var oldRpc;
var sub = params.sub || params.subject;
var subData;
function doRedirect(redirect) {
if (params.debug) {
console.log(prefix, 'params.redirect_uri:', params.redirect_uri);
console.log(prefix, 'redirect');
console.log(redirect);
}
if (!params.debug) {
window.location = redirect;
} else {
// yes, we're violating the security lint with purpose
document.body.innerHTML += window.location.host + window.location.pathname
+ '<br/><br/>You\'ve passed the \'debug\' parameter so we\'re pausing'
+ ' to let you look at logs or whatever it is that you intended to do.'
+ '<br/><br/>Continue with redirect: <a href="' + redirect + '">' + redirect + '</' + 'a>';
}
}
function onError(err) {
var redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({
state: params.state
, error: err.code
, error_description: err.message
, error_uri: err.uri
, debug: params.debug || undefined
});
doRedirect(redirect);
}
function onSuccess(urlsafe64, hasSub) {
if (params.debug) {
console.log(prefix, 'directives');
console.log(resp);
console.log(prefix, 'base64');
console.log(urlsafe64);
}
// TODO try postMessage back to redirect_uri domain right here
// window.postMessage();
// TODO SECURITY make sure it's https NOT http
// NOTE: this can be only up to 2,083 characters
redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({
state: params.state
, directives: oldRpc ? urlsafe64 : undefined
, data: !oldRpc ? urlsafe64 : undefined
, sub: hasSub && sub || undefined
, debug: params.debug || undefined
});
doRedirect(redirect);
}
if (params.debug) {
console.warn(prefix, "DEBUG MODE ENABLED. Automatic redirects disabled.");
console.log(prefix, 'hash||search:');
console.log(window.location.hash || window.location.search);
console.log(prefix, 'params:');
console.log(params);
}
if ('rpc' !== params.response_type) {
err = new Error("response_type '" + params.response_type + "' is not supported");
err.code = "E_RESPONSE_TYPE";
// TODO err.uri
onError(err);
return;
}
if (params.action) {
oldRpc = true;
}
var loco = window.location.href.replace(/\/\.well-known.*/, '');
//var loco = 'sso.hellabit.com';
var resp;
if (/localstorage/i.test(params._scheme)) {
if (sub) {
subData = localStorage.getItem(sub + '@oauth3.org:issuer');
}
resp = subData || localStorage.getItem('oauth3.org:issuer') || loco;
onSuccess(resp, subData && true);
return;
}
var fileWhiteList = [
'.well-known/oauth3/directives.json'
, '.well-known/oauth3/scopes.json'
];
if (-1 === fileWhiteList.indexOf(params._pathname)) {
err = new Error("No access to requested file: " + params._pathname);
err.code = "E_ACCESS_DENIED"
// TODO err.uri
onError(err);
}
OAUTH3.request({ url: params._pathname.replace(/^\.well-known\/oauth3\//, '') }).then(function (resp) {
urlsafe64 = OAUTH3._base64.encodeUrlSafe(JSON.stringify(resp.data, null, 0));
onSuccess(urlsafe64);
});
}());
</script>
</body>
</html>

26
_apis/oauth3/scopes.json Normal file
View File

@ -0,0 +1,26 @@
{
"oauth3_authn": "Basic secure authentication"
, "auth@oauth3.org": "Basic secure authentication"
, "wallet": "Access to payments and subscriptions"
, "bucket": "Access to file storage"
, "db": "Access to app data"
, "domains": "Domain registration (and Glue and NS records)"
, "domains@oauth3.org": "Domain registration (and Glue and NS records)"
, "domains:glue": "Glue Record management (for vanity nameservers)"
, "domains:ns": "Name Server management"
, "dns": "DNS records (A/AAAA, TXT, SRV, MX, etc)"
, "hello@example.com": "Hello World Example Access"
, "authn@oauth3.org": "Basic secure authentication"
, "wallet@oauth3.org": "Access to payments and subscriptions"
, "bucket@oauth3.org": "Access to file storage"
, "db@oauth3.org": "Access to app data"
, "domains@oauth3.org": "Domain registration (and Glue and NS records)"
, "domains:glue@oauth3.org": "Glue Record management (for vanity nameservers)"
, "domains:ns@oauth3.org": "Name Server management"
, "dns@oauth3.org": "DNS records (A/AAAA, TXT, SRV, MX, etc)"
, "www@daplie.com": "Websites and webapps"
, "*": "FULL ACCOUNT ACCESS"
}

96
navigator.auth.js Normal file
View File

@ -0,0 +1,96 @@
(function () {
'use strict';
function create(myOpts) {
return {
requestScope: function (opts) {
// TODO pre-generate URL
// deliver existing session if it exists
var scope = opts && opts.scope || [];
if (myOpts.session) {
if (!scope.length || scope.every(function (scp) {
return -1 !== opts.myOpts.session.scope.indexOf(scp);
})) {
return OAUTH3.PromiseA.resolve(myOpts.session);
}
}
// request a new session otherwise
return OAUTH3.implicitGrant(myOpts.directives, {
client_id: myOpts.conf.client_uri
, client_uri: myOpts.conf.client_uri
// maybe use inline instead?
, windowType: 'popup'
, scope: scope
}).then(function (session) {
return session;
});
}
, session: function () {
return myOpts.session;
}
, refresh: function (session) {
return OAUTH3.implicitGrant(myOpts.directives, {
client_id: myOpts.conf.client_uri
, client_uri: myOpts.conf.client_uri
, windowType: 'background'
}).then(function (_session) {
session = _session;
return session;
});
}
, logout: function () {
return OAUTH3.logout(myOpts.directives, {
client_id: myOpts.conf.client_uri
, client_uri: myOpts.conf.client_uri
});
}
, switchUser: function () {
// should open dialog with user selection dialog
}
}
}
window.navigator.auth = {
getUserAuthenticator: function (opts) {
var conf = {};
var directives;
var session;
opts = opts || {};
conf.client_uri = opts.client_uri || OAUTH3.clientUri(opts.location || window.location);
return OAUTH3.issuer({ broker: opts.issuer_uri || 'https://new.oauth3.org' }).then(function (issuer) {
conf.issuer_uri = issuer;
conf.provider_uri = issuer;
return OAUTH3.directives(conf.provider_uri, {
client_id: conf.client_uri
, client_uri: conf.client_uri
}).then(function (_directives) {
directives = _directives;
var myOpts = {
directives: directives
, conf: conf
};
return OAUTH3.implicitGrant(directives, {
client_id: conf.client_uri
, client_uri: conf.client_uri
, windowType: 'background'
}).then(function (_session) {
session = _session;
myOpts.session = session;
return create(myOpts);
}, function (err) {
console.error('[DEBUG] implicitGrant err:');
console.error(err);
return create(myOpts);
});
});
});
}
};
}());

View File

@ -1,4 +1,4 @@
/* global Promise */
/ * global Promise */
;(function (exports) {
'use strict';
@ -169,7 +169,7 @@
}
, scope: {
parse: function (scope) {
return (scope||'').split(/[+, ]+/g);
return (scope||'').toString().split(/[+, ]+/g);
}
, stringify: function (scope) {
if (Array.isArray(scope)) {
@ -294,34 +294,46 @@
}
}
, urls: {
discover: function (providerUri, opts) {
rpc: function (providerUri, opts) {
if (!providerUri) {
throw new Error("cannot discover without providerUri");
throw new Error("cannot run rpc without providerUri");
}
if (!opts.client_id) {
throw new Error("cannot discover without options.client_id");
throw new Error("cannot run rpc without options.client_id");
}
var clientId = OAUTH3.url.normalize(opts.client_id || opts.client_uri);
providerUri = OAUTH3.url.normalize(providerUri);
var params = {
action: 'directives'
, state: opts.state || OAUTH3.utils.randomState()
state: opts.state || OAUTH3.utils.randomState()
, redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html#/')
, response_type: 'rpc'
, _method: 'GET'
, _pathname: '.well-known/oauth3/directives.json'
, _scheme: opts._scheme
, _pathname: opts._pathname
, debug: opts.debug || undefined
};
var result = {
var toRequest = {
url: providerUri + '/.well-known/oauth3/#/?' + OAUTH3.query.stringify(params)
, state: params.state
, method: 'GET'
, query: params
};
return result;
return toRequest;
}
, broker: function (providerUri, opts) {
opts._scheme = "localstorage:";
opts._pathname = "issuer";
return OAUTH3.urls.rpc(providerUri, opts);
}
, discover: function (providerUri, opts) {
return OAUTH3.urls.directives(providerUri, opts);
}
, directives: function (providerUri, opts) {
opts._pathname = ".well-known/oauth3/scopes.json";
return OAUTH3.urls.rpc(providerUri, opts);
}
, implicitGrant: function (directive, opts) {
//
@ -530,6 +542,14 @@
return OAUTH3.PromiseA.resolve(OAUTH3._hooks.directives.clear());
}
}
, scopes: {
get: function(providerUri) {
//TODO: retrieve cached scopes
}
, set: function(providerUri, scopes) {
//TODO: cache scopes
}
}
, session: {
refresh: function (oldSession, newSession) {
var providerUri = oldSession.provider_uri;
@ -658,9 +678,29 @@
}
}
}
, discover: function (providerUri, opts) {
, discoverScopes: function (providerUri, opts) {
return OAUTH.scopes(providerUri, opts);
}
, scopes: function (providerUri, opts) {
if (!providerUri) {
throw new Error('oauth3.discover(providerUri, opts) received providerUri as ' + providerUri);
throw new Error('oauth3.discoverScopes(providerUri, opts) received providerUri as :', providerUri);
}
opts = opts || {};
opts._pathname = ".well-known/oauth3/scopes.json";
//TODO: add caching
return OAUTH3._rpcHelper(providerUri, opts).then(function(scopes) {
return scopes;
});
}
, discover: function (providerUri, opts) {
return OAUTH3.directives(providerUri, opts);
}
, directives: function (providerUri, opts) {
if (!providerUri) {
throw new Error('oauth3.discover(providerUri, opts) received providerUri as :', providerUri);
}
return OAUTH3.hooks.directives.get(providerUri).then(function (directives) {
@ -668,7 +708,8 @@
return directives;
}
return OAUTH3._discoverHelper(providerUri, opts).then(function (directives) {
opts._pathname = ".well-known/oauth3/directives.json";
return OAUTH3._rpcHelper(providerUri, opts).then(function (directives) {
directives.azp = directives.azp || OAUTH3.url.normalize(providerUri);
directives.issuer = directives.issuer || OAUTH3.url.normalize(providerUri);
directives.api = OAUTH3.url.normalize((directives.api||':hostname').replace(/:hostname/, OAUTH3.uri.normalize(directives.issuer) || OAUTH3.uri.normalize(providerUri)));
@ -677,8 +718,8 @@
});
});
}
, _discoverHelper: function(providerUri, opts) {
return OAUTH3._browser.discover(providerUri, opts);
, _rpcHelper: function(providerUri, opts) {
return OAUTH3._browser.rpc(providerUri, opts);
}
, request: function (preq, opts) {
function fetch() {
@ -706,6 +747,21 @@
*/
return OAUTH3._browser.request(preq, opts);
}
, issuer: function (opts) {
if (!opts) { opts = {}; }
// TODO this will default to browserlogin.org
var broker = opts.broker || 'https://new.oauth3.org';
//var broker = opts.broker || 'https://broker.oauth3.org';
opts._rpc = "broker";
opts._scheme = "localstorage:";
opts._pathname = "issuer";
return OAUTH3._rpcHelper(broker, opts).then(function(issuer) {
return issuer;
});
}
, implicitGrant: function (directives, opts) {
var promise;
var providerUri = directives.azp || directives.issuer || directives;
@ -816,12 +872,19 @@
});
});
}
, logout: function(providerUri, opts) {
return OAUTH3.hooks.directives.get(providerUri).then(function (directives) {
, logout: function(issuerUri, opts) {
var directives;
if ('string' !== typeof issuerUri) {
directives = issuerUri;
return OAUTH3._logoutHelper(directives, opts);
}
return OAUTH3.hooks.directives.get(issuerUri).then(function (directives) {
return OAUTH3._logoutHelper(directives, opts);
});
}
, _logoutHelper: function(providerUri, directives, opts) {
, _logoutHelper: function(directives, opts) {
var issuerUri = directives.issuer_uri || directives.provider_uri;
var logoutReq = OAUTH3.urls.logout(
directives
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location))
@ -844,10 +907,10 @@
if (params.error) {
// TODO directives.audience
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(directives.issuer /*providerUri*/, params));
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(directives.issuer /*issuerUri*/, params));
}
OAUTH3.hooks.session.clear(providerUri);
OAUTH3.hooks.session.clear(issuerUri);
return params;
});
}
@ -858,40 +921,50 @@
//
, _browser: {
window: 'undefined' !== typeof window ? window : null
// TODO we don't need to include this if we're using jQuery or angular
, discover: function(providerUri, opts) {
, rpc: function(providerUri, opts) {
opts = opts || {};
providerUri = OAUTH3.url.normalize(providerUri);
// TODO SECURITY should we whitelist our own self?
if (OAUTH3.uri.normalize(providerUri).replace(/\/.*/, '') === OAUTH3.uri.normalize(OAUTH3._browser.window.location.hostname)) {
console.warn("It looks like you're a provider checking for your own directive,"
console.warn("It looks like you're a provider trying to run rpc on yourself,"
+ " so we we're just gonna use"
+ " OAUTH3.request({ method: 'GET', url: '.well-known/oauth3/directive.json' })");
return OAUTH3.request({
method: 'GET'
, url: OAUTH3.url.normalize(providerUri) + '/.well-known/oauth3/directives.json'
}).then(function (resp) {
return resp.data;
});
+ " OAUTH3.request({ method: 'GET', url: "
+ "'" + opts._pathname + "' })");
if (/localstorage/i.test(opts._scheme)) {
return OAUTH3.PromiseA.resolve(localStorage.getItem(opts._pathname));
}
else {
return OAUTH3.request({
method: 'GET'
, url: OAUTH3.url.normalize(providerUri) + '/' + opts._pathname // '/.well-known/oauth3/' + discoverFile
}).then(function (resp) {
return resp.data;
});
}
}
if (!(opts.client_id || opts.client_uri).match(OAUTH3._browser.window.location.hostname)) {
if (!(opts.client_id || opts.client_uri || '').match(OAUTH3._browser.window.location.hostname)) {
console.warn("It looks like your client_id doesn't match your current window..."
+ " this probably won't end well");
console.warn(opts.client_id || opts.client_uri, OAUTH3._browser.window.location.hostname);
}
var discReq = OAUTH3.urls.discover(
var discReq = OAUTH3.urls[opts._rpc || 'rpc'](
providerUri
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location))
, windowType: opts.broker && opts.windowType || 'background'
, broker: opts.broker
, state: opts._state || undefined
, debug: opts.debug
, _scheme: opts._scheme
, _pathname: opts._pathname
, _method: opts._method
}
);
opts._state = discReq.state;
//var discReq = OAUTH3.urls.discover(providerUri, opts);
//var discReq = OAUTH3.urls.rpc(providerUri, opts);
// hmm... we're gonna need a broker for this since switching windows is distracting,
// popups are obnoxious, iframes are sometimes blocked, and most servers don't implement CORS
@ -920,9 +993,16 @@
}
// TODO params should have response_type indicating json, binary, etc
var directives = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.result || params.directives));
var result;
try {
result = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.data || params.result || params.directives));
} catch(e) {
result = params.data || params.result;
}
console.log('result:', result);
// caller will call OAUTH3.hooks.directives.set(providerUri, directives);
return directives;
return result;
});
});
}
@ -1054,11 +1134,10 @@
}
var timeout = opts.timeout;
if (opts.debug) {
timeout = timeout || 3 * 60 * 1000;
}
else {
timeout = timeout || ('background' === windowType ? 15 * 1000 : 3 * 60 * 1000);
if ('background' === windowType) {
if (!timeout) {
timeout = 7 * 1000;
}
}
return new OAUTH3.PromiseA(function (resolve, reject) {
@ -1080,14 +1159,16 @@
cleanup();
};
tok = setTimeout(function () {
var err = new Error(
"the '" + windowType + "' request did not complete within " + Math.round(timeout / 1000) + "s"
);
err.code = "E_TIMEOUT";
reject(err);
cleanup();
}, timeout);
if (timeout) {
tok = setTimeout(function () {
var err = new Error(
"the '" + windowType + "' request did not complete within " + Math.round(timeout / 1000) + "s"
);
err.code = "E_TIMEOUT";
reject(err);
cleanup();
}, timeout);
}
setTimeout(function () {
if (!OAUTH3._browser._frames[state]) {

View File

@ -371,8 +371,8 @@ OAUTH3.authn.resourceOwnerPassword = function (directive, opts) {
OAUTH3.authz = {};
OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
var clientUri = OAUTH3.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer);
var scope = clientParams.scope || 'oauth3_authn';
if ('oauth3_authn' === scope) {
var scope = clientParams.scope || 'authn@oauth3.org';
if ('authn@oauth3.org' === scope.toString()) {
// implicit ppid grant is automatic
console.warn('[security] fix scope checking on backend so that we can do automatic grants');
// TODO check user preference if implicit ppid grant is allowed

View File

@ -27,10 +27,10 @@
OAUTH3.authz.scopes = function () {
return OAUTH3.PromiseA.resolve({
pending: ['oauth3_authn'] // not yet accepted
, granted: [] // all granted, ever
, requested: ['oauth3_authn'] // all requested, now
, accepted: [] // granted (ever) and requested (now)
pending: [ 'authn@oauth3.org' ] // not yet accepted
, granted: [] // all granted, ever
, requested: [ 'authn@oauth3.org' ] // all requested, now
, accepted: [] // granted (ever) and requested (now)
});
};
OAUTH3.authz.grants = function (providerUri, opts) {

1
well-known Symbolic link
View File

@ -0,0 +1 @@
_apis

View File

@ -1,71 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color: #ffcccc;
}
</style>
</head>
<body>
OAuth3 RPC
<script src="../../assets/oauth3.org/oauth3.core.js"></script>
<script>
;(function () {
'use strict';
// Taken from oauth3.core.js
// TODO what about search within hash?
var prefix = "(" + window.location.hostname + ") [.well-known/oauth3/]";
var params = OAUTH3.query.parse(window.location.hash || window.location.search);
if (params.debug) {
console.warn(prefix, "DEBUG MODE ENABLED. Automatic redirects disabled.");
}
console.log(prefix, 'hash||search:');
console.log(window.location.hash || window.location.search);
console.log(prefix, 'params:');
console.log(params);
OAUTH3.request({ url: 'directives.json' }).then(function (resp) {
var urlsafe64 = OAUTH3._base64.encodeUrlSafe(JSON.stringify(resp.data, null, 0));
var redirect;
console.log(prefix, 'directives');
console.log(resp);
console.log(prefix, 'base64');
console.log(urlsafe64);
// TODO try postMessage back to redirect_uri domain right here
// window.postMessage();
// TODO make sure it's https NOT http
// NOTE: this can be only up to 2,083 characters
console.log(prefix, 'params.redirect_uri:', params.redirect_uri);
redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({
state: params.state
, directives: urlsafe64
, debug: params.debug || undefined
})
console.log(prefix, 'redirect');
console.log(redirect);
if (!params.debug) {
window.location = redirect;
} else {
// yes, we're violating the security lint with purpose
document.body.innerHTML += window.location.host + window.location.pathname
+ '<br/><br/>You\'ve passed the \'debug\' parameter so we\'re pausing'
+ ' to let you look at logs or whatever it is that you intended to do.'
+ '<br/><br/>Continue with redirect: <a href="' + redirect + '">' + redirect + '</' + 'a>';
}
});
}());
</script>
</body>
</html>