243 lines
8.3 KiB
JavaScript
243 lines
8.3 KiB
JavaScript
/*! @azure/msal-common v14.4.0 2023-11-07 */
|
|
'use strict';
|
|
import { extractTokenClaims } from '../../account/AuthToken.mjs';
|
|
import { createClientAuthError } from '../../error/ClientAuthError.mjs';
|
|
import { Separators, CredentialType, AuthenticationScheme, SERVER_TELEM_CONSTANTS } from '../../utils/Constants.mjs';
|
|
import { TimeUtils } from '../../utils/TimeUtils.mjs';
|
|
import { tokenClaimsCnfRequiredForSignedJwt } from '../../error/ClientAuthErrorCodes.mjs';
|
|
|
|
/*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License.
|
|
*/
|
|
/**
|
|
* Cache Key: <home_account_id>-<environment>-<credential_type>-<client_id or familyId>-<realm>-<scopes>-<claims hash>-<scheme>
|
|
* IdToken Example: uid.utid-login.microsoftonline.com-idtoken-app_client_id-contoso.com
|
|
* AccessToken Example: uid.utid-login.microsoftonline.com-accesstoken-app_client_id-contoso.com-scope1 scope2--pop
|
|
* RefreshToken Example: uid.utid-login.microsoftonline.com-refreshtoken-1-contoso.com
|
|
* @param credentialEntity
|
|
* @returns
|
|
*/
|
|
function generateCredentialKey(credentialEntity) {
|
|
const credentialKey = [
|
|
generateAccountId(credentialEntity),
|
|
generateCredentialId(credentialEntity),
|
|
generateTarget(credentialEntity),
|
|
generateClaimsHash(credentialEntity),
|
|
generateScheme(credentialEntity),
|
|
];
|
|
return credentialKey.join(Separators.CACHE_KEY_SEPARATOR).toLowerCase();
|
|
}
|
|
/**
|
|
* Create IdTokenEntity
|
|
* @param homeAccountId
|
|
* @param authenticationResult
|
|
* @param clientId
|
|
* @param authority
|
|
*/
|
|
function createIdTokenEntity(homeAccountId, environment, idToken, clientId, tenantId) {
|
|
const idTokenEntity = {
|
|
credentialType: CredentialType.ID_TOKEN,
|
|
homeAccountId: homeAccountId,
|
|
environment: environment,
|
|
clientId: clientId,
|
|
secret: idToken,
|
|
realm: tenantId,
|
|
};
|
|
return idTokenEntity;
|
|
}
|
|
/**
|
|
* Create AccessTokenEntity
|
|
* @param homeAccountId
|
|
* @param environment
|
|
* @param accessToken
|
|
* @param clientId
|
|
* @param tenantId
|
|
* @param scopes
|
|
* @param expiresOn
|
|
* @param extExpiresOn
|
|
*/
|
|
function createAccessTokenEntity(homeAccountId, environment, accessToken, clientId, tenantId, scopes, expiresOn, extExpiresOn, base64Decode, refreshOn, tokenType, userAssertionHash, keyId, requestedClaims, requestedClaimsHash) {
|
|
const atEntity = {
|
|
homeAccountId: homeAccountId,
|
|
credentialType: CredentialType.ACCESS_TOKEN,
|
|
secret: accessToken,
|
|
cachedAt: TimeUtils.nowSeconds().toString(),
|
|
expiresOn: expiresOn.toString(),
|
|
extendedExpiresOn: extExpiresOn.toString(),
|
|
environment: environment,
|
|
clientId: clientId,
|
|
realm: tenantId,
|
|
target: scopes,
|
|
tokenType: tokenType || AuthenticationScheme.BEARER,
|
|
};
|
|
if (userAssertionHash) {
|
|
atEntity.userAssertionHash = userAssertionHash;
|
|
}
|
|
if (refreshOn) {
|
|
atEntity.refreshOn = refreshOn.toString();
|
|
}
|
|
if (requestedClaims) {
|
|
atEntity.requestedClaims = requestedClaims;
|
|
atEntity.requestedClaimsHash = requestedClaimsHash;
|
|
}
|
|
/*
|
|
* Create Access Token With Auth Scheme instead of regular access token
|
|
* Cast to lower to handle "bearer" from ADFS
|
|
*/
|
|
if (atEntity.tokenType?.toLowerCase() !==
|
|
AuthenticationScheme.BEARER.toLowerCase()) {
|
|
atEntity.credentialType = CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME;
|
|
switch (atEntity.tokenType) {
|
|
case AuthenticationScheme.POP:
|
|
// Make sure keyId is present and add it to credential
|
|
const tokenClaims = extractTokenClaims(accessToken, base64Decode);
|
|
if (!tokenClaims?.cnf?.kid) {
|
|
throw createClientAuthError(tokenClaimsCnfRequiredForSignedJwt);
|
|
}
|
|
atEntity.keyId = tokenClaims.cnf.kid;
|
|
break;
|
|
case AuthenticationScheme.SSH:
|
|
atEntity.keyId = keyId;
|
|
}
|
|
}
|
|
return atEntity;
|
|
}
|
|
/**
|
|
* Create RefreshTokenEntity
|
|
* @param homeAccountId
|
|
* @param authenticationResult
|
|
* @param clientId
|
|
* @param authority
|
|
*/
|
|
function createRefreshTokenEntity(homeAccountId, environment, refreshToken, clientId, familyId, userAssertionHash) {
|
|
const rtEntity = {
|
|
credentialType: CredentialType.REFRESH_TOKEN,
|
|
homeAccountId: homeAccountId,
|
|
environment: environment,
|
|
clientId: clientId,
|
|
secret: refreshToken,
|
|
};
|
|
if (userAssertionHash) {
|
|
rtEntity.userAssertionHash = userAssertionHash;
|
|
}
|
|
if (familyId) {
|
|
rtEntity.familyId = familyId;
|
|
}
|
|
return rtEntity;
|
|
}
|
|
function isCredentialEntity(entity) {
|
|
return (entity.hasOwnProperty("homeAccountId") &&
|
|
entity.hasOwnProperty("environment") &&
|
|
entity.hasOwnProperty("credentialType") &&
|
|
entity.hasOwnProperty("clientId") &&
|
|
entity.hasOwnProperty("secret"));
|
|
}
|
|
/**
|
|
* Validates an entity: checks for all expected params
|
|
* @param entity
|
|
*/
|
|
function isAccessTokenEntity(entity) {
|
|
if (!entity) {
|
|
return false;
|
|
}
|
|
return (isCredentialEntity(entity) &&
|
|
entity.hasOwnProperty("realm") &&
|
|
entity.hasOwnProperty("target") &&
|
|
(entity["credentialType"] === CredentialType.ACCESS_TOKEN ||
|
|
entity["credentialType"] ===
|
|
CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME));
|
|
}
|
|
/**
|
|
* Validates an entity: checks for all expected params
|
|
* @param entity
|
|
*/
|
|
function isIdTokenEntity(entity) {
|
|
if (!entity) {
|
|
return false;
|
|
}
|
|
return (isCredentialEntity(entity) &&
|
|
entity.hasOwnProperty("realm") &&
|
|
entity["credentialType"] === CredentialType.ID_TOKEN);
|
|
}
|
|
/**
|
|
* Validates an entity: checks for all expected params
|
|
* @param entity
|
|
*/
|
|
function isRefreshTokenEntity(entity) {
|
|
if (!entity) {
|
|
return false;
|
|
}
|
|
return (isCredentialEntity(entity) &&
|
|
entity["credentialType"] === CredentialType.REFRESH_TOKEN);
|
|
}
|
|
/**
|
|
* Generate Account Id key component as per the schema: <home_account_id>-<environment>
|
|
*/
|
|
function generateAccountId(credentialEntity) {
|
|
const accountId = [
|
|
credentialEntity.homeAccountId,
|
|
credentialEntity.environment,
|
|
];
|
|
return accountId.join(Separators.CACHE_KEY_SEPARATOR).toLowerCase();
|
|
}
|
|
/**
|
|
* Generate Credential Id key component as per the schema: <credential_type>-<client_id>-<realm>
|
|
*/
|
|
function generateCredentialId(credentialEntity) {
|
|
const clientOrFamilyId = credentialEntity.credentialType === CredentialType.REFRESH_TOKEN
|
|
? credentialEntity.familyId || credentialEntity.clientId
|
|
: credentialEntity.clientId;
|
|
const credentialId = [
|
|
credentialEntity.credentialType,
|
|
clientOrFamilyId,
|
|
credentialEntity.realm || "",
|
|
];
|
|
return credentialId.join(Separators.CACHE_KEY_SEPARATOR).toLowerCase();
|
|
}
|
|
/**
|
|
* Generate target key component as per schema: <target>
|
|
*/
|
|
function generateTarget(credentialEntity) {
|
|
return (credentialEntity.target || "").toLowerCase();
|
|
}
|
|
/**
|
|
* Generate requested claims key component as per schema: <requestedClaims>
|
|
*/
|
|
function generateClaimsHash(credentialEntity) {
|
|
return (credentialEntity.requestedClaimsHash || "").toLowerCase();
|
|
}
|
|
/**
|
|
* Generate scheme key componenet as per schema: <scheme>
|
|
*/
|
|
function generateScheme(credentialEntity) {
|
|
/*
|
|
* PoP Tokens and SSH certs include scheme in cache key
|
|
* Cast to lowercase to handle "bearer" from ADFS
|
|
*/
|
|
return credentialEntity.tokenType &&
|
|
credentialEntity.tokenType.toLowerCase() !==
|
|
AuthenticationScheme.BEARER.toLowerCase()
|
|
? credentialEntity.tokenType.toLowerCase()
|
|
: "";
|
|
}
|
|
/**
|
|
* validates if a given cache entry is "Telemetry", parses <key,value>
|
|
* @param key
|
|
* @param entity
|
|
*/
|
|
function isServerTelemetryEntity(key, entity) {
|
|
const validateKey = key.indexOf(SERVER_TELEM_CONSTANTS.CACHE_KEY) === 0;
|
|
let validateEntity = true;
|
|
if (entity) {
|
|
validateEntity =
|
|
entity.hasOwnProperty("failedRequests") &&
|
|
entity.hasOwnProperty("errors") &&
|
|
entity.hasOwnProperty("cacheHits");
|
|
}
|
|
return validateKey && validateEntity;
|
|
}
|
|
|
|
export { createAccessTokenEntity, createIdTokenEntity, createRefreshTokenEntity, generateCredentialKey, isAccessTokenEntity, isCredentialEntity, isIdTokenEntity, isRefreshTokenEntity, isServerTelemetryEntity };
|
|
//# sourceMappingURL=CacheHelpers.mjs.map
|