Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: add cognito identity #126

Merged
merged 8 commits into from
Oct 30, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor
  • Loading branch information
Ran Isenberg committed Oct 29, 2023
commit 59e1ca93aae249fd98db050bbec56d7612277c4e
4 changes: 2 additions & 2 deletions infrastructure/product/crud_api_construct.py
Original file line number Diff line number Diff line change
@@ -13,11 +13,11 @@


class CrudApiConstruct(Construct):
def __init__(self, scope: Construct, id_: str, lambda_layer: PythonLayerVersion) -> None:
def __init__(self, scope: Construct, id_: str, lambda_layer: PythonLayerVersion, is_production: bool) -> None:
super().__init__(scope, id_)
self.api_db = ApiDbConstruct(self, f'{id_}db')
self.common_layer = lambda_layer
self.idp = IdentityProviderConstruct(self, f'{id_}users')
self.idp = IdentityProviderConstruct(self, f'{id_}users', is_production)
self.rest_api = self._build_api_gw()
api_resource: aws_apigateway.Resource = self.rest_api.root.add_resource('api')
product_resource = api_resource.add_resource(constants.PRODUCT_RESOURCE).add_resource('{product}')
65 changes: 30 additions & 35 deletions infrastructure/product/identity_provider_construct.py
Original file line number Diff line number Diff line change
@@ -12,17 +12,33 @@


class IdentityProviderConstruct(Construct):
def __init__(self, scope: Construct, id_: str, is_production: bool = False) -> None:
def __init__(self, scope: Construct, id_: str, is_production: bool) -> None:
super().__init__(scope, id_)
self.id_ = id_
self.user_pool = self._create_user_pool(is_production)
self.app_client = self._create_app_client(self.user_pool)
if not is_production:
self._create_test_user(self.user_pool)

# Create the Cognito User Pool with recommended settings
self.user_pool = cognito.UserPool(
def _create_app_client(self, user_pool: cognito.UserPool) -> cognito.UserPoolClient:
app_client = cognito.UserPoolClient(
self,
'UserPoolClient',
user_pool=user_pool,
auth_flows=cognito.AuthFlow(user_password=True), # Allow username/password authentication
)

CfnOutput(self, id=constants.IDENTITY_APP_CLIENT_ID_OUTPUT, value=app_client.user_pool_client_id).override_logical_id(
constants.IDENTITY_APP_CLIENT_ID_OUTPUT
)
return app_client

def _create_user_pool(self, is_production: bool) -> cognito.UserPool:
user_pool = cognito.UserPool(
self,
'UserPool',
user_pool_name=constants.IDENTITY_USER_NAME,
advanced_security_mode=cognito.AdvancedSecurityMode.ENFORCED,
# Password policy
password_policy=cognito.PasswordPolicy(
min_length=12,
require_lowercase=True,
@@ -36,50 +52,32 @@ def __init__(self, scope: Construct, id_: str, is_production: bool = False) -> N
mfa=cognito.Mfa.OPTIONAL if not is_production else cognito.Mfa.REQUIRED,
)

CfnOutput(self, id=constants.IDENTITY_USER_POOL_ID_OUTPUT, value=self.user_pool.user_pool_id).override_logical_id(
CfnOutput(self, id=constants.IDENTITY_USER_POOL_ID_OUTPUT, value=user_pool.user_pool_id).override_logical_id(
constants.IDENTITY_USER_POOL_ID_OUTPUT
)
return user_pool

app_client = cognito.UserPoolClient(
self,
'UserPoolClient',
user_pool=self.user_pool,
auth_flows=cognito.AuthFlow(user_password=True), # Allow username/password authentication
)

CfnOutput(self, id=constants.IDENTITY_APP_CLIENT_ID_OUTPUT, value=app_client.user_pool_client_id).override_logical_id(
constants.IDENTITY_APP_CLIENT_ID_OUTPUT
)

# Custom Resource to set user password directly
def _create_test_user(self, user_pool: cognito.UserPool):
create_test_user = AwsCustomResource(
self,
'AwsCustom-CreateUser',
on_create={
'service': 'CognitoIdentityServiceProvider',
'action': 'adminCreateUser',
'parameters': {
'UserPoolId': self.user_pool.user_pool_id,
'UserPoolId': user_pool.user_pool_id,
'Username': constants.TEST_USER_USERNAME,
'MessageAction': 'SUPPRESS',
'TemporaryPassword': constants.TEST_USER_TEMP_PWD,
},
'physical_resource_id': PhysicalResourceId.of(f'{self.id_}CreateTestUserResource'),
},
# on_delete={
# 'service': 'CognitoIdentityServiceProvider',
# 'action': 'adminDeleteUser',
# 'parameters': {
# 'UserPoolId': user_pool.user_pool_id,
# 'Username': constants.TEST_USER_USERNAME,
# },
# },
policy=AwsCustomResourcePolicy.from_sdk_calls(resources=[self.user_pool.user_pool_arn]),
policy=AwsCustomResourcePolicy.from_sdk_calls(resources=[user_pool.user_pool_arn]),
install_latest_aws_sdk=True,
removal_policy=RemovalPolicy.DESTROY,
timeout=Duration.minutes(1),
)
create_test_user.node.add_dependency(self.user_pool.node.default_child)
create_test_user.node.add_dependency(user_pool.node.default_child)

# Save the user's credentials to AWS Secrets Manager
user_credentials_secret = secrets.Secret(
@@ -108,7 +106,6 @@ def __init__(self, scope: Construct, id_: str, is_production: bool = False) -> N
with open(path.join(path.dirname(__file__), 'custom_resource_handler.py'), encoding='utf-8') as file:
handler_code = file.read()

# Lambda Function
lambda_function = _lambda.Function(
self,
'SetPassHandler',
@@ -119,19 +116,17 @@ def __init__(self, scope: Construct, id_: str, is_production: bool = False) -> N

# Grant permission to Lambda to get secrets and interact with Cognito
user_credentials_secret.grant_read(lambda_function)
lambda_function.add_to_role_policy(
iam.PolicyStatement(actions=['cognito-idp:AdminSetUserPassword'], resources=[self.user_pool.user_pool_arn])
)
lambda_function.add_to_role_policy(iam.PolicyStatement(actions=['cognito-idp:AdminSetUserPassword'], resources=[user_pool.user_pool_arn]))

provider = Provider(scope=self, id=f'{id_}Provider', on_event_handler=lambda_function)
provider = Provider(scope=self, id=f'{self.id_}Provider', on_event_handler=lambda_function)
lambda_resource = CustomResource(
scope=self,
id=f'{id_}SetAdminFunc',
id=f'{self.id_}SetAdminFunc',
service_token=provider.service_token,
removal_policy=RemovalPolicy.DESTROY,
properties={
'SecretName': user_credentials_secret.secret_name,
'UserPoolId': self.user_pool.user_pool_id,
'UserPoolId': user_pool.user_pool_id,
},
resource_type='Custom::IdentitySetTestPassword',
)
1 change: 1 addition & 0 deletions infrastructure/product/service_stack.py
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ def __init__(self, scope: Construct, id: str, is_production: bool, **kwargs) ->
self,
id_=get_construct_name(id, constants.CRUD_CONSTRUCT_NAME),
lambda_layer=self.shared_layer,
is_production=is_production,
)

self.stream_processor = StreamProcessorConstruct(
Loading