Skip to content

Commit 1b8736e

Browse files
committed
Add golang auth examples
1 parent 87932fa commit 1b8736e

20 files changed

+526
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ serverless install -u https://github.com/serverless/examples/tree/master/folder-
4444
|:--------------------------- |:-----|
4545
| [Aws Dotnet Rest Api With Dynamodb](https://github.com/serverless/examples/tree/master/aws-dotnet-rest-api-with-dynamodb/src/DotNetServerless.Lambda) <br/> Reading/Writing operations using .NET Core and DynamoDB | dotnet |
4646
| [Aws Lambda Layer](https://github.com/serverless/examples/tree/master/aws-ffmpeg-layer) | nodeJS |
47+
| [Aws Golang Auth Examples](https://github.com/serverless/examples/tree/master/aws-golang-auth-examples) <br/> These example shows how to run a Golang lambda with authentication | golang |
4748
| [Aws Golang Dynamo Stream To Elasticsearch](https://github.com/serverless/examples/tree/master/aws-golang-dynamo-stream-to-elasticsearch) <br/> This example deploys a DynamoDB Table, an Elasticsearch Node, and a lambda triggered off of a Dynamo Stream which updates an elasticsearch index with the data from the Dynamo Table | golang |
4849
| [Aws Golang Simple Http Endpoint](https://github.com/serverless/examples/tree/master/aws-golang-simple-http-endpoint) <br/> Example demonstrates how to setup a simple HTTP GET endpoint with golang | golang |
4950
| [Aws Golang Stream Kinesis To Elasticsearch](https://github.com/serverless/examples/tree/master/aws-golang-stream-kinesis-to-elasticsearch) <br/> Pull data from AWS Kinesis streams and forward to elasticsearch | golang |

aws-golang-auth-examples/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
bin/**
2+
vendor
3+
.serverless
4+
*.coverprofile

aws-golang-auth-examples/Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
help:
2+
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
3+
4+
functions := $(shell find functions -name \*main.go | awk -F'/' '{print $$2}')
5+
6+
build: ## Build golang binaries
7+
@for function in $(functions) ; do \
8+
env GOOS=linux go build -ldflags="-s -w" -o bin/$$function functions/$$function/main.go ; \
9+
done

aws-golang-auth-examples/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Go Serverless Examples
2+
3+
A few example of AWS lambda functions written in GoLang.
4+
5+
Functions:
6+
7+
- `hello-world`: Exactly what is says on the tin. Listening on a `/hello` path.
8+
- `auth`: An AWS API Gateway custom authorizer that sits in front of `hello-world`. It expects an auth bearer of `hello` as a header and is on the base `/` path. The auth header should be `Authorization: bearer hello`
9+
- `auth2` and `hello-world2`: The same as `auth` above except using auth contexts. Any name can be used as a bearer token, for example `Authorization: bearer Bob`. The response will then return `Hello, Bob!`
10+
11+
I hope to add to these examples over time, if you have ideas please feel free to raise issues or pull requests.
12+
13+
For more info on these example check out the [blog post](https://cloudnative.ly/lambdas-with-golang-a-technical-guide-6f381284897b)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main_test
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestAuth(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "Auth Suite")
13+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"strings"
6+
7+
"github.com/aws/aws-lambda-go/events"
8+
"github.com/aws/aws-lambda-go/lambda"
9+
)
10+
11+
func handler(request events.APIGatewayCustomAuthorizerRequest) (events.APIGatewayCustomAuthorizerResponse, error) {
12+
token := request.AuthorizationToken
13+
tokenSlice := strings.Split(token, " ")
14+
var bearerToken string
15+
if len(tokenSlice) > 1 {
16+
bearerToken = tokenSlice[len(tokenSlice)-1]
17+
}
18+
if bearerToken != "hello" {
19+
return events.APIGatewayCustomAuthorizerResponse{}, errors.New("Unauthorized")
20+
}
21+
22+
return generatePolicy("user", "Allow", request.MethodArn), nil
23+
}
24+
25+
func main() {
26+
lambda.Start(handler)
27+
}
28+
29+
func generatePolicy(principalID, effect, resource string) events.APIGatewayCustomAuthorizerResponse {
30+
authResponse := events.APIGatewayCustomAuthorizerResponse{PrincipalID: principalID}
31+
32+
if effect != "" && resource != "" {
33+
authResponse.PolicyDocument = events.APIGatewayCustomAuthorizerPolicy{
34+
Version: "2012-10-17",
35+
Statement: []events.IAMPolicyStatement{
36+
{
37+
Action: []string{"execute-api:Invoke"},
38+
Effect: effect,
39+
Resource: []string{resource},
40+
},
41+
},
42+
}
43+
}
44+
return authResponse
45+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package main
2+
3+
import (
4+
"github.com/aws/aws-lambda-go/events"
5+
6+
. "github.com/onsi/ginkgo"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
var _ = Describe("the auth function", func() {
11+
var (
12+
response events.APIGatewayCustomAuthorizerResponse
13+
request events.APIGatewayCustomAuthorizerRequest
14+
err error
15+
)
16+
17+
JustBeforeEach(func() {
18+
response, err = handler(request)
19+
})
20+
21+
AfterEach(func() {
22+
request = events.APIGatewayCustomAuthorizerRequest{}
23+
response = events.APIGatewayCustomAuthorizerResponse{}
24+
})
25+
26+
Context("When the auth bearer is not set", func() {
27+
It("Fails auth", func() {
28+
Expect(err).To(MatchError("Unauthorized"))
29+
Expect(response).To(Equal(events.APIGatewayCustomAuthorizerResponse{}))
30+
})
31+
})
32+
33+
Context("When the auth bearer is set", func() {
34+
Context("and auth fails", func() {
35+
BeforeEach(func() {
36+
request = events.APIGatewayCustomAuthorizerRequest{
37+
AuthorizationToken: "bearer token",
38+
MethodArn: "testARN",
39+
}
40+
})
41+
42+
It("Fails auth", func() {
43+
Expect(err).To(MatchError("Unauthorized"))
44+
Expect(response).To(Equal(events.APIGatewayCustomAuthorizerResponse{}))
45+
})
46+
})
47+
48+
Context("and auth succeeds", func() {
49+
BeforeEach(func() {
50+
request = events.APIGatewayCustomAuthorizerRequest{
51+
AuthorizationToken: "bearer hello",
52+
MethodArn: "testARN",
53+
}
54+
})
55+
56+
It("authorizes", func() {
57+
Expect(err).To(BeNil())
58+
Expect(response.PolicyDocument.Version).To(Equal("2012-10-17"))
59+
Expect(response.PolicyDocument.Statement).To(Equal([]events.IAMPolicyStatement{
60+
{
61+
Action: []string{"execute-api:Invoke"},
62+
Effect: "Allow",
63+
Resource: []string{"testARN"},
64+
},
65+
}))
66+
})
67+
})
68+
})
69+
})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main_test
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestAuth(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "Auth Suite")
13+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"strings"
6+
7+
"github.com/aws/aws-lambda-go/events"
8+
"github.com/aws/aws-lambda-go/lambda"
9+
)
10+
11+
func handler(request events.APIGatewayCustomAuthorizerRequest) (events.APIGatewayCustomAuthorizerResponse, error) {
12+
token := request.AuthorizationToken
13+
tokenSlice := strings.Split(token, " ")
14+
var bearerToken string
15+
if len(tokenSlice) > 1 {
16+
bearerToken = tokenSlice[len(tokenSlice)-1]
17+
}
18+
if bearerToken == "" {
19+
return events.APIGatewayCustomAuthorizerResponse{}, errors.New("Unauthorized")
20+
}
21+
22+
return generatePolicy("user", "Allow", request.MethodArn, map[string]interface{}{"name": bearerToken}), nil
23+
}
24+
25+
func main() {
26+
lambda.Start(handler)
27+
}
28+
29+
func generatePolicy(principalID, effect, resource string, context map[string]interface{}) events.APIGatewayCustomAuthorizerResponse {
30+
authResponse := events.APIGatewayCustomAuthorizerResponse{PrincipalID: principalID}
31+
32+
if effect != "" && resource != "" {
33+
authResponse.PolicyDocument = events.APIGatewayCustomAuthorizerPolicy{
34+
Version: "2012-10-17",
35+
Statement: []events.IAMPolicyStatement{
36+
{
37+
Action: []string{"execute-api:Invoke"},
38+
Effect: effect,
39+
Resource: []string{resource},
40+
},
41+
},
42+
}
43+
}
44+
authResponse.Context = context
45+
return authResponse
46+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package main
2+
3+
import (
4+
"github.com/aws/aws-lambda-go/events"
5+
6+
. "github.com/onsi/ginkgo"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
var _ = Describe("the auth function", func() {
11+
var (
12+
response events.APIGatewayCustomAuthorizerResponse
13+
request events.APIGatewayCustomAuthorizerRequest
14+
err error
15+
)
16+
17+
JustBeforeEach(func() {
18+
response, err = handler(request)
19+
})
20+
21+
AfterEach(func() {
22+
request = events.APIGatewayCustomAuthorizerRequest{}
23+
response = events.APIGatewayCustomAuthorizerResponse{}
24+
})
25+
26+
Context("When the auth bearer is not set", func() {
27+
It("Fails auth", func() {
28+
Expect(err).To(MatchError("Unauthorized"))
29+
Expect(response).To(Equal(events.APIGatewayCustomAuthorizerResponse{}))
30+
})
31+
})
32+
33+
Context("When the auth bearer is set", func() {
34+
Context("and auth succeeds", func() {
35+
BeforeEach(func() {
36+
request = events.APIGatewayCustomAuthorizerRequest{
37+
AuthorizationToken: "bearer Bob",
38+
MethodArn: "testARN",
39+
}
40+
})
41+
42+
It("authorizes", func() {
43+
Expect(err).To(BeNil())
44+
Expect(response.PolicyDocument.Version).To(Equal("2012-10-17"))
45+
Expect(response.PolicyDocument.Statement).To(Equal([]events.IAMPolicyStatement{
46+
{
47+
Action: []string{"execute-api:Invoke"},
48+
Effect: "Allow",
49+
Resource: []string{"testARN"},
50+
},
51+
}))
52+
Expect(response.Context["name"]).To(Equal("Bob"))
53+
})
54+
})
55+
})
56+
})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main_test
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestHelloWorld(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "HelloWorld Suite")
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import (
4+
"github.com/aws/aws-lambda-go/events"
5+
"github.com/aws/aws-lambda-go/lambda"
6+
)
7+
8+
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
9+
return events.APIGatewayProxyResponse{
10+
Body: "Hello, World!",
11+
StatusCode: 200,
12+
}, nil
13+
}
14+
15+
func main() {
16+
lambda.Start(handler)
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/aws/aws-lambda-go/events"
7+
8+
. "github.com/onsi/ginkgo"
9+
. "github.com/onsi/gomega"
10+
)
11+
12+
var _ = Describe("Hello world", func() {
13+
var (
14+
response events.APIGatewayProxyResponse
15+
request events.APIGatewayProxyRequest
16+
err error
17+
)
18+
19+
JustBeforeEach(func() {
20+
response, err = handler(request)
21+
Expect(err).To(BeNil())
22+
})
23+
24+
It(`Returns "Hello, World!" and an OK status`, func() {
25+
Expect(response.Body).To(Equal("Hello, World!"))
26+
Expect(response.StatusCode).To(Equal(http.StatusOK))
27+
})
28+
})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main_test
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestHelloWorld(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "HelloWorld Suite")
13+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
7+
"github.com/aws/aws-lambda-go/events"
8+
"github.com/aws/aws-lambda-go/lambda"
9+
)
10+
11+
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
12+
var name string
13+
if _, ok := request.RequestContext.Authorizer["name"]; ok {
14+
name = request.RequestContext.Authorizer["name"].(string)
15+
} else {
16+
return events.APIGatewayProxyResponse{
17+
Body: "Unauthorized: Must be an authorized user with a name",
18+
StatusCode: http.StatusUnauthorized,
19+
}, nil
20+
}
21+
22+
return events.APIGatewayProxyResponse{
23+
Body: fmt.Sprintf("Hello, %s!", name),
24+
StatusCode: http.StatusOK,
25+
}, nil
26+
}
27+
28+
func main() {
29+
lambda.Start(handler)
30+
}

0 commit comments

Comments
 (0)