;(function (exports) { 'use strict'; var core = window.OAUTH3_CORE; // Provider-Only core.urls.loginCode = function (directive, opts) { // // Example Resource Owner Password Request // (generally for 1st party and direct-partner mobile apps, and webapps) // // POST https://api.example.com/api/org.oauth3.provider/otp // { "request_otp": true, "client_id": "<>", "scope": "<>" // , "username": "<>" } // opts = opts || {}; var clientId = opts.appId || opts.clientId; var args = directive.credential_otp; if (!directive.credential_otp) { console.log('[debug] loginCode directive:'); console.log(directive); } var params = { "username": opts.id || opts.username , "request_otp": true // opts.requestOtp || undefined //, "jwt": opts.jwt // TODO sign a proof , debug: opts.debug || undefined }; var uri = args.url; var body; if (opts.clientUri) { params.client_uri = opts.clientUri; } if (opts.clientAgreeTos) { params.client_agree_tos = opts.clientAgreeTos; } if (clientId) { params.client_id = clientId; } if ('GET' === args.method.toUpperCase()) { uri += '?' + core.querystringify(params); } else { body = params; } return { url: uri , method: args.method , data: body }; }; core.urls.resourceOwnerPassword = function (directive, opts) { // // Example Resource Owner Password Request // (generally for 1st party and direct-partner mobile apps, and webapps) // // POST https://example.com/api/org.oauth3.provider/access_token // { "grant_type": "password", "client_id": "<>", "scope": "<>" // , "username": "<>", "password": "password" } // opts = opts || {}; var type = 'access_token'; var grantType = 'password'; if (!opts.password) { if (opts.otp) { // for backwards compat opts.password = opts.otp; // 'otp:' + opts.otpUuid + ':' + opts.otp; } } var scope = opts.scope || directive.authn_scope; var clientId = opts.appId || opts.clientId || opts.client_id; var clientAgreeTos = opts.clientAgreeTos || opts.client_agree_tos; var clientUri = opts.clientUri || opts.client_uri || opts.clientUrl || opts.client_url; var args = directive[type]; var otpCode = opts.otp || opts.otpCode || opts.otp_code || opts.otpToken || opts.otp_token || undefined; var params = { "grant_type": grantType , "username": opts.username , "password": opts.password || otpCode || undefined , "totp": opts.totp || opts.totpToken || opts.totp_token || undefined , "otp": otpCode , "password_type": otpCode && 'otp' , "otp_code": otpCode , "otp_uuid": opts.otpUuid || opts.otp_uuid || undefined , "user_agent": opts.userAgent || opts.useragent || opts.user_agent || undefined // AJ's Macbook , "jwk": (opts.rememberDevice || opts.remember_device) && opts.jwk || undefined //, "public_key": opts.rememberDevice && opts.publicKey || undefined //, "public_key_type": opts.rememberDevice && opts.publicKeyType || undefined // RSA/ECDSA //, "jwt": opts.jwt // TODO sign a proof with a previously loaded public_key , debug: opts.debug || undefined }; var uri = args.url; var body; if (opts.totp) { params.totp = opts.totp; } if (clientId) { params.clientId = clientId; } if (clientUri) { params.clientUri = clientUri; params.clientAgreeTos = clientAgreeTos; if (!clientAgreeTos) { throw new Error('Developer Error: missing clientAgreeTos uri'); } } if (scope) { params.scope = core.stringifyscope(scope); } if ('GET' === args.method.toUpperCase()) { uri += '?' + core.querystringify(params); } else { body = params; } return { url: uri , method: args.method , data: body }; }; core.urls.grants = function (directive, opts) { // directive = { issuer, authorization_decision } // opts = { response_type, scopes{ granted, requested, pending, accepted } } if (!opts) { throw new Error("You must supply a directive and an options object."); } if (!opts.client_id) { throw new Error("You must supply options.client_id."); } if (!opts.session) { throw new Error("You must supply options.session."); } if (!opts.referrer) { console.warn("You should supply options.referrer"); } if (!opts.method) { console.warn("You must supply options.method as either 'GET', or 'POST'"); } if ('POST' === opts.method) { if ('string' !== typeof opts.scope) { console.warn("You should supply options.scope as a space-delimited string of scopes"); } if (-1 === ['token', 'code'].indexOf(opts.response_type)) { throw new Error("You must supply options.response_type as 'token' or 'code'"); } } var url = core.urls.resolve(directive.issuer, directive.grants.url) .replace(/(:azp|:client_id)/g, core.normalizeUri(opts.client_id || opts.client_uri)) .replace(/(:sub|:account_id)/g, opts.session.token.sub) ; var data = { client_id: opts.client_id , client_uri: opts.client_uri , referrer: opts.referrer , response_type: opts.response_type , scope: opts.scope , tenant_id: opts.tenant_id }; var body; if ('GET' === opts.method) { url += '?' + core.querystringify(data); } else { body = data; } return { method: opts.method , url: url , data: body , session: opts.session }; }; core.urls.authorizationDecision = function (directive, opts) { var url = core.urls.resolve(directive.issuer, directive.authorization_decision.url); if (!opts) { throw new Error("You must supply a directive and an options object"); } console.info(url); throw new Error("NOT IMPLEMENTED authorization_decision"); }; core.authz = core.authz || {}; core.authz.scopes = function (session, clientParams) { // OAuth3.requests.grants(providerUri, {}); // return list of grants // OAuth3.checkGrants(providerUri, {}); // var clientUri = OAUTH3.core.normalizeUri(clientParams.client_uri || window.document.referrer); var scope = clientParams.scope || ''; var clientObj = clientParams; if (!scope) { scope = 'oauth3_authn'; } //$('.js-user-avatar').attr('src', userAvatar); /* console.log('grants options'); console.log(loc.hash); console.log(loc.search); console.log(clientObj); console.log(session.token); console.log(window.document.referrer); */ return OAUTH3.requests.grants(CONFIG.host, { method: 'GET' , client_id: clientUri , client_uri: clientUri , session: session }).then(function (grantResults) { var grants; var grantedScopes; var grantedScopesMap; var pendingScopes; var acceptedScopes; var scopes = scope.split(/[+, ]/g); var callbackUrl; console.log('previous grants:'); console.log(grantResults); if (grantResults.data.error) { window.alert('grantResults: ' + grantResults.data.error_description || grantResults.data.error.message); return; } // it doesn't matter who the referrer is as long as the destination // is an authorized destination for the client in question // (though it may not hurt to pass the referrer's info on to the client) if (!OAUTH3.checkRedirect(grantResults.data.client, clientObj)) { callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK' + '?redirect_uri=' + clientObj.redirect_uri + '&allowed_urls=' + grantResults.data.client.url + '&client_id=' + clientUri + '&referrer_uri=' + OAUTH3.core.normalizeUri(window.document.referrer) ; location.href = callbackUrl; return; } if ('oauth3_authn' === scope) { // implicit ppid grant is automatic console.warn('[security] fix scope checking on backend so that we can do automatic grants'); // TODO check user preference if implicit ppid grant is allowed //return generateToken(session, clientObj); } grants = (grantResults.originalData||grantResults.data).grants.filter(function (grant) { if (clientUri === (grant.azp || grant.oauth_client_id || grant.oauthClientId)) { return true; } }); grantedScopesMap = {}; acceptedScopes = []; pendingScopes = scopes.filter(function (requestedScope) { return grants.every(function (grant) { if (!grant.scope) { grant.scope = 'oauth3_authn'; } var gscopes = grant.scope.split(/[+, ]/g); gscopes.forEach(function (s) { grantedScopesMap[s] = true; }); if (-1 !== gscopes.indexOf(requestedScope)) { // already accepted in the past acceptedScopes.push(requestedScope); } else { // true, is pending return true; } }); }); grantedScopes = Object.keys(grantedScopesMap); return { pending: pendingScopes // not yet accepted , granted: grantedScopes // all granted, ever , requested: scopes // all requested, now , accepted: acceptedScopes // granted (ever) and requested (now) }; }); }; exports.OAUTH3_CORE_PROVIDER = core; if ('undefined' !== typeof module) { module.exports = core; } }('undefined' !== typeof exports ? exports : window));