-
Notifications
You must be signed in to change notification settings - Fork 1
/
handler.go
88 lines (72 loc) · 2.71 KB
/
handler.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
package auth
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/golang-jwt/jwt/v4"
)
// Event all data we expect within a request
type Event struct {
Headers EventHeaders `json:"headers"`
Query EventQuery `json:"queryStringParameters"`
}
// EventHeaders all header fields we expect in a request
type EventHeaders struct {
Authorization string `json:"authorization"`
Accept string `json:"accept,omitempty"`
}
// EventQuery all query fields we expect in a request
type EventQuery struct {
Role string `json:"role"`
}
// Claims all claim fields a token from Gitlab could have
type Claims struct {
ClaimsJSON []byte
RegisteredClaims *jwt.RegisteredClaims
}
// Rule represents a single claim to role mapping
type Rule struct {
Role string `json:"role"`
Region string `json:"region"`
Duration int64 `json:"duration"`
ClaimValues json.RawMessage `json:"claim_values"`
}
// Handler lambda function interface
type Handler func(ctx context.Context, event Event) (HandlerResponse, error)
// NewHandler creates the actual Handler function
func NewHandler(consumer AwsConsumerInterface, validator TokenValidatorInterface) Handler {
return func(ctx context.Context, event Event) (HandlerResponse, error) {
logger := Logger(ctx)
if event.Headers.Authorization == "" || event.Query.Role == "" {
return RespondError(ctx, fmt.Errorf("invalid arguments"), http.StatusBadRequest)
}
iamRules, err := consumer.RetrieveRulesFromRoleTags(ctx, event.Query.Role)
if err != nil {
return RespondError(ctx, err, http.StatusBadRequest)
}
logger.Infof("Retrieved Event for Role %s\n%s", event.Query.Role, event.Headers.Authorization)
rules := append(consumer.Rules(), iamRules...)
claims, err := validator.RetrieveClaimsFromToken(ctx, event.Headers.Authorization)
if err != nil {
return RespondError(ctx, err, http.StatusUnauthorized)
}
logger.Debugf("Claims JSON: %s", claims.ClaimsJSON)
logger.Infof("Validated Token")
role, err := validator.ValidateClaimsForRule(ctx, claims, event.Query.Role, rules)
if err != nil {
return RespondError(ctx, err, http.StatusInternalServerError)
} else if role == nil {
return RespondError(ctx, fmt.Errorf("unable to find matching role for the given token"), http.StatusUnauthorized)
}
logger.Infof("Retrieved request from %s to assume role %s", claims.RegisteredClaims.Subject, role.Role)
credentials, err := consumer.AssumeRole(ctx, role, claims.RegisteredClaims.Subject)
if err != nil {
return RespondError(ctx, err, http.StatusInternalServerError)
}
if event.Headers.Accept == "text/x-shellscript" {
return RespondShellscript(ctx, credentials)
}
return RespondJSON(ctx, credentials)
}
}