UNPKG

@aws-amplify/cli-internal

Version:
775 lines • 52 kB
"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