-
Notifications
You must be signed in to change notification settings - Fork 550
/
identity_context.go
138 lines (112 loc) · 4.11 KB
/
identity_context.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package auth
import (
"context"
"fmt"
"time"
"github.com/flyteorg/flyte/flyteplugins/go/tasks/pluginmachinery/utils"
"github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service"
"k8s.io/apimachinery/pkg/util/sets"
)
var (
emptyIdentityContext = IdentityContext{}
)
type claimsType = map[string]interface{}
// IdentityContext is an abstract entity to enclose the authenticated identity of the user/app. Both gRPC and HTTP
// servers have interceptors to set the IdentityContext on the context.Context.
// To retrieve the current IdentityContext call auth.IdentityContextFromContext(ctx).
// To check whether there is an identity set, call auth.IdentityContextFromContext(ctx).IsEmpty()
type IdentityContext struct {
audience string
userID string
appID string
authenticatedAt time.Time
userInfo *service.UserInfoResponse
// Set to pointer just to keep this struct go-simple to support equal operator
scopes *sets.String
// Raw JWT token from the IDP. Set to a pointer to support the equal operator for this struct.
claims *claimsType
// executionIdentity stores a unique string that can be used to identify the user associated with a given task.
// This identifier is passed down to the ExecutionSpec and can be used for various purposes, such as setting the user identifier on a pod label.
// By default, the execution user identifier is filled with the value of IdentityContext.userID. However, you can customize your middleware to assign other values if needed.
// Providing a user identifier can be useful for tracking tasks and associating them with specific users, especially in multi-user environments.
executionIdentity string
}
func (c IdentityContext) Audience() string {
return c.audience
}
func (c IdentityContext) UserID() string {
return c.userID
}
func (c IdentityContext) AppID() string {
return c.appID
}
func (c IdentityContext) UserInfo() *service.UserInfoResponse {
if c.userInfo == nil {
return &service.UserInfoResponse{}
}
return c.userInfo
}
func (c IdentityContext) IsEmpty() bool {
return c == emptyIdentityContext
}
func (c IdentityContext) Scopes() sets.String {
if c.scopes != nil {
return *c.scopes
}
return sets.NewString()
}
func (c IdentityContext) Claims() map[string]interface{} {
if c.claims != nil {
return *c.claims
}
return make(map[string]interface{})
}
func (c IdentityContext) WithContext(ctx context.Context) context.Context {
return context.WithValue(ctx, ContextKeyIdentityContext, c)
}
func (c IdentityContext) AuthenticatedAt() time.Time {
return c.authenticatedAt
}
func (c IdentityContext) ExecutionIdentity() string {
return c.executionIdentity
}
// WithExecutionUserIdentifier creates a copy of the original identity context and attach ExecutionIdentity
func (c IdentityContext) WithExecutionUserIdentifier(euid string) IdentityContext {
c.executionIdentity = euid
return c
}
// NewIdentityContext creates a new IdentityContext.
func NewIdentityContext(audience, userID, appID string, authenticatedAt time.Time, scopes sets.String, userInfo *service.UserInfoResponse, claims map[string]interface{}) (
IdentityContext, error) {
// For some reason, google IdP returns a subject in the ID Token but an empty subject in the /user_info endpoint
if userInfo == nil {
userInfo = &service.UserInfoResponse{}
}
if len(userInfo.Subject) == 0 {
userInfo.Subject = userID
}
if len(claims) > 0 {
claimsStruct, err := utils.MarshalObjToStruct(claims)
if err != nil {
return IdentityContext{}, fmt.Errorf("failed to marshal claims [%+v] to struct: %w", claims, err)
}
userInfo.AdditionalClaims = claimsStruct
}
return IdentityContext{
audience: audience,
userID: userID,
appID: appID,
userInfo: userInfo,
authenticatedAt: authenticatedAt,
scopes: &scopes,
claims: &claims,
}, nil
}
// IdentityContextFromContext retrieves the authenticated identity from context.Context.
func IdentityContextFromContext(ctx context.Context) IdentityContext {
existing := ctx.Value(ContextKeyIdentityContext)
if existing != nil {
return existing.(IdentityContext)
}
return emptyIdentityContext
}