diff --git a/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md b/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md new file mode 100644 index 00000000..737339cb --- /dev/null +++ b/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md @@ -0,0 +1,69 @@ +# Sample Function + +The following is a sample Lambda functions that are used for custom authentication with Cognito User Pools. +These Lambda triggers issue and verify their own challenges as part of a user pool [custom authentication flow](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow). + +Please see instructions for setting up the Cognito triggers at https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html + +Define Auth Challenge Lambda Trigger: +```go +package main + +import ( + "fmt" + + "github.com/aws/aws-lambda-go/lambda" + "github.com/aws/aws-lambda-go/events" +) + +func handler(event *events.CognitoEventUserPoolsDefineAuthChallenge) (*events.CognitoEventUserPoolsDefineAuthChallenge, error) { + fmt.Printf("Define Auth Challenge: %+v\n", event) + return event, nil +} + +func main() { + lambda.Start(handler) +} +``` + +Create Auth Challenge Lambda Trigger: +```go +package main + +import ( + "fmt" + + "github.com/aws/aws-lambda-go/lambda" + "github.com/aws/aws-lambda-go/events" +) + +func handler(event *events.CognitoEventUserPoolsCreateAuthChallenge) (*events.CognitoEventUserPoolsCreateAuthChallenge, error) { + fmt.Printf("Create Auth Challenge: %+v\n", event) + return event, nil +} + +func main() { + lambda.Start(handler) +} +``` + +Verify Auth Challenge Response Lambda Trigger: +```go +package main + +import ( + "fmt" + + "github.com/aws/aws-lambda-go/lambda" + "github.com/aws/aws-lambda-go/events" +) + +func handler(event *events.CognitoEventUserPoolsVerifyAuthChallenge) (*events.CognitoEventUserPoolsVerifyAuthChallenge, error) { + fmt.Printf("Verify Auth Challenge: %+v\n", event) + return event, nil +} + +func main() { + lambda.Start(handler) +} +``` diff --git a/events/cognito.go b/events/cognito.go index be24c887..9de9a615 100644 --- a/events/cognito.go +++ b/events/cognito.go @@ -147,6 +147,75 @@ type GroupConfiguration struct { PreferredRole *string `json:"preferredRole"` } +// CognitoEventUserPoolsChallengeResult represents a challenge that is presented to the user in the authentication +// process that is underway, along with the corresponding result. +type CognitoEventUserPoolsChallengeResult struct { + ChallengeName string `json:"challengeName"` + ChallengeResult bool `json:"challengeResult"` + ChallengeMetadata string `json:"challengeMetadata"` +} + +// CognitoEventUserPoolsDefineAuthChallengeRequest defines auth challenge request parameters +type CognitoEventUserPoolsDefineAuthChallengeRequest struct { + UserAttributes map[string]string `json:"userAttributes"` + Session []*CognitoEventUserPoolsChallengeResult `json:"session"` +} + +// CognitoEventUserPoolsDefineAuthChallengeResponse defines auth challenge response parameters +type CognitoEventUserPoolsDefineAuthChallengeResponse struct { + ChallengeName string `json:"challengeName"` + IssueTokens bool `json:"issueTokens"` + FailAuthentication bool `json:"failAuthentication"` +} + +// CognitoEventUserPoolsDefineAuthChallenge sent by AWS Cognito User Pools to initiate custom authentication flow +type CognitoEventUserPoolsDefineAuthChallenge struct { + CognitoEventUserPoolsHeader + Request CognitoEventUserPoolsDefineAuthChallengeRequest `json:"request"` + Response CognitoEventUserPoolsDefineAuthChallengeResponse `json:"response"` +} + +// CognitoEventUserPoolsCreateAuthChallengeRequest defines create auth challenge request parameters +type CognitoEventUserPoolsCreateAuthChallengeRequest struct { + UserAttributes map[string]string `json:"userAttributes"` + ChallengeName string `json:"challengeName"` + Session []*CognitoEventUserPoolsChallengeResult `json:"session"` +} + +// CognitoEventUserPoolsCreateAuthChallengeResponse defines create auth challenge response rarameters +type CognitoEventUserPoolsCreateAuthChallengeResponse struct { + PublicChallengeParameters map[string]string `json:"publicChallengeParameters"` + PrivateChallengeParameters map[string]string `json:"privateChallengeParameters"` + ChallengeMetadata string `json:"challengeMetadata"` +} + +// CognitoEventUserPoolsCreateAuthChallenge sent by AWS Cognito User Pools to create a challenge to present to the user +type CognitoEventUserPoolsCreateAuthChallenge struct { + CognitoEventUserPoolsHeader + Request CognitoEventUserPoolsCreateAuthChallengeRequest `json:"request"` + Response CognitoEventUserPoolsCreateAuthChallengeResponse `json:"response"` +} + +// CognitoEventUserPoolsVerifyAuthChallengeRequest defines verify auth challenge request parameters +type CognitoEventUserPoolsVerifyAuthChallengeRequest struct { + UserAttributes map[string]string `json:"userAttributes"` + PrivateChallengeParameters map[string]string `json:"privateChallengeParameters"` + ChallengeAnswer interface{} `json:"challengeAnswer"` +} + +// CognitoEventUserPoolsVerifyAuthChallengeResponse defines verify auth challenge response parameters +type CognitoEventUserPoolsVerifyAuthChallengeResponse struct { + AnswerCorrect bool `json:"answerCorrect"` +} + +// CognitoEventUserPoolsVerifyAuthChallenge sent by AWS Cognito User Pools to verify if the response from the end user +// for a custom Auth Challenge is valid or not +type CognitoEventUserPoolsVerifyAuthChallenge struct { + CognitoEventUserPoolsHeader + Request CognitoEventUserPoolsVerifyAuthChallengeRequest `json:"request"` + Response CognitoEventUserPoolsVerifyAuthChallengeResponse `json:"response"` +} + // CognitoEventUserPoolsCustomMessage is sent by AWS Cognito User Pools before a verification or MFA message is sent, // allowing a user to customize the message dynamically. type CognitoEventUserPoolsCustomMessage struct { diff --git a/events/cognito_test.go b/events/cognito_test.go index 47ca06b5..fad8755d 100644 --- a/events/cognito_test.go +++ b/events/cognito_test.go @@ -113,6 +113,33 @@ func TestCognitoEventUserPoolsPreTokenGenMarshaling(t *testing.T) { test.AssertJsonsEqual(t, inputJSON, outputJSON) } +func TestCognitoEventUserPoolsDefineAuthChallengeMarshaling(t *testing.T) { + var inputEvent CognitoEventUserPoolsDefineAuthChallenge + test.AssertJsonFile(t, "./testdata/cognito-event-userpools-define-auth-challenge.json", &inputEvent) +} + +func TestCognitoEventUserPoolsDefineAuthChallengeMalformedJson(t *testing.T) { + test.TestMalformedJson(t, CognitoEventUserPoolsDefineAuthChallenge{}) +} + +func TestCognitoEventUserPoolsCreateAuthChallengeMarshaling(t *testing.T) { + var inputEvent CognitoEventUserPoolsCreateAuthChallenge + test.AssertJsonFile(t, "./testdata/cognito-event-userpools-create-auth-challenge.json", &inputEvent) +} + +func TestCognitoEventUserPoolsCreateAuthChallengeMalformedJson(t *testing.T) { + test.TestMalformedJson(t, CognitoEventUserPoolsCreateAuthChallenge{}) +} + +func TestCognitoEventUserPoolsVerifyAuthChallengeMarshaling(t *testing.T) { + var inputEvent CognitoEventUserPoolsVerifyAuthChallenge + test.AssertJsonFile(t, "./testdata/cognito-event-userpools-verify-auth-challenge.json", &inputEvent) +} + +func TestCognitoEventUserPoolsVerifyAuthChallengeMalformedJson(t *testing.T) { + test.TestMalformedJson(t, CognitoEventUserPoolsVerifyAuthChallenge{}) +} + func TestCognitoEventUserPoolsPostAuthenticationMarshaling(t *testing.T) { // read json from file diff --git a/events/testdata/cognito-event-userpools-create-auth-challenge.json b/events/testdata/cognito-event-userpools-create-auth-challenge.json new file mode 100644 index 00000000..9a7240a9 --- /dev/null +++ b/events/testdata/cognito-event-userpools-create-auth-challenge.json @@ -0,0 +1,37 @@ +{ + "version": "1", + "region": "us-west-2", + "userPoolId": "", + "userName": "", + "callerContext": { + "awsSdkVersion": "aws-sdk-unknown-unknown", + "clientId": "" + }, + "triggerSource": "CreateAuthChallenge_Authentication", + "request": { + "userAttributes": { + "sub": "", + "cognito:user_status": "CONFIRMED", + "phone_number_verified": "true", + "cognito:phone_number_alias": "+12223334455", + "phone_number": "+12223334455" + }, + "challengeName": "CUSTOM_CHALLENGE", + "session": [ + { + "challengeName": "PASSWORD_VERIFIER", + "challengeResult": true, + "challengeMetadata": "metadata" + } + ] + }, + "response": { + "publicChallengeParameters": { + "a": "b" + }, + "privateChallengeParameters": { + "c": "d" + }, + "challengeMetadata": "challengeMetadata" + } +} \ No newline at end of file diff --git a/events/testdata/cognito-event-userpools-define-auth-challenge.json b/events/testdata/cognito-event-userpools-define-auth-challenge.json new file mode 100644 index 00000000..a2e48c83 --- /dev/null +++ b/events/testdata/cognito-event-userpools-define-auth-challenge.json @@ -0,0 +1,32 @@ +{ + "version": "1", + "region": "us-west-2", + "userPoolId": "", + "userName": "", + "callerContext": { + "awsSdkVersion": "aws-sdk-unknown-unknown", + "clientId": "" + }, + "triggerSource": "DefineAuthChallenge_Authentication", + "request": { + "userAttributes": { + "sub": "", + "cognito:user_status": "CONFIRMED", + "phone_number_verified": "true", + "cognito:phone_number_alias": "+12223334455", + "phone_number": "+12223334455" + }, + "session": [ + { + "challengeName": "PASSWORD_VERIFIER", + "challengeResult": true, + "challengeMetadata": "metadata" + } + ] + }, + "response": { + "challengeName": "challengeName", + "issueTokens": true, + "failAuthentication": true + } +} \ No newline at end of file diff --git a/events/testdata/cognito-event-userpools-verify-auth-challenge.json b/events/testdata/cognito-event-userpools-verify-auth-challenge.json new file mode 100644 index 00000000..7d906ded --- /dev/null +++ b/events/testdata/cognito-event-userpools-verify-auth-challenge.json @@ -0,0 +1,27 @@ +{ + "version": "1", + "region": "us-west-2", + "userPoolId": "", + "userName": "", + "callerContext": { + "awsSdkVersion": "aws-sdk-unknown-unknown", + "clientId": "" + }, + "triggerSource": "VerifyAuthChallengeResponse_Authentication", + "request": { + "userAttributes": { + "sub": "", + "cognito:user_status": "CONFIRMED", + "phone_number_verified": "true", + "cognito:phone_number_alias": "+12223334455", + "phone_number": "+12223334455" + }, + "privateChallengeParameters": { + "secret": "11122233" + }, + "challengeAnswer": "123xxxx" + }, + "response": { + "answerCorrect": true + } +} \ No newline at end of file