@aws-amplify/cli-internal
Version:
Amplify CLI
775 lines • 52 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthRenderer = void 0;
const typescript_1 = __importDefault(require("typescript"));
const client_cognito_identity_provider_1 = require("@aws-sdk/client-cognito-identity-provider");
const ts_1 = require("../../ts");
const resource_types_1 = require("../../../_common/resource-types");
const factory = typescript_1.default.factory;
const secretIdentifier = factory.createIdentifier('secret');
const googleClientID = 'GOOGLE_CLIENT_ID';
const googleClientSecret = 'GOOGLE_CLIENT_SECRET';
const amazonClientID = 'LOGINWITHAMAZON_CLIENT_ID';
const amazonClientSecret = 'LOGINWITHAMAZON_CLIENT_SECRET';
const facebookClientID = 'FACEBOOK_CLIENT_ID';
const facebookClientSecret = 'FACEBOOK_CLIENT_SECRET';
const appleClientID = 'SIWA_CLIENT_ID';
const appleKeyId = 'SIWA_KEY_ID';
const applePrivateKey = 'SIWA_PRIVATE_KEY';
const appleTeamID = 'SIWA_TEAM_ID';
const oidcClientID = 'OIDC_CLIENT_ID';
const oidcClientSecret = 'OIDC_CLIENT_SECRET';
const MAPPED_USER_ATTRIBUTE_NAME = {
address: 'address',
birthdate: 'birthdate',
email: 'email',
family_name: 'familyName',
gender: 'gender',
given_name: 'givenName',
locale: 'locale',
middle_name: 'middleName',
name: 'fullname',
nickname: 'nickname',
phone_number: 'phoneNumber',
picture: 'profilePicture',
preferred_username: 'preferredUsername',
profile: 'profilePage',
zoneinfo: 'timezone',
updated_at: 'lastUpdateTime',
website: 'website',
};
const MAP_IDENTITY_PROVIDER = {
[client_cognito_identity_provider_1.IdentityProviderTypeType.Google]: ['googleLogin', 'googleAttributes'],
[client_cognito_identity_provider_1.IdentityProviderTypeType.SignInWithApple]: ['appleLogin', 'appleAttributes'],
[client_cognito_identity_provider_1.IdentityProviderTypeType.LoginWithAmazon]: ['amazonLogin', 'amazonAttributes'],
[client_cognito_identity_provider_1.IdentityProviderTypeType.Facebook]: ['facebookLogin', 'facebookAttributes'],
};
function createTriggersProperty(triggers) {
return factory.createPropertyAssignment(factory.createIdentifier('triggers'), factory.createObjectLiteralExpression(triggers.map((t) => factory.createPropertyAssignment(factory.createIdentifier(t.event), factory.createIdentifier(t.resourceName))), true));
}
class AuthRenderer {
render(options) {
const namedImports = { '@aws-amplify/backend': new Set() };
const baseNodes = this.renderStandardAuth(options, namedImports);
const additionalImportDeclarations = this.renderCdkImports(options);
const backendTypeImport = this.renderBackendTypeImport();
const applyEscapeHatchesDeclarations = this.renderApplyEscapeHatches(options);
const postRefactorDeclaration = options.userPool.Domain ? this.renderPostRefactor(options) : undefined;
const allNodes = [];
let foundFirstNonImport = false;
for (const node of baseNodes) {
if (!foundFirstNonImport && typescript_1.default.isImportDeclaration(node)) {
allNodes.push(node);
}
else {
if (!foundFirstNonImport) {
for (const declaration of additionalImportDeclarations) {
allNodes.push(declaration);
}
allNodes.push(backendTypeImport);
foundFirstNonImport = true;
}
allNodes.push(node);
}
}
if (!foundFirstNonImport) {
for (const declaration of additionalImportDeclarations) {
allNodes.push(declaration);
}
allNodes.push(backendTypeImport);
}
allNodes.push(ts_1.newLineIdentifier);
allNodes.push(applyEscapeHatchesDeclarations);
if (postRefactorDeclaration) {
allNodes.push(ts_1.newLineIdentifier);
allNodes.push(postRefactorDeclaration);
}
return factory.createNodeArray(allNodes);
}
renderBackendTypeImport() {
return ts_1.TS.typeImport('../backend', 'Backend');
}
renderCdkImports(options) {
const additionalImports = this.buildAdditionalImports(options);
const declarations = [];
for (const [source, identifiers] of Object.entries(additionalImports)) {
declarations.push(ts_1.TS.namedImport(source, ...Array.from(identifiers)));
}
return declarations;
}
renderApplyEscapeHatches(options) {
const escapeHatchStatements = this.buildEscapeHatchStatements(options);
return ts_1.TS.exportedFunction('applyEscapeHatches', escapeHatchStatements);
}
renderPostRefactor(options) {
return ts_1.TS.exportedFunction('postRefactor', this.buildDomainOverrideStatements(options.userPool.Domain));
}
renderStandardAuth(options, namedImports) {
var _a, _b, _c;
namedImports['@aws-amplify/backend'].add('defineAuth');
const defineAuthProperties = [];
const loginFlags = AuthRenderer.deriveLoginFlags(options.identityProviders);
const hasExternalProviders = loginFlags.googleLogin ||
loginFlags.amazonLogin ||
loginFlags.appleLogin ||
loginFlags.facebookLogin ||
((_a = options.identityProviders) !== null && _a !== void 0 ? _a : []).some((p) => p.ProviderType === client_cognito_identity_provider_1.IdentityProviderTypeType.OIDC) ||
((_b = options.identityProviders) !== null && _b !== void 0 ? _b : []).some((p) => p.ProviderType === client_cognito_identity_provider_1.IdentityProviderTypeType.SAML);
if (hasExternalProviders) {
namedImports['@aws-amplify/backend'].add('secret');
}
defineAuthProperties.push(this.createLogInWithPropertyAssignment(options, loginFlags));
const standardAttributes = AuthRenderer.deriveStandardUserAttributes(options.userPool.SchemaAttributes);
const customAttributes = AuthRenderer.deriveCustomUserAttributes(options.userPool.SchemaAttributes);
const hasStandard = Object.keys(standardAttributes).length > 0;
const hasCustom = Object.keys(customAttributes).length > 0;
if (hasStandard || hasCustom) {
defineAuthProperties.push(this.createUserAttributeAssignments(hasStandard ? standardAttributes : undefined, hasCustom ? customAttributes : undefined));
}
const groups = AuthRenderer.deriveGroups(options.identityGroups);
if (groups.length > 0) {
defineAuthProperties.push(factory.createPropertyAssignment(factory.createIdentifier('groups'), factory.createArrayLiteralExpression(groups.map((g) => factory.createStringLiteral(g)))));
}
this.addLambdaTriggers((_c = options.triggers) !== null && _c !== void 0 ? _c : [], defineAuthProperties, namedImports);
const mfa = AuthRenderer.deriveMfaConfig(options.mfaConfig);
this.addMfaConfig(mfa, defineAuthProperties);
this.addFunctionAccess(options.access, defineAuthProperties, namedImports);
return ts_1.TS.renderResourceTsFile({
exportedVariableName: factory.createIdentifier('auth'),
functionCallParameter: factory.createObjectLiteralExpression(defineAuthProperties, true),
additionalImportedBackendIdentifiers: namedImports,
backendFunctionConstruct: 'defineAuth',
});
}
static deriveLoginFlags(providers) {
const flags = {
googleLogin: false,
amazonLogin: false,
appleLogin: false,
facebookLogin: false,
};
if (!providers)
return flags;
for (const provider of providers) {
const mapping = MAP_IDENTITY_PROVIDER[provider === null || provider === void 0 ? void 0 : provider.ProviderType];
if (mapping) {
flags[mapping[0]] = true;
}
}
return flags;
}
static deriveExternalProviders(details) {
var _a;
const oidcProviders = [];
let samlProvider;
const attributeMappings = {};
const providerScopes = {};
if (!details) {
return { oidcProviders, samlProvider, attributeMappings, providerScopes };
}
for (const provider of details) {
const { ProviderType, ProviderName, ProviderDetails, AttributeMapping } = provider;
if (ProviderType === client_cognito_identity_provider_1.IdentityProviderTypeType.OIDC && ProviderDetails) {
const { oidc_issuer, authorize_url, token_url, attributes_url, jwks_uri } = ProviderDetails;
const endpoints = authorize_url && token_url && attributes_url && jwks_uri
? { authorization: authorize_url, token: token_url, userInfo: attributes_url, jwksUri: jwks_uri }
: undefined;
const oidcMapping = AttributeMapping ? AuthRenderer.filterAttributeMapping(AttributeMapping) : undefined;
oidcProviders.push({
issuerUrl: oidc_issuer,
name: ProviderName,
endpoints,
attributeMapping: oidcMapping ? { ...oidcMapping.standard, ...oidcMapping.custom } : undefined,
});
}
else if (ProviderType === client_cognito_identity_provider_1.IdentityProviderTypeType.SAML && ProviderDetails) {
const { metadataURL, metadataContent } = ProviderDetails;
const samlMapping = AttributeMapping ? AuthRenderer.filterAttributeMapping(AttributeMapping) : undefined;
samlProvider = {
metadata: {
metadataContent: metadataURL || metadataContent,
metadataType: metadataURL ? 'URL' : 'FILE',
},
name: ProviderName,
attributeMapping: samlMapping ? { ...samlMapping.standard, ...samlMapping.custom } : undefined,
};
}
else {
if (AttributeMapping) {
const filteredMapping = AuthRenderer.filterAttributeMapping(AttributeMapping);
const attributeProperty = (_a = MAP_IDENTITY_PROVIDER[provider === null || provider === void 0 ? void 0 : provider.ProviderType]) === null || _a === void 0 ? void 0 : _a[1];
if (attributeProperty) {
attributeMappings[attributeProperty] = filteredMapping;
}
}
if (ProviderDetails) {
const scopes = AuthRenderer.deriveProviderSpecificScopes(ProviderDetails);
if (scopes.length > 0) {
const mapped = scopes.filter((scope) => scope.length > 0);
if (mapped.length > 0 && ProviderType) {
providerScopes[ProviderType] = mapped;
}
}
}
}
}
return { oidcProviders, samlProvider, attributeMappings, providerScopes };
}
static deriveMfaConfig(mfa) {
var _a, _b, _c, _d;
if ((mfa === null || mfa === void 0 ? void 0 : mfa.MfaConfiguration) === 'ON') {
return { mode: 'REQUIRED', sms: true, totp: (_b = (_a = mfa.SoftwareTokenMfaConfiguration) === null || _a === void 0 ? void 0 : _a.Enabled) !== null && _b !== void 0 ? _b : false };
}
if ((mfa === null || mfa === void 0 ? void 0 : mfa.MfaConfiguration) === 'OPTIONAL') {
return { mode: 'OPTIONAL', sms: true, totp: (_d = (_c = mfa.SoftwareTokenMfaConfiguration) === null || _c === void 0 ? void 0 : _c.Enabled) !== null && _d !== void 0 ? _d : false };
}
return { mode: 'OFF' };
}
static deriveStandardUserAttributes(schema) {
if (!schema)
return {};
const result = {};
for (const attribute of schema) {
if (!attribute.Name || !(attribute.Name in MAPPED_USER_ATTRIBUTE_NAME))
continue;
if (!attribute.Required)
continue;
result[MAPPED_USER_ATTRIBUTE_NAME[attribute.Name]] = {
required: attribute.Required,
mutable: attribute.Mutable,
};
}
return result;
}
static deriveCustomUserAttributes(schema) {
if (!schema)
return {};
const result = {};
for (const attribute of schema) {
if (attribute.Name && attribute.Name.startsWith('custom:')) {
const constraints = attribute.NumberAttributeConstraints && Object.keys(attribute.NumberAttributeConstraints).length > 0
? { min: Number(attribute.NumberAttributeConstraints.MinValue), max: Number(attribute.NumberAttributeConstraints.MaxValue) }
: attribute.StringAttributeConstraints && Object.keys(attribute.StringAttributeConstraints).length > 0
? {
minLen: Number(attribute.StringAttributeConstraints.MinLength),
maxLen: Number(attribute.StringAttributeConstraints.MaxLength),
}
: {};
result[attribute.Name] = {
mutable: attribute.Mutable,
dataType: attribute.AttributeDataType,
...constraints,
};
}
}
return result;
}
static deriveGroups(groups) {
if (!groups || groups.length === 0)
return [];
return groups
.filter((group) => group.Precedence !== undefined)
.sort((a, b) => (a.Precedence || 0) - (b.Precedence || 0))
.map((group) => group.GroupName)
.filter((name) => name !== undefined);
}
static deriveUserPoolOverrides(userPool) {
var _a, _b;
const overrides = {};
const passwordPolicy = (_b = (_a = userPool.Policies) === null || _a === void 0 ? void 0 : _a.PasswordPolicy) !== null && _b !== void 0 ? _b : {};
for (const key of Object.keys(passwordPolicy)) {
const typedKey = key;
if (passwordPolicy[typedKey] !== undefined) {
overrides[`Policies.PasswordPolicy.${typedKey}`] = passwordPolicy[typedKey];
}
}
if (userPool.UsernameAttributes === undefined || userPool.UsernameAttributes.length === 0) {
overrides.usernameAttributes = undefined;
}
else {
overrides.usernameAttributes = userPool.UsernameAttributes;
}
if (userPool.AliasAttributes !== undefined && userPool.AliasAttributes.length > 0) {
overrides.aliasAttributes = userPool.AliasAttributes;
}
return overrides;
}
static deriveProviderSpecificScopes(providerDetails) {
const scopeFields = ['authorize_scopes', 'authorized_scopes', 'scope', 'scopes'];
for (const field of scopeFields) {
if (providerDetails[field]) {
return providerDetails[field].split(/[\s,]+/).filter((scope) => scope.length > 0);
}
}
return [];
}
static filterAttributeMapping(attributeMapping) {
const standard = {};
const custom = {};
for (const [key, value] of Object.entries(attributeMapping)) {
if (key in MAPPED_USER_ATTRIBUTE_NAME) {
standard[MAPPED_USER_ATTRIBUTE_NAME[key]] = value;
}
else {
custom[key] = value;
}
}
return { standard, custom };
}
addLambdaTriggers(triggers, properties, namedImports) {
if (triggers.length === 0)
return;
properties.push(createTriggersProperty(triggers));
for (const trigger of triggers) {
const importPath = `../function/${trigger.resourceName}/resource`;
if (!namedImports[importPath]) {
namedImports[importPath] = new Set();
}
namedImports[importPath].add(trigger.resourceName);
}
}
addMfaConfig(mfa, properties) {
const multifactorProperties = [
factory.createPropertyAssignment(factory.createIdentifier('mode'), factory.createStringLiteral(mfa.mode)),
];
if (mfa.totp !== undefined) {
multifactorProperties.push(factory.createPropertyAssignment(factory.createIdentifier('totp'), mfa.totp ? factory.createTrue() : factory.createFalse()));
}
if (mfa.sms !== undefined) {
multifactorProperties.push(factory.createPropertyAssignment(factory.createIdentifier('sms'), mfa.sms ? factory.createTrue() : factory.createFalse()));
}
properties.push(factory.createPropertyAssignment(factory.createIdentifier('multifactor'), factory.createObjectLiteralExpression(multifactorProperties, true)));
}
addFunctionAccess(functions, properties, namedImports) {
if (!functions || functions.length === 0) {
return;
}
const functionsWithAuthAccess = functions.filter((func) => Object.keys(func.permissions).length > 0);
if (functionsWithAuthAccess.length === 0) {
return;
}
for (const func of functionsWithAuthAccess) {
const alreadyImported = Object.values(namedImports).some((names) => names.has(func.resourceName));
if (!alreadyImported) {
namedImports[`../function/${func.resourceName}/resource`] = new Set([func.resourceName]);
}
}
const accessRules = [];
for (const func of functionsWithAuthAccess) {
for (const [permission, enabled] of Object.entries(func.permissions)) {
if (enabled) {
accessRules.push(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('allow'), factory.createIdentifier('resource')), undefined, [factory.createIdentifier(func.resourceName)]), factory.createIdentifier('to')), undefined, [factory.createArrayLiteralExpression([factory.createStringLiteral(permission)])]));
}
}
}
if (accessRules.length > 0) {
properties.push(factory.createPropertyAssignment(factory.createIdentifier('access'), factory.createArrowFunction(undefined, undefined, [
factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier('allow')),
factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier('_unused')),
], undefined, undefined, factory.createArrayLiteralExpression(accessRules, true))));
}
}
createLogInWithPropertyAssignment(options, loginFlags) {
var _a, _b;
const logInWith = factory.createIdentifier('loginWith');
const assignments = [];
const emailOptions = options.userPool.EmailVerificationMessage || options.userPool.EmailVerificationSubject
? {
emailVerificationBody: (_a = options.userPool.EmailVerificationMessage) !== null && _a !== void 0 ? _a : '',
emailVerificationSubject: (_b = options.userPool.EmailVerificationSubject) !== null && _b !== void 0 ? _b : '',
}
: undefined;
if (emailOptions) {
assignments.push(factory.createPropertyAssignment(factory.createIdentifier('email'), this.createEmailDefinitionObject(emailOptions)));
}
else {
assignments.push(factory.createPropertyAssignment(factory.createIdentifier('email'), factory.createTrue()));
}
const externalProviders = AuthRenderer.deriveExternalProviders(options.identityProviders);
const hasExternalProviders = loginFlags.googleLogin ||
loginFlags.amazonLogin ||
loginFlags.appleLogin ||
loginFlags.facebookLogin ||
externalProviders.oidcProviders.length > 0 ||
externalProviders.samlProvider !== undefined;
if (hasExternalProviders) {
assignments.push(factory.createPropertyAssignment(factory.createIdentifier('externalProviders'), this.createExternalProvidersExpression(loginFlags, externalProviders, options.webClient.CallbackURLs, options.webClient.LogoutURLs)));
}
return factory.createPropertyAssignment(logInWith, factory.createObjectLiteralExpression(assignments, true));
}
createEmailDefinitionObject(emailOptions) {
const emailDefinitionAssignments = [];
if (emailOptions.emailVerificationSubject) {
emailDefinitionAssignments.push(factory.createPropertyAssignment('verificationEmailSubject', factory.createStringLiteral(emailOptions.emailVerificationSubject)));
}
if (emailOptions.emailVerificationBody) {
emailDefinitionAssignments.push(factory.createPropertyAssignment('verificationEmailBody', factory.createArrowFunction(undefined, undefined, [], undefined, undefined, factory.createStringLiteral(emailOptions.emailVerificationBody))));
}
return factory.createObjectLiteralExpression(emailDefinitionAssignments, true);
}
createExternalProvidersExpression(loginFlags, externalProviders, callbackUrls, logoutUrls) {
const providerAssignments = [];
if (loginFlags.googleLogin) {
const googleConfig = {
clientId: googleClientID,
clientSecret: googleClientSecret,
};
const googleScopes = externalProviders.providerScopes[client_cognito_identity_provider_1.IdentityProviderTypeType.Google];
if (googleScopes && googleScopes.length > 0) {
googleConfig.scopes = googleScopes.join(' ');
}
providerAssignments.push(AuthRenderer.createProviderPropertyAssignment('google', googleConfig, externalProviders.attributeMappings.googleAttributes));
}
if (loginFlags.appleLogin) {
const appleConfig = {
clientId: appleClientID,
keyId: appleKeyId,
privateKey: applePrivateKey,
teamId: appleTeamID,
};
const appleScopes = externalProviders.providerScopes[client_cognito_identity_provider_1.IdentityProviderTypeType.SignInWithApple];
if (appleScopes && appleScopes.length > 0) {
appleConfig.scopes = appleScopes.join(' ');
}
providerAssignments.push(AuthRenderer.createProviderPropertyAssignment('signInWithApple', appleConfig, externalProviders.attributeMappings.appleAttributes));
}
if (loginFlags.amazonLogin) {
const amazonConfig = {
clientId: amazonClientID,
clientSecret: amazonClientSecret,
};
const amazonScopes = externalProviders.providerScopes[client_cognito_identity_provider_1.IdentityProviderTypeType.LoginWithAmazon];
if (amazonScopes && amazonScopes.length > 0) {
amazonConfig.scopes = amazonScopes.join(' ');
}
providerAssignments.push(AuthRenderer.createProviderPropertyAssignment('loginWithAmazon', amazonConfig, externalProviders.attributeMappings.amazonAttributes));
}
if (loginFlags.facebookLogin) {
const facebookConfig = {
clientId: facebookClientID,
clientSecret: facebookClientSecret,
};
const facebookScopes = externalProviders.providerScopes[client_cognito_identity_provider_1.IdentityProviderTypeType.Facebook];
if (facebookScopes && facebookScopes.length > 0) {
facebookConfig.scopes = facebookScopes.join(' ');
}
providerAssignments.push(AuthRenderer.createProviderPropertyAssignment('facebook', facebookConfig, externalProviders.attributeMappings.facebookAttributes));
}
if (externalProviders.samlProvider) {
providerAssignments.push(factory.createPropertyAssignment(factory.createIdentifier('saml'), factory.createObjectLiteralExpression(AuthRenderer.createOidcSamlPropertyAssignments(externalProviders.samlProvider), true)));
}
if (externalProviders.oidcProviders.length > 0) {
providerAssignments.push(factory.createPropertyAssignment(factory.createIdentifier('oidc'), factory.createArrayLiteralExpression(externalProviders.oidcProviders.map((oidc, index) => factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier('clientId'), factory.createCallExpression(secretIdentifier, undefined, [
factory.createStringLiteral(`${oidcClientID}_${index + 1}`),
])),
factory.createPropertyAssignment(factory.createIdentifier('clientSecret'), factory.createCallExpression(secretIdentifier, undefined, [
factory.createStringLiteral(`${oidcClientSecret}_${index + 1}`),
])),
...AuthRenderer.createOidcSamlPropertyAssignments(oidc),
], true)), true)));
}
const properties = [
...providerAssignments,
typescript_1.default.addSyntheticLeadingComment(factory.createPropertyAssignment(factory.createIdentifier('callbackUrls'), factory.createArrayLiteralExpression(callbackUrls === null || callbackUrls === void 0 ? void 0 : callbackUrls.map((url) => factory.createStringLiteral(url)))), typescript_1.default.SyntaxKind.SingleLineCommentTrivia, ' Add the Gen2 Amplify Hosting URL (e.g. https://<branch>.<gen2-appId>.amplifyapp.com/) to the following array after the gen2-main branch is deployed.', true),
typescript_1.default.addSyntheticLeadingComment(factory.createPropertyAssignment(factory.createIdentifier('logoutUrls'), factory.createArrayLiteralExpression(logoutUrls === null || logoutUrls === void 0 ? void 0 : logoutUrls.map((url) => factory.createStringLiteral(url)))), typescript_1.default.SyntaxKind.SingleLineCommentTrivia, ' Add the Gen2 Amplify Hosting URL (e.g. https://<branch>.<gen2-appId>.amplifyapp.com/) to the following array after the gen2-main branch is deployed.', true),
];
return factory.createObjectLiteralExpression(properties, true);
}
createUserAttributeAssignments(standardAttributes, customAttributes) {
const userAttributeIdentifier = factory.createIdentifier('userAttributes');
const userAttributeProperties = [];
if (standardAttributes !== undefined) {
const standardAttributeProperties = Object.entries(standardAttributes).map(([key, value]) => {
return factory.createPropertyAssignment(factory.createIdentifier(key), AuthRenderer.createAttributeDefinition(value));
});
userAttributeProperties.push(...standardAttributeProperties);
}
if (customAttributes !== undefined) {
const customAttributeProperties = Object.entries(customAttributes)
.map(([key, value]) => {
if (value !== undefined) {
return factory.createPropertyAssignment(factory.createStringLiteral(key), AuthRenderer.createAttributeDefinition(value));
}
return undefined;
})
.filter((property) => property !== undefined);
userAttributeProperties.push(...customAttributeProperties);
}
return factory.createPropertyAssignment(userAttributeIdentifier, factory.createObjectLiteralExpression(userAttributeProperties, true));
}
static createAttributeDefinition(attribute) {
const properties = [];
for (const key of Object.keys(attribute)) {
const value = attribute[key];
if (typeof value === 'boolean') {
properties.push(factory.createPropertyAssignment(factory.createIdentifier(key), value ? factory.createTrue() : factory.createFalse()));
}
else if (typeof value === 'string') {
properties.push(factory.createPropertyAssignment(factory.createIdentifier(key), factory.createStringLiteral(value)));
}
else if (typeof value === 'number') {
properties.push(factory.createPropertyAssignment(factory.createIdentifier(key), factory.createNumericLiteral(value)));
}
}
return factory.createObjectLiteralExpression(properties, true);
}
static createProviderConfig(config, attributeMapping) {
const properties = [];
Object.entries(config).forEach(([key, value]) => {
if (key === 'scopes') {
const scopeArray = value.split(' ').filter((scope) => scope.length > 0);
properties.push(factory.createPropertyAssignment(factory.createIdentifier('scopes'), factory.createArrayLiteralExpression(scopeArray.map((scope) => factory.createStringLiteral(scope)))));
}
else {
properties.push(factory.createPropertyAssignment(factory.createIdentifier(key), factory.createCallExpression(secretIdentifier, undefined, [factory.createStringLiteral(value)])));
}
});
if (attributeMapping) {
const mappingProperties = [];
Object.entries(attributeMapping.standard).forEach(([key, value]) => mappingProperties.push(factory.createPropertyAssignment(factory.createIdentifier(key), factory.createStringLiteral(value))));
if (Object.keys(attributeMapping.custom).length > 0) {
const customProperties = [];
Object.entries(attributeMapping.custom).forEach(([key, value]) => customProperties.push(factory.createPropertyAssignment(factory.createIdentifier(key), factory.createStringLiteral(value))));
mappingProperties.push(factory.createPropertyAssignment(factory.createIdentifier('custom'), factory.createObjectLiteralExpression(customProperties, true)));
}
properties.push(factory.createPropertyAssignment(factory.createIdentifier('attributeMapping'), factory.createObjectLiteralExpression(mappingProperties, true)));
}
return properties;
}
static createProviderPropertyAssignment(name, config, attributeMapping) {
return factory.createPropertyAssignment(factory.createIdentifier(name), factory.createObjectLiteralExpression(AuthRenderer.createProviderConfig(config, attributeMapping), true));
}
static createOidcSamlPropertyAssignments(config) {
return Object.entries(config).flatMap(([key, value]) => {
if (typeof value === 'string') {
return [factory.createPropertyAssignment(factory.createIdentifier(key), factory.createStringLiteral(value))];
}
else if (typeof value === 'object' && value !== null) {
return [
factory.createPropertyAssignment(factory.createIdentifier(key), factory.createObjectLiteralExpression(AuthRenderer.createOidcSamlPropertyAssignments(value), true)),
];
}
return [];
});
}
buildEscapeHatchStatements(options) {
var _a, _b;
const statements = [];
const hasIdentityProviders = AuthRenderer.hasIdentityProviders(options.nativeClient);
const userPoolOverrides = AuthRenderer.deriveUserPoolOverrides(options.userPool);
if (Object.keys(userPoolOverrides).length > 0) {
statements.push(...this.buildUserPoolOverrideStatements(userPoolOverrides));
}
const needsCfnIdentityPool = ((_a = options.identityPool) === null || _a === void 0 ? void 0 : _a.AllowUnauthenticatedIdentities) === false || hasIdentityProviders;
if (needsCfnIdentityPool) {
statements.push(ts_1.TS.constFromBackend('cfnIdentityPool', 'auth', 'resources', 'cfnResources', 'cfnIdentityPool'));
}
if (((_b = options.identityPool) === null || _b === void 0 ? void 0 : _b.AllowUnauthenticatedIdentities) === false) {
statements.push(ts_1.TS.assignProp('cfnIdentityPool', 'allowUnauthenticatedIdentities', false));
}
if (hasIdentityProviders) {
statements.push(factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('cfnIdentityPool'), factory.createIdentifier('addPropertyDeletionOverride')), undefined, [factory.createStringLiteral('SupportedLoginProviders')])));
}
if (options.webClient.AllowedOAuthFlows) {
statements.push(ts_1.TS.constFromBackend('cfnUserPoolClient', 'auth', 'resources', 'cfnResources', 'cfnUserPoolClient'));
statements.push(ts_1.TS.assignProp('cfnUserPoolClient', 'allowedOAuthFlows', options.webClient.AllowedOAuthFlows));
}
statements.push(...this.buildNativeUserPoolClientStatements(options.nativeClient));
statements.push(ts_1.TS.retentionLoop(ts_1.TS.propAccess('backend', 'auth', 'stack', 'node'), resource_types_1.AUTH_RESOURCES_TO_RETAIN));
return statements;
}
buildDomainOverrideStatements(gen1Domain) {
if (!gen1Domain)
return [];
const domainExpr = factory.createAsExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createIdentifier('backend'), factory.createIdentifier('auth')), factory.createIdentifier('resources')), factory.createIdentifier('userPool')), factory.createIdentifier('node')), factory.createIdentifier('findChild')), undefined, [factory.createStringLiteral('UserPoolDomain')]), factory.createIdentifier('node')), factory.createIdentifier('defaultChild')), factory.createTypeReferenceNode('CfnUserPoolDomain'));
return [ts_1.TS.declareConst('cfnUserPoolDomain', domainExpr), ts_1.TS.assignProp('cfnUserPoolDomain', 'domain', gen1Domain)];
}
buildAdditionalImports(options) {
var _a, _b;
const imports = {};
if (!imports['aws-cdk-lib'])
imports['aws-cdk-lib'] = new Set();
imports['aws-cdk-lib'].add('CfnResource');
imports['aws-cdk-lib'].add('Duration');
if (AuthRenderer.hasIdentityProviders(options.nativeClient)) {
if (!imports['aws-cdk-lib/aws-cognito'])
imports['aws-cdk-lib/aws-cognito'] = new Set();
imports['aws-cdk-lib/aws-cognito'].add('OAuthScope');
imports['aws-cdk-lib/aws-cognito'].add('UserPoolClientIdentityProvider');
}
if (options.userPool.Domain) {
if (!imports['aws-cdk-lib/aws-cognito'])
imports['aws-cdk-lib/aws-cognito'] = new Set();
imports['aws-cdk-lib/aws-cognito'].add('CfnUserPoolDomain');
}
if (((_a = options.nativeClient.ReadAttributes) === null || _a === void 0 ? void 0 : _a.length) || ((_b = options.nativeClient.WriteAttributes) === null || _b === void 0 ? void 0 : _b.length)) {
if (!imports['aws-cdk-lib/aws-cognito'])
imports['aws-cdk-lib/aws-cognito'] = new Set();
imports['aws-cdk-lib/aws-cognito'].add('ClientAttributes');
}
return imports;
}
buildUserPoolOverrideStatements(overrides) {
const statements = [];
const mappedPolicyType = {
MinimumLength: 'minimumLength',
RequireUppercase: 'requireUppercase',
RequireLowercase: 'requireLowercase',
RequireNumbers: 'requireNumbers',
RequireSymbols: 'requireSymbols',
PasswordHistorySize: 'passwordHistorySize',
TemporaryPasswordValidityDays: 'temporaryPasswordValidityDays',
};
statements.push(ts_1.TS.constFromBackend('cfnUserPool', 'auth', 'resources', 'cfnResources', 'cfnUserPool'));
const policies = {
passwordPolicy: {},
};
for (const [overridePath, value] of Object.entries(overrides)) {
if (overridePath.includes('PasswordPolicy')) {
const policyKey = overridePath.split('.')[2];
if (value !== undefined && policyKey in mappedPolicyType) {
policies.passwordPolicy[mappedPolicyType[policyKey]] = value;
}
}
else {
statements.push(ts_1.TS.assignProp('cfnUserPool', overridePath, value));
}
}
statements.push(ts_1.TS.assignProp('cfnUserPool', 'policies', policies));
return statements;
}
buildNativeUserPoolClientStatements(userPoolClient) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
const statements = [];
const hasIdentityProviders = AuthRenderer.hasIdentityProviders(userPoolClient);
statements.push(ts_1.TS.constFromBackend('userPool', 'auth', 'resources', 'userPool'));
const clientProps = [];
if (userPoolClient.RefreshTokenValidity !== undefined) {
clientProps.push(factory.createPropertyAssignment('refreshTokenValidity', factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('Duration'), factory.createIdentifier('days')), undefined, [factory.createNumericLiteral(userPoolClient.RefreshTokenValidity)])));
}
if (userPoolClient.EnableTokenRevocation !== undefined) {
clientProps.push(factory.createPropertyAssignment('enableTokenRevocation', userPoolClient.EnableTokenRevocation ? factory.createTrue() : factory.createFalse()));
}
if (userPoolClient.EnablePropagateAdditionalUserContextData !== undefined) {
clientProps.push(factory.createPropertyAssignment('enablePropagateAdditionalUserContextData', userPoolClient.EnablePropagateAdditionalUserContextData ? factory.createTrue() : factory.createFalse()));
}
if (userPoolClient.AuthSessionValidity !== undefined) {
clientProps.push(factory.createPropertyAssignment('authSessionValidity', factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('Duration'), factory.createIdentifier('minutes')), undefined, [factory.createNumericLiteral(userPoolClient.AuthSessionValidity)])));
}
if (hasIdentityProviders) {
const providerMap = {
COGNITO: 'COGNITO',
Facebook: 'FACEBOOK',
Google: 'GOOGLE',
LoginWithAmazon: 'AMAZON',
SignInWithApple: 'APPLE',
};
const providerElements = userPoolClient.SupportedIdentityProviders.map((provider) => {
var _a;
const mapped = (_a = providerMap[provider]) !== null && _a !== void 0 ? _a : provider.toUpperCase();
return factory.createPropertyAccessExpression(factory.createIdentifier('UserPoolClientIdentityProvider'), factory.createIdentifier(mapped));
});
clientProps.push(factory.createPropertyAssignment('supportedIdentityProviders', factory.createArrayLiteralExpression(providerElements)));
}
if (((_a = userPoolClient.AllowedOAuthFlows) === null || _a === void 0 ? void 0 : _a.length) ||
((_b = userPoolClient.AllowedOAuthScopes) === null || _b === void 0 ? void 0 : _b.length) ||
((_c = userPoolClient.CallbackURLs) === null || _c === void 0 ? void 0 : _c.length) ||
((_d = userPoolClient.LogoutURLs) === null || _d === void 0 ? void 0 : _d.length)) {
const oAuthProps = [];
if ((_e = userPoolClient.CallbackURLs) === null || _e === void 0 ? void 0 : _e.length) {
oAuthProps.push(typescript_1.default.addSyntheticLeadingComment(factory.createPropertyAssignment('callbackUrls', factory.createArrayLiteralExpression(userPoolClient.CallbackURLs.map((url) => factory.createStringLiteral(url)))), typescript_1.default.SyntaxKind.SingleLineCommentTrivia, ' Add the Gen2 Amplify Hosting URL (e.g. https://<branch>.<gen2-appId>.amplifyapp.com/) to the following array after the gen2-main branch is deployed.', true));
}
if ((_f = userPoolClient.LogoutURLs) === null || _f === void 0 ? void 0 : _f.length) {
oAuthProps.push(typescript_1.default.addSyntheticLeadingComment(factory.createPropertyAssignment('logoutUrls', factory.createArrayLiteralExpression(userPoolClient.LogoutURLs.map((url) => factory.createStringLiteral(url)))), typescript_1.default.SyntaxKind.SingleLineCommentTrivia, ' Add the Gen2 Amplify Hosting URL (e.g. https://<branch>.<gen2-appId>.amplifyapp.com/) to the following array after the gen2-main branch is deployed.', true));
}
if ((_g = userPoolClient.AllowedOAuthFlows) === null || _g === void 0 ? void 0 : _g.length) {
oAuthProps.push(factory.createPropertyAssignment('flows', factory.createObjectLiteralExpression([
factory.createPropertyAssignment('authorizationCodeGrant', userPoolClient.AllowedOAuthFlows.includes('code') ? factory.createTrue() : factory.createFalse()),
factory.createPropertyAssignment('implicitCodeGrant', userPoolClient.AllowedOAuthFlows.includes('implicit') ? factory.createTrue() : factory.createFalse()),
factory.createPropertyAssignment('clientCredentials', userPoolClient.AllowedOAuthFlows.includes('client_credentials') ? factory.createTrue() : factory.createFalse()),
])));
}
if ((_h = userPoolClient.AllowedOAuthScopes) === null || _h === void 0 ? void 0 : _h.length) {
const scopeMap = {
phone: 'PHONE',
email: 'EMAIL',
openid: 'OPENID',
profile: 'PROFILE',
'aws.cognito.signin.user.admin': 'COGNITO_ADMIN',
};
const scopeElements = userPoolClient.AllowedOAuthScopes.filter((s) => scopeMap[s]).map((scope) => factory.createPropertyAccessExpression(factory.createIdentifier('OAuthScope'), factory.createIdentifier(scopeMap[scope])));
oAuthProps.push(factory.createPropertyAssignment('scopes', factory.createArrayLiteralExpression(scopeElements, true)));
}
clientProps.push(factory.createPropertyAssignment('oAuth', factory.createObjectLiteralExpression(oAuthProps, true)));
}
const hasOAuth = ((_k = (_j = userPoolClient.AllowedOAuthFlows) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : 0) > 0;
clientProps.push(factory.createPropertyAssignment('disableOAuth', hasOAuth ? factory.createFalse() : factory.createTrue()));
clientProps.push(factory.createPropertyAssignment('generateSecret', userPoolClient.ClientSecret ? factory.createTrue() : factory.createFalse()));
if ((_l = userPoolClient.ReadAttributes) === null || _l === void 0 ? void 0 : _l.length) {
clientProps.push(factory.createPropertyAssignment('readAttributes', AuthRenderer.buildClientAttributesExpression(userPoolClient.ReadAttributes)));
}
if ((_m = userPoolClient.WriteAttributes) === null || _m === void 0 ? void 0 : _m.length) {
clientProps.push(factory.createPropertyAssignment('writeAttributes', AuthRenderer.buildClientAttributesExpression(userPoolClient.WriteAttributes)));
}
const addClientCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('userPool'), factory.createIdentifier('addClient')), undefined, [factory.createStringLiteral('NativeAppClient'), factory.createObjectLiteralExpression(clientProps, true)]);
const clientVarName = 'nativeUserPoolClient';
statements.push(factory.createVariableStatement(undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier(clientVarName), undefined, undefined, addClientCall)], typescript_1.default.NodeFlags.Const)));
statements.push(...this.buildCognitoProvidersPushStatements(clientVarName));
if (hasIdentityProviders) {
statements.push(...this.buildProviderSetupStatements());
}
return statements;
}
static hasIdentityProviders(userPoolClient) {
var _a, _b;
return ((_b = (_a = userPoolClient.SupportedIdentityProviders) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0;
}
buildCognitoProvidersPushStatements(clientVarName) {
const statements = [];
statements.push(ts_1.TS.declareConst('cognitoProviders', ts_1.TS.propAccess('backend', 'auth', 'resources', 'cfnResources', 'cfnIdentityPool', 'cognitoIdentityProviders')));
const pushArg = factory.createObjectLiteralExpression([
factory.createPropertyAssignment('clientId', factory.createPropertyAccessExpression(factory.createIdentifier(clientVarName), factory.createIdentifier('userPoolClientId'))),
factory.createPropertyAssignment('providerName', factory.createTemplateExpression(factory.createTemplateHead('cognito-idp.'), [
factory.createTemplateSpan(ts_1.TS.propAccess('backend', 'auth', 'stack', 'region'), factory.createTemplateMiddle('.amazonaws.com/')),
factory.createTemplateSpan(factory.createPropertyAccessExpression(factory.createIdentifier('userPool'), factory.createIdentifier('userPoolId')), factory.createTemplateTail('')),
])),
], false);
const pushCall = factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('cognitoProviders'), factory.createIdentifier('push')), undefined, [pushArg]));
const ifStatement = factory.createIfStatement(factory.createBinaryExpression(factory.createIdentifier('cognitoProviders'), factory.createToken(typescript_1.default.SyntaxKind.AmpersandAmpersandToken), factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('Array'), factory.createIdentifier('isArray')), undefined, [factory.createIdentifier('cognitoProviders')])), factory.createBlock([pushCall], true));
statements.push(ifStatement);
return statements;
}
static buildClientAttributesExpression(attributes) {
const standardProps = [];
const customNames = [];
for (const attr of attributes) {
if (attr.startsWith('custom:')) {
customNames.push(attr);
}
else if (attr in MAPPED_USER_ATTRIBUTE_NAME) {
standardProps.push(factory.createPropertyAssignment(factory.createIdentifier(MAPPED_USER_ATTRIBUTE_NAME[attr]), factory.createTrue()));
}
}
let expr = factory.createNewExpression(factory.createIdentifier('ClientAttributes'), undefined, []);
if (standardProps.length > 0) {
expr = factory.createCallExpression(factory.createPropertyAccessExpression(expr, factory.createIdentifier('withStandardAttributes')), undefined, [factory.createObjectLiteralExpression(standardProps, true)]);
}
if (customNames.length > 0) {
expr = factory.createCallExpression(factory.createPropertyAccessExpression(expr, factory.createIdentifier('withCustomAttributes')), undefined, customNames.map((name) => factory.createStringLiteral(name)));
}
return expr;
}
buildProviderSetupStatements() {
const statements = [];
const findCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createIdentifier('backend'), factory.createIdentifier('auth')), factory.createIdentifier('stack')), factory.createIdentifier('node')), factory.createIdentifier('children')), factory.createIdentifier('find')), undefined, [
factory.createArrowFunction(undefined, undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier('child'))], undefined, factory.createToken(typescript_1.default.SyntaxKind.EqualsGreaterThanToken), factory.createBinaryExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createIdentifier('child'), factory.createIdentifier('node')), factory.createIdentifier('id')), factory.createToken(typescript_1.default.SyntaxKind.EqualsEqualsEqualsToken), factory.createStringLiteral('amplifyAuth'))),
]);
const providerSetupDeclaration = factory.createVariableStatement(undefined, factory.createVariableDeclarationList([
factory.createVariableDeclaration('providerSetupResult', undefined, undefined, factory.createPropertyAccessExpression(factory.createParenthesizedExpression(factory.createAsExpression(findCall, factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword))), factory.createIdentifier('providerSetupResult'))),
], typescript_1.default.NodeFlags.Const));
statements.push(providerSetupDeclaration);
const forEachStatement = factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('Object'), factory.createIdentifier('keys')), undefined, [factory.createIdentifier('providerSetupResult')]), factory.createIdentifier('forEa