Compare commits

..

No commits in common. "master" and "pre-issuer-rewrite" have entirely different histories.

12 changed files with 216 additions and 292 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

1
.gitignore vendored
View File

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

View File

@ -1,5 +0,0 @@
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
View File

@ -1,41 +0,0 @@
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,30 +1,20 @@
issuer.html
===========
This is a WALNUT module representing the html package for 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`
It must be installed to `/srv/walnut/packages/pages/issuer@oauth3.org`
```bash
git clone git@git.oauth3.org:OAuth3/org.oauth3.git /opt/walnut/packages/pages/issuer@oauth3.org
pushd /opt/walnut/packages/pages/issuer@oauth3.org
git clone git@git.daplie.com:OAuth3/issuer_oauth3.org.git /srv/walnut/packages/pages/issuer@oauth3.org
ln -s issuer@oauth3.org /srv/walnut/packages/pages/org.oauth3
pushd /srv/walnut/packages/pages/issuer@oauth3.org
bash ./install.sh
popd
```
```bash
echo "issuer@oauth3.org" >> /opt/walnut/var/sites/EXAMPLE.COM
echo "issuer@oauth3.org" >> /srv/walnut/packages/sites/EXAMPLE.COM
echo "org.oauth3" >> /srv/walnut/packages/sites/EXAMPLE.COM
```
This uses the OAuth3 JavaScript SDK `oauth3.js` as a subpackage in
`/opt/walnut/packages/pages/issuer@oauth3.org/assets/oauth3.org`.
This uses the OAuth3 JavaScript SDK `oauth3.js` as a subpackage in `/srv/walnut/packages/pages/issuer@oauth3.org/assets/oauth3.org`.
The 'login popup' is hosted on our tardigrade proxy VM.

View File

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

BIN
img/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -1,31 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<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/style.css"> -->
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:300">
<script src="https://use.fontawesome.com/3af0faae66.js"></script>
<link rel="stylesheet" type="text/css" href="/css/daplie-installer-overrides.css">
</head>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<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/style.css"> -->
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:300">
<script src="https://use.fontawesome.com/3af0faae66.js"></script>
<link rel="stylesheet" type="text/css" href="/css/daplie-installer-overrides.css">
</head>
<body>
<div class="fade mock-main">
<body class="fade mock-main">
<!-- STEP 1: ask the user where they want to log in -->
<!-- STEP 2: ask the user for their email -->
<!-- STEP 3+4: ask for login code and to remember device -->
<!-- TODO: remember-me-not implementation? -->
<!-- STEP 1: ask the user where they want to log in -->
<!-- STEP 2: ask the user for their email -->
<!-- STEP 3+4: ask for login code and to remember device -->
<!-- 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">
<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. 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>
<p class="org-title">Safelogin.org</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>
<form method="post" action="">
<div class="form-group">
<input type="email" class="form-control dap-input js-oauth3-email emailInput" placeholder="Enter an email address to start"></input>
@ -46,7 +45,7 @@
</div>
<div class="dap-bordered js-authn">
<p class="org-title">daplie.me</p>
<p class="org-title">Safelogin.org</p>
<!-- <div class="dap-normal-text">
<span class="fa fa-3x icon-centered-3x fa-purple fa-envelope"></span>
</div>
@ -62,7 +61,6 @@
<p class="code-lasts-text">Code lasts for 15 minutes.</p>
<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>
<p class="error-msg"></p>
</div>
<div class="dap-centered-div dap-space-on-top form-group">
<label class="js-remember-label dap-normal-text">
@ -72,7 +70,8 @@
<input class="js-remember-checkbox hidden" type="checkbox"></input>
</label>
</div>
<button type="submit" class="btn btn-primary submit-btn dap-full-button-green js-submit-code-btn" disabled>Submit</button>
<!-- <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-remember-btn js-authz-remember-me">Submit</button>
<!-- <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>
</form>
@ -86,14 +85,14 @@
</div>
<div class="dap-bordered dap-normal-text js-authz">
<p class="org-title">daplie.me</p>
<p class="org-title">Safelogin.org</p>
<!-- <br> -->
<!-- <div class="dap-user-plus-app">
<span class="fa fa-3x fa-purple fa-user-circle"></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">
</div> -->
<p class="dap-centered-text dap-normal-text almost-done-text">Almost done. Now it's time to set your preferences.</p>
<p class="dap-centered-text dap-normal-text almost-done-text">Almost done. Now its time to set your preferences.</p>
<br>
<form class="js-authorization-decision" action="#">
@ -140,60 +139,17 @@
<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">
</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]-->
<script src="./js/jquery-2.2.0.min.js"></script>
<script src="./js/jquery.mask.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/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>

View File

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

View File

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

View File

@ -9,7 +9,7 @@ $(function () {
var OAUTH3 = window.OAUTH3;
var CONFIG = {
host: OAUTH3.clientUri(window.location)
host: OAUTH3.utils.clientUri(window.location)
, directives: null // will be populated before the login button appears
};
var loc = window.location;
@ -20,8 +20,22 @@ $(function () {
};
$('.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
var clientParams = OAUTH3.query.parse(loc.hash || loc.search);
var clientParams = OAUTH3.query.parse(window.location.hash || window.location.search);
if (/authorization_dialog/.test(window.location.href)) {
// OAUTH3.lintClientParams(params, window)
// OAUTH3.normalizeClientParams(params, window)
@ -44,12 +58,12 @@ $(function () {
+ "'" + OAUTH3.url.normalize(window.document.referrer) + "'"
);
}
if (clientParams.client_uri && clientParams.client_uri !== clientParams.client_id) {
if (clientParams.client_uri) {
console.warn("'client_id' should be used instead of 'client_uri'");
}
if (!(clientParams.client_id || clientParams.client_uri)) {
window.alert("'client_id' must exist as the uri identifying the client");
console.error("'client_id' must exist as the uri identifying the client");
window.alert("'response_type' must exist and be either 'token' (implicit flow) or 'code' (authorization flow)");
console.error("'response_type' must exist and be either 'token' (implicit flow) or 'code' (authorization flow)");
clientParams.client_id = clientParams.client_uri = OAUTH3.url.normalize(window.document.referrer);
}
if (!clientParams.redirect_uri) {
@ -74,47 +88,32 @@ $(function () {
function getSession(providerUri) {
return OAUTH3.hooks.session.get(providerUri).then(function (session) {
if (session && session.access_token) {
normalizeSession(session);
return OAUTH3.PromiseA.resolve(session);
}
else {
return OAUTH3.PromiseA.reject(new Error("no access_token in session"));
}
if (session && session.access_token) {
normalizeSession(session);
return OAUTH3.PromiseA.resolve(session);
}
else {
return OAUTH3.PromiseA.reject(new Error("no access_token in session"));
}
});
}
function getGrants(session) {
var clientLogo = OAUTH3.url.normalize(clientParams.client_uri) // optional relative logo ?
var clientObj = OAUTH3.query.parse(loc.hash || loc.search);
var clientLogo = OAUTH3.url.normalize(clientObj.client_uri) // optional relative logo ?
+ '/.well-known/oauth3/logo-128x128.png'
;
var callbackUrl;
// TODO put in directives.json or similar
var grantDescriptions = {
// deprecated
'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)" // 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:ns': "Name Server management"
, '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"
};
@ -128,10 +127,10 @@ $(function () {
$('.js-client-logo').attr('src', clientLogo);
//$('.js-user-avatar').attr('src', userAvatar);
return OAUTH3.authz.scopes(CONFIG.host, session, clientParams).then(function (scopes) {
return OAUTH3.authz.scopes(CONFIG.host, session, clientObj).then(function (scopes) {
if (!scopes.pending.length) {
// looks like we've done all of this before
OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientParams, scopes);
OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientObj, scopes);
return;
}
@ -139,12 +138,10 @@ $(function () {
// 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"]
if (OAUTH3._browser.isIframe()) {
location.href = clientParams.redirect_uri +'#'+ OAUTH3.query.stringify({
state: clientParams.state
, error: 'access_denied'
, 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')
});
callbackUrl = clientObj.redirect_uri + '#state=' + clientObj.state + '&error=access_denied&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');
location.href = callbackUrl;
return;
}
@ -168,13 +165,8 @@ $(function () {
$scope.find('.js-scope-desc').text(grantDescriptions[scope]);
}
else {
//This disables the check/checkbox when we have an unrecognized grant.
//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-toggle').prop('checked', false);
$scope.find('.js-scope-toggle').prop('disabled', true);
$scope.find('.js-scope-desc').text(scope);
}
@ -182,6 +174,9 @@ $(function () {
});
$('.js-authz').show().addClass('in');
}, function (err) {
window.alert('grantResults: ' + err.message);
console.error('scope results', err);
});
}
@ -217,27 +212,56 @@ $(function () {
// TODO loading
email = $('.js-oauth3-email').val();
return OAUTH3.authn.otp(CONFIG.directives, {email: email, mock: true}).then(function (otpResults) {
if (otpResults.data.error) {
window.alert('otpResults: ' + otpResults.data.error_description || otpResults.data.error.message);
return;
return OAUTH3.authn.loginMeta(CONFIG.directives, {email: email, mock: true}).then(function (userResults) {
if (!userResults.data.error) {
console.log('User exists:', userResults);
}
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);
if (userResults.data.error) {
$('.js-authn-show').removeAttr('disabled');
console.warn('User does not exist:', email);
console.warn('User Results:', userResults);
//window.alert('userResults: ' + userResults.data.error_description || userResults.data.error.message);
//return;
}
$('.js-user-email').text(email);
return OAUTH3.authn.otp(CONFIG.directives, {email: email, mock: true}).then(function (otpResults) {
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
util.submitLoginCode = function (ev) {
ev.preventDefault();
ev.stopPropagation();
util.submitLoginCode = function (opts) {
// TODO
// perhaps we should check that the code is valid before continuing to login (so that we don't send the key)
@ -245,6 +269,7 @@ $(function () {
// TODO
// we should be sending the public key for this device as a jwk along with the authentication
// (and how long to remember this device)
var uuid = $('.js-authn-otp-uuid').val();
var code = $('.js-authn-otp-code').val().trim();
return OAUTH3.authn.resourceOwnerPassword(CONFIG.directives, {
@ -258,35 +283,36 @@ $(function () {
// TODO should be otp_id (agnostic of uuid)
, otp_uuid: uuid
// add expiration to the refresh token and/or public key
, remember_device: $('.js-remember-label').find('.js-remember-checkbox').prop('checked')
, expire: opts.rememberDevice || (1 * 60 * 60 * 1000)
, mock: true
}).then(function (session) {
$('.js-authn').removeClass('in').hide();
if (session.token.sub) {
return OAUTH3.PromiseA.resolve(session);
function getAccount(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 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 getGrants(session);
});
}).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) {
ev.preventDefault();
@ -303,6 +329,8 @@ $(function () {
});
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) {
scopes.new = acceptedScopes;
return OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientParams, scopes);
@ -316,17 +344,21 @@ $(function () {
ev.preventDefault();
ev.stopPropagation();
var loginWinObj = OAUTH3.query.parse(loc.hash || loc.search);
var denyObj = {
error: 'access_denied'
, error_description: 'The user has denied access.'
, error_uri: 'https://' + CONFIG.host + '/.well-known/oauth3/errors.html#/?error=access_denied'
, state: clientParams.state
, scope: clientParams.scope
, state: loginWinObj.state
, scope: loginWinObj.scope
};
window.location = clientParams.redirect_uri + '#' + OAUTH3.query.stringify(denyObj);
window.location = loginWinObj.redirect_uri + '#' + OAUTH3.query.stringify(denyObj);
};
util.handleLogout = function () {
var clientParams = OAUTH3.query.parse(loc.hash || loc.search);
localStorage.clear();
clientParams.redirect_uri += '?' + OAUTH3.query.stringify({
@ -339,21 +371,21 @@ $(function () {
util.editEmail = function () {
$('.js-authn').hide();
$('.js-userid-container').show();
debugger;
};
//
// Page Setup
//
$('.js-authorization-dialog').hide();
$('.js-logout-container').hide();
$('.js-userid-container').hide();
$('.js-authn').hide();
$('.js-authz').hide();
$('body').on('click', '.js-logout', util.handleLogout);
$('body').on('click', '.js-authn-show', util.submitAuthEmail);
$('body').on('click', '.js-submit-code-btn', util.submitLoginCode);
$('body').on('click', '.js-authz-remember-me', util.rememberDevice);
$('body').on('click', '.js-authz-remember-me-not', util.rememberDeviceNot);
$('body').on('click', '.js-login-allow', util.acceptScopesAndLogin);
$('body').on('click', '.js-login-deny', util.closeLoginDeny);
$('body').on('click', '.js-edit-email-button', util.editEmail);
@ -362,33 +394,40 @@ $(function () {
function handleAuthorizationDialog() {
return getSession(CONFIG.host).then(function (session) {
return getGrants(session);
}).catch(function () {
}, function (e) {
var clientObj = OAUTH3.query.parse(loc.hash || loc.search);
// TODO select the providers the client wants to show
// providers=daplie.com,facebook.com,google.com // etc
// TODO let the client specify switch_user
// TODO let the client specify relogin if stale
if (OAUTH3._browser.isIframe()) {
location.href = clientParams.redirect_uri +'#'+ OAUTH3.query.stringify({
state: clientParams.state
, error: 'access_denied'
, 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')
});
var callbackUrl = clientObj.redirect_uri + '#state=' + clientObj.state + '&error=access_denied&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');
location.href = callbackUrl;
}
if (clientParams.subject) {
$('.js-oauth3-email').val(clientParams.subject);
$('.js-authn-show').prop('disabled', false);
}
$('.js-userid-container').show();
}).then(function () {
//$('body').addClass('in');
});
}
// Session initialization
return OAUTH3.discover(CONFIG.host, { client_uri: CONFIG.host }).then(function (directives) {
return OAUTH3.discover(
OAUTH3.clientUri(window.location)
, { client_uri: OAUTH3.clientUri(window.location) }
).then(function (directives) {
// TODO cache directives in memory (and storage)
CONFIG.directives = directives;
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)) {
$('.js-authorization-dialog').show();
handleAuthorizationDialog();
@ -397,13 +436,8 @@ $(function () {
$('.js-logout-container').show();
}
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');
}
$('body').addClass('in');
});
});

View File

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