seems to work...
This commit is contained in:
		
							parent
							
								
									ab4dfdce58
								
							
						
					
					
						commit
						69a92fc2fd
					
				| @ -7,6 +7,12 @@ | ||||
|       clientUri: function (location) { | ||||
|         return OAUTH3.utils.uri.normalize(location.host + location.pathname); | ||||
|       } | ||||
|     , _formatError: function (providerUri, params) { | ||||
|         var err = new Error(params.error_description || params.error.message || "Unknown error with provider '" + providerUri + "'"); | ||||
|         err.uri = params.error_uri || params.error.uri; | ||||
|         err.code = params.error.code || params.error; | ||||
|         return err; | ||||
|       } | ||||
|     , atob: function (base64) { | ||||
|         return (exports.atob || require('atob'))(base64); | ||||
|       } | ||||
| @ -117,6 +123,59 @@ | ||||
|         return str; | ||||
|       } | ||||
|     } | ||||
|   , jwt: { | ||||
|       // decode only (no verification)
 | ||||
|       decode: function (str) { | ||||
| 
 | ||||
|         // 'abc.qrs.xyz'
 | ||||
|         // [ 'abc', 'qrs', 'xyz' ]
 | ||||
|         // [ {}, {}, 'foo' ]
 | ||||
|         // { header: {}, payload: {}, signature: }
 | ||||
|         var parts = str.split(/\./g); | ||||
|         var jsons = parts.slice(0, 2).map(function (urlsafe64) { | ||||
|           var atob = exports.atob || require('atob'); | ||||
|           var b64 = OAUTH3.utils._urlSafeBase64ToBase64(urlsafe64); | ||||
|           return atob(b64); | ||||
|         }); | ||||
| 
 | ||||
|         return { | ||||
|           header: JSON.parse(jsons[0]) | ||||
|         , payload: JSON.parse(jsons[1]) | ||||
|         , signature: parts[2] // should remain url-safe base64
 | ||||
|         }; | ||||
|       } | ||||
|     , getFreshness: function (tokenMeta, staletime, now) { | ||||
|         staletime = staletime || (15 * 60); | ||||
|         now = now || Date.now(); | ||||
|         var fresh = ((parseInt(tokenMeta.exp, 10) || 0) - Math.round(now / 1000)); | ||||
| 
 | ||||
|         if (fresh >= staletime) { | ||||
|           return 'fresh'; | ||||
|         } | ||||
| 
 | ||||
|         if (fresh <= 0) { | ||||
|           return 'expired'; | ||||
|         } | ||||
| 
 | ||||
|         return 'stale'; | ||||
|       } | ||||
|     /* | ||||
|       // encode-only (no signature)
 | ||||
|     , encode: function (parts) { | ||||
|         parts.header = parts.header || { alg: 'none', typ: 'jwt' }; | ||||
|         parts.signature = parts.signature || ''; | ||||
| 
 | ||||
|         var btoa = exports.btoa || require('btoa'); | ||||
|         var result = [ | ||||
|           core.utils.base64ToUrlSafeBase64(btoa(JSON.stringify(parts.header, null))) | ||||
|         , core.utils.base64ToUrlSafeBase64(btoa(JSON.stringify(parts.payload, null))) | ||||
|         , parts.signature // should already be url-safe base64
 | ||||
|         ].join('.'); | ||||
| 
 | ||||
|         return result; | ||||
|       } | ||||
|     */ | ||||
|     } | ||||
|   , urls: { | ||||
|       discover: function (providerUri, opts) { | ||||
|         if (!providerUri) { | ||||
| @ -205,6 +264,58 @@ | ||||
| 
 | ||||
|         return result; | ||||
|       } | ||||
|     , refreshToken: function (directive, opts) { | ||||
|         // grant_type=refresh_token
 | ||||
| 
 | ||||
|         // Example Refresh Token Request
 | ||||
|         // (generally for 1st or 3rd party server-side, mobile, and desktop apps)
 | ||||
|         //
 | ||||
|         // POST https://example.com/api/oauth3/access_token
 | ||||
|         //    { "grant_type": "refresh_token", "client_id": "<<id>>", "scope": "<<scope>>"
 | ||||
|         //    , "username": "<<username>>", "password": "password" }
 | ||||
|         //
 | ||||
|         opts = opts || {}; | ||||
|         var type = 'access_token'; | ||||
|         var grantType = 'refresh_token'; | ||||
| 
 | ||||
|         var scope = opts.scope || directive.authn_scope; | ||||
|         var clientSecret = opts.client_secret; | ||||
|         var args = directive[type]; | ||||
|         var params = { | ||||
|           "grant_type": grantType | ||||
|         , "refresh_token": opts.refresh_token || (opts.session && opts.session.refresh_token) | ||||
|         , "response_type": 'token' | ||||
|         , "client_id": opts.client_id || opts.client_uri | ||||
|         , "client_uri": opts.client_uri | ||||
|         //, "scope": undefined
 | ||||
|         //, "client_secret": undefined
 | ||||
|         , debug: opts.debug || undefined | ||||
|         }; | ||||
|         var uri = args.url; | ||||
|         var body; | ||||
| 
 | ||||
|         if (clientSecret) { | ||||
|           // TODO not allowed in the browser
 | ||||
|           console.warn("if this is a browser, you must not use client_secret"); | ||||
|           params.client_secret = clientSecret; | ||||
|         } | ||||
| 
 | ||||
|         if (scope) { | ||||
|           params.scope = OAUTH3.utils.scope.stringify(scope); | ||||
|         } | ||||
| 
 | ||||
|         if ('GET' === args.method.toUpperCase()) { | ||||
|           uri += '?' + OAUTH3.utils.query.stringify(params); | ||||
|         } else { | ||||
|           body = params; | ||||
|         } | ||||
| 
 | ||||
|         return { | ||||
|           url: uri | ||||
|         , method: args.method | ||||
|         , data: body | ||||
|         }; | ||||
|       } | ||||
|     } | ||||
|   , hooks: { | ||||
|       directives: { | ||||
| @ -236,6 +347,118 @@ | ||||
|           return directives; | ||||
|         } | ||||
|       } | ||||
|     , session: { | ||||
|         refresh: function (oldSession, newSession) { | ||||
|           var providerUri = oldSession.provider_uri; | ||||
|           var clientUri = oldSession.client_uri; | ||||
| 
 | ||||
|           console.info('[oauth3.hooks.refreshSession] oldSession', JSON.parse(JSON.stringify(oldSession))); | ||||
|           console.info('[oauth3.hooks.refreshSession] newSession', newSession); | ||||
|           Object.keys(oldSession).forEach(function (key) { | ||||
|             oldSession[key] = undefined; | ||||
|           }); | ||||
|           Object.keys(newSession).forEach(function (key) { | ||||
|             oldSession[key] = newSession[key]; | ||||
|           }); | ||||
| 
 | ||||
|           // info about the session of this API call
 | ||||
|           oldSession.provider_uri = providerUri;  // aud
 | ||||
|           oldSession.client_uri = clientUri;      // azp
 | ||||
| 
 | ||||
|           // info about the newly-discovered token
 | ||||
|           oldSession.token = OAUTH3.jwt.decode(oldSession.access_token).payload; | ||||
| 
 | ||||
|           oldSession.token.sub = oldSession.token.sub || oldSession.token.acx.id; | ||||
|           oldSession.token.client_uri = clientUri; | ||||
|           oldSession.token.provider_uri = providerUri; | ||||
| 
 | ||||
|           if (oldSession.refresh_token) { | ||||
|             oldSession.refresh = OAUTH3.jwt.decode(oldSession.refresh_token).payload; | ||||
|             oldSession.refresh.sub = oldSession.refresh.sub || oldSession.refresh.acx.id; | ||||
|             oldSession.refresh.provider_uri = providerUri; | ||||
|           } | ||||
| 
 | ||||
|           console.info('[oauth3.hooks.refreshSession] refreshedSession', oldSession); | ||||
| 
 | ||||
|           // set for a set of audiences
 | ||||
|           return OAUTH3.PromiseA.resolve(OAUTH3.hooks.session.set(providerUri, oldSession)); | ||||
|         } | ||||
|       , check: function (preq, opts) { | ||||
|           if (!preq.session) { | ||||
|             console.warn('[oauth3.hooks.checkSession] no session'); | ||||
|             return OAUTH3.PromiseA.resolve(null); | ||||
|           } | ||||
|           var freshness = OAUTH3.jwt.freshness(preq.session.token, opts.staletime); | ||||
|           console.info('[oauth3.hooks.checkSession] freshness', freshness, preq.session); | ||||
| 
 | ||||
|           switch (freshness) { | ||||
|             case 'stale': | ||||
|               return OAUTH3.hooks.session.stale(preq.session); | ||||
|             case 'expired': | ||||
|               return OAUTH3.hooks.session.expired(preq.session).then(function (newSession) { | ||||
|                 preq.session = newSession; | ||||
|                 return newSession; | ||||
|               }); | ||||
|             //case 'fresh':
 | ||||
|             default: | ||||
|               return OAUTH3.PromiseA.resolve(preq.session); | ||||
|           } | ||||
|         } | ||||
|       , stale: function (staleSession) { | ||||
|           console.info('[oauth3.hooks.sessionStale] called'); | ||||
|           if (OAUTH3.hooks.session._stalePromise) { | ||||
|             return OAUTH3.PromiseA.resolve(staleSession); | ||||
|           } | ||||
| 
 | ||||
|           OAUTH3.hooks.session._stalePromise = OAUTH3._refreshToken( | ||||
|             staleSession.provider_uri | ||||
|           , { client_uri: staleSession.client_uri | ||||
|             , session: staleSession | ||||
|             , debug: staleSession.debug | ||||
|             } | ||||
|           ).then(function (newSession) { | ||||
|             OAUTH3.hooks.session._stalePromise = null; | ||||
|             return newSession; // oauth3.hooks.refreshSession(staleSession, newSession);
 | ||||
|           }, function () { | ||||
|             OAUTH3.hooks.session._stalePromise = null; | ||||
|           }); | ||||
| 
 | ||||
|           return OAUTH3.PromiseA.resolve(staleSession); | ||||
|         } | ||||
|       , expired: function (expiredSession) { | ||||
|           console.info('[oauth3.hooks.sessionExpired] called'); | ||||
|           return OAUTH3._refreshToken( | ||||
|             expiredSession.provider_uri | ||||
|           , { client_uri: expiredSession.client_uri | ||||
|             , session: expiredSession | ||||
|             , debug: expiredSession.debug | ||||
|             } | ||||
|           ).then(function (newSession) { | ||||
|             return newSession; // oauth3.hooks.refreshSession(expiredSession, newSession);
 | ||||
|           }); | ||||
|         } | ||||
|       , set: function (providerUri, newSession) { | ||||
|           if (!providerUri) { | ||||
|             console.error(new Error('no providerUri').stack); | ||||
|             throw new Error("providerUri is not set"); | ||||
|           } | ||||
|           providerUri = OAUTH3.utils.uri.normalize(providerUri); | ||||
|           console.warn('[Warn] Please implement OAUTH3.hooks.session.set = function (providerUri, newSession) { return PromiseA<newSession>; }'); | ||||
|           console.warn(newSession); | ||||
|           if (!OAUTH3.hooks.session._sessions) { OAUTH3.hooks.session._sessions = {}; } | ||||
|           OAUTH3.hooks.session._sessions[providerUri] = newSession; | ||||
|           return OAUTH3.PromiseA.resolve(newSession); | ||||
|         } | ||||
|       , get: function (providerUri) { | ||||
|           providerUri = OAUTH3.utils.uri.normalize(providerUri); | ||||
|           if (!providerUri) { | ||||
|             throw new Error("providerUri is not set"); | ||||
|           } | ||||
|           console.warn('[Warn] Please implement OAUTH3.hooks.session.get = function (providerUri) { return PromiseA<savedSession>; }'); | ||||
|           if (!OAUTH3.hooks.session._sessions) { OAUTH3.hooks.session._sessions = {}; } | ||||
|           return OAUTH3.PromiseA.resolve(OAUTH3.hooks.session._sessions[providerUri]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   , discover: function (providerUri, opts) { | ||||
|       if (!providerUri) { | ||||
| @ -253,47 +476,6 @@ | ||||
|         }); | ||||
|       }); | ||||
|     } | ||||
|   , request: function (preq) { | ||||
|       return OAUTH3._browser.request(preq); | ||||
|     } | ||||
|   , implicitGrant: function(providerUri, opts) { | ||||
|       var promise; | ||||
| 
 | ||||
|       if (opts.broker) { | ||||
|         // Discovery can happen in-flow because we know that this is
 | ||||
|         // a valid oauth3 provider
 | ||||
|         console.info("broker implicit grant"); | ||||
|         promise = OAUTH3._discoverThenImplicitGrant(providerUri, opts); | ||||
|       } | ||||
|       else { | ||||
|         // Discovery must take place before calling implicitGrant
 | ||||
|         console.info("direct implicit grant"); | ||||
|         promise = OAUTH3._implicitGrant(OAUTH3.hooks.directives._getCached(providerUri), opts); | ||||
|       } | ||||
| 
 | ||||
|       return promise.then(function (tokens) { | ||||
|         return OAUTH3.hooks.refreshSession( | ||||
|           opts.session || { | ||||
|             provider_uri: providerUri | ||||
|           , client_id: opts.client_id | ||||
|           , client_uri: opts.client_uri || opts.clientUri | ||||
|           } | ||||
|         , tokens | ||||
|         ); | ||||
|       }); | ||||
|     } | ||||
|   , _discoverThenImplicitGrant: function(providerUri, opts) { | ||||
|       opts.windowType = opts.windowType || 'popup'; | ||||
|       return OAUTH3.discover(providerUri, opts).then(function (directives) { | ||||
|         console.info('Discover complete'); | ||||
|         return OAUTH3._implicitGrant(directives, opts).then(function (tokens) { | ||||
|           console.info('Implicit Grant complete', tokens); | ||||
|           OAUTH3._browser.closeFrame(tokens.state || opts._state); | ||||
|           //opts._state = undefined;
 | ||||
|           return tokens; | ||||
|         }); | ||||
|       }); | ||||
|     } | ||||
|   , _discoverHelper: function(providerUri, opts) { | ||||
|       return OAUTH3._discover(providerUri, opts); | ||||
|     } | ||||
| @ -360,6 +542,70 @@ | ||||
|         return directives; | ||||
|       }); | ||||
|     } | ||||
|   , request: function (preq, opts) { | ||||
|       function fetch() { | ||||
|         if (preq.session) { | ||||
|           // TODO check session.token.aud against preq.url to make sure they match
 | ||||
|           console.warn("[security] session audience checking has not been implemented yet (it's up to you to check)"); | ||||
|           preq.headers = preq.headers || {}; | ||||
|           preq.headers.Authorization = 'Bearer ' + (preq.session.access_token || preq.session.accessToken); | ||||
|         } | ||||
| 
 | ||||
|         return OAUTH3._requestHelper(preq, opts); | ||||
|       } | ||||
| 
 | ||||
|       if (!preq.session) { | ||||
|         return fetch(); | ||||
|       } | ||||
| 
 | ||||
|       return OAUTH3.hooks.session.check(preq, opts).then(fetch); | ||||
|     } | ||||
|   , _requestHelper: function (preq, opts) { | ||||
|       return OAUTH3._browser.request(preq, opts); | ||||
|     } | ||||
|   , implicitGrant: function(providerUri, opts) { | ||||
|       var promise; | ||||
| 
 | ||||
|       if (opts.broker) { | ||||
|         // Discovery can happen in-flow because we know that this is
 | ||||
|         // a valid oauth3 provider
 | ||||
|         console.info("broker implicit grant"); | ||||
|         promise = OAUTH3._discoverThenImplicitGrant(providerUri, opts); | ||||
|       } | ||||
|       else { | ||||
|         // Discovery must take place before calling implicitGrant
 | ||||
|         console.info("direct implicit grant"); | ||||
|         promise = OAUTH3._implicitGrant(OAUTH3.hooks.directives._getCached(providerUri), opts); | ||||
|       } | ||||
| 
 | ||||
|       return promise.then(function (tokens) { | ||||
|         // TODO abstract browser bits away
 | ||||
|         try { | ||||
|           OAUTH3._browser.closeFrame(tokens.state || opts._state, opts); | ||||
|         } catch(e) { | ||||
|           console.warn("[implicitGrant] TODO abstract browser bits away"); | ||||
|         } | ||||
|         opts._state = undefined; | ||||
|         return OAUTH3.hooks.session.refresh( | ||||
|           opts.session || { | ||||
|             provider_uri: providerUri | ||||
|           , client_id: opts.client_id | ||||
|           , client_uri: opts.client_uri || opts.clientUri | ||||
|           } | ||||
|         , tokens | ||||
|         ); | ||||
|       }); | ||||
|     } | ||||
|   , _discoverThenImplicitGrant: function(providerUri, opts) { | ||||
|       opts.windowType = opts.windowType || 'popup'; | ||||
|       return OAUTH3.discover(providerUri, opts).then(function (directives) { | ||||
|         console.info('Discover complete'); | ||||
|         return OAUTH3._implicitGrant(directives, opts).then(function (tokens) { | ||||
|           console.info('Implicit Grant complete', tokens); | ||||
|           return tokens; | ||||
|         }); | ||||
|       }); | ||||
|     } | ||||
|   , _implicitGrant: function(directives, opts) { | ||||
|       // TODO this may need to be synchronous for browser security policy
 | ||||
|       // Do some stuff
 | ||||
| @ -392,11 +638,24 @@ | ||||
|           return OAUTH3.PromiseA.reject(OAUTH3.utils._formatError(directives.issuer /*providerUri*/, tokens)); | ||||
|         } | ||||
| 
 | ||||
|         OAUTH3._browser.closeFrame(authReq.state, { debug: opts.debug || tokens.debug }); | ||||
| 
 | ||||
|         return tokens; | ||||
|       }); | ||||
|     } | ||||
|   , _refreshToken: function (providerUri, opts) { | ||||
|       console.info('[oauth3.requests.refreshToken] called', providerUri, opts); | ||||
|       return OAUTH3.discover(providerUri, opts).then(function (directive) { | ||||
|         var prequest = OAUTH3.urls.refreshToken(directive, opts); | ||||
| 
 | ||||
|         return OAUTH3.request(prequest).then(function (req) { | ||||
|           var data = req.data; | ||||
|           data.provider_uri = providerUri; | ||||
|           if (data.error) { | ||||
|             return OAUTH3.PromiseA.reject(OAUTH3.utils._formatError(providerUri, data)); | ||||
|           } | ||||
|           return OAUTH3.hooks.session.refresh(opts, data); | ||||
|         }); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     //
 | ||||
| @ -477,10 +736,7 @@ | ||||
|           } | ||||
| 
 | ||||
| 
 | ||||
|           console.log('[oauth3.implicit.js] callbackName', '--oauth3-callback-' + state); | ||||
|           window['--oauth3-callback-' + state] = function (params) { | ||||
|             console.log("YO HO YO HO, A Pirate's life for me!", state); | ||||
|             console.error(new Error("Pirate's Life").stack); | ||||
|             resolve(params); | ||||
|             cleanup(); | ||||
|           }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user