1
16
17 package bootstrap
18
19 import (
20 "context"
21 "reflect"
22 "testing"
23
24 corev1 "k8s.io/api/core/v1"
25 "k8s.io/apimachinery/pkg/api/errors"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/labels"
28 "k8s.io/apimachinery/pkg/runtime/schema"
29 "k8s.io/apiserver/pkg/authentication/user"
30 bootstrapapi "k8s.io/cluster-bootstrap/token/api"
31 )
32
33 type lister struct {
34 secrets []*corev1.Secret
35 }
36
37 func (l *lister) List(selector labels.Selector) (ret []*corev1.Secret, err error) {
38 return l.secrets, nil
39 }
40
41 func (l *lister) Get(name string) (*corev1.Secret, error) {
42 for _, s := range l.secrets {
43 if s.Name == name {
44 return s, nil
45 }
46 }
47 return nil, errors.NewNotFound(schema.GroupResource{}, name)
48 }
49
50 const (
51
52 tokenID = "foobar"
53 tokenSecret = "circumnavigation"
54 )
55
56 func TestTokenAuthenticator(t *testing.T) {
57 now := metav1.Now()
58
59 tests := []struct {
60 name string
61
62 secrets []*corev1.Secret
63 token string
64
65 wantNotFound bool
66 wantUser *user.DefaultInfo
67 }{
68 {
69 name: "valid token",
70 secrets: []*corev1.Secret{
71 {
72 ObjectMeta: metav1.ObjectMeta{
73 Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
74 },
75 Data: map[string][]byte{
76 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
77 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
78 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
79 },
80 Type: "bootstrap.kubernetes.io/token",
81 },
82 },
83 token: tokenID + "." + tokenSecret,
84 wantUser: &user.DefaultInfo{
85 Name: "system:bootstrap:" + tokenID,
86 Groups: []string{"system:bootstrappers"},
87 },
88 },
89 {
90 name: "valid token with extra group",
91 secrets: []*corev1.Secret{
92 {
93 ObjectMeta: metav1.ObjectMeta{
94 Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
95 },
96 Data: map[string][]byte{
97 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
98 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
99 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
100 bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("system:bootstrappers:foo"),
101 },
102 Type: "bootstrap.kubernetes.io/token",
103 },
104 },
105 token: tokenID + "." + tokenSecret,
106 wantUser: &user.DefaultInfo{
107 Name: "system:bootstrap:" + tokenID,
108 Groups: []string{"system:bootstrappers", "system:bootstrappers:foo"},
109 },
110 },
111 {
112 name: "invalid group",
113 secrets: []*corev1.Secret{
114 {
115 ObjectMeta: metav1.ObjectMeta{
116 Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
117 },
118 Data: map[string][]byte{
119 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
120 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
121 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
122 bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("foo"),
123 },
124 Type: "bootstrap.kubernetes.io/token",
125 },
126 },
127 token: tokenID + "." + tokenSecret,
128 wantNotFound: true,
129 },
130 {
131 name: "invalid secret name",
132 secrets: []*corev1.Secret{
133 {
134 ObjectMeta: metav1.ObjectMeta{
135 Name: "bad-name",
136 },
137 Data: map[string][]byte{
138 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
139 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
140 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
141 },
142 Type: "bootstrap.kubernetes.io/token",
143 },
144 },
145 token: tokenID + "." + tokenSecret,
146 wantNotFound: true,
147 },
148 {
149 name: "no usage",
150 secrets: []*corev1.Secret{
151 {
152 ObjectMeta: metav1.ObjectMeta{
153 Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
154 },
155 Data: map[string][]byte{
156 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
157 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
158 },
159 Type: "bootstrap.kubernetes.io/token",
160 },
161 },
162 token: tokenID + "." + tokenSecret,
163 wantNotFound: true,
164 },
165 {
166 name: "wrong token",
167 secrets: []*corev1.Secret{
168 {
169 ObjectMeta: metav1.ObjectMeta{
170 Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
171 },
172 Data: map[string][]byte{
173 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
174 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
175 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
176 },
177 Type: "bootstrap.kubernetes.io/token",
178 },
179 },
180 token: "barfoo" + "." + tokenSecret,
181 wantNotFound: true,
182 },
183 {
184 name: "deleted token",
185 secrets: []*corev1.Secret{
186 {
187 ObjectMeta: metav1.ObjectMeta{
188 Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
189 DeletionTimestamp: &now,
190 },
191 Data: map[string][]byte{
192 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
193 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
194 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
195 },
196 Type: "bootstrap.kubernetes.io/token",
197 },
198 },
199 token: tokenID + "." + tokenSecret,
200 wantNotFound: true,
201 },
202 {
203 name: "expired token",
204 secrets: []*corev1.Secret{
205 {
206 ObjectMeta: metav1.ObjectMeta{
207 Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
208 },
209 Data: map[string][]byte{
210 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
211 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
212 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
213 bootstrapapi.BootstrapTokenExpirationKey: []byte("2009-11-10T23:00:00Z"),
214 },
215 Type: "bootstrap.kubernetes.io/token",
216 },
217 },
218 token: tokenID + "." + tokenSecret,
219 wantNotFound: true,
220 },
221 {
222 name: "not expired token",
223 secrets: []*corev1.Secret{
224 {
225 ObjectMeta: metav1.ObjectMeta{
226 Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
227 },
228 Data: map[string][]byte{
229 bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
230 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
231 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
232 bootstrapapi.BootstrapTokenExpirationKey: []byte("2109-11-10T23:00:00Z"),
233 },
234 Type: "bootstrap.kubernetes.io/token",
235 },
236 },
237 token: tokenID + "." + tokenSecret,
238 wantUser: &user.DefaultInfo{
239 Name: "system:bootstrap:" + tokenID,
240 Groups: []string{"system:bootstrappers"},
241 },
242 },
243 {
244 name: "token id wrong length",
245 secrets: []*corev1.Secret{
246 {
247 ObjectMeta: metav1.ObjectMeta{
248 Name: bootstrapapi.BootstrapTokenSecretPrefix + "foo",
249 },
250 Data: map[string][]byte{
251 bootstrapapi.BootstrapTokenIDKey: []byte("foo"),
252 bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
253 bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
254 },
255 Type: "bootstrap.kubernetes.io/token",
256 },
257 },
258
259 token: "foo" + "." + tokenSecret,
260 wantNotFound: true,
261 },
262 }
263
264 for _, test := range tests {
265 func() {
266 a := NewTokenAuthenticator(&lister{test.secrets})
267 resp, found, err := a.AuthenticateToken(context.Background(), test.token)
268 if err != nil {
269 t.Errorf("test %q returned an error: %v", test.name, err)
270 return
271 }
272
273 if !found {
274 if !test.wantNotFound {
275 t.Errorf("test %q expected to get user", test.name)
276 }
277 return
278 }
279
280 if test.wantNotFound {
281 t.Errorf("test %q expected to not get a user", test.name)
282 return
283 }
284
285 gotUser := resp.User.(*user.DefaultInfo)
286 if !reflect.DeepEqual(gotUser, test.wantUser) {
287 t.Errorf("test %q want user=%#v, got=%#v", test.name, test.wantUser, gotUser)
288 }
289 }()
290 }
291 }
292
View as plain text