| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  | ;(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": "<<id>>", "scope": "<<scope>>"
 | 
					
						
							|  |  |  |     //    , "username": "<<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": "<<id>>", "scope": "<<scope>>"
 | 
					
						
							|  |  |  |     //    , "username": "<<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'"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-10 21:34:00 -05:00
										 |  |  |     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'"); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var url = core.urls.resolve(directive.issuer, directive.grants.url) | 
					
						
							| 
									
										
										
										
											2017-02-10 22:23:21 -05:00
										 |  |  |       .replace(/(:azp|:client_id)/g, core.normalizeUri(opts.client_id || opts.client_uri)) | 
					
						
							| 
									
										
										
										
											2017-02-13 12:46:12 -05:00
										 |  |  |       .replace(/(:sub|:account_id)/g, opts.session.token.sub) | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  |       ; | 
					
						
							|  |  |  |     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"); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-10 21:34:00 -05:00
										 |  |  |   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);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-13 12:46:12 -05:00
										 |  |  |     /* | 
					
						
							| 
									
										
										
										
											2017-02-10 21:34:00 -05:00
										 |  |  |     console.log('grants options'); | 
					
						
							|  |  |  |     console.log(loc.hash); | 
					
						
							|  |  |  |     console.log(loc.search); | 
					
						
							|  |  |  |     console.log(clientObj); | 
					
						
							| 
									
										
										
										
											2017-02-13 12:46:12 -05:00
										 |  |  |     console.log(session.token); | 
					
						
							| 
									
										
										
										
											2017-02-10 21:34:00 -05:00
										 |  |  |     console.log(window.document.referrer); | 
					
						
							| 
									
										
										
										
											2017-02-13 12:46:12 -05:00
										 |  |  |     */ | 
					
						
							| 
									
										
										
										
											2017-02-10 21:34:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2017-02-13 14:35:48 -05:00
										 |  |  |         window.alert('grantResults: ' + grantResults.data.error_description || grantResults.data.error.message); | 
					
						
							| 
									
										
										
										
											2017-02-10 21:34:00 -05:00
										 |  |  |         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);
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-13 12:46:12 -05:00
										 |  |  |       grants = (grantResults.originalData||grantResults.data).grants.filter(function (grant) { | 
					
						
							| 
									
										
										
										
											2017-02-10 21:34:00 -05:00
										 |  |  |         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)
 | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-09 21:51:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   exports.OAUTH3_CORE_PROVIDER = core; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ('undefined' !== typeof module) { | 
					
						
							|  |  |  |     module.exports = core; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }('undefined' !== typeof exports ? exports : window)); |