From af3cb0553ee2f843b80c074f81030ef4f5550dbc Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Wed, 13 Feb 2019 13:52:48 -0800 Subject: [PATCH 1/5] Add events for Cognito custom authentication challenge Signed-off-by: Maksym Pavlenko --- ...nito_UserPools_CustomAuthLambdaTriggers.md | 69 +++++++++++++++++++ events/cognito.go | 69 +++++++++++++++++++ events/cognito_test.go | 27 ++++++++ ...event-userpools-create-auth-challenge.json | 37 ++++++++++ ...event-userpools-define-auth-challenge.json | 32 +++++++++ ...event-userpools-verify-auth-challenge.json | 27 ++++++++ 6 files changed, 261 insertions(+) create mode 100644 events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md create mode 100644 events/testdata/cognito-event-userpools-create-auth-challenge.json create mode 100644 events/testdata/cognito-event-userpools-define-auth-challenge.json create mode 100644 events/testdata/cognito-event-userpools-verify-auth-challenge.json diff --git a/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md b/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md new file mode 100644 index 00000000..a0c7fe28 --- /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) +} +``` \ No newline at end of file diff --git a/events/cognito.go b/events/cognito.go index a518abf8..15314ba8 100644 --- a/events/cognito.go +++ b/events/cognito.go @@ -106,3 +106,72 @@ type GroupConfiguration struct { IAMRolesToOverride []string `json:"iamRolesToOverride"` 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 string `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"` +} diff --git a/events/cognito_test.go b/events/cognito_test.go index a619e47a..5dda9e48 100644 --- a/events/cognito_test.go +++ b/events/cognito_test.go @@ -112,3 +112,30 @@ 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{}) +} 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 From 1ff5acfa65e4bf806d2b915f27cbd3afacdb24df Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Fri, 15 Mar 2019 17:38:59 +0000 Subject: [PATCH 2/5] fix inconsitent whitespace in README --- ...nito_UserPools_CustomAuthLambdaTriggers.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md b/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md index a0c7fe28..737339cb 100644 --- a/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md +++ b/events/README_Cognito_UserPools_CustomAuthLambdaTriggers.md @@ -10,10 +10,10 @@ Define Auth Challenge Lambda Trigger: package main import ( - "fmt" + "fmt" - "github.com/aws/aws-lambda-go/lambda" - "github.com/aws/aws-lambda-go/events" + "github.com/aws/aws-lambda-go/lambda" + "github.com/aws/aws-lambda-go/events" ) func handler(event *events.CognitoEventUserPoolsDefineAuthChallenge) (*events.CognitoEventUserPoolsDefineAuthChallenge, error) { @@ -22,7 +22,7 @@ func handler(event *events.CognitoEventUserPoolsDefineAuthChallenge) (*events.Co } func main() { - lambda.Start(handler) + lambda.Start(handler) } ``` @@ -31,10 +31,10 @@ Create Auth Challenge Lambda Trigger: package main import ( - "fmt" + "fmt" - "github.com/aws/aws-lambda-go/lambda" - "github.com/aws/aws-lambda-go/events" + "github.com/aws/aws-lambda-go/lambda" + "github.com/aws/aws-lambda-go/events" ) func handler(event *events.CognitoEventUserPoolsCreateAuthChallenge) (*events.CognitoEventUserPoolsCreateAuthChallenge, error) { @@ -43,7 +43,7 @@ func handler(event *events.CognitoEventUserPoolsCreateAuthChallenge) (*events.Co } func main() { - lambda.Start(handler) + lambda.Start(handler) } ``` @@ -52,10 +52,10 @@ Verify Auth Challenge Response Lambda Trigger: package main import ( - "fmt" + "fmt" - "github.com/aws/aws-lambda-go/lambda" - "github.com/aws/aws-lambda-go/events" + "github.com/aws/aws-lambda-go/lambda" + "github.com/aws/aws-lambda-go/events" ) func handler(event *events.CognitoEventUserPoolsVerifyAuthChallenge) (*events.CognitoEventUserPoolsVerifyAuthChallenge, error) { @@ -64,6 +64,6 @@ func handler(event *events.CognitoEventUserPoolsVerifyAuthChallenge) (*events.Co } func main() { - lambda.Start(handler) + lambda.Start(handler) } -``` \ No newline at end of file +``` From 3146b38a0d23cb21f1603a57cc82c30c28d5de6b Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Thu, 27 Jun 2019 13:09:26 -0700 Subject: [PATCH 3/5] Fix Cognito challenge answer type Signed-off-by: Maksym Pavlenko --- events/cognito.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/cognito.go b/events/cognito.go index dd2a0d54..be77aa2f 100644 --- a/events/cognito.go +++ b/events/cognito.go @@ -178,7 +178,7 @@ type CognitoEventUserPoolsCreateAuthChallenge struct { type CognitoEventUserPoolsVerifyAuthChallengeRequest struct { UserAttributes map[string]string `json:"userAttributes"` PrivateChallengeParameters map[string]string `json:"privateChallengeParameters"` - ChallengeAnswer string `json:"challengeAnswer"` + ChallengeAnswer interface{} `json:"challengeAnswer"` } // CognitoEventUserPoolsVerifyAuthChallengeResponse defines verify auth challenge response parameters From fdb79e7a0bb4d5c8dca1f3dd673b4c6d562011da Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Thu, 27 Jun 2019 13:20:38 -0700 Subject: [PATCH 4/5] Merge master and resolve conflicts Signed-off-by: Maksym Pavlenko --- .github/ISSUE_TEMPLATE/feature_request.md | 20 +++ .travis.yml | 18 +-- Gopkg.lock | 44 ------ Gopkg.toml | 21 --- README.md | 13 +- events/README.md | 4 + events/README_Chime_Bots.md | 67 +++++++++ events/chime_bot.go | 31 ++++ events/chime_bot_test.go | 138 ++++++++++++++++++ events/cognito.go | 43 ++++++ events/cognito_test.go | 53 ++++++- events/lex.go | 9 +- ...cognito-event-userpools-custommessage.json | 23 +++ .../cognito-event-userpools-migrateuser.json | 27 ++++ go.mod | 2 - 15 files changed, 423 insertions(+), 90 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 Gopkg.lock delete mode 100644 Gopkg.toml create mode 100644 events/README_Chime_Bots.md create mode 100644 events/chime_bot.go create mode 100644 events/chime_bot_test.go create mode 100644 events/testdata/cognito-event-userpools-custommessage.json create mode 100644 events/testdata/cognito-event-userpools-migrateuser.json diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..bbcbbe7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.travis.yml b/.travis.yml index d717bfbe..efb68685 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,28 +5,18 @@ go: - 1.11 - tip +env: GO111MODULE=on + before_install: - - curl -L -s https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64 -o $GOPATH/bin/dep - - chmod +x $GOPATH/bin/dep + - go mod download install: - - dep ensure - go get golang.org/x/lint/golint - go get github.com/haya14busa/goverage matrix: - include: - - go: 1.12 - env: GO111MODULE=on - before_install: - - go mod download - install: - - go get golang.org/x/lint/golint - - go get github.com/haya14busa/goverage allow_failures: - go: tip - - go: 1.12 - env: GO111MODULE=on fast_finish: true notifications: @@ -43,4 +33,4 @@ script: - golint $LINT_PKGS # lint - ignore failures for now after_success: - - bash <(curl -s https://codecov.io/bash) \ No newline at end of file + - bash <(curl -s https://codecov.io/bash) diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index f0d4dba5..00000000 --- a/Gopkg.lock +++ /dev/null @@ -1,44 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b" - name = "github.com/davecgh/go-spew" - packages = ["spew"] - pruneopts = "" - revision = "346938d642f2ec3594ed81d874461961cd0faa76" - version = "v1.1.0" - -[[projects]] - digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411" - name = "github.com/pmezard/go-difflib" - packages = ["difflib"] - pruneopts = "" - revision = "792786c7400a136282c1664665ae0a8db921c6c2" - version = "v1.0.0" - -[[projects]] - digest = "1:a30066593578732a356dc7e5d7f78d69184ca65aeeff5939241a3ab10559bb06" - name = "github.com/stretchr/testify" - packages = ["assert"] - pruneopts = "" - revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" - version = "v1.2.1" - -[[projects]] - digest = "1:e85837cb04b78f61688c6eba93ea9d14f60d611e2aaf8319999b1a60d2dafbfa" - name = "gopkg.in/urfave/cli.v1" - packages = ["."] - pruneopts = "" - revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1" - version = "v1.20.0" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = [ - "github.com/stretchr/testify/assert", - "gopkg.in/urfave/cli.v1", - ] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index 323002ca..00000000 --- a/Gopkg.toml +++ /dev/null @@ -1,21 +0,0 @@ - -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" diff --git a/README.md b/README.md index 7a679d6b..97edaa73 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,7 @@ -# aws-lambda-go - -Libraries, samples, and tools to help Go developers develop AWS Lambda functions. - -To learn more about writing AWS Lambda functions in Go, go to [the official documentation](https://docs.aws.amazon.com/lambda/latest/dg/go-programming-model.html) - +# AWS Lambda for Go [![GoDoc][1]][2] -[![GoCard][3]][4] [![Build Status][5]][6] +[![GoCard][3]][4] [![codecov][7]][8] [1]: https://godoc.org/github.com/aws/aws-lambda-go?status.svg @@ -18,6 +13,10 @@ To learn more about writing AWS Lambda functions in Go, go to [the official docu [7]: https://codecov.io/gh/aws/aws-lambda-go/branch/master/graph/badge.svg [8]: https://codecov.io/gh/aws/aws-lambda-go +Libraries, samples, and tools to help Go developers develop AWS Lambda functions. + +To learn more about writing AWS Lambda functions in Go, go to [the official documentation](https://docs.aws.amazon.com/lambda/latest/dg/go-programming-model.html) + # Getting Started ``` Go diff --git a/events/README.md b/events/README.md index 9081a4bb..d1a50f92 100644 --- a/events/README.md +++ b/events/README.md @@ -14,6 +14,8 @@ This package provides input types for Lambda functions that process AWS events. [CloudFormation Events](../cfn/README.md) +[Chime Bot Events](README_Chime_Bots.md) + [Code Commit Events](README_CodeCommit.md) [Cognito Events](README_Cognito.md) @@ -32,6 +34,8 @@ This package provides input types for Lambda functions that process AWS events. [Kinesis Firehose Events](README_KinesisFirehose.md) +[Lex Events](README_Lex.md) + [S3 Events](README_S3.md) [SES Events](README_SES.md) diff --git a/events/README_Chime_Bots.md b/events/README_Chime_Bots.md new file mode 100644 index 00000000..d5d933d8 --- /dev/null +++ b/events/README_Chime_Bots.md @@ -0,0 +1,67 @@ +# Sample Function + +The following is a sample class and Lambda function that receives a Amazon Chime Bot event and handles the various event types accordingly. + +```go + +package main + +import ( + "fmt" + "context" + "net/http" + "bytes" + "encoding/json" + "errors" + "strconv" + + "github.com/aws/aws-lambda-go/events" +) + +func handler(_ context.Context, chimeBotEvent events.ChimeBotEvent) error { + switch chimeBotEvent.EventType { + case "Invite": + if err := message(chimeBotEvent.InboundHTTPSEndpoint.URL, "Thanks for inviting me to this room " + chimeBotEvent.Sender.SenderID); err != nil { + return fmt.Errorf("failed to send webhook message: %v", err) + } + return nil + case "Mention": + if err := message(chimeBotEvent.InboundHTTPSEndpoint.URL, "Thanks for mentioning me " + chimeBotEvent.Sender.SenderID); err != nil { + return fmt.Errorf("failed to send webhook message: %v", err) + } + return nil + case "Remove": + fmt.Printf("I have been removed from %q by %q", chimeBotEvent.Discussion.DiscussionType, chimeBotEvent.Sender.SenderID) + return nil + default: + return fmt.Errorf("event type %q is unsupported", chimeBotEvent.EventType) + } +} + +func message(url, content string) (error) { + input := &bytes.Buffer{} + if err := json.NewEncoder(input).Encode(webhookInput{Content:content}); err != nil { + return errors.New("failed to marshal request: " + err.Error()) + } + + resp, err := http.Post("POST", url, input) + if err != nil { + return errors.New("failed to execute post http request: " + err.Error()) + } + + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + + if resp.StatusCode != http.StatusOK { + return errors.New("bad response: status code not is " + strconv.Itoa(http.StatusOK) + " not " + strconv.Itoa(resp.StatusCode)) + } + + return nil +} + +type webhookInput struct { + Content string `json:"Content"` +} + +``` diff --git a/events/chime_bot.go b/events/chime_bot.go new file mode 100644 index 00000000..fa08f003 --- /dev/null +++ b/events/chime_bot.go @@ -0,0 +1,31 @@ +// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +package events + +import ( + "time" +) + +type ChimeBotEvent struct { + Sender ChimeBotEventSender `json:"Sender"` + Discussion ChimeBotEventDiscussion `json:"Discussion"` + EventType string `json:"EventType"` + InboundHTTPSEndpoint *ChimeBotEventInboundHTTPSEndpoint `json:"InboundHttpsEndpoint,omitempty"` + EventTimestamp time.Time `json:"EventTimestamp"` + Message string `json:"Message,omitempty"` +} + +type ChimeBotEventSender struct { + SenderID string `json:"SenderId"` + SenderIDType string `json:"SenderIdType"` +} + +type ChimeBotEventDiscussion struct { + DiscussionID string `json:"DiscussionId"` + DiscussionType string `json:"DiscussionType"` +} + +type ChimeBotEventInboundHTTPSEndpoint struct { + EndpointType string `json:"EndpointType"` + URL string `json:"Url"` +} diff --git a/events/chime_bot_test.go b/events/chime_bot_test.go new file mode 100644 index 00000000..18598ba9 --- /dev/null +++ b/events/chime_bot_test.go @@ -0,0 +1,138 @@ +// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +package events + +import ( + "encoding/json" + "testing" + + "github.com/aws/aws-lambda-go/events/test" + "github.com/stretchr/testify/assert" + "time" +) + +func TestChimeBotEventMarshaling(t *testing.T) { + // From https://docs.aws.amazon.com/chime/latest/ag/manage-chat-bots.html + tests := map[string]struct { + inputJSON string + expectedEvent ChimeBotEvent + }{ + "Example Invite Event": { + inputJSON: ` { + "Sender": { + "SenderId": "user@example.com", + "SenderIdType": "EmailId" + }, + "Discussion": { + "DiscussionId": "abcdef12-g34h-56i7-j8kl-mn9opqr012st", + "DiscussionType": "Room" + }, + "EventType": "Invite", + "InboundHttpsEndpoint": { + "EndpointType": "Persistent", + "Url": "https://hooks.a.chime.aws/incomingwebhooks/a1b2c34d-5678-90e1-f23g-h45i67j8901k?token=ABCDefGHiJK1LMnoP2Q3RST4uvwxYZAbC56DeFghIJkLM7N8OP9QRsTuV0WXYZABcdefgHiJ" + }, + "EventTimestamp": "2019-04-04T21:27:52.736Z" +}`, + expectedEvent: ChimeBotEvent{ + Sender: ChimeBotEventSender{ + SenderID: "user@example.com", + SenderIDType: "EmailId", + }, + Discussion: ChimeBotEventDiscussion{ + DiscussionID: "abcdef12-g34h-56i7-j8kl-mn9opqr012st", + DiscussionType: "Room", + }, + EventType: "Invite", + InboundHTTPSEndpoint: &ChimeBotEventInboundHTTPSEndpoint{ + EndpointType: "Persistent", + URL: "https://hooks.a.chime.aws/incomingwebhooks/a1b2c34d-5678-90e1-f23g-h45i67j8901k?token=ABCDefGHiJK1LMnoP2Q3RST4uvwxYZAbC56DeFghIJkLM7N8OP9QRsTuV0WXYZABcdefgHiJ", + }, + EventTimestamp: time.Date(2019, 04, 04, 21, 27, 52, 736000000, time.UTC), + Message: "", + }, + }, + "Example Mention Event": { + inputJSON: `{ + "Sender": { + "SenderId": "user@example.com", + "SenderIdType": "EmailId" + }, + "Discussion": { + "DiscussionId": "abcdef12-g34h-56i7-j8kl-mn9opqr012st", + "DiscussionType": "Room" + }, + "EventType": "Mention", + "InboundHttpsEndpoint": { + "EndpointType": "ShortLived", + "Url": "https://hooks.a.chime.aws/incomingwebhooks/a1b2c34d-5678-90e1-f23g-h45i67j8901k?token=ABCDefGHiJK1LMnoP2Q3RST4uvwxYZAbC56DeFghIJkLM7N8OP9QRsTuV0WXYZABcdefgHiJ" + }, + "EventTimestamp": "2019-04-04T21:30:43.181Z", + "Message": "@botDisplayName@example.com Hello Chatbot" +}`, + expectedEvent: ChimeBotEvent{ + Sender: ChimeBotEventSender{ + SenderID: "user@example.com", + SenderIDType: "EmailId", + }, + Discussion: ChimeBotEventDiscussion{ + DiscussionID: "abcdef12-g34h-56i7-j8kl-mn9opqr012st", + DiscussionType: "Room", + }, + EventType: "Mention", + InboundHTTPSEndpoint: &ChimeBotEventInboundHTTPSEndpoint{ + EndpointType: "ShortLived", + URL: "https://hooks.a.chime.aws/incomingwebhooks/a1b2c34d-5678-90e1-f23g-h45i67j8901k?token=ABCDefGHiJK1LMnoP2Q3RST4uvwxYZAbC56DeFghIJkLM7N8OP9QRsTuV0WXYZABcdefgHiJ", + }, + EventTimestamp: time.Date(2019, 04, 04, 21, 30, 43, 181000000, time.UTC), + Message: "@botDisplayName@example.com Hello Chatbot", + }, + }, + "Example Remove Event": { + inputJSON: `{ + "Sender": { + "SenderId": "user@example.com", + "SenderIdType": "EmailId" + }, + "Discussion": { + "DiscussionId": "abcdef12-g34h-56i7-j8kl-mn9opqr012st", + "DiscussionType": "Room" + }, + "EventType": "Remove", + "EventTimestamp": "2019-04-04T21:27:29.626Z" +}`, + expectedEvent: ChimeBotEvent{ + Sender: ChimeBotEventSender{ + SenderID: "user@example.com", + SenderIDType: "EmailId", + }, + Discussion: ChimeBotEventDiscussion{ + DiscussionID: "abcdef12-g34h-56i7-j8kl-mn9opqr012st", + DiscussionType: "Room", + }, + EventType: "Remove", + EventTimestamp: time.Date(2019, 04, 04, 21, 27, 29, 626000000, time.UTC), + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + var testEvent ChimeBotEvent + if err := json.Unmarshal([]byte(test.inputJSON), &testEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } + + assert.Equal(t, testEvent, test.expectedEvent) + + outputJSON, err := json.Marshal(testEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + assert.JSONEq(t, test.inputJSON, string(outputJSON)) + }) + } +} + +func TestChimeBotMarshalingMalformedJSON(t *testing.T) { + test.TestMalformedJson(t, ChimeBotEvent{}) +} diff --git a/events/cognito.go b/events/cognito.go index be77aa2f..cd60802a 100644 --- a/events/cognito.go +++ b/events/cognito.go @@ -52,6 +52,14 @@ type CognitoEventUserPoolsPostAuthentication struct { Response CognitoEventUserPoolsPostAuthenticationResponse `json:"response"` } +// CognitoEventUserPoolsMigrateUser is sent by AWS 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 + CognitoEventUserPoolsMigrateUserRequest `json:"request"` + CognitoEventUserPoolsMigrateUserResponse `json:"response"` +} + // CognitoEventUserPoolsCallerContext contains information about the caller type CognitoEventUserPoolsCallerContext struct { AWSSDKVersion string `json:"awsSdkVersion"` @@ -111,6 +119,20 @@ type CognitoEventUserPoolsPostAuthenticationRequest struct { type CognitoEventUserPoolsPostAuthenticationResponse struct { } +// CognitoEventUserPoolsMigrateUserRequest contains the request portion of a MigrateUser event +type CognitoEventUserPoolsMigrateUserRequest struct { + Password string `json:"password"` +} + +// CognitoEventUserPoolsMigrateUserResponse contains the response portion of a MigrateUser event +type CognitoEventUserPoolsMigrateUserResponse struct { + UserAttributes map[string]string `json:"userAttributes"` + FinalUserStatus string `json:"finalUserStatus"` + MessageAction string `json:"messageAction"` + DesiredDeliveryMediums []string `json:"desiredDeliveryMediums"` + ForceAliasCreation bool `json:"forceAliasCreation"` +} + // ClaimsOverrideDetails allows lambda to add, supress or override claims in the token type ClaimsOverrideDetails struct { GroupOverrideDetails GroupConfiguration `json:"groupOverrideDetails"` @@ -193,3 +215,24 @@ type CognitoEventUserPoolsVerifyAuthChallenge struct { 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 { + CognitoEventUserPoolsHeader + Request CognitoEventUserPoolsCustomMessageRequest `json:"request"` + Response CognitoEventUserPoolsCustomMessageResponse `json:"response"` +} + +// CognitoEventUserPoolsCustomMessageRequest contains the request portion of a CustomMessage event +type CognitoEventUserPoolsCustomMessageRequest struct { + UserAttributes map[string]interface{} `json:"userAttributes"` + CodeParameter string `json:"codeParameter"` +} + +// CognitoEventUserPoolsCustomMessageResponse contains the response portion of a CustomMessage event +type CognitoEventUserPoolsCustomMessageResponse struct { + SMSMessage string `json:"smsMessage"` + EmailMessage string `json:"emailMessage"` + EmailSubject string `json:"emailSubject"` +} diff --git a/events/cognito_test.go b/events/cognito_test.go index 629e3ee2..fad8755d 100644 --- a/events/cognito_test.go +++ b/events/cognito_test.go @@ -139,7 +139,7 @@ func TestCognitoEventUserPoolsVerifyAuthChallengeMarshaling(t *testing.T) { func TestCognitoEventUserPoolsVerifyAuthChallengeMalformedJson(t *testing.T) { test.TestMalformedJson(t, CognitoEventUserPoolsVerifyAuthChallenge{}) } - + func TestCognitoEventUserPoolsPostAuthenticationMarshaling(t *testing.T) { // read json from file @@ -162,3 +162,54 @@ func TestCognitoEventUserPoolsPostAuthenticationMarshaling(t *testing.T) { assert.JSONEq(t, string(inputJSON), string(outputJSON)) } + +func TestCognitoEventUserPoolsMigrateUserMarshalingMalformedJson(t *testing.T) { + test.TestMalformedJson(t, CognitoEventUserPoolsMigrateUser{}) +} + +func TestCognitoEventUserPoolsMigrateUserMarshaling(t *testing.T) { + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/cognito-event-userpools-migrateuser.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into CognitoEvent + var inputEvent CognitoEventUserPoolsMigrateUser + 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 TestCognitoEventUserPoolsCustomMessageMarshaling(t *testing.T) { + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/cognito-event-userpools-custommessage.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into CognitoEvent + var inputEvent CognitoEventUserPoolsCustomMessage + 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) + } + + assert.JSONEq(t, string(inputJSON), string(outputJSON)) +} + +func TestCognitoUserPoolsCustomMessageMarshalingMalformedJson(t *testing.T) { + test.TestMalformedJson(t, CognitoEventUserPoolsCustomMessage{}) +} diff --git a/events/lex.go b/events/lex.go index 28590a8a..70bfbd0b 100644 --- a/events/lex.go +++ b/events/lex.go @@ -5,7 +5,7 @@ type LexEvent struct { InvocationSource string `json:"invocationSource,omitempty"` UserID string `json:"userId,omitempty"` InputTranscript string `json:"inputTranscript,omitempty"` - SessionAttributes map[string]string `json:"sessionAttributes,omitempty"` + SessionAttributes SessionAttributes `json:"sessionAttributes,omitempty"` RequestAttributes map[string]string `json:"requestAttributes,omitempty"` Bot *LexBot `json:"bot,omitempty"` OutputDialogMode string `json:"outputDialogMode,omitempty"` @@ -41,8 +41,15 @@ type LexDialogAction struct { ResponseCard *LexResponseCard `json:"responseCard,omitempty"` } +type SessionAttributes map[string]string + type Slots map[string]*string +type LexResponse struct { + SessionAttributes SessionAttributes `json:"sessionAttributes,omitempty"` + DialogAction LexDialogAction `json:"dialogAction,omitempty"` +} + type LexResponseCard struct { Version int64 `json:"version,omitempty"` ContentType string `json:"contentType,omitempty"` diff --git a/events/testdata/cognito-event-userpools-custommessage.json b/events/testdata/cognito-event-userpools-custommessage.json new file mode 100644 index 00000000..48c43f29 --- /dev/null +++ b/events/testdata/cognito-event-userpools-custommessage.json @@ -0,0 +1,23 @@ +{ + "version": "1", + "triggerSource": "CustomMessage_SignUp/CustomMessage_ResendCode/CustomMessage_ForgotPassword/CustomMessage_VerifyUserAttribute", + "region": "", + "userPoolId": "", + "userName": "", + "callerContext": { + "awsSdkVersion": "", + "clientId": "" + }, + "request": { + "userAttributes": { + "phone_number_verified": true, + "email_verified": false + }, + "codeParameter": "####" + }, + "response": { + "smsMessage": "", + "emailMessage": "", + "emailSubject": "" + } +} diff --git a/events/testdata/cognito-event-userpools-migrateuser.json b/events/testdata/cognito-event-userpools-migrateuser.json new file mode 100644 index 00000000..4991195d --- /dev/null +++ b/events/testdata/cognito-event-userpools-migrateuser.json @@ -0,0 +1,27 @@ +{ + "version": "1", + "triggerSource": "UserMigration_Authentication", + "region": "", + "userPoolId": "", + "userName": "", + "callerContext": { + "awsSdkVersion": "", + "clientId": "" + }, + "request": { + "password": "" + }, + "response": { + "userAttributes": { + "email": "", + "phone_number": "" + }, + "finalUserStatus": "", + "messageAction": "", + "desiredDeliveryMediums": [ + "", + "" + ], + "forceAliasCreation": true + } +} \ No newline at end of file diff --git a/go.mod b/go.mod index 76e68829..86401c1b 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,5 @@ module github.com/aws/aws-lambda-go -go 1.12 - require ( github.com/davecgh/go-spew v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect From a283149445a03e47c9a9bac080bbe21a859928f7 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Sat, 6 Jul 2019 13:28:53 +0100 Subject: [PATCH 5/5] Update cognito.go ChallengeMetaData -> ChallengeMetadata --- events/cognito.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/cognito.go b/events/cognito.go index 29a04b2c..9de9a615 100644 --- a/events/cognito.go +++ b/events/cognito.go @@ -152,7 +152,7 @@ type GroupConfiguration struct { type CognitoEventUserPoolsChallengeResult struct { ChallengeName string `json:"challengeName"` ChallengeResult bool `json:"challengeResult"` - ChallengeMetaData string `json:"challengeMetadata"` + ChallengeMetadata string `json:"challengeMetadata"` } // CognitoEventUserPoolsDefineAuthChallengeRequest defines auth challenge request parameters