190 lines
8.0 KiB
JavaScript
190 lines
8.0 KiB
JavaScript
'use strict';
|
|
|
|
var propertyProvider = require('@smithy/property-provider');
|
|
var sharedIniFileLoader = require('@smithy/shared-ini-file-loader');
|
|
var client = require('@aws-sdk/core/client');
|
|
var tokenProviders = require('@aws-sdk/token-providers');
|
|
|
|
const isSsoProfile = (arg) => arg &&
|
|
(typeof arg.sso_start_url === "string" ||
|
|
typeof arg.sso_account_id === "string" ||
|
|
typeof arg.sso_session === "string" ||
|
|
typeof arg.sso_region === "string" ||
|
|
typeof arg.sso_role_name === "string");
|
|
|
|
const SHOULD_FAIL_CREDENTIAL_CHAIN = false;
|
|
const resolveSSOCredentials = async ({ ssoStartUrl, ssoSession, ssoAccountId, ssoRegion, ssoRoleName, ssoClient, clientConfig, parentClientConfig, profile, filepath, configFilepath, ignoreCache, logger, }) => {
|
|
let token;
|
|
const refreshMessage = `To refresh this SSO session run aws sso login with the corresponding profile.`;
|
|
if (ssoSession) {
|
|
try {
|
|
const _token = await tokenProviders.fromSso({
|
|
profile,
|
|
filepath,
|
|
configFilepath,
|
|
ignoreCache,
|
|
})();
|
|
token = {
|
|
accessToken: _token.token,
|
|
expiresAt: new Date(_token.expiration).toISOString(),
|
|
};
|
|
}
|
|
catch (e) {
|
|
throw new propertyProvider.CredentialsProviderError(e.message, {
|
|
tryNextLink: SHOULD_FAIL_CREDENTIAL_CHAIN,
|
|
logger,
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
try {
|
|
token = await sharedIniFileLoader.getSSOTokenFromFile(ssoStartUrl);
|
|
}
|
|
catch (e) {
|
|
throw new propertyProvider.CredentialsProviderError(`The SSO session associated with this profile is invalid. ${refreshMessage}`, {
|
|
tryNextLink: SHOULD_FAIL_CREDENTIAL_CHAIN,
|
|
logger,
|
|
});
|
|
}
|
|
}
|
|
if (new Date(token.expiresAt).getTime() - Date.now() <= 0) {
|
|
throw new propertyProvider.CredentialsProviderError(`The SSO session associated with this profile has expired. ${refreshMessage}`, {
|
|
tryNextLink: SHOULD_FAIL_CREDENTIAL_CHAIN,
|
|
logger,
|
|
});
|
|
}
|
|
const { accessToken } = token;
|
|
const { SSOClient, GetRoleCredentialsCommand } = await Promise.resolve().then(function () { return require('./loadSso-CVy8iqsZ.js'); });
|
|
const sso = ssoClient ||
|
|
new SSOClient(Object.assign({}, clientConfig ?? {}, {
|
|
logger: clientConfig?.logger ?? parentClientConfig?.logger,
|
|
region: clientConfig?.region ?? ssoRegion,
|
|
}));
|
|
let ssoResp;
|
|
try {
|
|
ssoResp = await sso.send(new GetRoleCredentialsCommand({
|
|
accountId: ssoAccountId,
|
|
roleName: ssoRoleName,
|
|
accessToken,
|
|
}));
|
|
}
|
|
catch (e) {
|
|
throw new propertyProvider.CredentialsProviderError(e, {
|
|
tryNextLink: SHOULD_FAIL_CREDENTIAL_CHAIN,
|
|
logger,
|
|
});
|
|
}
|
|
const { roleCredentials: { accessKeyId, secretAccessKey, sessionToken, expiration, credentialScope, accountId } = {}, } = ssoResp;
|
|
if (!accessKeyId || !secretAccessKey || !sessionToken || !expiration) {
|
|
throw new propertyProvider.CredentialsProviderError("SSO returns an invalid temporary credential.", {
|
|
tryNextLink: SHOULD_FAIL_CREDENTIAL_CHAIN,
|
|
logger,
|
|
});
|
|
}
|
|
const credentials = {
|
|
accessKeyId,
|
|
secretAccessKey,
|
|
sessionToken,
|
|
expiration: new Date(expiration),
|
|
...(credentialScope && { credentialScope }),
|
|
...(accountId && { accountId }),
|
|
};
|
|
if (ssoSession) {
|
|
client.setCredentialFeature(credentials, "CREDENTIALS_SSO", "s");
|
|
}
|
|
else {
|
|
client.setCredentialFeature(credentials, "CREDENTIALS_SSO_LEGACY", "u");
|
|
}
|
|
return credentials;
|
|
};
|
|
|
|
const validateSsoProfile = (profile, logger) => {
|
|
const { sso_start_url, sso_account_id, sso_region, sso_role_name } = profile;
|
|
if (!sso_start_url || !sso_account_id || !sso_region || !sso_role_name) {
|
|
throw new propertyProvider.CredentialsProviderError(`Profile is configured with invalid SSO credentials. Required parameters "sso_account_id", ` +
|
|
`"sso_region", "sso_role_name", "sso_start_url". Got ${Object.keys(profile).join(", ")}\nReference: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html`, { tryNextLink: false, logger });
|
|
}
|
|
return profile;
|
|
};
|
|
|
|
const fromSSO = (init = {}) => async ({ callerClientConfig } = {}) => {
|
|
init.logger?.debug("@aws-sdk/credential-provider-sso - fromSSO");
|
|
const { ssoStartUrl, ssoAccountId, ssoRegion, ssoRoleName, ssoSession } = init;
|
|
const { ssoClient } = init;
|
|
const profileName = sharedIniFileLoader.getProfileName({
|
|
profile: init.profile ?? callerClientConfig?.profile,
|
|
});
|
|
if (!ssoStartUrl && !ssoAccountId && !ssoRegion && !ssoRoleName && !ssoSession) {
|
|
const profiles = await sharedIniFileLoader.parseKnownFiles(init);
|
|
const profile = profiles[profileName];
|
|
if (!profile) {
|
|
throw new propertyProvider.CredentialsProviderError(`Profile ${profileName} was not found.`, { logger: init.logger });
|
|
}
|
|
if (!isSsoProfile(profile)) {
|
|
throw new propertyProvider.CredentialsProviderError(`Profile ${profileName} is not configured with SSO credentials.`, {
|
|
logger: init.logger,
|
|
});
|
|
}
|
|
if (profile?.sso_session) {
|
|
const ssoSessions = await sharedIniFileLoader.loadSsoSessionData(init);
|
|
const session = ssoSessions[profile.sso_session];
|
|
const conflictMsg = ` configurations in profile ${profileName} and sso-session ${profile.sso_session}`;
|
|
if (ssoRegion && ssoRegion !== session.sso_region) {
|
|
throw new propertyProvider.CredentialsProviderError(`Conflicting SSO region` + conflictMsg, {
|
|
tryNextLink: false,
|
|
logger: init.logger,
|
|
});
|
|
}
|
|
if (ssoStartUrl && ssoStartUrl !== session.sso_start_url) {
|
|
throw new propertyProvider.CredentialsProviderError(`Conflicting SSO start_url` + conflictMsg, {
|
|
tryNextLink: false,
|
|
logger: init.logger,
|
|
});
|
|
}
|
|
profile.sso_region = session.sso_region;
|
|
profile.sso_start_url = session.sso_start_url;
|
|
}
|
|
const { sso_start_url, sso_account_id, sso_region, sso_role_name, sso_session } = validateSsoProfile(profile, init.logger);
|
|
return resolveSSOCredentials({
|
|
ssoStartUrl: sso_start_url,
|
|
ssoSession: sso_session,
|
|
ssoAccountId: sso_account_id,
|
|
ssoRegion: sso_region,
|
|
ssoRoleName: sso_role_name,
|
|
ssoClient: ssoClient,
|
|
clientConfig: init.clientConfig,
|
|
parentClientConfig: init.parentClientConfig,
|
|
profile: profileName,
|
|
filepath: init.filepath,
|
|
configFilepath: init.configFilepath,
|
|
ignoreCache: init.ignoreCache,
|
|
logger: init.logger,
|
|
});
|
|
}
|
|
else if (!ssoStartUrl || !ssoAccountId || !ssoRegion || !ssoRoleName) {
|
|
throw new propertyProvider.CredentialsProviderError("Incomplete configuration. The fromSSO() argument hash must include " +
|
|
'"ssoStartUrl", "ssoAccountId", "ssoRegion", "ssoRoleName"', { tryNextLink: false, logger: init.logger });
|
|
}
|
|
else {
|
|
return resolveSSOCredentials({
|
|
ssoStartUrl,
|
|
ssoSession,
|
|
ssoAccountId,
|
|
ssoRegion,
|
|
ssoRoleName,
|
|
ssoClient,
|
|
clientConfig: init.clientConfig,
|
|
parentClientConfig: init.parentClientConfig,
|
|
profile: profileName,
|
|
filepath: init.filepath,
|
|
configFilepath: init.configFilepath,
|
|
ignoreCache: init.ignoreCache,
|
|
logger: init.logger,
|
|
});
|
|
}
|
|
};
|
|
|
|
exports.fromSSO = fromSSO;
|
|
exports.isSsoProfile = isSsoProfile;
|
|
exports.validateSsoProfile = validateSsoProfile;
|