68 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			68 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| var PromiseA = require('bluebird');
 | |
| var OpErr = PromiseA.OperationalError;
 | |
| 
 | |
| function makeB64UrlSafe(b64) {
 | |
|   return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=*$/, '');
 | |
| }
 | |
| 
 | |
| function checkIssuerToken(req, expectedSub) {
 | |
|   if (!req.oauth3 || !req.oauth3.verifyAsync) {
 | |
|     return PromiseA.reject(new OpErr("request requires a token for authorization"));
 | |
|   }
 | |
|   return req.oauth3.verifyAsync().then(function (token) {
 | |
|     // Now that we've confirmed the token is valid we also need to make sure the issuer, audience,
 | |
|     // and authorized party are all us, because no other app should be managing user identity.
 | |
|     if (token.iss !== req.experienceId || token.aud !== token.iss || token.azp !== token.iss) {
 | |
|       throw new OpErr("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 (!expectedSub || !Array.isArray(token.axs) || !token.axs.length) {
 | |
|         throw new OpErr("no account pairwise identifier");
 | |
|       }
 | |
| 
 | |
|       var allowed = token.axs.some(function (acc) {
 | |
|         return expectedSub === (acc.id || acc.ppid || acc.appScopedId);
 | |
|       });
 | |
|       if (!allowed) {
 | |
|         throw new OpErr("no account pairwise identifier matching '" + expectedSub + "'");
 | |
|       }
 | |
|       sub = expectedSub;
 | |
|     }
 | |
| 
 | |
|     if (expectedSub && expectedSub !== sub) {
 | |
|       throw new OpErr("token does not allow access to resources for '"+expectedSub+"'");
 | |
|     }
 | |
|     return sub;
 | |
|   });
 | |
| }
 | |
| 
 | |
| async function getPrimarySub(grantStore, secondary) {
 | |
|   var results = await Promise.all([
 | |
|     grantStore.find({ sub:    secondary }),
 | |
|     grantStore.find({ azpSub: secondary }),
 | |
|   ]);
 | |
| 
 | |
|   // Extract only the sub field from each row and reduce the duplicates so that each value
 | |
|   // can only appear in the final list once.
 | |
|   var subList = [].concat.apply([], results).map(grant => grant.sub);
 | |
|   subList = subList.filter((sub, ind, list) => list.indexOf(sub) === ind);
 | |
| 
 | |
|   if (subList.length > 1) {
 | |
|     // This should not ever happen since there is a check for PPID collisions when saving
 | |
|     // grants, but it's probably better to have this check anyway just incase something
 | |
|     // happens that isn't currently accounted for.
 | |
|     console.error('acounts ' + JSON.stringify(subList) + ' are all associated with "'+secondary+'"');
 | |
|     throw new Error('PPID collision');
 | |
|   }
 | |
| 
 | |
|   return subList[0];
 | |
| }
 | |
| 
 | |
| module.exports.checkIssuerToken = checkIssuerToken;
 | |
| module.exports.getPrimarySub = getPrimarySub;
 | |
| module.exports.makeB64UrlSafe = makeB64UrlSafe;
 |