Compare commits

..

43 Commits

Author SHA1 Message Date
b8253fa500 update sponsor 2018-04-23 22:08:07 +00:00
AJ ONeal
25d7874104 Merge branch 'v1.2' into v1 2017-11-13 11:27:52 -07:00
AJ ONeal
a2ecd36db4 update urls 2017-11-13 11:27:50 -07:00
AJ ONeal
8c09dccd2e update urls 2017-11-10 12:21:40 -07:00
AJ ONeal
6953f535a1 Merge branch 'master' into v1.2 2017-11-10 12:18:14 -07:00
AJ ONeal
426d6a4cbe update paths and urls 2017-11-10 12:17:36 -07:00
AJ ONeal
ff5c13f3fc add standard files 2017-11-10 12:12:38 -07:00
e4a84ea0b5 begin token inspector 2017-11-08 21:55:04 +00:00
fdf7897b09 Merge branch 'checkbox-fix' into v1.2 2017-11-08 20:15:32 +00:00
ad454ba7b6 The grant checkboxes are now initialing correctly 2017-11-07 14:45:40 -07:00
40bfe2e534 Clicking grant labels now correctly toggles the check mark. 2017-11-07 14:23:26 -07:00
aj
e1701ffdd9 checkout v1.2 to match current branch 2017-10-23 23:13:05 +00:00
AJ ONeal
03f5186659 Merge branch 'master' into v1.1 2017-10-23 21:45:00 +00:00
AJ ONeal
5719f6a78e merge with daplie.me 2017-10-23 21:29:16 +00:00
tigerbot
d28ab68abc Merge branch 'issuer-rewrite'
# Conflicts:
#	README.md
#	index.html
#	install.sh
2017-10-19 16:49:03 -06:00
tigerbot
8bf164b5aa Merge branch 'daplie.me' 2017-10-19 16:38:28 -06:00
aj
cc066a0bcd org.oauth3 -> oauth3.org 2017-08-15 20:28:03 +00:00
aj
7d18f05baf org.oauth3 -> oauth3.org 2017-08-15 20:26:10 +00:00
aj
3c3100a851 add some scopes 2017-08-12 00:02:07 +00:00
tigerbot
3645d66f5c Merge branch 'daplie.me' into issuer-rewrite 2017-08-07 11:20:51 -06:00
AJ ONeal
e5cd4ada23 Merge branch 'daplie.me' of git.daplie.com:OAuth3/org.oauth3 into daplie.me 2017-08-01 18:27:04 +00:00
AJ ONeal
c2b6d2b7ed use proper scope names 2017-08-01 18:26:08 +00:00
AJ ONeal
1b0c5417bf cleanup 2017-08-01 18:24:38 +00:00
tigerbot
8f30d80b38 changed how the "remember me" checkbox is handled 2017-08-01 11:39:20 -06:00
tigerbot
3e81aebc4a removed funky character from the html 2017-07-27 13:06:05 -06:00
tigerbot
9b61d7c464 made some indentation in index.html more consistent 2017-07-27 11:55:03 -06:00
tigerbot
7902dea5f3 removed useless check for account existence 2017-07-26 18:16:30 -06:00
tigerbot
cd1ff73eea handled case of un-refreshable saved session 2017-07-25 16:55:12 -06:00
tigerbot
ea788bcb76 reduced duplicate parsing of location 2017-07-25 16:55:12 -06:00
Jon Lambson
dc5139686e changing back to daplie.me 2017-07-12 10:44:28 -06:00
Jon Lambson
210df2a4c8 changed to safelogin.org 2017-07-12 10:39:01 -06:00
Jon Lambson
22b1d535ca fixing error 2017-07-12 10:28:13 -06:00
Jon Lambson
1642251cb7 clearing error 2017-07-12 10:26:53 -06:00
Jon Lambson
1d02c1d424 error msg 2017-07-12 10:08:56 -06:00
Jon Lambson
d446057524 fixing typo 2017-07-12 10:00:49 -06:00
Jon Lambson
624ccf02a0 i donno 2017-07-12 09:59:07 -06:00
Jon Lambson
37bd95fd54 testing 2017-07-12 09:56:17 -06:00
Jon Lambson
837bdd80c9 fixing js 2017-07-11 16:40:36 -06:00
Jon Lambson
c588ea7d3d fixing disabled 2017-07-11 16:29:07 -06:00
Jon Lambson
e9a4ff8f9a added validation for maxLength 2017-07-11 16:09:42 -06:00
Jon Lambson
e748d8f849 removing incorrect js 2017-07-11 12:44:11 -06:00
Jon Lambson
a2364ac874 closing popup after denying app 2017-07-11 11:58:38 -06:00
Jon Lambson
acb366767a safelogin.org to daplie.me 2017-07-10 16:28:28 -06:00
12 changed files with 292 additions and 216 deletions

BIN
.DS_Store vendored

Binary file not shown.

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
*.*sw* *.*sw*
bower_components/ bower_components/
assets/ assets/
.DS_Store

5
CHANGELOG Normal file
View File

@ -0,0 +1,5 @@
v1.2.1 - Authorization Dialog for ID Issuer
* Resource Owner Password token exchange
* Public / Private Keypair generation
* Public key (remember device) syncing
* BUG: Remember me is not operational

41
LICENSE Normal file
View File

@ -0,0 +1,41 @@
Copyright 2017 Daplie, Inc
This is open source software; you can redistribute it and/or modify it under the
terms of either:
a) the "MIT License"
b) the "Apache-2.0 License"
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Apache-2.0 License Summary
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,20 +1,30 @@
This is a WALNUT module representing the html package for oauth3.org. issuer.html
===========
It must be installed to `/srv/walnut/packages/pages/issuer@oauth3.org` | [oauth3.js](https://git.oauth3.org/OAuth3/oauth3.js)
| *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 [ppl](https://ppl.family)
This is a browser application which implements the issuer side of the *authorization_dialog* flow for OAuth3.
It may be used client-side only (public key or granted scope syncing will be disabled),
or will the *issuer.rest.walnut.js* APIs on the backend for full functionality.
For use with walnut it must be installed to `/opt/walnut/packages/pages/issuer@oauth3.org`
```bash ```bash
git clone git@git.daplie.com:OAuth3/issuer_oauth3.org.git /srv/walnut/packages/pages/issuer@oauth3.org git clone git@git.oauth3.org:OAuth3/org.oauth3.git /opt/walnut/packages/pages/issuer@oauth3.org
ln -s issuer@oauth3.org /srv/walnut/packages/pages/org.oauth3 pushd /opt/walnut/packages/pages/issuer@oauth3.org
pushd /srv/walnut/packages/pages/issuer@oauth3.org
bash ./install.sh bash ./install.sh
popd popd
``` ```
```bash ```bash
echo "issuer@oauth3.org" >> /srv/walnut/packages/sites/EXAMPLE.COM echo "issuer@oauth3.org" >> /opt/walnut/var/sites/EXAMPLE.COM
echo "org.oauth3" >> /srv/walnut/packages/sites/EXAMPLE.COM
``` ```
This uses the OAuth3 JavaScript SDK `oauth3.js` as a subpackage in `/srv/walnut/packages/pages/issuer@oauth3.org/assets/oauth3.org`. This uses the OAuth3 JavaScript SDK `oauth3.js` as a subpackage in
`/opt/walnut/packages/pages/issuer@oauth3.org/assets/oauth3.org`.
The 'login popup' is hosted on our tardigrade proxy VM.

View File

@ -12,10 +12,6 @@ html, body {
background-color: #282828; background-color: #282828;
color: #FFFFFF; color: #FFFFFF;
} }
/*override bootstrap fade*/
.fade {
opacity: 1;
}
input.emailInput::placeholder { input.emailInput::placeholder {
font-family : Brown Regular; font-family : Brown Regular;
font-size : 14px; font-size : 14px;
@ -445,3 +441,6 @@ span.dap-small-text.js-scope-desc.noselect {
color : #808080; color : #808080;
color : rgb(128, 128, 128); color : rgb(128, 128, 128);
} }
.error-msg {
color: #FDA748;
}

BIN
img/.DS_Store vendored

Binary file not shown.

View File

@ -1,30 +1,31 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login Facilitator: OAuth3.org</title> <title>Login Facilitator: OAuth3.org</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
<!-- <link rel="stylesheet" type="text/css" href="/css/style.css"> --> <!-- <link rel="stylesheet" type="text/css" href="/css/style.css"> -->
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:300"> <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:300">
<script src="https://use.fontawesome.com/3af0faae66.js"></script> <script src="https://use.fontawesome.com/3af0faae66.js"></script>
<link rel="stylesheet" type="text/css" href="/css/daplie-installer-overrides.css"> <link rel="stylesheet" type="text/css" href="/css/daplie-installer-overrides.css">
</head> </head>
<body class="fade mock-main"> <body>
<div class="fade mock-main">
<!-- STEP 1: ask the user where they want to log in --> <!-- STEP 1: ask the user where they want to log in -->
<!-- STEP 2: ask the user for their email --> <!-- STEP 2: ask the user for their email -->
<!-- STEP 3+4: ask for login code and to remember device --> <!-- STEP 3+4: ask for login code and to remember device -->
<!-- TODO: remember-me-not implementation? --> <!-- TODO: remember-me-not implementation? -->
<!-- <button class="btn btn-secondary js-authz-show js-authz-remember-me-not">Just this once</button>--> <!-- <button class="btn btn-secondary js-authz-show js-authz-remember-me-not">Just this once</button>-->
<!-- Step 5: ask for permissions --> <!-- Step 5: ask for permissions -->
<div class="dap-bordered js-userid-container"> <div class="dap-bordered js-userid-container">
<p class="org-title">Safelogin.org</p> <p class="org-title">daplie.me</p>
<p class="dap-centered-text dap-normal-text welcome-text center-it">Welcome to a new way to login. Safelogin.org helps you create an Internet ID that allows you to choose what info is shared about you when you login into a site or app online.</p> <p class="dap-centered-text dap-normal-text welcome-text center-it">Welcome to a new way to login. daplie.me helps you create an Internet ID that allows you to choose what info is shared about you when you login into a site or app online.</p>
<form method="post" action=""> <form method="post" action="">
<div class="form-group"> <div class="form-group">
<input type="email" class="form-control dap-input js-oauth3-email emailInput" placeholder="Enter an email address to start"></input> <input type="email" class="form-control dap-input js-oauth3-email emailInput" placeholder="Enter an email address to start"></input>
@ -45,7 +46,7 @@
</div> </div>
<div class="dap-bordered js-authn"> <div class="dap-bordered js-authn">
<p class="org-title">Safelogin.org</p> <p class="org-title">daplie.me</p>
<!-- <div class="dap-normal-text"> <!-- <div class="dap-normal-text">
<span class="fa fa-3x icon-centered-3x fa-purple fa-envelope"></span> <span class="fa fa-3x icon-centered-3x fa-purple fa-envelope"></span>
</div> </div>
@ -61,6 +62,7 @@
<p class="code-lasts-text">Code lasts for 15 minutes.</p> <p class="code-lasts-text">Code lasts for 15 minutes.</p>
<input type="hidden" class="js-authn-otp-uuid"> <input type="hidden" class="js-authn-otp-uuid">
<input class="dap-input js-authn-otp-code form-control" placeholder="XXXX-XXXX-XXXX" maxlength="14"></input> <input class="dap-input js-authn-otp-code form-control" placeholder="XXXX-XXXX-XXXX" maxlength="14"></input>
<p class="error-msg"></p>
</div> </div>
<div class="dap-centered-div dap-space-on-top form-group"> <div class="dap-centered-div dap-space-on-top form-group">
<label class="js-remember-label dap-normal-text"> <label class="js-remember-label dap-normal-text">
@ -70,8 +72,7 @@
<input class="js-remember-checkbox hidden" type="checkbox"></input> <input class="js-remember-checkbox hidden" type="checkbox"></input>
</label> </label>
</div> </div>
<!-- <button class="dap-full-button-green js-remember-btn js-authz-remember-me">SIGN IN ONCE</button> --> <button type="submit" class="btn btn-primary submit-btn dap-full-button-green js-submit-code-btn" disabled>Submit</button>
<button type="submit" class="btn btn-primary submit-btn dap-full-button-green js-remember-btn js-authz-remember-me">Submit</button>
<!-- <a href="./authnocode.html" target="_blank" class="btn btn-primary">Send Code Again</a> --> <!-- <a href="./authnocode.html" target="_blank" class="btn btn-primary">Send Code Again</a> -->
<button class="btn btn-primary js-edit-email-button" type="button">Edit My Email</button> <button class="btn btn-primary js-edit-email-button" type="button">Edit My Email</button>
</form> </form>
@ -85,14 +86,14 @@
</div> </div>
<div class="dap-bordered dap-normal-text js-authz"> <div class="dap-bordered dap-normal-text js-authz">
<p class="org-title">Safelogin.org</p> <p class="org-title">daplie.me</p>
<!-- <br> --> <!-- <br> -->
<!-- <div class="dap-user-plus-app"> <!-- <div class="dap-user-plus-app">
<span class="fa fa-3x fa-purple fa-user-circle"></span> <span class="fa fa-3x fa-purple fa-user-circle"></span>
<span class="fa fa-2x fa-gray fa-plus"></span> <span class="fa fa-2x fa-gray fa-plus"></span>
<img class="dap-lab-logo" src="./img/Daplie-Badge-Purple.png" alt="Daplie Labs Logo"> <img class="dap-lab-logo" src="./img/Daplie-Badge-Purple.png" alt="Daplie Labs Logo">
</div> --> </div> -->
<p class="dap-centered-text dap-normal-text almost-done-text">Almost done. Now its time to set your preferences.</p> <p class="dap-centered-text dap-normal-text almost-done-text">Almost done. Now it's time to set your preferences.</p>
<br> <br>
<form class="js-authorization-decision" action="#"> <form class="js-authorization-decision" action="#">
@ -139,17 +140,60 @@
<button type="button" class="dap-full-button-green js-logout btn btn-primary">Sign Out</button> <button type="button" class="dap-full-button-green js-logout btn btn-primary">Sign Out</button>
<img src="./img/sponsored-by.png" class="sponsored-by-logo"> <img src="./img/sponsored-by.png" class="sponsored-by-logo">
</div> </div>
</div>
<div class="fade mock-bare">
<div class="container">
<div class="jumbotron">
<h1>OAuth3 Playground</h1>
</div>
<div class="row">
<div class="col-md-3">
Login Status:
</div>
<div class="col-md-9">
...
</div>
</div>
<div class="row">
<div class="col-md-3">
Current Sessions:
</div>
<div class="col-md-9">
...
</div>
</div>
<div class="row">
<div class="col-md-3">
Approved Devices:
</div>
<div class="col-md-9">
...
</div>
</div>
<div class="row">
<div class="col-md-3">
Approved Applications:
</div>
<div class="col-md-9">
...
</div>
</div>
</div>
</div>
<!--[if IE]><script src="bower_components/rsvp.js/rsvp.js"></script><![endif]--> <!--[if IE]><script src="bower_components/rsvp.js/rsvp.js"></script><![endif]-->
<script src="./js/jquery-2.2.0.min.js"></script> <script src="./js/jquery-2.2.0.min.js"></script>
<script src="./js/jquery.mask.min.js"></script> <script src="./js/jquery.mask.min.js"></script>
<script src="./js/bootstrap.min.js"></script> <script src="./js/bootstrap.min.js"></script>
<script src="/assets/oauth3.org/oauth3.core.js"></script>
<script src="/assets/oauth3.org/oauth3.crypto.js"></script>
<script src="/assets/oauth3.org/oauth3.issuer.js"></script>
<script src="./js/issuer.js"></script> <script src="./js/issuer.js"></script>
<script src="./js/script.js"></script> <script src="./js/script.js"></script>
<script src="/assets/oauth3.org/oauth3.core.js"></script>
<script src="/assets/oauth3.org/oauth3.issuer.js"></script>
<!--script src="/assets/oauth3.org/oauth3.mock.js"></script-->
</body> </body>
</html> </html>

View File

@ -2,14 +2,15 @@
set -e set -e
set -u set -u
# git clone https://git.daplie.com/OAuth3/issuer_oauth3.org.git /srv/walnut/packages/pages/issuer@oauth3.org # git clone https://git.oauth3.org/OAuth3/issuer.html.git /srv/walnut/packages/pages/issuer@oauth3.org
# git clone https://git.oauth3.org/OAuth3/azp.html.git /srv/walnut/packages/pages/azp@oauth3.org
mkdir -p assets mkdir -p assets
if ! [ -d ./assets/oauth3.org ]; then if ! [ -d ./assets/oauth3.org ]; then
git clone https://git.daplie.com/OAuth3/oauth3.js.git ./assets/oauth3.org git clone https://git.oauth3.org/OAuth3/oauth3.js.git ./assets/oauth3.org
fi fi
pushd ./assets/oauth3.org pushd ./assets/oauth3.org
git checkout v1 git checkout v1.2
git pull git pull
popd popd

View File

@ -10,7 +10,7 @@ $(function () {
var auth = OAUTH3.create(); var auth = OAUTH3.create();
auth.init().then(function () { auth.init().then(function () {
$('body').addClass('in'); $('.mock-main').addClass('in');
}); });
auth.setProvider(providerUri).then(function () { auth.setProvider(providerUri).then(function () {

View File

@ -9,7 +9,7 @@ $(function () {
var OAUTH3 = window.OAUTH3; var OAUTH3 = window.OAUTH3;
var CONFIG = { var CONFIG = {
host: OAUTH3.utils.clientUri(window.location) host: OAUTH3.clientUri(window.location)
, directives: null // will be populated before the login button appears , directives: null // will be populated before the login button appears
}; };
var loc = window.location; var loc = window.location;
@ -20,22 +20,8 @@ $(function () {
}; };
$('.js-scopes-container').html(''); $('.js-scopes-container').html('');
/*
OAUTH3._hooks.sessions.all = function (providerUri) {
};
*/
OAUTH3._hooks = { sessions: {} };
OAUTH3._hooks.sessions.get = function (providerUri, id) {
return JSON.parse(window.localStorage.getItem('session-' + providerUri + (id || '')) || 'null');
};
OAUTH3._hooks.sessions.set = function (providerUri, newSession, id) {
window.localStorage.setItem('session-' + providerUri, JSON.stringify(newSession));
window.localStorage.setItem('session-' + providerUri + (id || newSession.id || newSession.token.id || ''), JSON.stringify(newSession));
return newSession;
};
// TODO let query.parse do location.hash || location.search || location // TODO let query.parse do location.hash || location.search || location
var clientParams = OAUTH3.query.parse(window.location.hash || window.location.search); var clientParams = OAUTH3.query.parse(loc.hash || loc.search);
if (/authorization_dialog/.test(window.location.href)) { if (/authorization_dialog/.test(window.location.href)) {
// OAUTH3.lintClientParams(params, window) // OAUTH3.lintClientParams(params, window)
// OAUTH3.normalizeClientParams(params, window) // OAUTH3.normalizeClientParams(params, window)
@ -58,12 +44,12 @@ $(function () {
+ "'" + OAUTH3.url.normalize(window.document.referrer) + "'" + "'" + OAUTH3.url.normalize(window.document.referrer) + "'"
); );
} }
if (clientParams.client_uri) { if (clientParams.client_uri && clientParams.client_uri !== clientParams.client_id) {
console.warn("'client_id' should be used instead of 'client_uri'"); console.warn("'client_id' should be used instead of 'client_uri'");
} }
if (!(clientParams.client_id || clientParams.client_uri)) { if (!(clientParams.client_id || clientParams.client_uri)) {
window.alert("'response_type' must exist and be either 'token' (implicit flow) or 'code' (authorization flow)"); window.alert("'client_id' must exist as the uri identifying the client");
console.error("'response_type' must exist and be either 'token' (implicit flow) or 'code' (authorization flow)"); console.error("'client_id' must exist as the uri identifying the client");
clientParams.client_id = clientParams.client_uri = OAUTH3.url.normalize(window.document.referrer); clientParams.client_id = clientParams.client_uri = OAUTH3.url.normalize(window.document.referrer);
} }
if (!clientParams.redirect_uri) { if (!clientParams.redirect_uri) {
@ -88,32 +74,47 @@ $(function () {
function getSession(providerUri) { function getSession(providerUri) {
return OAUTH3.hooks.session.get(providerUri).then(function (session) { return OAUTH3.hooks.session.get(providerUri).then(function (session) {
if (session && session.access_token) { if (session && session.access_token) {
normalizeSession(session); normalizeSession(session);
return OAUTH3.PromiseA.resolve(session); return OAUTH3.PromiseA.resolve(session);
} }
else { else {
return OAUTH3.PromiseA.reject(new Error("no access_token in session")); return OAUTH3.PromiseA.reject(new Error("no access_token in session"));
} }
}); });
} }
function getGrants(session) { function getGrants(session) {
var clientObj = OAUTH3.query.parse(loc.hash || loc.search); var clientLogo = OAUTH3.url.normalize(clientParams.client_uri) // optional relative logo ?
var clientLogo = OAUTH3.url.normalize(clientObj.client_uri) // optional relative logo ?
+ '/.well-known/oauth3/logo-128x128.png' + '/.well-known/oauth3/logo-128x128.png'
; ;
var callbackUrl;
// TODO put in directives.json or similar // TODO put in directives.json or similar
var grantDescriptions = { var grantDescriptions = {
// deprecated
'oauth3_authn': "Basic secure authentication" 'oauth3_authn': "Basic secure authentication"
, 'auth@oauth3.org': "Basic secure authentication"
, 'wallet': "Access to payments and subscriptions" , 'wallet': "Access to payments and subscriptions"
, 'bucket': "Access to file storage" , 'bucket': "Access to file storage"
, 'db': "Access to app data" , 'db': "Access to app data"
, 'domains': "Domain registration (and Glue and NS records)" // TODO make an alias , 'domains': "Domain registration (and Glue and NS records)" // TODO make an alias
, 'domains@oauth3.org': "Domain registration (and Glue and NS records)" // TODO make an alias
, 'domains:glue': "Glue Record management (for vanity nameservers)" , 'domains:glue': "Glue Record management (for vanity nameservers)"
, 'domains:ns': "Name Server management" , 'domains:ns': "Name Server management"
, 'dns': "DNS records (A/AAAA, TXT, SRV, MX, etc)" , 'dns': "DNS records (A/AAAA, TXT, SRV, MX, etc)"
// new
, '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)" // TODO make an alias
, '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" , '*': "FULL ACCOUNT ACCESS"
}; };
@ -127,10 +128,10 @@ $(function () {
$('.js-client-logo').attr('src', clientLogo); $('.js-client-logo').attr('src', clientLogo);
//$('.js-user-avatar').attr('src', userAvatar); //$('.js-user-avatar').attr('src', userAvatar);
return OAUTH3.authz.scopes(CONFIG.host, session, clientObj).then(function (scopes) { return OAUTH3.authz.scopes(CONFIG.host, session, clientParams).then(function (scopes) {
if (!scopes.pending.length) { if (!scopes.pending.length) {
// looks like we've done all of this before // looks like we've done all of this before
OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientObj, scopes); OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientParams, scopes);
return; return;
} }
@ -138,10 +139,12 @@ $(function () {
// TODO secure iFrame from click-jacking by requiring input? // TODO secure iFrame from click-jacking by requiring input?
// ex: input.security-code[type="text"].val(Math.random()); input.js-verify-code[placeholder="Type what you see"] // ex: input.security-code[type="text"].val(Math.random()); input.js-verify-code[placeholder="Type what you see"]
if (OAUTH3._browser.isIframe()) { if (OAUTH3._browser.isIframe()) {
callbackUrl = clientObj.redirect_uri + '#state=' + clientObj.state + '&error=access_denied&error_description=' location.href = clientParams.redirect_uri +'#'+ OAUTH3.query.stringify({
+ encodeURIComponent("You're requesting permission in an iframe, but the permissions have not yet been granted") state: clientParams.state
+ '&error_uri=' + encodeURIComponent('https://oauth3.org/docs/errors/#E_IFRAME_DENIED'); , error: 'access_denied'
location.href = callbackUrl; , error_description: encodeURIComponent("You're requesting permission in an iframe, but the permissions have not yet been granted")
, error_uri: encodeURIComponent('https://oauth3.org/docs/errors/#E_IFRAME_DENIED')
});
return; return;
} }
@ -165,8 +168,13 @@ $(function () {
$scope.find('.js-scope-desc').text(grantDescriptions[scope]); $scope.find('.js-scope-desc').text(grantDescriptions[scope]);
} }
else { else {
$scope.find('.js-scope-toggle').prop('checked', false); //This disables the check/checkbox when we have an unrecognized grant.
$scope.find('.js-scope-toggle').prop('disabled', true); //This is disabled for testing until we can discover grants automatically.
//TODO: Enable this when grants are discoverable
//TODO: Indicate to user that this is disabled, not just unchecked.
//$scope.find('.js-scope-toggle').prop('checked', false);
//$scope.find('.check').attr("src", "./img/unpressed-check.png");
//$scope.find('.js-scope-toggle').prop('disabled', true);
$scope.find('.js-scope-desc').text(scope); $scope.find('.js-scope-desc').text(scope);
} }
@ -174,9 +182,6 @@ $(function () {
}); });
$('.js-authz').show().addClass('in'); $('.js-authz').show().addClass('in');
}, function (err) {
window.alert('grantResults: ' + err.message);
console.error('scope results', err);
}); });
} }
@ -212,56 +217,27 @@ $(function () {
// TODO loading // TODO loading
email = $('.js-oauth3-email').val(); email = $('.js-oauth3-email').val();
return OAUTH3.authn.loginMeta(CONFIG.directives, {email: email, mock: true}).then(function (userResults) { return OAUTH3.authn.otp(CONFIG.directives, {email: email, mock: true}).then(function (otpResults) {
if (!userResults.data.error) {
console.log('User exists:', userResults); if (otpResults.data.error) {
window.alert('otpResults: ' + otpResults.data.error_description || otpResults.data.error.message);
return;
} }
if (userResults.data.error) { var ua = window.navigator.userAgent;
$('.js-authn-show').removeAttr('disabled'); $('.js-sniffed-device').text(ua);
console.warn('User does not exist:', email); $('.js-userid-container').removeClass('in').hide();
console.warn('User Results:', userResults); $('.js-authn').show().addClass('in');
//window.alert('userResults: ' + userResults.data.error_description || userResults.data.error.message); $('.js-authn-otp-uuid').val(otpResults.data.uuid);
//return;
}
return OAUTH3.authn.otp(CONFIG.directives, {email: email, mock: true}).then(function (otpResults) { $('.js-user-email').text(email);
if (otpResults.data.error) {
window.alert('otpResults: ' + otpResults.data.error_description || otpResults.data.error.message);
return;
}
var ua = window.navigator.userAgent;
$('.js-sniffed-device').text(ua);
$('.js-userid-container').removeClass('in').hide();
$('.js-authn').show().addClass('in');
$('.js-authn-otp-uuid').val(otpResults.data.uuid);
$('.js-user-email').text(email);
});
});
};
util.rememberDevice = function (ev) {
ev.preventDefault();
ev.stopPropagation();
util.submitLoginCode({
rememberDevice: true
});
};
util.rememberDeviceNot = function (ev) {
ev.preventDefault();
ev.stopPropagation();
util.submitLoginCode({
rememberDevice: false
}); });
}; };
// Reference Implementation // Reference Implementation
util.submitLoginCode = function (ev) {
util.submitLoginCode = function (opts) { ev.preventDefault();
ev.stopPropagation();
// TODO // TODO
// perhaps we should check that the code is valid before continuing to login (so that we don't send the key) // perhaps we should check that the code is valid before continuing to login (so that we don't send the key)
@ -269,7 +245,6 @@ $(function () {
// TODO // TODO
// we should be sending the public key for this device as a jwk along with the authentication // we should be sending the public key for this device as a jwk along with the authentication
// (and how long to remember this device) // (and how long to remember this device)
var uuid = $('.js-authn-otp-uuid').val(); var uuid = $('.js-authn-otp-uuid').val();
var code = $('.js-authn-otp-code').val().trim(); var code = $('.js-authn-otp-code').val().trim();
return OAUTH3.authn.resourceOwnerPassword(CONFIG.directives, { return OAUTH3.authn.resourceOwnerPassword(CONFIG.directives, {
@ -283,36 +258,35 @@ $(function () {
// TODO should be otp_id (agnostic of uuid) // TODO should be otp_id (agnostic of uuid)
, otp_uuid: uuid , otp_uuid: uuid
// add expiration to the refresh token and/or public key // add expiration to the refresh token and/or public key
, expire: opts.rememberDevice || (1 * 60 * 60 * 1000) , remember_device: $('.js-remember-label').find('.js-remember-checkbox').prop('checked')
, mock: true , mock: true
}).then(function (session) { }).then(function (session) {
$('.js-authn').removeClass('in').hide(); $('.js-authn').removeClass('in').hide();
if (session.token.sub) {
function getAccount(session) { return OAUTH3.PromiseA.resolve(session);
if (session.token.sub) {
return OAUTH3.PromiseA.resolve(session);
}
return OAUTH3.requests.accounts.create(CONFIG.directives, session, {
display_name: email.replace(/@.*/, '')
, comment: "created for '" + email + "' by '" + CONFIG.host + "'"
, priority: 1000 // default priority for first account
, name: undefined // TODO we could ask in the UI
}).then(function (resp) {
var results = resp.data;
return OAUTH3.hooks.session.refresh(session, {
access_token: (results.access_token || results.accessToken)
, refresh_token: (results.refresh_token || results.refreshToken)
});
});
} }
return getAccount(session).then(function () { return OAUTH3.requests.accounts.create(CONFIG.directives, session, {
return getGrants(session); display_name: email.replace(/@.*/, '')
, comment: "created for '" + email + "' by '" + CONFIG.host + "'"
, priority: 1000 // default priority for first account
, name: undefined // TODO we could ask in the UI
}).then(function (resp) {
var results = resp.data;
return OAUTH3.hooks.session.refresh(session, {
access_token: (results.access_token || results.accessToken)
, refresh_token: (results.refresh_token || results.refreshToken)
});
}); });
}).then(function (session) {
return getGrants(session).catch(function (err) {
window.alert('grantResults: ' + err.message);
console.error('scope results', err);
});
}, function (error) {
console.error(error);
$('.error-msg').text('Incorrect code');
}); });
}; };
util.acceptScopesAndLogin = function (ev) { util.acceptScopesAndLogin = function (ev) {
ev.preventDefault(); ev.preventDefault();
@ -329,8 +303,6 @@ $(function () {
}); });
getSession(CONFIG.host).then(function (session) { getSession(CONFIG.host).then(function (session) {
var clientParams = OAUTH3.query.parse(loc.hash || loc.search);
return OAUTH3.authz.scopes(CONFIG.host, session, clientParams).then(function (scopes) { return OAUTH3.authz.scopes(CONFIG.host, session, clientParams).then(function (scopes) {
scopes.new = acceptedScopes; scopes.new = acceptedScopes;
return OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientParams, scopes); return OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientParams, scopes);
@ -344,21 +316,17 @@ $(function () {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
var loginWinObj = OAUTH3.query.parse(loc.hash || loc.search);
var denyObj = { var denyObj = {
error: 'access_denied' error: 'access_denied'
, error_description: 'The user has denied access.' , error_description: 'The user has denied access.'
, error_uri: 'https://' + CONFIG.host + '/.well-known/oauth3/errors.html#/?error=access_denied' , error_uri: 'https://' + CONFIG.host + '/.well-known/oauth3/errors.html#/?error=access_denied'
, state: loginWinObj.state , state: clientParams.state
, scope: loginWinObj.scope , scope: clientParams.scope
}; };
window.location = loginWinObj.redirect_uri + '#' + OAUTH3.query.stringify(denyObj); window.location = clientParams.redirect_uri + '#' + OAUTH3.query.stringify(denyObj);
}; };
util.handleLogout = function () { util.handleLogout = function () {
var clientParams = OAUTH3.query.parse(loc.hash || loc.search);
localStorage.clear(); localStorage.clear();
clientParams.redirect_uri += '?' + OAUTH3.query.stringify({ clientParams.redirect_uri += '?' + OAUTH3.query.stringify({
@ -371,21 +339,21 @@ $(function () {
util.editEmail = function () { util.editEmail = function () {
$('.js-authn').hide(); $('.js-authn').hide();
$('.js-userid-container').show(); $('.js-userid-container').show();
debugger;
}; };
// //
// Page Setup // Page Setup
// //
$('.js-authorization-dialog').hide();
$('.js-logout-container').hide();
$('.js-userid-container').hide(); $('.js-userid-container').hide();
$('.js-authn').hide(); $('.js-authn').hide();
$('.js-authz').hide(); $('.js-authz').hide();
$('body').on('click', '.js-logout', util.handleLogout); $('body').on('click', '.js-logout', util.handleLogout);
$('body').on('click', '.js-authn-show', util.submitAuthEmail); $('body').on('click', '.js-authn-show', util.submitAuthEmail);
$('body').on('click', '.js-authz-remember-me', util.rememberDevice); $('body').on('click', '.js-submit-code-btn', util.submitLoginCode);
$('body').on('click', '.js-authz-remember-me-not', util.rememberDeviceNot);
$('body').on('click', '.js-login-allow', util.acceptScopesAndLogin); $('body').on('click', '.js-login-allow', util.acceptScopesAndLogin);
$('body').on('click', '.js-login-deny', util.closeLoginDeny); $('body').on('click', '.js-login-deny', util.closeLoginDeny);
$('body').on('click', '.js-edit-email-button', util.editEmail); $('body').on('click', '.js-edit-email-button', util.editEmail);
@ -394,40 +362,33 @@ $(function () {
function handleAuthorizationDialog() { function handleAuthorizationDialog() {
return getSession(CONFIG.host).then(function (session) { return getSession(CONFIG.host).then(function (session) {
return getGrants(session); return getGrants(session);
}, function (e) { }).catch(function () {
var clientObj = OAUTH3.query.parse(loc.hash || loc.search);
// TODO select the providers the client wants to show // TODO select the providers the client wants to show
// providers=daplie.com,facebook.com,google.com // etc // providers=daplie.com,facebook.com,google.com // etc
// TODO let the client specify switch_user // TODO let the client specify switch_user
// TODO let the client specify relogin if stale // TODO let the client specify relogin if stale
if (OAUTH3._browser.isIframe()) { if (OAUTH3._browser.isIframe()) {
var callbackUrl = clientObj.redirect_uri + '#state=' + clientObj.state + '&error=access_denied&error_description=' location.href = clientParams.redirect_uri +'#'+ OAUTH3.query.stringify({
+ encodeURIComponent("You're requesting permission in an iframe, but the user is not yet authenticated") state: clientParams.state
+ '&error_uri=' + encodeURIComponent('https://oauth3.org/docs/errors/#E_IFRAME_DENIED'); , error: 'access_denied'
location.href = callbackUrl; , error_description: encodeURIComponent("You're requesting permission in an iframe, but the user is not yet authenticated")
, error_uri: encodeURIComponent('https://oauth3.org/docs/errors/#E_IFRAME_DENIED')
});
} }
if (clientParams.subject) { if (clientParams.subject) {
$('.js-oauth3-email').val(clientParams.subject); $('.js-oauth3-email').val(clientParams.subject);
$('.js-authn-show').prop('disabled', false); $('.js-authn-show').prop('disabled', false);
} }
$('.js-userid-container').show(); $('.js-userid-container').show();
}).then(function () {
//$('body').addClass('in');
}); });
} }
// Session initialization // Session initialization
return OAUTH3.discover( return OAUTH3.discover(CONFIG.host, { client_uri: CONFIG.host }).then(function (directives) {
OAUTH3.clientUri(window.location)
, { client_uri: OAUTH3.clientUri(window.location) }
).then(function (directives) {
// TODO cache directives in memory (and storage) // TODO cache directives in memory (and storage)
CONFIG.directives = directives; CONFIG.directives = directives;
directives.issuer = directives.issuer || (window.location.host + window.location.pathname).replace(/\/$/, ''); directives.issuer = directives.issuer || (window.location.host + window.location.pathname).replace(/\/$/, '');
$('.js-authorization-dialog').hide();
$('.js-logout-container').hide();
if (/authorization_dialog/.test(window.location.href)) { if (/authorization_dialog/.test(window.location.href)) {
$('.js-authorization-dialog').show(); $('.js-authorization-dialog').show();
handleAuthorizationDialog(); handleAuthorizationDialog();
@ -436,8 +397,13 @@ $(function () {
$('.js-logout-container').show(); $('.js-logout-container').show();
} }
$('body').addClass('in'); if (document.location.hash.slice(1) || document.location.search) {
console.log('[DEBUG] search:', document.location.search);
console.log('[DEBUG] hash:', document.location.search);
$('.mock-main').addClass('in');
} else {
console.log('[DEBUG] not an auth window');
$('.mock-bare').addClass('in');
}
}); });
}); });

View File

@ -47,50 +47,59 @@ $('body').on('click', '.js-remember-label', function (ev) {
$('body').on('click', '.check', function () { $('body').on('click', '.check', function () {
'use strict'; 'use strict';
var $img = $(this);
if($img.attr("src") === "./img/pressed-check.png") {
$img.attr("src", "./img/unpressed-check.png");
$img.removeClass("is-checked");
} else if($img.attr("src") === "./img/unpressed-check.png") {
$img.attr("src", "./img/pressed-check.png");
$img.addClass("is-checked");
}
}); });
$('body').on('click', '.js-auth-li-enabled', function (ev) { $('body').on('click', '.js-auth-li-enabled', function (ev) {
'use strict'; 'use strict';
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
var $this = $(this); var $this = $(this);
if ($this.find('.js-auth-checkbox').is(':checked') === true) { var $hiddenCheckbox = $this.find('.js-auth-checkbox');
$this.find('.js-auth-checkbox').prop( "checked", false ); var $img = $this.find('.check');
var newStatus = $hiddenCheckbox.prop('checked') ? "unchecked" : "checked";
if(newStatus === 'checked') {
$img.attr('src', './img/pressed-check.png');
$img.addClass("is-checked");
$hiddenCheckbox.prop( "checked", true );
} else { } else {
$this.find('.js-auth-checkbox').prop( "checked", true ); $img.attr("src", "./img/unpressed-check.png");
$img.removeClass("is-checked");
$hiddenCheckbox.prop( "checked", false );
} }
}); });
// $('body').on('keyup keypress', '.js-authn-otp-code', function (e) { $('body').on('keyup keypress', '.js-authn-otp-code', function (e) {
// 'use strict'; 'use strict';
// var keyCode = e.keyCode || e.which; // var keyCode = e.keyCode || e.which;
// var regex = new RegExp('^[0-9 \-]+$'); // var regex = new RegExp('^[0-9 \-]+$');
// var key = String.fromCharCode(!e.charCode ? e.which : e.charCode); // var key = String.fromCharCode(!e.charCode ? e.which : e.charCode);
// var oauthCode = $(this).val().split('-').join('').replace(/\s/g, ''); // var oauthCode = $(this).val().split('-').join('').replace(/\s/g, '');
// //
// if (!regex.test(key)) { // if (!regex.test(key)) {
// event.preventDefault(); // event.preventDefault();
// return false; // return false;
// } // }
// //
// if (oauthCode.length > 0) { // if (oauthCode.length > 0) {
// oauthCode = oauthCode.match(new RegExp('.{1,4}', 'g')).join("-"); // oauthCode = oauthCode.match(new RegExp('.{1,4}', 'g')).join("-");
// } // }
// //
// $(this).val(oauthCode); // $(this).val(oauthCode);
// //
// if($(this).val().length === $(this).attr("maxlength")){ // if($(this).val().length === $(this).attr("maxlength")){
// $('.submit-btn').prop("disabled", false); // $('.submit-btn').prop("disabled", false);
// } // }
// }); if ($(this).val().length === 14) {
$('.submit-btn').prop('disabled', false);
} else {
$('.error-msg').empty();
$('.submit-btn').prop('disabled', true);
}
});
$('.js-authn-otp-code').mask('####-####-####'); $('.js-authn-otp-code').mask('####-####-####');