...
1
16
17 package tokenreview
18
19 import (
20 "context"
21 "errors"
22 "fmt"
23 "net/http"
24
25 apierrors "k8s.io/apimachinery/pkg/api/errors"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/runtime"
28 "k8s.io/apiserver/pkg/authentication/authenticator"
29 genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
30 "k8s.io/apiserver/pkg/registry/rest"
31 "k8s.io/klog/v2"
32 "k8s.io/kubernetes/pkg/apis/authentication"
33 )
34
35 var badAuthenticatorAuds = apierrors.NewInternalError(errors.New("error validating audiences"))
36
37 type REST struct {
38 tokenAuthenticator authenticator.Request
39 apiAudiences []string
40 }
41
42 func NewREST(tokenAuthenticator authenticator.Request, apiAudiences []string) *REST {
43 return &REST{
44 tokenAuthenticator: tokenAuthenticator,
45 apiAudiences: apiAudiences,
46 }
47 }
48
49 func (r *REST) NamespaceScoped() bool {
50 return false
51 }
52
53 func (r *REST) New() runtime.Object {
54 return &authentication.TokenReview{}
55 }
56
57
58 func (r *REST) Destroy() {
59
60
61 }
62
63 var _ rest.SingularNameProvider = &REST{}
64
65 func (r *REST) GetSingularName() string {
66 return "tokenreview"
67 }
68
69 func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
70 tokenReview, ok := obj.(*authentication.TokenReview)
71 if !ok {
72 return nil, apierrors.NewBadRequest(fmt.Sprintf("not a TokenReview: %#v", obj))
73 }
74 namespace := genericapirequest.NamespaceValue(ctx)
75 if len(namespace) != 0 {
76 return nil, apierrors.NewBadRequest(fmt.Sprintf("namespace is not allowed on this type: %v", namespace))
77 }
78
79 if len(tokenReview.Spec.Token) == 0 {
80 return nil, apierrors.NewBadRequest(fmt.Sprintf("token is required for TokenReview in authentication"))
81 }
82
83 if createValidation != nil {
84 if err := createValidation(ctx, obj.DeepCopyObject()); err != nil {
85 return nil, err
86 }
87 }
88
89 if r.tokenAuthenticator == nil {
90 return tokenReview, nil
91 }
92
93
94 fakeReq := &http.Request{Header: http.Header{}}
95 fakeReq.Header.Add("Authorization", "Bearer "+tokenReview.Spec.Token)
96
97 auds := tokenReview.Spec.Audiences
98 if len(auds) == 0 {
99 auds = r.apiAudiences
100 }
101 if len(auds) > 0 {
102 fakeReq = fakeReq.WithContext(authenticator.WithAudiences(fakeReq.Context(), auds))
103 }
104
105 resp, ok, err := r.tokenAuthenticator.AuthenticateRequest(fakeReq)
106 tokenReview.Status.Authenticated = ok
107 if err != nil {
108 tokenReview.Status.Error = err.Error()
109 }
110
111 if len(auds) > 0 && resp != nil && len(authenticator.Audiences(auds).Intersect(resp.Audiences)) == 0 {
112 klog.Errorf("error validating audience. want=%q got=%q", auds, resp.Audiences)
113 return nil, badAuthenticatorAuds
114 }
115
116 if resp != nil && resp.User != nil {
117 tokenReview.Status.User = authentication.UserInfo{
118 Username: resp.User.GetName(),
119 UID: resp.User.GetUID(),
120 Groups: resp.User.GetGroups(),
121 Extra: map[string]authentication.ExtraValue{},
122 }
123 for k, v := range resp.User.GetExtra() {
124 tokenReview.Status.User.Extra[k] = authentication.ExtraValue(v)
125 }
126 tokenReview.Status.Audiences = resp.Audiences
127 }
128
129 return tokenReview, nil
130 }
131
View as plain text