restricted saving keys to the issuer only
This commit is contained in:
		
							parent
							
								
									f260b5afc0
								
							
						
					
					
						commit
						faea77bd10
					
				
							
								
								
									
										88
									
								
								rest.js
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								rest.js
									
									
									
									
									
								
							| @ -20,6 +20,46 @@ module.exports.create = function (bigconf, deps, app) { | |||||||
|     next(); |     next(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |   function authorizeIssuer(req, res, next) { | ||||||
|  |     var promise = PromiseA.resolve().then(function () { | ||||||
|  |       // It might seem unnecessary to wrap a promise in another promise, but this way it will
 | ||||||
|  |       // catch the error thrown when a token isn't provided and verifyAsync isn't a function.
 | ||||||
|  |       return req.oauth3.verifyAsync(); | ||||||
|  |     }).then(function (token) { | ||||||
|  |       // Now that we've confirmed the token is valid we also need to make sure the authorized party
 | ||||||
|  |       // is us.
 | ||||||
|  |       // TODO: For the time being the only verify-able tokens are the ones we issued, but this
 | ||||||
|  |       // will not always be the case. We will need a better way to verify the authorized party.
 | ||||||
|  |       if (token.iss !== token.azp || token.iss !== token.aud) { | ||||||
|  |         throw new Error("token does not allow access to requested resource"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       var sub = token.sub || token.ppid || (token.acx && (token.acx.id || token.acx.appScopedId)); | ||||||
|  |       if (!sub) { | ||||||
|  |         if (!Array.isArray(token.axs) || !token.axs.length) { | ||||||
|  |           throw new Error("no account pairwise identifier"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         var allowed = token.axs.some(function (acc) { | ||||||
|  |           return req.params.sub === (acc.id || acc.ppid || acc.appScopedId); | ||||||
|  |         }); | ||||||
|  |         if (!allowed) { | ||||||
|  |           throw new Error("no account pairwise identifier matching '" + req.params.sub + "'"); | ||||||
|  |         } | ||||||
|  |         sub = req.params.sub; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (req.params.sub !== sub) { | ||||||
|  |         throw new Error("token does not allow access to resources for '"+req.params.sub+"'"); | ||||||
|  |       } | ||||||
|  |       next(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     app.handleRejection(req, res, promise, '[issuer@oauth3.org] authorize req as issuer'); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|   Jwks.thumbprint = function (jwk) { |   Jwks.thumbprint = function (jwk) { | ||||||
|     // To produce a thumbprint we need to create a JSON string with only the required keys for
 |     // To produce a thumbprint we need to create a JSON string with only the required keys for
 | ||||||
|     // the key type, with the keys sorted lexicographically and no white space. We then need
 |     // the key type, with the keys sorted lexicographically and no white space. We then need
 | ||||||
| @ -88,44 +128,12 @@ module.exports.create = function (bigconf, deps, app) { | |||||||
|       return { success: true }; |       return { success: true }; | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     app.handlePromise(req, res, promise, "[issuer@oauth3.org] create JWK"); |     app.handlePromise(req, res, promise, "[issuer@oauth3.org] save JWK"); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   Grants.authorizeReq = function (req) { |  | ||||||
|     return PromiseA.resolve().then(function () { |  | ||||||
|       // It might seem unnecessary to wrap a promise in another promise, but this way it will
 |  | ||||||
|       // catch the error thrown when a token isn't found and verifyAsync isn't a function.
 |  | ||||||
|       return req.oauth3.verifyAsync(); |  | ||||||
|     }).then(function (token) { |  | ||||||
|       // Just because the token is valid doesn't mean the token is authorized to get or save grants.
 |  | ||||||
|       // The only place that should be allowed to access grants on behalf of the user is the issuer.
 |  | ||||||
|       if (token.iss !== token.azp) { |  | ||||||
|         throw new Error("token does not allow access to grants"); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       var sub = token.sub || token.ppid || (token.acx && (token.acx.id || token.acx.appScopedId)); |  | ||||||
|       if (!sub) { |  | ||||||
|         if (!Array.isArray(token.axs) || !token.axs.length) { |  | ||||||
|           throw new Error("no account pairwise identifier"); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         var allowed = token.axs.some(function (acc) { |  | ||||||
|           return req.params.sub === (acc.id || acc.ppid || acc.appScopedId); |  | ||||||
|         }); |  | ||||||
|         if (!allowed) { |  | ||||||
|           throw new Error("no account pairwise identifier matching '" + req.params.sub + "'"); |  | ||||||
|         } |  | ||||||
|         sub = req.params.sub; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return sub; |  | ||||||
|     }); |  | ||||||
|   }; |  | ||||||
| 
 | 
 | ||||||
|   Grants.restful.getOne = function (req, res) { |   Grants.restful.getOne = function (req, res) { | ||||||
|     var promise = Grants.authorizeReq(req).then(function (sub) { |     var promise = req.Store.get(req.params.sub+'/'+req.params.azp).then(function (grant) { | ||||||
|       return req.Store.get(sub+'/'+req.params.azp); |  | ||||||
|     }).then(function (grant) { |  | ||||||
|       if (!grant) { |       if (!grant) { | ||||||
|         throw new Error('no grants found'); |         throw new Error('no grants found'); | ||||||
|       } |       } | ||||||
| @ -140,9 +148,7 @@ module.exports.create = function (bigconf, deps, app) { | |||||||
|     app.handlePromise(req, res, promise, "[issuer@oauth3.org] retrieve grants"); |     app.handlePromise(req, res, promise, "[issuer@oauth3.org] retrieve grants"); | ||||||
|   }; |   }; | ||||||
|   Grants.restful.getAll = function (req, res) { |   Grants.restful.getAll = function (req, res) { | ||||||
|     var promise = Grants.authorizeReq(req).then(function (sub) { |     var promise = req.Store.find({ sub: req.params.sub }).then(function (results) { | ||||||
|       return req.Store.find({ sub: sub }); |  | ||||||
|     }).then(function (results) { |  | ||||||
|       return results.map(function (grant) { |       return results.map(function (grant) { | ||||||
|         return { |         return { | ||||||
|           sub:   grant.sub, |           sub:   grant.sub, | ||||||
| @ -158,14 +164,14 @@ module.exports.create = function (bigconf, deps, app) { | |||||||
|     app.handlePromise(req, res, promise, "[issuer@oauth3.org] retrieve grants"); |     app.handlePromise(req, res, promise, "[issuer@oauth3.org] retrieve grants"); | ||||||
|   }; |   }; | ||||||
|   Grants.restful.saveNew = function (req, res) { |   Grants.restful.saveNew = function (req, res) { | ||||||
|     var promise = Grants.authorizeReq(req).then(function (sub) { |     var promise = PromiseA.resolve().then(function () { | ||||||
|       if (typeof req.body.scope !== 'string') { |       if (typeof req.body.scope !== 'string') { | ||||||
|         throw new Error("malformed request: 'scope' should be a string"); |         throw new Error("malformed request: 'scope' should be a string"); | ||||||
|       } |       } | ||||||
|       var scope = req.body.scope.split(/[+ ,]+/g).join(','); |       var scope = req.body.scope.split(/[+ ,]+/g).join(','); | ||||||
| 
 | 
 | ||||||
|       var grant = { |       var grant = { | ||||||
|         sub:   sub, |         sub:   req.params.sub, | ||||||
|         azp:   req.params.azp, |         azp:   req.params.azp, | ||||||
|         scope: scope, |         scope: scope, | ||||||
|       }; |       }; | ||||||
| @ -179,9 +185,11 @@ module.exports.create = function (bigconf, deps, app) { | |||||||
| 
 | 
 | ||||||
|   app.use(   '/jwks', attachSiteStore.bind(null, 'IssuerOauth3OrgJwks')); |   app.use(   '/jwks', attachSiteStore.bind(null, 'IssuerOauth3OrgJwks')); | ||||||
|   app.get(   '/jwks/:kid.json', Jwks.restful.get); |   app.get(   '/jwks/:kid.json', Jwks.restful.get); | ||||||
|  |   app.use(   '/jwks/:sub', authorizeIssuer); // Everything but getting keys is only for the issuer
 | ||||||
|   app.post(  '/jwks/:sub', Jwks.restful.saveNew); |   app.post(  '/jwks/:sub', Jwks.restful.saveNew); | ||||||
| 
 | 
 | ||||||
|   app.use(   '/grants', attachSiteStore.bind(null, 'IssuerOauth3OrgGrants')); |   // Everything regarding grants is only for the issuer
 | ||||||
|  |   app.use(   '/grants/:sub', authorizeIssuer, attachSiteStore.bind(null, 'IssuerOauth3OrgGrants')); | ||||||
|   app.get(   '/grants/:sub', Grants.restful.getAll); |   app.get(   '/grants/:sub', Grants.restful.getAll); | ||||||
|   app.get(   '/grants/:sub/:azp', Grants.restful.getOne); |   app.get(   '/grants/:sub/:azp', Grants.restful.getOne); | ||||||
|   app.post(  '/grants/:sub/:azp', Grants.restful.saveNew); |   app.post(  '/grants/:sub/:azp', Grants.restful.saveNew); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user