80 lines
3.6 KiB
JavaScript
80 lines
3.6 KiB
JavaScript
|
import { TokenProviderError } from "@smithy/property-provider";
|
||
|
import { getProfileName, getSSOTokenFromFile, loadSsoSessionData, parseKnownFiles, } from "@smithy/shared-ini-file-loader";
|
||
|
import { EXPIRE_WINDOW_MS, REFRESH_MESSAGE } from "./constants";
|
||
|
import { getNewSsoOidcToken } from "./getNewSsoOidcToken";
|
||
|
import { validateTokenExpiry } from "./validateTokenExpiry";
|
||
|
import { validateTokenKey } from "./validateTokenKey";
|
||
|
import { writeSSOTokenToFile } from "./writeSSOTokenToFile";
|
||
|
const lastRefreshAttemptTime = new Date(0);
|
||
|
export const fromSso = (init = {}) => async () => {
|
||
|
init.logger?.debug("@aws-sdk/token-providers", "fromSso");
|
||
|
const profiles = await parseKnownFiles(init);
|
||
|
const profileName = getProfileName(init);
|
||
|
const profile = profiles[profileName];
|
||
|
if (!profile) {
|
||
|
throw new TokenProviderError(`Profile '${profileName}' could not be found in shared credentials file.`, false);
|
||
|
}
|
||
|
else if (!profile["sso_session"]) {
|
||
|
throw new TokenProviderError(`Profile '${profileName}' is missing required property 'sso_session'.`);
|
||
|
}
|
||
|
const ssoSessionName = profile["sso_session"];
|
||
|
const ssoSessions = await loadSsoSessionData(init);
|
||
|
const ssoSession = ssoSessions[ssoSessionName];
|
||
|
if (!ssoSession) {
|
||
|
throw new TokenProviderError(`Sso session '${ssoSessionName}' could not be found in shared credentials file.`, false);
|
||
|
}
|
||
|
for (const ssoSessionRequiredKey of ["sso_start_url", "sso_region"]) {
|
||
|
if (!ssoSession[ssoSessionRequiredKey]) {
|
||
|
throw new TokenProviderError(`Sso session '${ssoSessionName}' is missing required property '${ssoSessionRequiredKey}'.`, false);
|
||
|
}
|
||
|
}
|
||
|
const ssoStartUrl = ssoSession["sso_start_url"];
|
||
|
const ssoRegion = ssoSession["sso_region"];
|
||
|
let ssoToken;
|
||
|
try {
|
||
|
ssoToken = await getSSOTokenFromFile(ssoSessionName);
|
||
|
}
|
||
|
catch (e) {
|
||
|
throw new TokenProviderError(`The SSO session token associated with profile=${profileName} was not found or is invalid. ${REFRESH_MESSAGE}`, false);
|
||
|
}
|
||
|
validateTokenKey("accessToken", ssoToken.accessToken);
|
||
|
validateTokenKey("expiresAt", ssoToken.expiresAt);
|
||
|
const { accessToken, expiresAt } = ssoToken;
|
||
|
const existingToken = { token: accessToken, expiration: new Date(expiresAt) };
|
||
|
if (existingToken.expiration.getTime() - Date.now() > EXPIRE_WINDOW_MS) {
|
||
|
return existingToken;
|
||
|
}
|
||
|
if (Date.now() - lastRefreshAttemptTime.getTime() < 30 * 1000) {
|
||
|
validateTokenExpiry(existingToken);
|
||
|
return existingToken;
|
||
|
}
|
||
|
validateTokenKey("clientId", ssoToken.clientId, true);
|
||
|
validateTokenKey("clientSecret", ssoToken.clientSecret, true);
|
||
|
validateTokenKey("refreshToken", ssoToken.refreshToken, true);
|
||
|
try {
|
||
|
lastRefreshAttemptTime.setTime(Date.now());
|
||
|
const newSsoOidcToken = await getNewSsoOidcToken(ssoToken, ssoRegion);
|
||
|
validateTokenKey("accessToken", newSsoOidcToken.accessToken);
|
||
|
validateTokenKey("expiresIn", newSsoOidcToken.expiresIn);
|
||
|
const newTokenExpiration = new Date(Date.now() + newSsoOidcToken.expiresIn * 1000);
|
||
|
try {
|
||
|
await writeSSOTokenToFile(ssoSessionName, {
|
||
|
...ssoToken,
|
||
|
accessToken: newSsoOidcToken.accessToken,
|
||
|
expiresAt: newTokenExpiration.toISOString(),
|
||
|
refreshToken: newSsoOidcToken.refreshToken,
|
||
|
});
|
||
|
}
|
||
|
catch (error) {
|
||
|
}
|
||
|
return {
|
||
|
token: newSsoOidcToken.accessToken,
|
||
|
expiration: newTokenExpiration,
|
||
|
};
|
||
|
}
|
||
|
catch (error) {
|
||
|
validateTokenExpiry(existingToken);
|
||
|
return existingToken;
|
||
|
}
|
||
|
};
|