Compare commits
No commits in common. "master" and "scope-discovery" have entirely different histories.
master
...
scope-disc
|
@ -1 +1 @@
|
||||||
_apis
|
well-known
|
64
README.md
64
README.md
|
@ -5,7 +5,7 @@ oauth3.js
|
||||||
| [issuer.html](https://git.oauth3.org/OAuth3/issuer.html)
|
| [issuer.html](https://git.oauth3.org/OAuth3/issuer.html)
|
||||||
| [issuer.rest.walnut.js](https://git.oauth3.org/OAuth3/issuer.rest.walnut.js)
|
| [issuer.rest.walnut.js](https://git.oauth3.org/OAuth3/issuer.rest.walnut.js)
|
||||||
| [issuer.srv](https://git.oauth3.org/OAuth3/issuer.srv)
|
| [issuer.srv](https://git.oauth3.org/OAuth3/issuer.srv)
|
||||||
| Sponsored by [ppl](https://ppl.family)
|
| Sponsored by [Daplie](https://daplie.com)
|
||||||
|
|
||||||
The world's smallest, fastest, and most secure OAuth3 (and OAuth2) JavaScript implementation
|
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!)
|
(Yes! works in browsers and node.js with no extra dependencies or bloat and no hacks!)
|
||||||
|
@ -29,7 +29,8 @@ 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)
|
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.
|
5. Double-click to unzip the folder.
|
||||||
6. Copy the file `oauth3.core.js` into the folder `example.com/assets/oauth3.org/`
|
6. Copy the file `oauth3.core.js` into the folder `example.com/assets/oauth3.org/`
|
||||||
7. Copy the folder `_apis` into the folder `example.com/`
|
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)
|
||||||
9. Add `<script src="assets/oauth3.org/oauth3.core.js"></script>` to your `index.html`
|
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`
|
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:
|
10. Create files in `example.com` called `app.js` and `index.html` and put this in it:
|
||||||
|
@ -58,13 +59,13 @@ If you have no idea what you're doing
|
||||||
`app.js`:
|
`app.js`:
|
||||||
```js
|
```js
|
||||||
var OAUTH3 = window.OAUTH3;
|
var OAUTH3 = window.OAUTH3;
|
||||||
var oauth3 = OAUTH3.create(window.location); // use window.location to set Client URI (your app's id)
|
var auth = 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
|
// 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
|
// 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
|
// example https://oauth3.org
|
||||||
return oauth3.setIdentityProvider(providerUri);
|
return oauth3.setIdentityProvider(providerUri);
|
||||||
}
|
}
|
||||||
|
@ -86,13 +87,11 @@ function onClickLogin() {
|
||||||
console.info('Secure PPID (aka subject):', session.token.sub);
|
console.info('Secure PPID (aka subject):', session.token.sub);
|
||||||
|
|
||||||
return oauth3.request({
|
return oauth3.request({
|
||||||
url: 'https://api.oauth3.org/api/issuer@oauth3.org/jwks/:sub/:kid'
|
url: 'https://oauth3.org/api/issuer@oauth3.org/inspect'
|
||||||
.replace(/:sub/g, session.token.sub)
|
|
||||||
.replace(/:kid/g, session.token.kid || session.token.iss)
|
|
||||||
, session: session
|
, session: session
|
||||||
}).then(function (resp) {
|
}).then(function (resp) {
|
||||||
|
|
||||||
console.info("Signing Public Key JWK:");
|
console.info("Inspect Token:");
|
||||||
console.log(resp.data);
|
console.log(resp.data);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -145,13 +144,13 @@ it might look like this:
|
||||||
example.com
|
example.com
|
||||||
│
|
│
|
||||||
│
|
│
|
||||||
├── _apis
|
├── .well-known (hidden)
|
||||||
│ └── oauth3.org
|
│ └── oauth3
|
||||||
│ ├── callback.html
|
│ ├── callback.html
|
||||||
│ ├── directives.json
|
│ ├── directives.json
|
||||||
│ └── index.html
|
│ └── index.html
|
||||||
├── assets
|
├── assets
|
||||||
│ └── oauth3.org
|
│ └── org.oauth3
|
||||||
│ └── oauth3.core.js
|
│ └── oauth3.core.js
|
||||||
│
|
│
|
||||||
│
|
│
|
||||||
|
@ -172,17 +171,17 @@ Installation (if you know what you're doing)
|
||||||
pushd /path/to/your/web/app
|
pushd /path/to/your/web/app
|
||||||
|
|
||||||
|
|
||||||
# clone the project as assets/oauth3.org
|
# clone the project as assets/org.oauth3
|
||||||
mkdir -p assets
|
mkdir -p assets
|
||||||
git clone git@git.oauth3.org:OAuth3/oauth3.js.git assets/oauth3.org
|
git clone git@git.daplie.com:OAuth3/oauth3.js.git assets/org.oauth3
|
||||||
pushd assets/oauth3.org
|
pushd assets/org.oauth3
|
||||||
git checkout v1
|
git checkout v1
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
|
||||||
# symlink `_apis/oauth3.org` to `assets/oauth3.org/_apis/oauth3.org`
|
# symlink `.well-known/oauth3` to `assets/org.oauth3/.well-known/oauth3`
|
||||||
mkdir -p _apis
|
mkdir -p .well-known
|
||||||
ln -sf ../assets/oauth3.org/_apis/oauth3 _apis/oauth3.org
|
ln -sf ../assets/org.oauth3/.well-known/oauth3 .well-known/oauth3
|
||||||
```
|
```
|
||||||
|
|
||||||
**Advanced Installation with `bower`**
|
**Advanced Installation with `bower`**
|
||||||
|
@ -192,17 +191,17 @@ ln -sf ../assets/oauth3.org/_apis/oauth3 _apis/oauth3.org
|
||||||
bower install oauth3
|
bower install oauth3
|
||||||
|
|
||||||
|
|
||||||
# create a `_apis` folder and an `assets` folder
|
# create a `.well-known` folder and an `assets` folder
|
||||||
mkdir -p _apis assets
|
mkdir -p .well-known assets
|
||||||
|
|
||||||
|
|
||||||
# symlink `_apis/oauth3.org` to `bower_components/oauth3.org/_apis/oauth3.org`
|
# symlink `.well-known/oauth3` to `bower_components/oauth3/.well-known/oauth3`
|
||||||
ln -sf ../bower_components/oauth3.org/_apis/oauth3.org _apis/oauth3.org
|
ln -sf ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3
|
||||||
|
|
||||||
|
|
||||||
# symlink `assets/oauth3.org` to `bower_components/oauth3.org`
|
# symlink `assets/org.oauth3` to `bower_components/oauth3`
|
||||||
ln -sf ../bower_components/oauth3.org/_apis/oauth3.org _apis/oauth3.org
|
ln -sf ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3
|
||||||
ln -sf ../bower_components/oauth3.org assets/oauth3.org
|
ln -sf ../bower_components/oauth3 assets/org.oauth3
|
||||||
```
|
```
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
|
@ -211,7 +210,7 @@ Usage
|
||||||
Update your HTML to include the the following script tag:
|
Update your HTML to include the the following script tag:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="assets/oauth3.org/oauth3.core.js"></script>
|
<script src="assets/org.oauth3/oauth3.core.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
You can create a very simple demo application like this:
|
You can create a very simple demo application like this:
|
||||||
|
@ -290,7 +289,7 @@ You're all set. Nothing else is needed.
|
||||||
We've created an `Oauth3` service just for you:
|
We've created an `Oauth3` service just for you:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="assets/oauth3.org/oauth3.ng.js"></script>
|
<script src="assets/org.oauth3/oauth3.ng.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -323,7 +322,7 @@ promise = oauth3.init(opts); // set and fetch your own si
|
||||||
// promises your site's config // opts = { location, session, issuer, audience }
|
// 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),
|
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 _apis/oauth3.org),
|
// promises the provider's config // gets the config for that site (from their .well-known/oauth3),
|
||||||
// and caches it in internal state as the default
|
// 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)
|
promise = oauth3.setResourceProvider(url); // changes the Resource Provider URI (the site you're getting stuff from)
|
||||||
|
@ -340,11 +339,12 @@ promise = oauth3.request({ url, method, data }); // make an (authorized) arbi
|
||||||
// (contacts, photos, whatever)
|
// (contacts, photos, whatever)
|
||||||
|
|
||||||
promise = oauth3.api(apiname, opts); // make an (authorized) well-known api call to an audience
|
promise = oauth3.api(apiname, opts); // make an (authorized) well-known api call to an audience
|
||||||
// Ex: oauth3.api('dns.list', { sld: 'example', tld: 'com' });
|
// See https://labs.daplie.com/docs/ for API schemas
|
||||||
|
// Ex: oauth3.api('dns.list', { sld: 'daplie', tld: 'com' });
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
api = await oauth3.package(audience, schemaname); // make an (authorized) well-known api call to an audience
|
api = await oauth3.package(audience, schemaname); // make an (authorized) well-known api call to an audience
|
||||||
// Ex: api = await oauth3.package('domains.example.com', 'dns@oauth3.org');
|
// Ex: api = await oauth3.package('domains.daplie.com', 'dns@oauth3.org');
|
||||||
// api.list({ sld: 'mydomain', tld: 'com' });
|
// api.list({ sld: 'mydomain', tld: 'com' });
|
||||||
|
|
||||||
|
|
||||||
|
@ -353,10 +353,6 @@ promise = oauth3.logout(); // opens logout window for t
|
||||||
oauth3.session(); // returns the current session, if any
|
oauth3.session(); // returns the current session, if any
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- TODO
|
|
||||||
Track down the old https://labs.daplie.com/docs/ for API schemas
|
|
||||||
--
|
|
||||||
|
|
||||||
|
|
||||||
Real API
|
Real API
|
||||||
----------
|
----------
|
||||||
|
@ -498,5 +494,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)
|
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
|
and have the path always key off of the base URL - if oauth3 directives are to be found at
|
||||||
https://example.com/username/_apis/oauth3.org/index.json then /api/whatever would refer
|
https://example.com/username/.well-known/oauth3/directives.json then /api/whatever would refer
|
||||||
to https://example.com/username/api/whatever.
|
to https://example.com/username/api/whatever.
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 43 B |
Binary file not shown.
Before Width: | Height: | Size: 43 B |
|
@ -1,140 +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);
|
|
||||||
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>
|
|
|
@ -1,96 +0,0 @@
|
||||||
(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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}());
|
|
236
oauth3.core.js
236
oauth3.core.js
|
@ -169,7 +169,7 @@
|
||||||
}
|
}
|
||||||
, scope: {
|
, scope: {
|
||||||
parse: function (scope) {
|
parse: function (scope) {
|
||||||
return (scope||'').toString().split(/[+, ]+/g);
|
return (scope||'').split(/[+, ]+/g);
|
||||||
}
|
}
|
||||||
, stringify: function (scope) {
|
, stringify: function (scope) {
|
||||||
if (Array.isArray(scope)) {
|
if (Array.isArray(scope)) {
|
||||||
|
@ -294,23 +294,25 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, urls: {
|
, urls: {
|
||||||
rpc: function (providerUri, opts) {
|
, discover: function (providerUri, opts) {
|
||||||
if (!providerUri) {
|
if (!providerUri) {
|
||||||
throw new Error("cannot run rpc without providerUri");
|
throw new Error("cannot discover without providerUri");
|
||||||
}
|
}
|
||||||
if (!opts.client_id) {
|
if (!opts.client_id) {
|
||||||
throw new Error("cannot run rpc without options.client_id");
|
throw new Error("cannot discover without options.client_id");
|
||||||
}
|
}
|
||||||
var clientId = OAUTH3.url.normalize(opts.client_id || opts.client_uri);
|
var clientId = OAUTH3.url.normalize(opts.client_id || opts.client_uri);
|
||||||
providerUri = OAUTH3.url.normalize(providerUri);
|
providerUri = OAUTH3.url.normalize(providerUri);
|
||||||
|
var discoverFile = opts.discoverFile || "directives.json";
|
||||||
|
|
||||||
var params = {
|
var params = {
|
||||||
state: opts.state || OAUTH3.utils.randomState()
|
action: 'directives' //TODO: change this to not be directive specific. Is it even used?
|
||||||
|
, state: opts.state || OAUTH3.utils.randomState()
|
||||||
, redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html#/')
|
, redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html#/')
|
||||||
, response_type: 'rpc'
|
, response_type: 'rpc'
|
||||||
|
, discoverFile: opts.discoveFile || "directives.json"
|
||||||
, _method: 'GET'
|
, _method: 'GET'
|
||||||
, _scheme: opts._scheme
|
, _pathname: '.well-known/oauth3/directives.json'
|
||||||
, _pathname: opts._pathname
|
|
||||||
, debug: opts.debug || undefined
|
, debug: opts.debug || undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -323,18 +325,6 @@
|
||||||
|
|
||||||
return toRequest;
|
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) {
|
, implicitGrant: function (directive, opts) {
|
||||||
//
|
//
|
||||||
// Example Implicit Grant Request
|
// Example Implicit Grant Request
|
||||||
|
@ -679,26 +669,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, discoverScopes: function (providerUri, opts) {
|
, discoverScopes: function (providerUri, opts) {
|
||||||
return OAUTH.scopes(providerUri, opts);
|
|
||||||
}
|
|
||||||
, scopes: function (providerUri, opts) {
|
|
||||||
if (!providerUri) {
|
if (!providerUri) {
|
||||||
throw new Error('oauth3.discoverScopes(providerUri, opts) received providerUri as :', providerUri);
|
throw new Error('oauth3.discoverScopes(providerUri, opts) received providerUri as :', providerUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = opts || {};
|
var opts = opts || {};
|
||||||
opts._pathname = ".well-known/oauth3/scopes.json";
|
opts.discoverFile = "scopes.json";
|
||||||
|
|
||||||
//TODO: add caching
|
//TODO: add caching
|
||||||
|
|
||||||
return OAUTH3._rpcHelper(providerUri, opts).then(function(scopes) {
|
return OAUTH3._discoverHelper(providerUri, opts).then(function(scopes) {
|
||||||
return scopes;
|
return scopes;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
, discover: function (providerUri, opts) {
|
, discover: function (providerUri, opts) {
|
||||||
return OAUTH3.directives(providerUri, opts);
|
|
||||||
}
|
|
||||||
, directives: function (providerUri, opts) {
|
|
||||||
if (!providerUri) {
|
if (!providerUri) {
|
||||||
throw new Error('oauth3.discover(providerUri, opts) received providerUri as :', providerUri);
|
throw new Error('oauth3.discover(providerUri, opts) received providerUri as :', providerUri);
|
||||||
}
|
}
|
||||||
|
@ -708,8 +693,7 @@
|
||||||
return directives;
|
return directives;
|
||||||
}
|
}
|
||||||
|
|
||||||
opts._pathname = ".well-known/oauth3/directives.json";
|
return OAUTH3._discoverHelper(providerUri, opts).then(function (directives) {
|
||||||
return OAUTH3._rpcHelper(providerUri, opts).then(function (directives) {
|
|
||||||
directives.azp = directives.azp || OAUTH3.url.normalize(providerUri);
|
directives.azp = directives.azp || OAUTH3.url.normalize(providerUri);
|
||||||
directives.issuer = directives.issuer || 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)));
|
directives.api = OAUTH3.url.normalize((directives.api||':hostname').replace(/:hostname/, OAUTH3.uri.normalize(directives.issuer) || OAUTH3.uri.normalize(providerUri)));
|
||||||
|
@ -718,8 +702,9 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
, _rpcHelper: function(providerUri, opts) {
|
, _discoverHelper: function(providerUri, opts) {
|
||||||
return OAUTH3._browser.rpc(providerUri, opts);
|
opts.discoverFile = "directives.json";
|
||||||
|
return OAUTH3._browser.discover(providerUri, opts);
|
||||||
}
|
}
|
||||||
, request: function (preq, opts) {
|
, request: function (preq, opts) {
|
||||||
function fetch() {
|
function fetch() {
|
||||||
|
@ -747,21 +732,6 @@
|
||||||
*/
|
*/
|
||||||
return OAUTH3._browser.request(preq, opts);
|
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) {
|
, implicitGrant: function (directives, opts) {
|
||||||
var promise;
|
var promise;
|
||||||
var providerUri = directives.azp || directives.issuer || directives;
|
var providerUri = directives.azp || directives.issuer || directives;
|
||||||
|
@ -872,19 +842,12 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
, logout: function(issuerUri, opts) {
|
, logout: function(providerUri, opts) {
|
||||||
var directives;
|
return OAUTH3.hooks.directives.get(providerUri).then(function (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);
|
return OAUTH3._logoutHelper(directives, opts);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
, _logoutHelper: function(directives, opts) {
|
, _logoutHelper: function(providerUri, directives, opts) {
|
||||||
var issuerUri = directives.issuer_uri || directives.provider_uri;
|
|
||||||
var logoutReq = OAUTH3.urls.logout(
|
var logoutReq = OAUTH3.urls.logout(
|
||||||
directives
|
directives
|
||||||
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location))
|
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location))
|
||||||
|
@ -907,10 +870,10 @@
|
||||||
|
|
||||||
if (params.error) {
|
if (params.error) {
|
||||||
// TODO directives.audience
|
// TODO directives.audience
|
||||||
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(directives.issuer /*issuerUri*/, params));
|
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(directives.issuer /*providerUri*/, params));
|
||||||
}
|
}
|
||||||
|
|
||||||
OAUTH3.hooks.session.clear(issuerUri);
|
OAUTH3.hooks.session.clear(providerUri);
|
||||||
return params;
|
return params;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -921,50 +884,48 @@
|
||||||
//
|
//
|
||||||
, _browser: {
|
, _browser: {
|
||||||
window: 'undefined' !== typeof window ? window : null
|
window: 'undefined' !== typeof window ? window : null
|
||||||
, rpc: function(providerUri, opts) {
|
// TODO we don't need to include this if we're using jQuery or angular
|
||||||
|
, discover: function(providerUri, opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
providerUri = OAUTH3.url.normalize(providerUri);
|
providerUri = OAUTH3.url.normalize(providerUri);
|
||||||
|
|
||||||
// TODO SECURITY should we whitelist our own self?
|
// If no discoverFile was specified, who knows what they want, but
|
||||||
|
// this function used to only support directives.json, so it's worth
|
||||||
|
// a shot.
|
||||||
|
var discoverFile = opts.discoverFile || "directives.json";
|
||||||
|
|
||||||
if (OAUTH3.uri.normalize(providerUri).replace(/\/.*/, '') === OAUTH3.uri.normalize(OAUTH3._browser.window.location.hostname)) {
|
if (OAUTH3.uri.normalize(providerUri).replace(/\/.*/, '') === OAUTH3.uri.normalize(OAUTH3._browser.window.location.hostname)) {
|
||||||
console.warn("It looks like you're a provider trying to run rpc on yourself,"
|
console.warn("It looks like you're a provider trying to discover on yourself,"
|
||||||
+ " so we we're just gonna use"
|
+ " so we we're just gonna use"
|
||||||
+ " OAUTH3.request({ method: 'GET', url: "
|
+ " OAUTH3.request({ method: 'GET', url: "
|
||||||
+ "'" + opts._pathname + "' })");
|
+ "'/.well-known/oauth3/" + discoverFile + "' })");
|
||||||
|
|
||||||
if (/localstorage/i.test(opts._scheme)) {
|
return OAUTH3.request({
|
||||||
return OAUTH3.PromiseA.resolve(localStorage.getItem(opts._pathname));
|
method: 'GET'
|
||||||
}
|
, url: OAUTH3.url.normalize(providerUri) + '/.well-known/oauth3/' + discoverFile
|
||||||
else {
|
}).then(function (resp) {
|
||||||
return OAUTH3.request({
|
return resp.data;
|
||||||
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..."
|
console.warn("It looks like your client_id doesn't match your current window..."
|
||||||
+ " this probably won't end well");
|
+ " this probably won't end well");
|
||||||
console.warn(opts.client_id || opts.client_uri, OAUTH3._browser.window.location.hostname);
|
console.warn(opts.client_id || opts.client_uri, OAUTH3._browser.window.location.hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
var discReq = OAUTH3.urls[opts._rpc || 'rpc'](
|
var discReq = OAUTH3.urls.discover(
|
||||||
providerUri
|
providerUri
|
||||||
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location))
|
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location))
|
||||||
, windowType: opts.broker && opts.windowType || 'background'
|
, windowType: opts.broker && opts.windowType || 'background'
|
||||||
, broker: opts.broker
|
, broker: opts.broker
|
||||||
, state: opts._state || undefined
|
, state: opts._state || undefined
|
||||||
, debug: opts.debug
|
, debug: opts.debug
|
||||||
, _scheme: opts._scheme
|
, discoverFile: opts.discoverFile
|
||||||
, _pathname: opts._pathname
|
|
||||||
, _method: opts._method
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
opts._state = discReq.state;
|
opts._state = discReq.state;
|
||||||
//var discReq = OAUTH3.urls.rpc(providerUri, opts);
|
//var discReq = OAUTH3.urls.discover(providerUri, opts);
|
||||||
|
|
||||||
// hmm... we're gonna need a broker for this since switching windows is distracting,
|
// 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
|
// popups are obnoxious, iframes are sometimes blocked, and most servers don't implement CORS
|
||||||
|
@ -974,36 +935,27 @@
|
||||||
// TODO allow node to open a desktop browser window
|
// TODO allow node to open a desktop browser window
|
||||||
opts._windowType = opts.windowType;
|
opts._windowType = opts.windowType;
|
||||||
opts.windowType = opts.windowType || 'background';
|
opts.windowType = opts.windowType || 'background';
|
||||||
return OAUTH3._browser.testPixel(providerUri).then(function () {
|
return OAUTH3._browser.frameRequest(
|
||||||
return OAUTH3._browser.frameRequest(
|
OAUTH3.url.resolve(providerUri, discReq.url)
|
||||||
OAUTH3.url.resolve(providerUri, discReq.url)
|
, discReq.state
|
||||||
, discReq.state
|
// why not just pass opts whole?
|
||||||
// why not just pass opts whole?
|
, { windowType: opts.windowType
|
||||||
, { windowType: opts.windowType
|
, reuseWindow: opts.broker && '-broker'
|
||||||
, reuseWindow: opts.broker && '-broker'
|
, debug: opts.debug
|
||||||
, debug: opts.debug
|
}
|
||||||
}
|
).then(function (params) {
|
||||||
).then(function (params) {
|
opts.windowType = opts._windowType;
|
||||||
opts.windowType = opts._windowType;
|
|
||||||
|
|
||||||
// caller will call OAUTH3._browser.closeFrame(discReq.state, { debug: opts.debug || params.debug });
|
// caller will call OAUTH3._browser.closeFrame(discReq.state, { debug: opts.debug || params.debug });
|
||||||
if (params.error) {
|
if (params.error) {
|
||||||
// TODO directives.issuer || directives.audience
|
// TODO directives.issuer || directives.audience
|
||||||
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, params));
|
return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, params));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO params should have response_type indicating json, binary, etc
|
// TODO params should have response_type indicating json, binary, etc
|
||||||
var result;
|
var result = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.result || params.directives));
|
||||||
try {
|
// caller will call OAUTH3.hooks.directives.set(providerUri, directives);
|
||||||
result = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.data || params.result || params.directives));
|
return result;
|
||||||
} catch(e) {
|
|
||||||
result = params.data || params.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('result:', result);
|
|
||||||
// caller will call OAUTH3.hooks.directives.set(providerUri, directives);
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
, request: function (preq, _sys) {
|
, request: function (preq, _sys) {
|
||||||
|
@ -1102,28 +1054,6 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
, testPixel: function (targetUri) {
|
|
||||||
var url = OAUTH3.url.resolve(OAUTH3.url.normalize(targetUri), '.well-known/oauth3/clear.gif');
|
|
||||||
return new OAUTH3.PromiseA(function (resolve, reject) {
|
|
||||||
var img = document.createElement('img');
|
|
||||||
img.addEventListener('load', function () {
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
img.addEventListener('error', function () {
|
|
||||||
var err = new Error("OAuth3 support not detected: '" + url + "' not found");
|
|
||||||
err.code = 'E_NOT_SUPPORTED';
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
// works with CSP
|
|
||||||
img.style.position = 'absolute';
|
|
||||||
img.style.left = '-2px';
|
|
||||||
img.style.bottom = '-2px';
|
|
||||||
img.className = 'js-oauth3-discover';
|
|
||||||
img.src = url;
|
|
||||||
document.body.appendChild(img);
|
|
||||||
console.log('img', img);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
, frameRequest: function (url, state, opts) {
|
, frameRequest: function (url, state, opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
var previousFrame = OAUTH3._browser._frames[state];
|
var previousFrame = OAUTH3._browser._frames[state];
|
||||||
|
@ -1134,10 +1064,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout = opts.timeout;
|
var timeout = opts.timeout;
|
||||||
if ('background' === windowType) {
|
if (opts.debug) {
|
||||||
if (!timeout) {
|
timeout = timeout || 3 * 60 * 1000;
|
||||||
timeout = 7 * 1000;
|
}
|
||||||
}
|
else {
|
||||||
|
timeout = timeout || ('background' === windowType ? 15 * 1000 : 3 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OAUTH3.PromiseA(function (resolve, reject) {
|
return new OAUTH3.PromiseA(function (resolve, reject) {
|
||||||
|
@ -1159,16 +1090,14 @@
|
||||||
cleanup();
|
cleanup();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (timeout) {
|
tok = setTimeout(function () {
|
||||||
tok = setTimeout(function () {
|
var err = new Error(
|
||||||
var err = new Error(
|
"the '" + windowType + "' request did not complete within " + Math.round(timeout / 1000) + "s"
|
||||||
"the '" + windowType + "' request did not complete within " + Math.round(timeout / 1000) + "s"
|
);
|
||||||
);
|
err.code = "E_TIMEOUT";
|
||||||
err.code = "E_TIMEOUT";
|
reject(err);
|
||||||
reject(err);
|
cleanup();
|
||||||
cleanup();
|
}, timeout);
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (!OAUTH3._browser._frames[state]) {
|
if (!OAUTH3._browser._frames[state]) {
|
||||||
|
@ -1371,23 +1300,6 @@
|
||||||
OAUTH3.utils = {
|
OAUTH3.utils = {
|
||||||
clientUri: OAUTH3.clientUri
|
clientUri: OAUTH3.clientUri
|
||||||
, query: OAUTH3.query
|
, query: OAUTH3.query
|
||||||
, parseSubject: function (sub) {
|
|
||||||
var parts = sub.split('@');
|
|
||||||
var issuer;
|
|
||||||
var subject;
|
|
||||||
|
|
||||||
if (/@/.test(sub)) {
|
|
||||||
// The username may have a single @, the provider may not
|
|
||||||
// user@thing.com@whatever.com -> user@thing.com, whatever.com
|
|
||||||
issuer = parts.pop();
|
|
||||||
subject = parts.join('@');
|
|
||||||
} else {
|
|
||||||
//subject = '';
|
|
||||||
issuer = parts.join('@');
|
|
||||||
}
|
|
||||||
|
|
||||||
return { subject: subject, issuer: issuer };
|
|
||||||
}
|
|
||||||
, scope: OAUTH3.scope
|
, scope: OAUTH3.scope
|
||||||
, uri: OAUTH3.uri
|
, uri: OAUTH3.uri
|
||||||
, url: OAUTH3.url
|
, url: OAUTH3.url
|
||||||
|
|
120
oauth3.issuer.js
120
oauth3.issuer.js
|
@ -218,7 +218,6 @@ OAUTH3.urls.grants = function (directive, opts) {
|
||||||
, session: opts.session
|
, session: opts.session
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
//OAUTH3.urls.accessToken = function (directive, opts)
|
|
||||||
OAUTH3.urls.clientToken = function (directive, opts) {
|
OAUTH3.urls.clientToken = function (directive, opts) {
|
||||||
var tokenDir = directive.access_token;
|
var tokenDir = directive.access_token;
|
||||||
if (!tokenDir) {
|
if (!tokenDir) {
|
||||||
|
@ -295,7 +294,7 @@ OAUTH3.urls.credentialMeta = function (directive, opts) {
|
||||||
.replace(':id', opts.email)
|
.replace(':id', opts.email)
|
||||||
};
|
};
|
||||||
|
|
||||||
OAUTH3.authn = OAUTH3.authn || {};
|
OAUTH3.authn = {};
|
||||||
OAUTH3.authn.loginMeta = function (directive, opts) {
|
OAUTH3.authn.loginMeta = function (directive, opts) {
|
||||||
var url = OAUTH3.urls.credentialMeta(directive, opts);
|
var url = OAUTH3.urls.credentialMeta(directive, opts);
|
||||||
return OAUTH3.request({
|
return OAUTH3.request({
|
||||||
|
@ -371,8 +370,8 @@ OAUTH3.authn.resourceOwnerPassword = function (directive, opts) {
|
||||||
OAUTH3.authz = {};
|
OAUTH3.authz = {};
|
||||||
OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
|
OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
|
||||||
var clientUri = OAUTH3.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 || 'authn@oauth3.org';
|
var scope = clientParams.scope || 'oauth3_authn';
|
||||||
if ('authn@oauth3.org' === scope.toString()) {
|
if ('oauth3_authn' === scope) {
|
||||||
// implicit ppid grant is automatic
|
// implicit ppid grant is automatic
|
||||||
console.warn('[security] fix scope checking on backend so that we can do automatic grants');
|
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
|
// TODO check user preference if implicit ppid grant is allowed
|
||||||
|
@ -574,85 +573,68 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s
|
||||||
};
|
};
|
||||||
|
|
||||||
OAUTH3.requests = {};
|
OAUTH3.requests = {};
|
||||||
//OAUTH3.accounts = {};
|
|
||||||
OAUTH3.requests.accounts = {};
|
OAUTH3.requests.accounts = {};
|
||||||
OAUTH3.urls.accounts = {};
|
OAUTH3.requests.accounts.update = function (directive, session, opts) {
|
||||||
OAUTH3.urls.accounts._ = function (directives, directive, session, opts) {
|
var dir = directive.update_account || {
|
||||||
opts = opts || {};
|
method: 'POST'
|
||||||
var dir = directive || {
|
, url: OAUTH3.url.normalize(directive.api) + '/api/issuer@oauth3.org/accounts/:accountId'
|
||||||
//url: OAUTH3.url.normalize(directives.api) + '/api/issuer@oauth3.org/accounts/:accountId'
|
|
||||||
url: OAUTH3.url.normalize(directives.api) + '/api/issuer@oauth3.org/acl/profiles/:accountId'
|
|
||||||
//, method: 'GET'
|
|
||||||
, bearer: 'Bearer'
|
, bearer: 'Bearer'
|
||||||
};
|
};
|
||||||
var url = dir.url
|
var url = dir.url
|
||||||
.replace(/:accountId/, opts.accountId || '')
|
.replace(/:accountId/, opts.accountId)
|
||||||
.replace(/\/$/, '')
|
|
||||||
;
|
;
|
||||||
|
|
||||||
return {
|
return OAUTH3.request({
|
||||||
url: url
|
method: dir.method || 'POST'
|
||||||
//, method: dir.method || 'POST'
|
, url: url
|
||||||
, session: session
|
|
||||||
/*
|
|
||||||
, headers: {
|
, headers: {
|
||||||
'Authorization': (dir.bearer || 'Bearer') + ' ' + (session.access_token || session.accessToken)
|
'Authorization': (dir.bearer || 'Bearer') + ' ' + session.accessToken
|
||||||
}
|
}
|
||||||
*/
|
, json: {
|
||||||
};
|
name: opts.name
|
||||||
|
, comment: opts.comment
|
||||||
|
, displayName: opts.displayName
|
||||||
|
, priority: opts.priority
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
OAUTH3.urls.accounts.get = function (directives, session) {
|
OAUTH3.requests.accounts.create = function (directive, session, account) {
|
||||||
var urlObj = OAUTH3.urls.accounts._(directives, directives.account, session);
|
var dir = directive.create_account || {
|
||||||
urlObj.method = (directives.account || { method: 'GET' }).method;
|
method: 'POST'
|
||||||
return urlObj;
|
, url: OAUTH3.url.normalize(directive.api) + '/api/issuer@oauth3.org/accounts'
|
||||||
};
|
, bearer: 'Bearer'
|
||||||
OAUTH3.urls.accounts.update = function (directives, session, opts) {
|
|
||||||
var urlObj = OAUTH3.urls.accounts._(directives, directives.update_account, session, opts);
|
|
||||||
urlObj.method = (directives.update_account || { method: 'POST' }).method;
|
|
||||||
urlObj.json = {
|
|
||||||
name: opts.name
|
|
||||||
, comment: opts.comment
|
|
||||||
, displayName: opts.displayName
|
|
||||||
, priority: opts.priority
|
|
||||||
};
|
};
|
||||||
return urlObj;
|
var data = {
|
||||||
};
|
|
||||||
OAUTH3.urls.accounts.create = function (directives, session, account) {
|
|
||||||
var urlObj = OAUTH3.urls.accounts._(directives, directives.create_account, session);
|
|
||||||
var profile = {
|
|
||||||
nick: account.display_name
|
|
||||||
// "name" is unique and what would be reserved in a url {{name}}.issuer.org or issuer.org/users/{{name}}
|
|
||||||
, name: account.name
|
|
||||||
, comment: account.comment
|
|
||||||
, display_name: account.display_name
|
|
||||||
, priority: account.priority
|
|
||||||
};
|
|
||||||
var credentials = [ { token: session.access_token } ];
|
|
||||||
urlObj.method = (directives.create_account || { method: 'POST' }).method;
|
|
||||||
urlObj.json = {
|
|
||||||
// TODO fix the server to just use one scheme
|
// TODO fix the server to just use one scheme
|
||||||
// account = { nick, self: { comment, username } }
|
// account = { nick, self: { comment, username } }
|
||||||
// account = { name, comment, display_name, priority }
|
// account = { name, comment, display_name, priority }
|
||||||
credentials: credentials
|
account: {
|
||||||
, profile: profile
|
nick: account.display_name
|
||||||
// 'account' is deprecated in favor of 'profile'
|
, name: account.name
|
||||||
, account: profile
|
, comment: account.comment
|
||||||
// 'logins' is deprecated in favor of 'credentials'
|
, display_name: account.display_name
|
||||||
, logins: credentials
|
, 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 urlObj;
|
|
||||||
};
|
return OAUTH3.request({
|
||||||
OAUTH3.requests.accounts.get = function (directives, session) {
|
method: dir.method || 'POST'
|
||||||
var urlObj = OAUTH3.urls.accounts.get(directives, session);
|
, url: dir.url
|
||||||
return OAUTH3.request(urlObj);
|
, session: session
|
||||||
};
|
, data: data
|
||||||
OAUTH3.requests.accounts.update = function (directives, session, opts) {
|
});
|
||||||
var urlObj = OAUTH3.urls.accounts.update(directives, session, opts);
|
|
||||||
return OAUTH3.request(urlObj);
|
|
||||||
};
|
|
||||||
OAUTH3.requests.accounts.create = function (directive, session, account) {
|
|
||||||
var urlObj = OAUTH3.urls.accounts.create(directives, session, account);
|
|
||||||
return OAUTH3.request(urlObj);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OAUTH3.hooks.grants = {
|
OAUTH3.hooks.grants = {
|
||||||
|
|
|
@ -27,10 +27,10 @@
|
||||||
|
|
||||||
OAUTH3.authz.scopes = function () {
|
OAUTH3.authz.scopes = function () {
|
||||||
return OAUTH3.PromiseA.resolve({
|
return OAUTH3.PromiseA.resolve({
|
||||||
pending: [ 'authn@oauth3.org' ] // not yet accepted
|
pending: ['oauth3_authn'] // not yet accepted
|
||||||
, granted: [] // all granted, ever
|
, granted: [] // all granted, ever
|
||||||
, requested: [ 'authn@oauth3.org' ] // all requested, now
|
, requested: ['oauth3_authn'] // all requested, now
|
||||||
, accepted: [] // granted (ever) and requested (now)
|
, accepted: [] // granted (ever) and requested (now)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
OAUTH3.authz.grants = function (providerUri, opts) {
|
OAUTH3.authz.grants = function (providerUri, opts) {
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
_apis
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
<!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);
|
||||||
|
|
||||||
|
var fileWhiteList = [
|
||||||
|
"directives.json"
|
||||||
|
, "scopes.json" ];
|
||||||
|
|
||||||
|
//Serving arbitrary files/paths is probably not a good idea.
|
||||||
|
//Let's make sure this is something we want to serve.
|
||||||
|
if(fileWhiteList.indexOf(params.discoverFile) === -1) {
|
||||||
|
//Nope!
|
||||||
|
var redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({
|
||||||
|
state: params.state
|
||||||
|
, error: "No access to requested file: " + params.discoverFile
|
||||||
|
, error_code: "E_ACCESS_DENIED"
|
||||||
|
, debug: params.debug || undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
console.error(prefix, "Requested file is not listed as a discoverable file:"
|
||||||
|
, fileWhiteList);
|
||||||
|
console.log("Redirecting with error: ", 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/>The requested file was not a discoverable file (see console for details).'
|
||||||
|
+ '<br/><br/>Continue with error redirect: <a href="' + redirect + '">' + redirect + '</' + 'a>';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OAUTH3.request({ url: params.discoverfile }).then(function (resp) {
|
||||||
|
var urlsafe64 = OAUTH3._base64.encodeUrlSafe(JSON.stringify(resp.data, null, 0));
|
||||||
|
var redirect;
|
||||||
|
var returnParams;
|
||||||
|
|
||||||
|
console.log(prefix, 'file contents');
|
||||||
|
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 //kept for now, probably should remove this.
|
||||||
|
, result: 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>
|
Loading…
Reference in New Issue