From f6add2e9533de33bcc68a8472e13402cb3f0700c Mon Sep 17 00:00:00 2001 From: Brandon Cotter Date: Tue, 19 Dec 2023 11:53:45 -0800 Subject: [PATCH 1/4] Fixed Cognito service name and added event structure for Cognito pre token generation event V2 --- events/cognito.go | 72 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/events/cognito.go b/events/cognito.go index c24a3e3e..411a59c2 100644 --- a/events/cognito.go +++ b/events/cognito.go @@ -2,7 +2,7 @@ package events -// CognitoEvent contains data from an event sent from AWS Cognito Sync +// CognitoEvent contains data from an event sent from Amazon Cognito Sync type CognitoEvent struct { DatasetName string `json:"datasetName"` DatasetRecords map[string]CognitoDatasetRecord `json:"datasetRecords"` @@ -13,14 +13,14 @@ type CognitoEvent struct { Version int `json:"version"` } -// CognitoDatasetRecord represents a record from an AWS Cognito Sync event +// CognitoDatasetRecord represents a record from an Amazon Cognito Sync event type CognitoDatasetRecord struct { NewValue string `json:"newValue"` OldValue string `json:"oldValue"` Op string `json:"op"` } -// CognitoEventUserPoolsPreSignup is sent by AWS Cognito User Pools when a user attempts to register +// CognitoEventUserPoolsPreSignup is sent by Amazon Cognito User Pools when a user attempts to register // (sign up), allowing a Lambda to perform custom validation to accept or deny the registration request type CognitoEventUserPoolsPreSignup struct { CognitoEventUserPoolsHeader @@ -28,7 +28,7 @@ type CognitoEventUserPoolsPreSignup struct { Response CognitoEventUserPoolsPreSignupResponse `json:"response"` } -// CognitoEventUserPoolsPreAuthentication is sent by AWS Cognito User Pools when a user submits their information +// CognitoEventUserPoolsPreAuthentication is sent by Amazon Cognito User Pools when a user submits their information // to be authenticated, allowing you to perform custom validations to accept or deny the sign in request. type CognitoEventUserPoolsPreAuthentication struct { CognitoEventUserPoolsHeader @@ -36,7 +36,7 @@ type CognitoEventUserPoolsPreAuthentication struct { Response CognitoEventUserPoolsPreAuthenticationResponse `json:"response"` } -// CognitoEventUserPoolsPostConfirmation is sent by AWS Cognito User Pools after a user is confirmed, +// CognitoEventUserPoolsPostConfirmation is sent by Amazon Cognito User Pools after a user is confirmed, // allowing the Lambda to send custom messages or add custom logic. type CognitoEventUserPoolsPostConfirmation struct { CognitoEventUserPoolsHeader @@ -44,7 +44,7 @@ type CognitoEventUserPoolsPostConfirmation struct { Response CognitoEventUserPoolsPostConfirmationResponse `json:"response"` } -// CognitoEventUserPoolsPreTokenGen is sent by AWS Cognito User Pools when a user attempts to retrieve +// CognitoEventUserPoolsPreTokenGen is sent by Amazon Cognito User Pools when a user attempts to retrieve // credentials, allowing a Lambda to perform insert, suppress or override claims type CognitoEventUserPoolsPreTokenGen struct { CognitoEventUserPoolsHeader @@ -52,7 +52,15 @@ type CognitoEventUserPoolsPreTokenGen struct { Response CognitoEventUserPoolsPreTokenGenResponse `json:"response"` } -// CognitoEventUserPoolsPostAuthentication is sent by AWS Cognito User Pools after a user is authenticated, +// CognitoEventUserPoolsPreTokenGenV2 is sent by Amazon Cognito User Pools when a user attempts to retrieve +// credentials, allowing a Lambda to perform insert, suppress or override claims and scopes +type CognitoEventUserPoolsPreTokenGenV2 struct { + CognitoEventUserPoolsHeader + Request CognitoEventUserPoolsPreTokenGenV2Request `json:"request"` + Response CognitoEventUserPoolsPreTokenGenV2Response `json:"response"` +} + +// CognitoEventUserPoolsPostAuthentication is sent by Amazon Cognito User Pools after a user is authenticated, // allowing the Lambda to add custom logic. type CognitoEventUserPoolsPostAuthentication struct { CognitoEventUserPoolsHeader @@ -60,7 +68,7 @@ type CognitoEventUserPoolsPostAuthentication struct { Response CognitoEventUserPoolsPostAuthenticationResponse `json:"response"` } -// CognitoEventUserPoolsMigrateUser is sent by AWS Cognito User Pools when a user does not exist in the +// CognitoEventUserPoolsMigrateUser is sent by Amazon Cognito User Pools when a user does not exist in the // user pool at the time of sign-in with a password, or in the forgot-password flow. type CognitoEventUserPoolsMigrateUser struct { CognitoEventUserPoolsHeader @@ -74,7 +82,7 @@ type CognitoEventUserPoolsCallerContext struct { ClientID string `json:"clientId"` } -// CognitoEventUserPoolsHeader contains common data from events sent by AWS Cognito User Pools +// CognitoEventUserPoolsHeader contains common data from events sent by Amazon Cognito User Pools type CognitoEventUserPoolsHeader struct { Version string `json:"version"` TriggerSource string `json:"triggerSource"` @@ -125,11 +133,24 @@ type CognitoEventUserPoolsPreTokenGenRequest struct { ClientMetadata map[string]string `json:"clientMetadata"` } -// CognitoEventUserPoolsPreTokenGenResponse containst the response portion of a PreTokenGen event +// CognitoEventUserPoolsPreTokenGenV2Request contains request portion of V2 PreTokenGen event +type CognitoEventUserPoolsPreTokenGenV2Request struct { + UserAttributes map[string]string `json:"userAttributes"` + GroupConfiguration GroupConfiguration `json:"groupConfiguration"` + ClientMetadata map[string]string `json:"clientMetadata"` + Scopes []string `json:"scopes"` +} + +// CognitoEventUserPoolsPreTokenGenResponse contains the response portion of a PreTokenGen event type CognitoEventUserPoolsPreTokenGenResponse struct { ClaimsOverrideDetails ClaimsOverrideDetails `json:"claimsOverrideDetails"` } +// CognitoEventUserPoolsPreTokenGenV2Response contains the response portion of a V2 PreTokenGen event +type CognitoEventUserPoolsPreTokenGenV2Response struct { + ClaimsAndScopeOverrideDetails ClaimsAndScopeOverrideDetails `json:"claimsAndScopeOverrideDetails"` +} + // CognitoEventUserPoolsPostAuthenticationRequest contains the request portion of a PostAuthentication event type CognitoEventUserPoolsPostAuthenticationRequest struct { NewDeviceUsed bool `json:"newDeviceUsed"` @@ -157,6 +178,27 @@ type CognitoEventUserPoolsMigrateUserResponse struct { ForceAliasCreation bool `json:"forceAliasCreation"` } +// ClaimsAndScopeOverrideDetails allows lambda to add, suppress or override V2 claims and scopes in the token +type ClaimsAndScopeOverrideDetails struct { + IDTokenGeneration IDTokenGeneration `json:"idTokenGeneration"` + AccessTokenGeneration AccessTokenGeneration `json:"accessTokenGeneration"` + GroupOverrideDetails GroupConfiguration `json:"groupOverrideDetails"` +} + +// IDTokenGeneration allows lambda to modify the ID token +type IDTokenGeneration struct { + ClaimsToAddOrOverride map[string]string `json:"claimsToAddOrOverride"` + ClaimsToSuppress []string `json:"claimsToSuppress"` +} + +// AccessTokenGeneration allows lambda to modify the access token +type AccessTokenGeneration struct { + ClaimsToAddOrOverride map[string]string `json:"claimsToAddOrOverride"` + ClaimsToSuppress []string `json:"claimsToSuppress"` + ScopesToAdd []string `json:"scopesToAdd"` + ScopesToSuppress []string `json:"scopesToSuppress"` +} + // ClaimsOverrideDetails allows lambda to add, suppress or override claims in the token type ClaimsOverrideDetails struct { GroupOverrideDetails GroupConfiguration `json:"groupOverrideDetails"` @@ -164,7 +206,7 @@ type ClaimsOverrideDetails struct { ClaimsToSuppress []string `json:"claimsToSuppress"` } -// GroupConfiguration allows lambda to override groups, roles and set a perferred role +// GroupConfiguration allows lambda to override groups, roles and set a preferred role type GroupConfiguration struct { GroupsToOverride []string `json:"groupsToOverride"` IAMRolesToOverride []string `json:"iamRolesToOverride"` @@ -194,7 +236,7 @@ type CognitoEventUserPoolsDefineAuthChallengeResponse struct { FailAuthentication bool `json:"failAuthentication"` } -// CognitoEventUserPoolsDefineAuthChallenge sent by AWS Cognito User Pools to initiate custom authentication flow +// CognitoEventUserPoolsDefineAuthChallenge sent by Amazon Cognito User Pools to initiate custom authentication flow type CognitoEventUserPoolsDefineAuthChallenge struct { CognitoEventUserPoolsHeader Request CognitoEventUserPoolsDefineAuthChallengeRequest `json:"request"` @@ -216,7 +258,7 @@ type CognitoEventUserPoolsCreateAuthChallengeResponse struct { ChallengeMetadata string `json:"challengeMetadata"` } -// CognitoEventUserPoolsCreateAuthChallenge sent by AWS Cognito User Pools to create a challenge to present to the user +// CognitoEventUserPoolsCreateAuthChallenge sent by Amazon Cognito User Pools to create a challenge to present to the user type CognitoEventUserPoolsCreateAuthChallenge struct { CognitoEventUserPoolsHeader Request CognitoEventUserPoolsCreateAuthChallengeRequest `json:"request"` @@ -236,7 +278,7 @@ type CognitoEventUserPoolsVerifyAuthChallengeResponse struct { AnswerCorrect bool `json:"answerCorrect"` } -// CognitoEventUserPoolsVerifyAuthChallenge sent by AWS Cognito User Pools to verify if the response from the end user +// CognitoEventUserPoolsVerifyAuthChallenge sent by Amazon 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 @@ -244,7 +286,7 @@ type CognitoEventUserPoolsVerifyAuthChallenge struct { Response CognitoEventUserPoolsVerifyAuthChallengeResponse `json:"response"` } -// CognitoEventUserPoolsCustomMessage is sent by AWS Cognito User Pools before a verification or MFA message is sent, +// CognitoEventUserPoolsCustomMessage is sent by Amazon Cognito User Pools before a verification or MFA message is sent, // allowing a user to customize the message dynamically. type CognitoEventUserPoolsCustomMessage struct { CognitoEventUserPoolsHeader From 849ad2a2560d127fd02ad2df1d7ee9368437e927 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 19 Dec 2023 13:19:50 -0800 Subject: [PATCH 2/4] gofmt -s -w . --- events/cognito.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/events/cognito.go b/events/cognito.go index 411a59c2..b272c1a1 100644 --- a/events/cognito.go +++ b/events/cognito.go @@ -180,23 +180,23 @@ type CognitoEventUserPoolsMigrateUserResponse struct { // ClaimsAndScopeOverrideDetails allows lambda to add, suppress or override V2 claims and scopes in the token type ClaimsAndScopeOverrideDetails struct { - IDTokenGeneration IDTokenGeneration `json:"idTokenGeneration"` - AccessTokenGeneration AccessTokenGeneration `json:"accessTokenGeneration"` - GroupOverrideDetails GroupConfiguration `json:"groupOverrideDetails"` + IDTokenGeneration IDTokenGeneration `json:"idTokenGeneration"` + AccessTokenGeneration AccessTokenGeneration `json:"accessTokenGeneration"` + GroupOverrideDetails GroupConfiguration `json:"groupOverrideDetails"` } // IDTokenGeneration allows lambda to modify the ID token type IDTokenGeneration struct { - ClaimsToAddOrOverride map[string]string `json:"claimsToAddOrOverride"` - ClaimsToSuppress []string `json:"claimsToSuppress"` + ClaimsToAddOrOverride map[string]string `json:"claimsToAddOrOverride"` + ClaimsToSuppress []string `json:"claimsToSuppress"` } // AccessTokenGeneration allows lambda to modify the access token type AccessTokenGeneration struct { - ClaimsToAddOrOverride map[string]string `json:"claimsToAddOrOverride"` - ClaimsToSuppress []string `json:"claimsToSuppress"` - ScopesToAdd []string `json:"scopesToAdd"` - ScopesToSuppress []string `json:"scopesToSuppress"` + ClaimsToAddOrOverride map[string]string `json:"claimsToAddOrOverride"` + ClaimsToSuppress []string `json:"claimsToSuppress"` + ScopesToAdd []string `json:"scopesToAdd"` + ScopesToSuppress []string `json:"scopesToSuppress"` } // ClaimsOverrideDetails allows lambda to add, suppress or override claims in the token From 013dc2d3ab06b2c0cf2dc65ff7604890b3e4fdfb Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 19 Dec 2023 16:05:16 -0800 Subject: [PATCH 3/4] Add sample data and serde test --- events/cognito_test.go | 22 ++++++ ...ognito-event-userpools-pretokengen-v2.json | 70 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 events/testdata/cognito-event-userpools-pretokengen-v2.json diff --git a/events/cognito_test.go b/events/cognito_test.go index 88cb3121..12cd1654 100644 --- a/events/cognito_test.go +++ b/events/cognito_test.go @@ -140,6 +140,28 @@ func TestCognitoEventUserPoolsPreTokenGenMarshaling(t *testing.T) { test.AssertJsonsEqual(t, inputJSON, outputJSON) } +func TestCognitoEventUserPoolsPreTokenGenV2Marshaling(t *testing.T) { + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/cognito-event-userpools-pretokengen-v2.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into CognitoEvent + var inputEvent CognitoEventUserPoolsPreTokenGenV2 + if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } + + // serialize to json + outputJSON, err := json.Marshal(inputEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + + 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) diff --git a/events/testdata/cognito-event-userpools-pretokengen-v2.json b/events/testdata/cognito-event-userpools-pretokengen-v2.json new file mode 100644 index 00000000..2f39f12c --- /dev/null +++ b/events/testdata/cognito-event-userpools-pretokengen-v2.json @@ -0,0 +1,70 @@ +{ + "version": "2", + "triggerSource": "TokenGeneration_Authentication", + "region": "us-west-2", + "userPoolId": "us-east-1_EXAMPLE", + "userName": "brcotter", + "callerContext": { + "awsSdkVersion": "aws-sdk-unknown-unknown", + "clientId": "1example23456789" + }, + "request": { + "userAttributes": { + "sub": "a36036a8-9061-424d-a737-56d57dae7bc6", + "cognito:email_alias": "testuser@example.com", + "cognito:user_status": "CONFIRMED", + "email_verified": "true", + "email": "testuser@example.com" + }, + "groupConfiguration": { + "groupsToOverride": [], + "iamRolesToOverride": [] + }, + "scopes": [ + "aws.cognito.signin.user.admin" + ] + }, + "response": { + "claimsAndScopeOverrideDetails": { + "idTokenGeneration": { + "claimsToAddOrOverride": { + "family_name": "xyz" + }, + "claimsToSuppress": [ + "email", + "birthdate" + ] + }, + "accessTokenGeneration": { + "claimsToAddOrOverride": { + "family_name": "xyz" + }, + "claimsToSuppress": [ + "email", + "birthdate" + ], + "scopesToAdd": [ + "scope1", + "scope2", + "scopeLomond" + ], + "scopesToSuppress": [ + "phone_number" + ] + }, + "groupOverrideDetails": { + "groupsToOverride": [ + "group-A", + "group-B", + "group-C" + ], + "iamRolesToOverride": [ + "arn:aws:iam::123456789012:role/sns_callerA", + "arn:aws:iam::123456789012:role/sns_callerB", + "arn:aws:iam::123456789012:role/sns_callerC" + ], + "preferredRole": "arn:aws:iam::123456789012:role/sns_caller" + } + } + } +} \ No newline at end of file From 453a56b3122d7371fd1878992f1e48b8ca3a7a5c Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 19 Dec 2023 16:33:14 -0800 Subject: [PATCH 4/4] Tweak the test data to avoid having to break response marshaling compatability of the GroupConfiguration struct --- events/cognito.go | 2 +- events/testdata/cognito-event-userpools-pretokengen-v2.json | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/events/cognito.go b/events/cognito.go index b272c1a1..f02619da 100644 --- a/events/cognito.go +++ b/events/cognito.go @@ -137,7 +137,7 @@ type CognitoEventUserPoolsPreTokenGenRequest struct { type CognitoEventUserPoolsPreTokenGenV2Request struct { UserAttributes map[string]string `json:"userAttributes"` GroupConfiguration GroupConfiguration `json:"groupConfiguration"` - ClientMetadata map[string]string `json:"clientMetadata"` + ClientMetadata map[string]string `json:"clientMetadata,omitempty"` Scopes []string `json:"scopes"` } diff --git a/events/testdata/cognito-event-userpools-pretokengen-v2.json b/events/testdata/cognito-event-userpools-pretokengen-v2.json index 2f39f12c..6feeb184 100644 --- a/events/testdata/cognito-event-userpools-pretokengen-v2.json +++ b/events/testdata/cognito-event-userpools-pretokengen-v2.json @@ -18,7 +18,8 @@ }, "groupConfiguration": { "groupsToOverride": [], - "iamRolesToOverride": [] + "iamRolesToOverride": [], + "preferredRole": null }, "scopes": [ "aws.cognito.signin.user.admin" @@ -67,4 +68,4 @@ } } } -} \ No newline at end of file +}