Skip to content

Commit 9661f13

Browse files
authored
Merge pull request #178 from gyft/cognito-custom-auth
feat(data_classes): Cognito custom auth triggers
2 parents c7a584f + 802324f commit 9661f13

9 files changed

+463
-17
lines changed

aws_lambda_powertools/utilities/data_classes/cognito_user_pool_event.py

+274-11
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def validation_data(self) -> Optional[Dict[str, str]]:
6868
@property
6969
def client_metadata(self) -> Optional[Dict[str, str]]:
7070
"""One or more key-value pairs that you can provide as custom input to the Lambda function
71-
that you specify for the pre sign-up data_classes."""
71+
that you specify for the pre sign-up trigger."""
7272
return self["request"].get("clientMetadata")
7373

7474

@@ -135,7 +135,7 @@ def user_attributes(self) -> Dict[str, str]:
135135
@property
136136
def client_metadata(self) -> Optional[Dict[str, str]]:
137137
"""One or more key-value pairs that you can provide as custom input to the Lambda function
138-
that you specify for the post confirmation data_classes."""
138+
that you specify for the post confirmation trigger."""
139139
return self["request"].get("clientMetadata")
140140

141141

@@ -172,7 +172,7 @@ def validation_data(self) -> Optional[Dict[str, str]]:
172172
@property
173173
def client_metadata(self) -> Optional[Dict[str, str]]:
174174
"""One or more key-value pairs that you can provide as custom input to the Lambda function
175-
that you specify for the pre sign-up data_classes."""
175+
that you specify for the pre sign-up trigger."""
176176
return self["request"].get("clientMetadata")
177177

178178

@@ -283,7 +283,7 @@ def user_attributes(self) -> Dict[str, str]:
283283
@property
284284
def client_metadata(self) -> Optional[Dict[str, str]]:
285285
"""One or more key-value pairs that you can provide as custom input to the Lambda function
286-
that you specify for the pre sign-up data_classes."""
286+
that you specify for the pre sign-up trigger."""
287287
return self["request"].get("clientMetadata")
288288

289289

@@ -329,9 +329,9 @@ class CustomMessageTriggerEvent(BaseTriggerEvent):
329329
- `CustomMessage_AdminCreateUser` To send the temporary password to a new user.
330330
- `CustomMessage_ResendCode` To resend the confirmation code to an existing user.
331331
- `CustomMessage_ForgotPassword` To send the confirmation code for Forgot Password request.
332-
- `CustomMessage_UpdateUserAttribute` When a user's email or phone number is changed, this data_classes sends a
332+
- `CustomMessage_UpdateUserAttribute` When a user's email or phone number is changed, this trigger sends a
333333
verification code automatically to the user. Cannot be used for other attributes.
334-
- `CustomMessage_VerifyUserAttribute` This data_classes sends a verification code to the user when they manually
334+
- `CustomMessage_VerifyUserAttribute` This trigger sends a verification code to the user when they manually
335335
request it for a new email or phone number.
336336
- `CustomMessage_Authentication` To send MFA code during authentication.
337337
@@ -369,7 +369,7 @@ def validation_data(self) -> Optional[Dict[str, str]]:
369369
class PreAuthenticationTriggerEvent(BaseTriggerEvent):
370370
"""Pre Authentication Lambda Trigger
371371
372-
Amazon Cognito invokes this data_classes when a user attempts to sign in, allowing custom validation
372+
Amazon Cognito invokes this trigger when a user attempts to sign in, allowing custom validation
373373
to accept or deny the authentication request.
374374
375375
Notes:
@@ -404,14 +404,14 @@ def user_attributes(self) -> Dict[str, str]:
404404
@property
405405
def client_metadata(self) -> Optional[Dict[str, str]]:
406406
"""One or more key-value pairs that you can provide as custom input to the Lambda function
407-
that you specify for the post authentication data_classes."""
407+
that you specify for the post authentication trigger."""
408408
return self["request"].get("clientMetadata")
409409

410410

411411
class PostAuthenticationTriggerEvent(BaseTriggerEvent):
412412
"""Post Authentication Lambda Trigger
413413
414-
Amazon Cognito invokes this data_classes after signing in a user, allowing you to add custom logic
414+
Amazon Cognito invokes this trigger after signing in a user, allowing you to add custom logic
415415
after authentication.
416416
417417
Notes:
@@ -462,7 +462,7 @@ def user_attributes(self) -> Dict[str, str]:
462462
@property
463463
def client_metadata(self) -> Optional[Dict[str, str]]:
464464
"""One or more key-value pairs that you can provide as custom input to the Lambda function
465-
that you specify for the pre token generation data_classes."""
465+
that you specify for the pre token generation trigger."""
466466
return self["request"].get("clientMetadata")
467467

468468

@@ -531,7 +531,7 @@ def claims_override_details(self) -> ClaimsOverrideDetails:
531531
class PreTokenGenerationTriggerEvent(BaseTriggerEvent):
532532
"""Pre Token Generation Lambda Trigger
533533
534-
Amazon Cognito invokes this data_classes before token generation allowing you to customize identity token claims.
534+
Amazon Cognito invokes this trigger before token generation allowing you to customize identity token claims.
535535
536536
Notes:
537537
----
@@ -558,3 +558,266 @@ def request(self) -> PreTokenGenerationTriggerEventRequest:
558558
def response(self) -> PreTokenGenerationTriggerEventResponse:
559559
"""Pre Token Generation Response Parameters"""
560560
return PreTokenGenerationTriggerEventResponse(self._data)
561+
562+
563+
class ChallengeResult(DictWrapper):
564+
@property
565+
def challenge_name(self) -> str:
566+
"""The challenge type.
567+
568+
One of: CUSTOM_CHALLENGE, SRP_A, PASSWORD_VERIFIER, SMS_MFA, DEVICE_SRP_AUTH,
569+
DEVICE_PASSWORD_VERIFIER, or ADMIN_NO_SRP_AUTH."""
570+
return self["challengeName"]
571+
572+
@property
573+
def challenge_result(self) -> bool:
574+
"""Set to true if the user successfully completed the challenge, or false otherwise."""
575+
return bool(self["challengeResult"])
576+
577+
@property
578+
def challenge_metadata(self) -> Optional[str]:
579+
"""Your name for the custom challenge. Used only if challengeName is CUSTOM_CHALLENGE."""
580+
return self.get("challengeMetadata")
581+
582+
583+
class DefineAuthChallengeTriggerEventRequest(DictWrapper):
584+
@property
585+
def user_attributes(self) -> Dict[str, str]:
586+
"""One or more name-value pairs representing user attributes. The attribute names are the keys."""
587+
return self["request"]["userAttributes"]
588+
589+
@property
590+
def user_not_found(self) -> Optional[bool]:
591+
"""A Boolean that is populated when PreventUserExistenceErrors is set to ENABLED for your user pool client.
592+
A value of true means that the user id (user name, email address, etc.) did not match any existing users. """
593+
return self["request"].get("userNotFound")
594+
595+
@property
596+
def session(self) -> List[ChallengeResult]:
597+
"""An array of ChallengeResult elements, each of which contains the following elements:"""
598+
return [ChallengeResult(result) for result in self["request"]["session"]]
599+
600+
@property
601+
def client_metadata(self) -> Optional[Dict[str, str]]:
602+
"""One or more key-value pairs that you can provide as custom input to the Lambda function that you specify
603+
for the define auth challenge trigger."""
604+
return self["request"].get("clientMetadata")
605+
606+
607+
class DefineAuthChallengeTriggerEventResponse(DictWrapper):
608+
@property
609+
def challenge_name(self) -> str:
610+
return self["response"]["challengeName"]
611+
612+
@property
613+
def fail_authentication(self) -> bool:
614+
return bool(self["response"]["failAuthentication"])
615+
616+
@property
617+
def issue_tokens(self) -> bool:
618+
return bool(self["response"]["issueTokens"])
619+
620+
@challenge_name.setter
621+
def challenge_name(self, value: str):
622+
"""A string containing the name of the next challenge.
623+
If you want to present a new challenge to your user, specify the challenge name here."""
624+
self["response"]["challengeName"] = value
625+
626+
@fail_authentication.setter
627+
def fail_authentication(self, value: bool):
628+
"""Set to true if you want to terminate the current authentication process, or false otherwise."""
629+
self["response"]["failAuthentication"] = value
630+
631+
@issue_tokens.setter
632+
def issue_tokens(self, value: bool):
633+
"""Set to true if you determine that the user has been sufficiently authenticated by
634+
completing the challenges, or false otherwise."""
635+
self["response"]["issueTokens"] = value
636+
637+
638+
class DefineAuthChallengeTriggerEvent(BaseTriggerEvent):
639+
"""Define Auth Challenge Lambda Trigger
640+
641+
Amazon Cognito invokes this trigger to initiate the custom authentication flow.
642+
643+
Notes:
644+
----
645+
`triggerSource` can be one of the following:
646+
647+
- `DefineAuthChallenge_Authentication` Define Auth Challenge.
648+
649+
Documentation:
650+
--------------
651+
- https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-define-auth-challenge.html
652+
"""
653+
654+
@property
655+
def request(self) -> DefineAuthChallengeTriggerEventRequest:
656+
"""Define Auth Challenge Request Parameters"""
657+
return DefineAuthChallengeTriggerEventRequest(self._data)
658+
659+
@property
660+
def response(self) -> DefineAuthChallengeTriggerEventResponse:
661+
"""Define Auth Challenge Response Parameters"""
662+
return DefineAuthChallengeTriggerEventResponse(self._data)
663+
664+
665+
class CreateAuthChallengeTriggerEventRequest(DictWrapper):
666+
@property
667+
def user_attributes(self) -> Dict[str, str]:
668+
"""One or more name-value pairs representing user attributes. The attribute names are the keys."""
669+
return self["request"]["userAttributes"]
670+
671+
@property
672+
def user_not_found(self) -> Optional[bool]:
673+
"""This boolean is populated when PreventUserExistenceErrors is set to ENABLED for your User Pool client."""
674+
return self["request"].get("userNotFound")
675+
676+
@property
677+
def challenge_name(self) -> str:
678+
"""The name of the new challenge."""
679+
return self["request"]["challengeName"]
680+
681+
@property
682+
def session(self) -> List[ChallengeResult]:
683+
"""An array of ChallengeResult elements, each of which contains the following elements:"""
684+
return [ChallengeResult(result) for result in self["request"]["session"]]
685+
686+
@property
687+
def client_metadata(self) -> Optional[Dict[str, str]]:
688+
"""One or more key-value pairs that you can provide as custom input to the Lambda function that you
689+
specify for the create auth challenge trigger.."""
690+
return self["request"].get("clientMetadata")
691+
692+
693+
class CreateAuthChallengeTriggerEventResponse(DictWrapper):
694+
@property
695+
def public_challenge_parameters(self) -> Dict[str, str]:
696+
return self["response"]["publicChallengeParameters"]
697+
698+
@property
699+
def private_challenge_parameters(self) -> Dict[str, str]:
700+
return self["response"]["privateChallengeParameters"]
701+
702+
@property
703+
def challenge_metadata(self) -> str:
704+
return self["response"]["challengeMetadata"]
705+
706+
@public_challenge_parameters.setter
707+
def public_challenge_parameters(self, value: Dict[str, str]):
708+
"""One or more key-value pairs for the client app to use in the challenge to be presented to the user.
709+
This parameter should contain all of the necessary information to accurately present the challenge to
710+
the user."""
711+
self["response"]["publicChallengeParameters"] = value
712+
713+
@private_challenge_parameters.setter
714+
def private_challenge_parameters(self, value: Dict[str, str]):
715+
"""This parameter is only used by the Verify Auth Challenge Response Lambda trigger.
716+
This parameter should contain all of the information that is required to validate the user's
717+
response to the challenge. In other words, the publicChallengeParameters parameter contains the
718+
question that is presented to the user and privateChallengeParameters contains the valid answers
719+
for the question."""
720+
self["response"]["privateChallengeParameters"] = value
721+
722+
@challenge_metadata.setter
723+
def challenge_metadata(self, value: str):
724+
"""Your name for the custom challenge, if this is a custom challenge."""
725+
self["response"]["challengeMetadata"] = value
726+
727+
728+
class CreateAuthChallengeTriggerEvent(BaseTriggerEvent):
729+
"""Create Auth Challenge Lambda Trigger
730+
731+
Amazon Cognito invokes this trigger after Define Auth Challenge if a custom challenge has been
732+
specified as part of the Define Auth Challenge trigger.
733+
It creates a custom authentication flow.
734+
735+
Notes:
736+
----
737+
`triggerSource` can be one of the following:
738+
739+
- `CreateAuthChallenge_Authentication` Create Auth Challenge.
740+
741+
Documentation:
742+
--------------
743+
- https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-create-auth-challenge.html
744+
"""
745+
746+
@property
747+
def request(self) -> CreateAuthChallengeTriggerEventRequest:
748+
"""Create Auth Challenge Request Parameters"""
749+
return CreateAuthChallengeTriggerEventRequest(self._data)
750+
751+
@property
752+
def response(self) -> CreateAuthChallengeTriggerEventResponse:
753+
"""Create Auth Challenge Response Parameters"""
754+
return CreateAuthChallengeTriggerEventResponse(self._data)
755+
756+
757+
class VerifyAuthChallengeResponseTriggerEventRequest(DictWrapper):
758+
@property
759+
def user_attributes(self) -> Dict[str, str]:
760+
"""One or more name-value pairs representing user attributes. The attribute names are the keys."""
761+
return self["request"]["userAttributes"]
762+
763+
@property
764+
def private_challenge_parameters(self) -> Dict[str, str]:
765+
"""This parameter comes from the Create Auth Challenge trigger, and is
766+
compared against a user’s challengeAnswer to determine whether the user passed the challenge."""
767+
return self["request"]["privateChallengeParameters"]
768+
769+
@property
770+
def challenge_answer(self) -> Any:
771+
"""The answer from the user's response to the challenge."""
772+
return self["request"]["challengeAnswer"]
773+
774+
@property
775+
def client_metadata(self) -> Optional[Dict[str, str]]:
776+
"""One or more key-value pairs that you can provide as custom input to the Lambda function that
777+
you specify for the verify auth challenge trigger."""
778+
return self["request"].get("clientMetadata")
779+
780+
@property
781+
def user_not_found(self) -> Optional[bool]:
782+
"""This boolean is populated when PreventUserExistenceErrors is set to ENABLED for your User Pool client."""
783+
return self["request"].get("userNotFound")
784+
785+
786+
class VerifyAuthChallengeResponseTriggerEventResponse(DictWrapper):
787+
@property
788+
def answer_correct(self) -> bool:
789+
return bool(self["response"]["answerCorrect"])
790+
791+
@answer_correct.setter
792+
def answer_correct(self, value: bool):
793+
"""Set to true if the user has successfully completed the challenge, or false otherwise."""
794+
self["response"]["answerCorrect"] = value
795+
796+
797+
class VerifyAuthChallengeResponseTriggerEvent(BaseTriggerEvent):
798+
"""Verify Auth Challenge Response Lambda Trigger
799+
800+
Amazon Cognito invokes this trigger to verify if the response from the end user for a custom
801+
Auth Challenge is valid or not.
802+
It is part of a user pool custom authentication flow.
803+
804+
Notes:
805+
----
806+
`triggerSource` can be one of the following:
807+
808+
- `VerifyAuthChallengeResponse_Authentication` Verify Auth Challenge Response.
809+
810+
Documentation:
811+
--------------
812+
- https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-verify-auth-challenge-response.html
813+
"""
814+
815+
@property
816+
def request(self) -> VerifyAuthChallengeResponseTriggerEventRequest:
817+
"""Verify Auth Challenge Request Parameters"""
818+
return VerifyAuthChallengeResponseTriggerEventRequest(self._data)
819+
820+
@property
821+
def response(self) -> VerifyAuthChallengeResponseTriggerEventResponse:
822+
"""Verify Auth Challenge Response Parameters"""
823+
return VerifyAuthChallengeResponseTriggerEventResponse(self._data)

aws_lambda_powertools/utilities/data_classes/ses_event.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ def ses(self) -> SESMessage:
193193

194194

195195
class SESEvent(DictWrapper):
196-
"""Amazon SES to receive message event data_classes
196+
"""Amazon SES to receive message event trigger
197197
198198
NOTE: There is a 30-second timeout on RequestResponse invocations.
199199

docs/content/utilities/data_classes.mdx

+3
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ Pre authentication | `data_classes.cognito_user_pool_event.PreAuthenticationTrig
114114
Pre sign-up | `data_classes.cognito_user_pool_event.PreSignUpTriggerEvent`
115115
Pre token generation | `data_classes.cognito_user_pool_event.PreTokenGenerationTriggerEvent`
116116
User migration | `data_classes.cognito_user_pool_event.UserMigrationTriggerEvent`
117+
Define Auth Challenge | `data_classes.cognito_user_pool_event.DefineAuthChallengeTriggerEvent`
118+
Create Auth Challenge | `data_classes.cognito_user_pool_event.CreateAuthChallengeTriggerEvent`
119+
Verify Auth Challenge | `data_classes.cognito_user_pool_event.VerifyAuthChallengeResponseTriggerEvent`
117120

118121
```python:title=lambda_app.py
119122
from aws_lambda_powertools.utilities.cognito_user_pool_event import PostConfirmationTriggerEvent

0 commit comments

Comments
 (0)