k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 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 // Fake values for testing. 52 tokenID = "foobar" // 6 letters 53 tokenSecret = "circumnavigation" // 16 letters 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 // Token ID must be 6 characters. 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 }