diff --git a/backend/compact-connect/common_constructs/user_pool.py b/backend/compact-connect/common_constructs/user_pool.py index e19988b1a..6abfc45d8 100644 --- a/backend/compact-connect/common_constructs/user_pool.py +++ b/backend/compact-connect/common_constructs/user_pool.py @@ -1,3 +1,4 @@ +import base64 from collections.abc import Mapping from aws_cdk import CfnOutput, Duration, RemovalPolicy @@ -6,12 +7,14 @@ AdvancedSecurityMode, AuthFlow, AutoVerifiedAttrs, + CfnManagedLoginBranding, CfnUserPoolRiskConfigurationAttachment, ClientAttributes, CognitoDomainOptions, DeviceTracking, FeaturePlan, ICustomAttribute, + ManagedLoginVersion, Mfa, MfaSecondFactor, OAuthFlows, @@ -20,6 +23,7 @@ PasswordPolicy, SignInAliases, StandardAttributes, + UserPoolClient, UserPoolEmail, ) from aws_cdk.aws_cognito import UserPool as CdkUserPool @@ -83,7 +87,9 @@ def __init__( # pylint: disable=too-many-arguments if cognito_domain_prefix: self.user_pool_domain = self.add_domain( - f'{construct_id}Domain', cognito_domain=CognitoDomainOptions(domain_prefix=cognito_domain_prefix) + f'{construct_id}Domain', + cognito_domain=CognitoDomainOptions(domain_prefix=cognito_domain_prefix), + managed_login_version=ManagedLoginVersion.NEWER_MANAGED_LOGIN, ) CfnOutput(self, f'{construct_id}UsersDomain', value=self.user_pool_domain.domain_name) @@ -222,3 +228,58 @@ def _add_risk_configuration(self, security_profile: SecurityProfile): ) ), ) + + def add_managed_login_styles( + self, + user_pool_client: UserPoolClient, + branding_assets: list[any] = None, + branding_settings: dict = None, + ): + # Handle custom styles + login_branding = CfnManagedLoginBranding( + self, + 'MyCfnManagedLoginBranding', + user_pool_id=self.user_pool_id, + assets=branding_assets, + client_id=user_pool_client.user_pool_client_id, + return_merged_resources=False, + settings=branding_settings, + use_cognito_provided_values=False, + ) + + login_branding.add_dependency(user_pool_client.node.default_child) + + def prepare_assets_for_managed_login_ui( + self, ico_filepath: str, logo_filepath: str, background_file_path: str | None = None + ): + # options found: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-managedloginbranding-assettype.html#cfn-cognito-managedloginbranding-assettype-category + assets = [] + base_64_favicon = self.convert_img_to_base_64(ico_filepath) + assets.append( + CfnManagedLoginBranding.AssetTypeProperty( + category='FAVICON_ICO', color_mode='LIGHT', extension='ICO', bytes=base_64_favicon + ) + ) + + base_64_logo = self.convert_img_to_base_64(logo_filepath) + assets.append( + CfnManagedLoginBranding.AssetTypeProperty( + category='FORM_LOGO', color_mode='LIGHT', extension='PNG', bytes=base_64_logo + ) + ) + + if background_file_path: + base_64_background = self.convert_img_to_base_64(background_file_path) + assets.append( + CfnManagedLoginBranding.AssetTypeProperty( + category='PAGE_BACKGROUND', color_mode='LIGHT', extension='PNG', bytes=base_64_background + ) + ) + + return assets + + def convert_img_to_base_64(self, file_path: str): + with open(file_path, 'rb') as binary_file: + binary_file_data = binary_file.read() + base64_encoded_data = base64.b64encode(binary_file_data) + return base64_encoded_data.decode('utf-8') diff --git a/backend/compact-connect/pipeline/backend_stage.py b/backend/compact-connect/pipeline/backend_stage.py index d0307cce8..47916817c 100644 --- a/backend/compact-connect/pipeline/backend_stage.py +++ b/backend/compact-connect/pipeline/backend_stage.py @@ -3,6 +3,7 @@ from constructs import Construct from stacks.api_stack import ApiStack from stacks.ingest_stack import IngestStack +from stacks.managed_login_stack import ManagedLoginStack from stacks.persistent_stack import PersistentStack from stacks.reporting_stack import ReportingStack from stacks.transaction_monitoring_stack import TransactionMonitoringStack @@ -35,6 +36,16 @@ def __init__( environment_name=environment_name, ) + self.managed_login_stack = ManagedLoginStack( + self, + 'ManagedLoginStack', + env=environment, + environment_context=environment_context, + environment_name=environment_name, + standard_tags=standard_tags, + persistent_stack=self.persistent_stack, + ) + self.ingest_stack = IngestStack( self, 'IngestStack', diff --git a/backend/compact-connect/resources/assets/compact-connect-logo.png b/backend/compact-connect/resources/assets/compact-connect-logo.png new file mode 100644 index 000000000..4303d2150 Binary files /dev/null and b/backend/compact-connect/resources/assets/compact-connect-logo.png differ diff --git a/backend/compact-connect/resources/assets/favicon.ico b/backend/compact-connect/resources/assets/favicon.ico new file mode 100644 index 000000000..d5097c99c Binary files /dev/null and b/backend/compact-connect/resources/assets/favicon.ico differ diff --git a/backend/compact-connect/resources/assets/staff-background.png b/backend/compact-connect/resources/assets/staff-background.png new file mode 100644 index 000000000..0b9906e1f Binary files /dev/null and b/backend/compact-connect/resources/assets/staff-background.png differ diff --git a/backend/compact-connect/resources/provider_managed_login_style_settings.json b/backend/compact-connect/resources/provider_managed_login_style_settings.json new file mode 100644 index 000000000..635b39222 --- /dev/null +++ b/backend/compact-connect/resources/provider_managed_login_style_settings.json @@ -0,0 +1,449 @@ +{ + "components": { + "secondaryButton": { + "lightMode": { + "hover": { + "backgroundColor": "f2f8fdff", + "borderColor": "033160ff", + "textColor": "033160ff" + }, + "defaults": { + "backgroundColor": "ffffffff", + "borderColor": "2459A9ff", + "textColor": "2459A9ff" + }, + "active": { + "backgroundColor": "d3e7f9ff", + "borderColor": "033160ff", + "textColor": "033160ff" + } + }, + "darkMode": { + "hover": { + "backgroundColor": "192534ff", + "borderColor": "89bdeeff", + "textColor": "89bdeeff" + }, + "defaults": { + "backgroundColor": "0f1b2aff", + "borderColor": "539fe5ff", + "textColor": "539fe5ff" + }, + "active": { + "backgroundColor": "354150ff", + "borderColor": "89bdeeff", + "textColor": "89bdeeff" + } + } + }, + "form": { + "lightMode": { + "backgroundColor": "ffffffff", + "borderColor": "ffffffff" + }, + "borderRadius": 8.0, + "backgroundImage": { + "enabled": false + }, + "logo": { + "location": "CENTER", + "position": "TOP", + "enabled": true, + "formInclusion": "IN" + }, + "darkMode": { + "backgroundColor": "0f1b2aff", + "borderColor": "424650ff" + } + }, + "alert": { + "lightMode": { + "error": { + "backgroundColor": "fff7f7ff", + "borderColor": "d91515ff" + } + }, + "borderRadius": 12.0, + "darkMode": { + "error": { + "backgroundColor": "1a0000ff", + "borderColor": "eb6f6fff" + } + } + }, + "favicon": { + "enabledTypes": [ + "ICO" + ] + }, + "pageBackground": { + "image": { + "enabled": false + }, + "lightMode": { + "color": "f5f6f8ff" + }, + "darkMode": { + "color": "0f1b2aff" + } + }, + "pageText": { + "lightMode": { + "bodyColor": "414d5cff", + "headingColor": "000716ff", + "descriptionColor": "414d5c00" + }, + "darkMode": { + "bodyColor": "b6bec9ff", + "headingColor": "d1d5dbff", + "descriptionColor": "b6bec9ff" + } + }, + "phoneNumberSelector": { + "displayType": "TEXT" + }, + "primaryButton": { + "lightMode": { + "hover": { + "backgroundColor": "033160ff", + "textColor": "ffffffff" + }, + "defaults": { + "backgroundColor": "2459A9ff", + "textColor": "ffffffff" + }, + "active": { + "backgroundColor": "033160ff", + "textColor": "ffffffff" + }, + "disabled": { + "backgroundColor": "ffffffff", + "borderColor": "ffffffff" + } + }, + "darkMode": { + "hover": { + "backgroundColor": "89bdeeff", + "textColor": "000716ff" + }, + "defaults": { + "backgroundColor": "539fe5ff", + "textColor": "000716ff" + }, + "active": { + "backgroundColor": "539fe5ff", + "textColor": "000716ff" + }, + "disabled": { + "backgroundColor": "ffffffff", + "borderColor": "ffffffff" + } + } + }, + "pageFooter": { + "lightMode": { + "borderColor": "d5dbdbff", + "background": { + "color": "fafafaff" + } + }, + "backgroundImage": { + "enabled": false + }, + "logo": { + "location": "START", + "enabled": false + }, + "darkMode": { + "borderColor": "424650ff", + "background": { + "color": "0f141aff" + } + } + }, + "pageHeader": { + "lightMode": { + "borderColor": "d5dbdbff", + "background": { + "color": "fafafaff" + } + }, + "backgroundImage": { + "enabled": false + }, + "logo": { + "location": "START", + "enabled": false + }, + "darkMode": { + "borderColor": "424650ff", + "background": { + "color": "0f141aff" + } + } + }, + "idpButton": { + "standard": { + "lightMode": { + "hover": { + "backgroundColor": "f2f8fdff", + "borderColor": "033160ff", + "textColor": "033160ff" + }, + "defaults": { + "backgroundColor": "ffffffff", + "borderColor": "424650ff", + "textColor": "424650ff" + }, + "active": { + "backgroundColor": "d3e7f9ff", + "borderColor": "033160ff", + "textColor": "033160ff" + } + }, + "darkMode": { + "hover": { + "backgroundColor": "192534ff", + "borderColor": "89bdeeff", + "textColor": "89bdeeff" + }, + "defaults": { + "backgroundColor": "0f1b2aff", + "borderColor": "c6c6cdff", + "textColor": "c6c6cdff" + }, + "active": { + "backgroundColor": "354150ff", + "borderColor": "89bdeeff", + "textColor": "89bdeeff" + } + } + }, + "custom": {} + } + }, + "componentClasses": { + "dropDown": { + "lightMode": { + "hover": { + "itemBackgroundColor": "f4f4f4ff", + "itemBorderColor": "7d8998ff", + "itemTextColor": "000716ff" + }, + "defaults": { + "itemBackgroundColor": "ffffffff" + }, + "match": { + "itemBackgroundColor": "414d5cff", + "itemTextColor": "0972d3ff" + } + }, + "borderRadius": 8.0, + "darkMode": { + "hover": { + "itemBackgroundColor": "081120ff", + "itemBorderColor": "5f6b7aff", + "itemTextColor": "e9ebedff" + }, + "defaults": { + "itemBackgroundColor": "192534ff" + }, + "match": { + "itemBackgroundColor": "d1d5dbff", + "itemTextColor": "89bdeeff" + } + } + }, + "input": { + "lightMode": { + "defaults": { + "backgroundColor": "ffffffff", + "borderColor": "7d8998ff" + }, + "placeholderColor": "5f6b7aff" + }, + "borderRadius": 8.0, + "darkMode": { + "defaults": { + "backgroundColor": "0f1b2aff", + "borderColor": "5f6b7aff" + }, + "placeholderColor": "8d99a8ff" + } + }, + "inputDescription": { + "lightMode": { + "textColor": "5f6b7aff" + }, + "darkMode": { + "textColor": "8d99a8ff" + } + }, + "buttons": { + "borderRadius": 8.0 + }, + "optionControls": { + "lightMode": { + "defaults": { + "backgroundColor": "ffffffff", + "borderColor": "7d8998ff" + }, + "selected": { + "backgroundColor": "0972d3ff", + "foregroundColor": "ffffffff" + } + }, + "darkMode": { + "defaults": { + "backgroundColor": "0f1b2aff", + "borderColor": "7d8998ff" + }, + "selected": { + "backgroundColor": "539fe5ff", + "foregroundColor": "000716ff" + } + } + }, + "statusIndicator": { + "lightMode": { + "success": { + "backgroundColor": "f2fcf3ff", + "borderColor": "037f0cff", + "indicatorColor": "037f0cff" + }, + "pending": { + "indicatorColor": "AAAAAAAA" + }, + "warning": { + "backgroundColor": "fffce9ff", + "borderColor": "8d6605ff", + "indicatorColor": "8d6605ff" + }, + "error": { + "backgroundColor": "fff7f7ff", + "borderColor": "d91515ff", + "indicatorColor": "d91515ff" + } + }, + "darkMode": { + "success": { + "backgroundColor": "001a02ff", + "borderColor": "29ad32ff", + "indicatorColor": "29ad32ff" + }, + "pending": { + "indicatorColor": "AAAAAAAA" + }, + "warning": { + "backgroundColor": "1d1906ff", + "borderColor": "e0ca57ff", + "indicatorColor": "e0ca57ff" + }, + "error": { + "backgroundColor": "1a0000ff", + "borderColor": "eb6f6fff", + "indicatorColor": "eb6f6fff" + } + } + }, + "divider": { + "lightMode": { + "borderColor": "ebebf0ff" + }, + "darkMode": { + "borderColor": "232b37ff" + } + }, + "idpButtons": { + "icons": { + "enabled": true + } + }, + "focusState": { + "lightMode": { + "borderColor": "0972d3ff" + }, + "darkMode": { + "borderColor": "539fe5ff" + } + }, + "inputLabel": { + "lightMode": { + "textColor": "000716ff" + }, + "darkMode": { + "textColor": "d1d5dbff" + } + }, + "link": { + "lightMode": { + "hover": { + "textColor": "033160ff" + }, + "defaults": { + "textColor": "0972d3ff" + } + }, + "darkMode": { + "hover": { + "textColor": "89bdeeff" + }, + "defaults": { + "textColor": "539fe5ff" + } + } + } + }, + "categories": { + "form": { + "sessionTimerDisplay": "NONE", + "instructions": { + "enabled": false + }, + "languageSelector": { + "enabled": false + }, + "displayGraphics": true, + "location": { + "horizontal": "CENTER", + "vertical": "CENTER" + } + }, + "auth": { + "federation": { + "interfaceStyle": "BUTTON_LIST", + "order": [] + }, + "authMethodOrder": [ + [ + { + "display": "BUTTON", + "type": "FEDERATED" + }, + { + "display": "INPUT", + "type": "USERNAME_PASSWORD" + } + ] + ] + }, + "global": { + "colorSchemeMode": "LIGHT", + "pageHeader": { + "enabled": false + }, + "pageFooter": { + "enabled": false + }, + "spacingDensity": "REGULAR" + }, + "signUp": { + "acceptanceElements": [ + { + "enforcement": "NONE", + "textKey": "en" + } + ] + } + } +} diff --git a/backend/compact-connect/resources/staff_managed_login_style_settings.json b/backend/compact-connect/resources/staff_managed_login_style_settings.json new file mode 100644 index 000000000..4e2ff6f19 --- /dev/null +++ b/backend/compact-connect/resources/staff_managed_login_style_settings.json @@ -0,0 +1,449 @@ +{ + "components": { + "secondaryButton": { + "lightMode": { + "hover": { + "backgroundColor": "f2f8fdff", + "borderColor": "033160ff", + "textColor": "033160ff" + }, + "defaults": { + "backgroundColor": "ffffffff", + "borderColor": "2459A9ff", + "textColor": "2459A9ff" + }, + "active": { + "backgroundColor": "d3e7f9ff", + "borderColor": "033160ff", + "textColor": "033160ff" + } + }, + "darkMode": { + "hover": { + "backgroundColor": "192534ff", + "borderColor": "89bdeeff", + "textColor": "89bdeeff" + }, + "defaults": { + "backgroundColor": "0f1b2aff", + "borderColor": "539fe5ff", + "textColor": "539fe5ff" + }, + "active": { + "backgroundColor": "354150ff", + "borderColor": "89bdeeff", + "textColor": "89bdeeff" + } + } + }, + "form": { + "lightMode": { + "backgroundColor": "ffffffff", + "borderColor": "ffffffff" + }, + "borderRadius": 8.0, + "backgroundImage": { + "enabled": false + }, + "logo": { + "location": "CENTER", + "position": "TOP", + "enabled": true, + "formInclusion": "IN" + }, + "darkMode": { + "backgroundColor": "0f1b2aff", + "borderColor": "424650ff" + } + }, + "alert": { + "lightMode": { + "error": { + "backgroundColor": "fff7f7ff", + "borderColor": "d91515ff" + } + }, + "borderRadius": 12.0, + "darkMode": { + "error": { + "backgroundColor": "1a0000ff", + "borderColor": "eb6f6fff" + } + } + }, + "favicon": { + "enabledTypes": [ + "ICO" + ] + }, + "pageBackground": { + "image": { + "enabled": true + }, + "lightMode": { + "color": "f5f6f8ff" + }, + "darkMode": { + "color": "0f1b2aff" + } + }, + "pageText": { + "lightMode": { + "bodyColor": "414d5cff", + "headingColor": "000716ff", + "descriptionColor": "414d5c00" + }, + "darkMode": { + "bodyColor": "b6bec9ff", + "headingColor": "d1d5dbff", + "descriptionColor": "b6bec9ff" + } + }, + "phoneNumberSelector": { + "displayType": "TEXT" + }, + "primaryButton": { + "lightMode": { + "hover": { + "backgroundColor": "033160ff", + "textColor": "ffffffff" + }, + "defaults": { + "backgroundColor": "2459A9ff", + "textColor": "ffffffff" + }, + "active": { + "backgroundColor": "033160ff", + "textColor": "ffffffff" + }, + "disabled": { + "backgroundColor": "ffffffff", + "borderColor": "ffffffff" + } + }, + "darkMode": { + "hover": { + "backgroundColor": "89bdeeff", + "textColor": "000716ff" + }, + "defaults": { + "backgroundColor": "539fe5ff", + "textColor": "000716ff" + }, + "active": { + "backgroundColor": "539fe5ff", + "textColor": "000716ff" + }, + "disabled": { + "backgroundColor": "ffffffff", + "borderColor": "ffffffff" + } + } + }, + "pageFooter": { + "lightMode": { + "borderColor": "d5dbdbff", + "background": { + "color": "fafafaff" + } + }, + "backgroundImage": { + "enabled": false + }, + "logo": { + "location": "START", + "enabled": false + }, + "darkMode": { + "borderColor": "424650ff", + "background": { + "color": "0f141aff" + } + } + }, + "pageHeader": { + "lightMode": { + "borderColor": "d5dbdbff", + "background": { + "color": "fafafaff" + } + }, + "backgroundImage": { + "enabled": false + }, + "logo": { + "location": "START", + "enabled": false + }, + "darkMode": { + "borderColor": "424650ff", + "background": { + "color": "0f141aff" + } + } + }, + "idpButton": { + "standard": { + "lightMode": { + "hover": { + "backgroundColor": "f2f8fdff", + "borderColor": "033160ff", + "textColor": "033160ff" + }, + "defaults": { + "backgroundColor": "ffffffff", + "borderColor": "424650ff", + "textColor": "424650ff" + }, + "active": { + "backgroundColor": "d3e7f9ff", + "borderColor": "033160ff", + "textColor": "033160ff" + } + }, + "darkMode": { + "hover": { + "backgroundColor": "192534ff", + "borderColor": "89bdeeff", + "textColor": "89bdeeff" + }, + "defaults": { + "backgroundColor": "0f1b2aff", + "borderColor": "c6c6cdff", + "textColor": "c6c6cdff" + }, + "active": { + "backgroundColor": "354150ff", + "borderColor": "89bdeeff", + "textColor": "89bdeeff" + } + } + }, + "custom": {} + } + }, + "componentClasses": { + "dropDown": { + "lightMode": { + "hover": { + "itemBackgroundColor": "f4f4f4ff", + "itemBorderColor": "7d8998ff", + "itemTextColor": "000716ff" + }, + "defaults": { + "itemBackgroundColor": "ffffffff" + }, + "match": { + "itemBackgroundColor": "414d5cff", + "itemTextColor": "0972d3ff" + } + }, + "borderRadius": 8.0, + "darkMode": { + "hover": { + "itemBackgroundColor": "081120ff", + "itemBorderColor": "5f6b7aff", + "itemTextColor": "e9ebedff" + }, + "defaults": { + "itemBackgroundColor": "192534ff" + }, + "match": { + "itemBackgroundColor": "d1d5dbff", + "itemTextColor": "89bdeeff" + } + } + }, + "input": { + "lightMode": { + "defaults": { + "backgroundColor": "ffffffff", + "borderColor": "7d8998ff" + }, + "placeholderColor": "5f6b7aff" + }, + "borderRadius": 8.0, + "darkMode": { + "defaults": { + "backgroundColor": "0f1b2aff", + "borderColor": "5f6b7aff" + }, + "placeholderColor": "8d99a8ff" + } + }, + "inputDescription": { + "lightMode": { + "textColor": "5f6b7aff" + }, + "darkMode": { + "textColor": "8d99a8ff" + } + }, + "buttons": { + "borderRadius": 8.0 + }, + "optionControls": { + "lightMode": { + "defaults": { + "backgroundColor": "ffffffff", + "borderColor": "7d8998ff" + }, + "selected": { + "backgroundColor": "0972d3ff", + "foregroundColor": "ffffffff" + } + }, + "darkMode": { + "defaults": { + "backgroundColor": "0f1b2aff", + "borderColor": "7d8998ff" + }, + "selected": { + "backgroundColor": "539fe5ff", + "foregroundColor": "000716ff" + } + } + }, + "statusIndicator": { + "lightMode": { + "success": { + "backgroundColor": "f2fcf3ff", + "borderColor": "037f0cff", + "indicatorColor": "037f0cff" + }, + "pending": { + "indicatorColor": "AAAAAAAA" + }, + "warning": { + "backgroundColor": "fffce9ff", + "borderColor": "8d6605ff", + "indicatorColor": "8d6605ff" + }, + "error": { + "backgroundColor": "fff7f7ff", + "borderColor": "d91515ff", + "indicatorColor": "d91515ff" + } + }, + "darkMode": { + "success": { + "backgroundColor": "001a02ff", + "borderColor": "29ad32ff", + "indicatorColor": "29ad32ff" + }, + "pending": { + "indicatorColor": "AAAAAAAA" + }, + "warning": { + "backgroundColor": "1d1906ff", + "borderColor": "e0ca57ff", + "indicatorColor": "e0ca57ff" + }, + "error": { + "backgroundColor": "1a0000ff", + "borderColor": "eb6f6fff", + "indicatorColor": "eb6f6fff" + } + } + }, + "divider": { + "lightMode": { + "borderColor": "ebebf0ff" + }, + "darkMode": { + "borderColor": "232b37ff" + } + }, + "idpButtons": { + "icons": { + "enabled": true + } + }, + "focusState": { + "lightMode": { + "borderColor": "0972d3ff" + }, + "darkMode": { + "borderColor": "539fe5ff" + } + }, + "inputLabel": { + "lightMode": { + "textColor": "000716ff" + }, + "darkMode": { + "textColor": "d1d5dbff" + } + }, + "link": { + "lightMode": { + "hover": { + "textColor": "033160ff" + }, + "defaults": { + "textColor": "0972d3ff" + } + }, + "darkMode": { + "hover": { + "textColor": "89bdeeff" + }, + "defaults": { + "textColor": "539fe5ff" + } + } + } + }, + "categories": { + "form": { + "sessionTimerDisplay": "NONE", + "instructions": { + "enabled": false + }, + "languageSelector": { + "enabled": false + }, + "displayGraphics": true, + "location": { + "horizontal": "CENTER", + "vertical": "CENTER" + } + }, + "auth": { + "federation": { + "interfaceStyle": "BUTTON_LIST", + "order": [] + }, + "authMethodOrder": [ + [ + { + "display": "BUTTON", + "type": "FEDERATED" + }, + { + "display": "INPUT", + "type": "USERNAME_PASSWORD" + } + ] + ] + }, + "global": { + "colorSchemeMode": "LIGHT", + "pageHeader": { + "enabled": false + }, + "pageFooter": { + "enabled": false + }, + "spacingDensity": "REGULAR" + }, + "signUp": { + "acceptanceElements": [ + { + "enforcement": "NONE", + "textKey": "en" + } + ] + } + } +} \ No newline at end of file diff --git a/backend/compact-connect/stacks/api_stack/v1_api/api_model.py b/backend/compact-connect/stacks/api_stack/v1_api/api_model.py index 068ec0a4e..d1731634d 100644 --- a/backend/compact-connect/stacks/api_stack/v1_api/api_model.py +++ b/backend/compact-connect/stacks/api_stack/v1_api/api_model.py @@ -844,7 +844,7 @@ def _purchase_privilege_options_items_schema(self): 'licenseTypeAbbreviation': JsonSchema(type=JsonSchemaType.STRING), 'amount': JsonSchema(type=JsonSchemaType.NUMBER), }, - ) + ), ), 'militaryDiscount': JsonSchema( type=JsonSchemaType.OBJECT, diff --git a/backend/compact-connect/stacks/managed_login_stack.py b/backend/compact-connect/stacks/managed_login_stack.py new file mode 100644 index 000000000..162c7cc39 --- /dev/null +++ b/backend/compact-connect/stacks/managed_login_stack.py @@ -0,0 +1,85 @@ +import json + +from aws_cdk.aws_cognito import CfnManagedLoginBranding +from common_constructs.stack import AppStack +from constructs import Construct + +from stacks.persistent_stack import PersistentStack + + +class ManagedLoginStack(AppStack): + """ + Stack for managing Cognito managed login branding assets. + + This stack isolates the base64-encoded assets from the persistent stack + to avoid hitting CloudFormation template size limits. + + The style settings json data can be obtained by styling the user pool in the + console and then running the following CLI command: + aws cognito-idp describe-managed-login-branding --managed-login-branding-id + "" --user-pool-id "" --region + """ + + def __init__( + self, + scope: Construct, + construct_id: str, + *, + persistent_stack: PersistentStack, + **kwargs, + ) -> None: + super().__init__(scope, construct_id, **kwargs) + + # Create managed login branding for staff users + self._create_managed_login_for_staff_users(persistent_stack) + + # Create managed login branding for provider users + self._create_managed_login_for_provider_users(persistent_stack) + + def _create_managed_login_for_staff_users(self, persistent_stack: PersistentStack): + """Create managed login branding for staff users""" + # Load the style settings + with open('resources/staff_managed_login_style_settings.json') as f: + branding_settings = json.load(f) + + # Prepare the assets + branding_assets = persistent_stack.staff_users.prepare_assets_for_managed_login_ui( + ico_filepath='resources/assets/favicon.ico', + logo_filepath='resources/assets/compact-connect-logo.png', + background_file_path='resources/assets/staff-background.png', + ) + + # Create the managed login branding + CfnManagedLoginBranding( + self, + 'StaffManagedLoginBranding', + user_pool_id=persistent_stack.staff_users.user_pool_id, + assets=branding_assets, + client_id=persistent_stack.staff_users.ui_client.user_pool_client_id, + return_merged_resources=False, + settings=branding_settings, + use_cognito_provided_values=False, + ) + + def _create_managed_login_for_provider_users(self, persistent_stack: PersistentStack): + """Create managed login branding for provider users""" + # Load the style settings + with open('resources/provider_managed_login_style_settings.json') as f: + branding_settings = json.load(f) + + # Prepare the assets + branding_assets = persistent_stack.provider_users.prepare_assets_for_managed_login_ui( + ico_filepath='resources/assets/favicon.ico', logo_filepath='resources/assets/compact-connect-logo.png' + ) + + # Create the managed login branding + CfnManagedLoginBranding( + self, + 'ProviderManagedLoginBranding', + user_pool_id=persistent_stack.provider_users.user_pool_id, + assets=branding_assets, + client_id=persistent_stack.provider_users.ui_client.user_pool_client_id, + return_merged_resources=False, + settings=branding_settings, + use_cognito_provided_values=False, + ) diff --git a/backend/compact-connect/stacks/persistent_stack/compact_configuration_upload.py b/backend/compact-connect/stacks/persistent_stack/compact_configuration_upload.py index 2b9d6e7c9..bbcc1d359 100644 --- a/backend/compact-connect/stacks/persistent_stack/compact_configuration_upload.py +++ b/backend/compact-connect/stacks/persistent_stack/compact_configuration_upload.py @@ -226,8 +226,10 @@ def _validate_jurisdiction_configuration( # Check for duplicate license types if len(defined_license_types_list) != len(defined_license_types_set): - raise ValueError(f'Jurisdiction {jurisdiction["postalAbbreviation"]} in Compact {compact_abbr} ' - f'has duplicate license type fees') + raise ValueError( + f'Jurisdiction {jurisdiction["postalAbbreviation"]} in Compact {compact_abbr} ' + f'has duplicate license type fees' + ) # Check for unknown license types unknown_license_types = defined_license_types_set - compact_license_type_abbreviations