updated how grants are retrieved
This commit is contained in:
		
							parent
							
								
									c38554a9dd
								
							
						
					
					
						commit
						1ca6f0a324
					
				| @ -168,9 +168,12 @@ | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   , scope: { |   , scope: { | ||||||
|       stringify: function (scope) { |       parse: function (scope) { | ||||||
|  |         return (scope||'').split(/[+, ]+/g); | ||||||
|  |       } | ||||||
|  |     , stringify: function (scope) { | ||||||
|         if (Array.isArray(scope)) { |         if (Array.isArray(scope)) { | ||||||
|           scope = scope.join(' '); |           scope = scope.join(','); | ||||||
|         } |         } | ||||||
|         return scope; |         return scope; | ||||||
|       } |       } | ||||||
|  | |||||||
							
								
								
									
										203
									
								
								oauth3.issuer.js
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								oauth3.issuer.js
									
									
									
									
									
								
							| @ -3,39 +3,6 @@ | |||||||
| 
 | 
 | ||||||
| var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.core.js').OAUTH3; | var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.core.js').OAUTH3; | ||||||
| 
 | 
 | ||||||
| OAUTH3.query.parse = function (search) { |  | ||||||
|   // parse a query or a hash
 |  | ||||||
|   if (-1 !== ['#', '?'].indexOf(search[0])) { |  | ||||||
|     search = search.substring(1); |  | ||||||
|   } |  | ||||||
|   // Solve for case of search within hash
 |  | ||||||
|   // example: #/authorization_dialog/?state=...&redirect_uri=...
 |  | ||||||
|   var queryIndex = search.indexOf('?'); |  | ||||||
|   if (-1 !== queryIndex) { |  | ||||||
|     search = search.substr(queryIndex + 1); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   var args = search.split('&'); |  | ||||||
|   var argsParsed = {}; |  | ||||||
|   var i, arg, kvp, key, value; |  | ||||||
| 
 |  | ||||||
|   for (i = 0; i < args.length; i += 1) { |  | ||||||
|     arg = args[i]; |  | ||||||
|     if (-1 === arg.indexOf('=')) { |  | ||||||
|       argsParsed[decodeURIComponent(arg).trim()] = true; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|       kvp = arg.split('='); |  | ||||||
|       key = decodeURIComponent(kvp[0]).trim(); |  | ||||||
|       value = decodeURIComponent(kvp[1]).trim(); |  | ||||||
|       argsParsed[key] = value; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return argsParsed; |  | ||||||
| }; |  | ||||||
| OAUTH3.scope.parse = function (scope) { |  | ||||||
|   return (scope||'').split(/[, ]/g); |  | ||||||
| }; |  | ||||||
| OAUTH3.url.parse = function (url) { | OAUTH3.url.parse = function (url) { | ||||||
|   // TODO browser
 |   // TODO browser
 | ||||||
|   // Node should replace this
 |   // Node should replace this
 | ||||||
| @ -58,8 +25,16 @@ OAUTH3.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) { | |||||||
| }; | }; | ||||||
| OAUTH3.url.checkRedirect = function (client, query) { | OAUTH3.url.checkRedirect = function (client, query) { | ||||||
|   console.warn("[security] URL path checking not yet implemented"); |   console.warn("[security] URL path checking not yet implemented"); | ||||||
|  |   if (!query) { | ||||||
|  |     query = client; | ||||||
|  |     client = query.client_uri; | ||||||
|  |   } | ||||||
|  |   client = client.url || client; | ||||||
| 
 | 
 | ||||||
|   var clientUrl = OAUTH3.url.normalize(client.url); |   // 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)
 | ||||||
|  |   var clientUrl = OAUTH3.url.normalize(client); | ||||||
|   var redirectUrl = OAUTH3.url.normalize(query.redirect_uri); |   var redirectUrl = OAUTH3.url.normalize(query.redirect_uri); | ||||||
| 
 | 
 | ||||||
|   // General rule:
 |   // General rule:
 | ||||||
| @ -72,6 +47,18 @@ OAUTH3.url.checkRedirect = function (client, query) { | |||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   var callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK?'+OAUTH3.query.stringify({ | ||||||
|  |     'redirect_uri': redirectUrl | ||||||
|  |   , 'allowed_urls': clientUrl | ||||||
|  |   , 'client_id':    client | ||||||
|  |   , 'referrer_uri': OAUTH3.uri.normalize(window.document.referrer) | ||||||
|  |   }); | ||||||
|  |   if (query.debug) { | ||||||
|  |     console.log('Redirect Attack'); | ||||||
|  |     console.log(query); | ||||||
|  |     window.alert("DEBUG MODE checkRedirect error encountered. Check the console."); | ||||||
|  |   } | ||||||
|  |   location.href = callbackUrl; | ||||||
|   return false; |   return false; | ||||||
| }; | }; | ||||||
| OAUTH3.url.redirect = function (clientParams, grants, tokenOrError) { | OAUTH3.url.redirect = function (clientParams, grants, tokenOrError) { | ||||||
| @ -195,14 +182,12 @@ OAUTH3.urls.grants = function (directive, opts) { | |||||||
|     console.warn("You should supply options.referrer"); |     console.warn("You should supply options.referrer"); | ||||||
|   } |   } | ||||||
|   if (!opts.method) { |   if (!opts.method) { | ||||||
|     console.warn("You must supply options.method as either 'GET', or 'POST'"); |     console.warn("You should supply options.method as either 'GET', or 'POST'"); | ||||||
|  |     opts.method = 'GET'; | ||||||
|   } |   } | ||||||
|   if ('POST' === opts.method) { |   if ('POST' === opts.method) { | ||||||
|     if ('string' !== typeof opts.scope) { |     if ('string' !== typeof opts.scope) { | ||||||
|       console.warn("You should supply options.scope as a space-delimited string of scopes"); |       throw new Error("You must supply options.scope as a comma-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'"); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -214,12 +199,10 @@ OAUTH3.urls.grants = function (directive, opts) { | |||||||
|     client_id: opts.client_id |     client_id: opts.client_id | ||||||
|   , client_uri: opts.client_uri |   , client_uri: opts.client_uri | ||||||
|   , referrer: opts.referrer |   , referrer: opts.referrer | ||||||
|   , response_type: opts.response_type |  | ||||||
|   , scope: opts.scope |   , scope: opts.scope | ||||||
|   , tenant_id: opts.tenant_id |  | ||||||
|   }; |   }; | ||||||
|   var body; |  | ||||||
| 
 | 
 | ||||||
|  |   var body; | ||||||
|   if ('GET' === opts.method) { |   if ('GET' === opts.method) { | ||||||
|     url += '?' + OAUTH3.query.stringify(data); |     url += '?' + OAUTH3.query.stringify(data); | ||||||
|   } |   } | ||||||
| @ -290,50 +273,8 @@ OAUTH3.authn.resourceOwnerPassword = function (directive, opts) { | |||||||
| 
 | 
 | ||||||
| OAUTH3.authz = {}; | OAUTH3.authz = {}; | ||||||
| OAUTH3.authz.scopes = function (providerUri, session, clientParams) { | OAUTH3.authz.scopes = function (providerUri, session, clientParams) { | ||||||
|   // OAuth3.requests.grants(providerUri, {});         // return list of grants
 |  | ||||||
|   // OAuth3.checkGrants(providerUri, {});             //
 |  | ||||||
|   var clientUri = OAUTH3.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer); |   var clientUri = OAUTH3.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer); | ||||||
|   var scope = clientParams.scope || ''; |   var scope = clientParams.scope || 'oauth3_authn'; | ||||||
|   var clientObj = clientParams; |  | ||||||
| 
 |  | ||||||
|   if (!scope) { |  | ||||||
|     scope = 'oauth3_authn'; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return OAUTH3.authz.grants(providerUri, { |  | ||||||
|     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; |  | ||||||
| 
 |  | ||||||
|     // 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.url.checkRedirect(grantResults.client, clientObj)) { |  | ||||||
|       callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK' |  | ||||||
|         + '?redirect_uri=' + clientObj.redirect_uri |  | ||||||
|         + '&allowed_urls=' + grantResults.client.url |  | ||||||
|         + '&client_id=' + clientUri |  | ||||||
|         + '&referrer_uri=' + OAUTH3.uri.normalize(window.document.referrer) |  | ||||||
|         ; |  | ||||||
|       if (clientParams.debug) { |  | ||||||
|         console.log('grantResults Redirect Attack'); |  | ||||||
|         console.log(grantResults); |  | ||||||
|         console.log(clientObj); |  | ||||||
|         window.alert("DEBUG MODE checkRedirect error encountered. Check the console."); |  | ||||||
|       } |  | ||||||
|       location.href = callbackUrl; |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   if ('oauth3_authn' === scope) { |   if ('oauth3_authn' === scope) { | ||||||
|     // implicit ppid grant is automatic
 |     // implicit ppid grant is automatic
 | ||||||
|     console.warn('[security] fix scope checking on backend so that we can do automatic grants'); |     console.warn('[security] fix scope checking on backend so that we can do automatic grants'); | ||||||
| @ -341,38 +282,35 @@ OAUTH3.authz.scopes = function (providerUri, session, clientParams) { | |||||||
|     //return generateToken(session, clientObj);
 |     //return generateToken(session, clientObj);
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|     grants = (grantResults).grants.filter(function (grant) { |   return OAUTH3.authz.grants(providerUri, { | ||||||
|       if (clientUri === (grant.azp || grant.oauth_client_id || grant.oauthClientId)) { |     method: 'GET' | ||||||
|         return true; |   , client_id: clientUri | ||||||
|  |   , client_uri: clientUri | ||||||
|  |   , session: session | ||||||
|  |   }).then(function (results) { | ||||||
|  |     return results.grants; | ||||||
|  |   }, function (err) { | ||||||
|  |     if (!/no .*grants .*found/i.test(err.message)) { | ||||||
|  |       console.error(err); | ||||||
|  |     } | ||||||
|  |     return []; | ||||||
|  |   }).then(function (granted) { | ||||||
|  |     var requested = OAUTH3.scope.parse(scope); | ||||||
|  |     var accepted = []; | ||||||
|  |     var pending = []; | ||||||
|  |     requested.forEach(function (scp) { | ||||||
|  |       if (granted.indexOf(scp) < 0) { | ||||||
|  |         pending.push(scp); | ||||||
|  |       } else { | ||||||
|  |         accepted.push(scp); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     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 { |     return { | ||||||
|       pending: pendingScopes    // not yet accepted
 |       requested: requested  // all requested, now
 | ||||||
|     , granted: grantedScopes    // all granted, ever
 |     , granted:   granted    // all granted, ever
 | ||||||
|     , requested: scopes         // all requested, now
 |     , accepted:  accepted   // intersection of granted (ever) and requested (now)
 | ||||||
|     , accepted: acceptedScopes  // granted (ever) and requested (now)
 |     , pending:   pending     // not yet accepted
 | ||||||
|     }; |     }; | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| @ -381,34 +319,27 @@ OAUTH3.authz.grants = function (providerUri, opts) { | |||||||
|     client_id: providerUri |     client_id: providerUri | ||||||
|   , debug: opts.debug |   , debug: opts.debug | ||||||
|   }).then(function (directive) { |   }).then(function (directive) { | ||||||
| 
 |     return OAUTH3.request(OAUTH3.urls.grants(directive, opts), opts); | ||||||
|     return OAUTH3.request(OAUTH3.urls.grants(directive, opts), opts).then(function (grantsResult) { |   }).then(function (grantsResult) { | ||||||
|       if ('POST' === opts.method) { |  | ||||||
|         // TODO this is clientToken
 |  | ||||||
|         return grantsResult.originalData || grantsResult.data; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|     var grants = grantsResult.originalData || grantsResult.data; |     var grants = grantsResult.originalData || grantsResult.data; | ||||||
|       // TODO
 |  | ||||||
|     if (grants.error) { |     if (grants.error) { | ||||||
|       return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, grants)); |       return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, grants)); | ||||||
|     } |     } | ||||||
|  |     if ('POST' === opts.method) { | ||||||
|  |       return grants; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|       OAUTH3.hooks.grants.set(opts.client_id + '-client', grants.client); |     OAUTH3.hooks.grants.set(grants.sub+'/'+grants.azp, grants.scope); | ||||||
|       grants.grants.forEach(function (grant) { |  | ||||||
|         var clientId = grant.client_id || grant.oauth_client_id || grant.oauthClientId; |  | ||||||
|         // TODO should save as an array
 |  | ||||||
|         OAUTH3.hooks.grants.set(clientId, [ grant ]); |  | ||||||
|       }); |  | ||||||
| 
 |  | ||||||
|     return { |     return { | ||||||
|         client: OAUTH3.hooks.grants.get(opts.client_id + '-client') |       client: grants.azp | ||||||
|       , grants: OAUTH3.hooks.grants.get(opts.client_id) || [] |     , grants: OAUTH3.scope.parse(grants.scope) | ||||||
|     }; |     }; | ||||||
|   }); |   }); | ||||||
|   }); |  | ||||||
| }; | }; | ||||||
| OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) { | OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) { | ||||||
|  |   if (!OAUTH3.url.checkRedirect(clientParams.client_uri, clientParams)) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   scopes.new = scopes.new || []; |   scopes.new = scopes.new || []; | ||||||
| 
 | 
 | ||||||
| @ -427,15 +358,6 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s | |||||||
| 
 | 
 | ||||||
|       // TODO limit refresh token to an expirable token
 |       // TODO limit refresh token to an expirable token
 | ||||||
|       // TODO inform client not to persist token
 |       // TODO inform client not to persist token
 | ||||||
|       /* |  | ||||||
|       if (clientParams.dnsTxt) { |  | ||||||
|         Object.keys(results).forEach(function (key) { |  | ||||||
|           if (/refresh/.test(key)) { |  | ||||||
|             results[key] = undefined; |  | ||||||
|           } |  | ||||||
|         }); |  | ||||||
|       } |  | ||||||
|       */ |  | ||||||
|       OAUTH3.url.redirect(clientParams, scopes, results); |       OAUTH3.url.redirect(clientParams, scopes, results); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| @ -447,6 +369,7 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s | |||||||
|     throw new Error("Authorization Code Redirect NOT IMPLEMENTED"); |     throw new Error("Authorization Code Redirect NOT IMPLEMENTED"); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
| OAUTH3.requests = {}; | OAUTH3.requests = {}; | ||||||
| OAUTH3.requests.accounts = {}; | OAUTH3.requests.accounts = {}; | ||||||
| OAUTH3.requests.accounts.update = function (directive, session, opts) { | OAUTH3.requests.accounts.update = function (directive, session, opts) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user