forked from vdparikh/go-serverless-demo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauthorizer.go
121 lines (103 loc) · 3.68 KB
/
authorizer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"encoding/json"
"errors"
"fmt"
"strings"
jwt "github.com/dgrijalva/jwt-go"
"github.com/eawsy/aws-lambda-go-core/service/lambda/runtime"
"github.com/eawsy/aws-lambda-go-net/service/lambda/runtime/net/apigatewayproxy"
)
//AuthStruct ...
type AuthStruct struct {
AuthorizationToken string `json:"authorizationToken"`
MethodArn string `json:"methodArn"`
Type string `json:"type"`
}
// StatementStruct ...
type StatementStruct struct {
Effect string `json:"Effect"`
Action []string `json:"Action"`
Resource []string `json:"Resource"`
}
// AuthorizerResponse ...
type AuthorizerResponse struct {
PrincipalID string `json:"principalId"`
PolicyDocument struct {
Version string `json:"Version"`
Statement []StatementStruct `json:"Statement"`
} `json:"policyDocument"`
}
// VerifyHandle ... Verify OAUTH token and generate access policy
// This handler is not exposed as an API but is calling directly by the custom authorizer
var VerifyHandle apigatewayproxy.Handler
// generatePolicy
func generatePolicy(effect string, eventMap map[string]interface{}, user string) AuthorizerResponse {
resource := eventMap["methodArn"].(string)
var authResponse AuthorizerResponse
authResponse.PrincipalID = user
authResponse.PolicyDocument.Version = "2012-10-17" // default version
authResponse.PolicyDocument.Statement = append(
authResponse.PolicyDocument.Statement,
StatementStruct{effect, []string{"execute-api:Invoke"}, []string{resource}},
)
// authResponse.Headers = map[string]string{"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Credentials": "true"}
// You cannot explicitly set headers in the authorizer and has to be manually done from Console via Gateway Resources page
return authResponse
}
// VerifyHandler ...
// Function JWT Token and generates access policy for API Gateway
func VerifyHandler(evt json.RawMessage, ctx *runtime.Context) (interface{}, error) {
// Input Verification
// The Input to authorizer should be as below
// {
// "type":"TOKEN",
// "authorizationToken":"<caller-supplied-token>",
// "methodArn":"arn:aws:execute-api:<regionId>:<accountId>:<apiId>/<stage>/<method>/<resourcePath>"
// }
var e interface{}
_ = json.Unmarshal(evt, &e)
eventMap := e.(map[string]interface{})
authStruct := AuthStruct{}
err := json.Unmarshal(evt, &authStruct)
if err != nil {
return nil, errors.New(`Error: Invalid token`)
}
authorizationHeader := authStruct.AuthorizationToken
if authorizationHeader != "" {
bearerToken := strings.Split(authorizationHeader, " ")
// The token is normally as "bearer xxxx" and make sure length is 2
if len(bearerToken) == 2 {
token, error := jwt.Parse(bearerToken[1], func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("There was an error")
}
// As always use KMS or something better for secret management
return []byte("secret"), nil
})
// If token is Expired and/or invalid
if error != nil {
if error.Error() == "Token is expired" {
return nil, errors.New(`Unauthorized`)
}
return nil, errors.New(`Unauthorized`)
}
if token.Valid {
claims := token.Claims.(jwt.MapClaims)
tmp := strings.Split(authStruct.MethodArn, ":")
// Now this truly a hack for now to get the userId from the URI
// TODO: Make it better
if len(tmp) > 5 {
apiGatewayArnTmp := strings.Split(tmp[5], "/")
if len(apiGatewayArnTmp) > 4 {
subject := claims["sub"].(string)
if apiGatewayArnTmp[4] == subject {
return generatePolicy("Allow", eventMap, subject), nil
}
}
}
}
}
}
return nil, errors.New(`Unauthorized`)
}