func TestAuthenticateRequestTokenError(t *testing.T) { auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) { return nil, false, errors.New("error") })) user, ok, err := auth.AuthenticateRequest(&http.Request{ Header: http.Header{"Authorization": []string{"Bearer token"}}, }) if ok || user != nil || err == nil { t.Errorf("expected error") } }
func TestAuthenticateRequestTokenInvalid(t *testing.T) { auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) { return nil, false, nil })) user, ok, err := auth.AuthenticateRequest(&http.Request{ Header: http.Header{"Authorization": []string{"Bearer token"}}, }) if ok || user != nil { t.Errorf("expected not authenticated user") } if err != invalidToken { t.Errorf("expected invalidToken error, got %v", err) } }
func TestAuthenticateRequest(t *testing.T) { auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) { if token != "token" { t.Errorf("unexpected token: %s", token) } return &user.DefaultInfo{Name: "user"}, true, nil })) user, ok, err := auth.AuthenticateRequest(&http.Request{ Header: http.Header{"Authorization": []string{"Bearer token"}}, }) if !ok || user == nil || err != nil { t.Errorf("expected valid user") } }
func TestAuthenticateRequestBadValue(t *testing.T) { testCases := []struct { Req *http.Request }{ {Req: &http.Request{}}, {Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer"}}}}, {Req: &http.Request{Header: http.Header{"Authorization": []string{"bear token"}}}}, {Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer: token"}}}}, } for i, testCase := range testCases { auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) { t.Errorf("authentication should not have been called") return nil, false, nil })) user, ok, err := auth.AuthenticateRequest(testCase.Req) if ok || user != nil || err != nil { t.Errorf("%d: expected not authenticated (no token)", i) } } }
// startServiceAccountTestServer returns a started server // It is the responsibility of the caller to ensure the returned stopFunc is called func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclient.Config, func()) { // Listener h := &framework.MasterHolder{Initialized: make(chan struct{})} apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { <-h.Initialized h.M.GenericAPIServer.Handler.ServeHTTP(w, req) })) // Anonymous client config clientConfig := restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &api.Registry.GroupOrDie(v1.GroupName).GroupVersion}} // Root client // TODO: remove rootClient after we refactor pkg/admission to use the clientset. rootClientset := clientset.NewForConfigOrDie(&restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &api.Registry.GroupOrDie(v1.GroupName).GroupVersion}, BearerToken: rootToken}) internalRootClientset := internalclientset.NewForConfigOrDie(&restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &api.Registry.GroupOrDie(v1.GroupName).GroupVersion}, BearerToken: rootToken}) // Set up two authenticators: // 1. A token authenticator that maps the rootToken to the "root" user // 2. A ServiceAccountToken authenticator that validates ServiceAccount tokens rootTokenAuth := authenticator.TokenFunc(func(token string) (user.Info, bool, error) { if token == rootToken { return &user.DefaultInfo{Name: rootUserName}, true, nil } return nil, false, nil }) serviceAccountKey, _ := rsa.GenerateKey(rand.Reader, 2048) serviceAccountTokenGetter := serviceaccountcontroller.NewGetterFromClient(rootClientset) serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator([]interface{}{&serviceAccountKey.PublicKey}, true, serviceAccountTokenGetter) authenticator := union.New( bearertoken.New(rootTokenAuth), bearertoken.New(serviceAccountTokenAuth), ) // Set up a stub authorizer: // 1. The "root" user is allowed to do anything // 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace // 3. ServiceAccounts named "rw" are allowed any operation in their namespace authorizer := authorizer.AuthorizerFunc(func(attrs authorizer.Attributes) (bool, string, error) { username := "" if user := attrs.GetUser(); user != nil { username = user.GetName() } ns := attrs.GetNamespace() // If the user is "root"... if username == rootUserName { // allow them to do anything return true, "", nil } // If the user is a service account... if serviceAccountNamespace, serviceAccountName, err := serviceaccountapiserver.SplitUsername(username); err == nil { // Limit them to their own namespace if serviceAccountNamespace == ns { switch serviceAccountName { case readOnlyServiceAccountName: if attrs.IsReadOnly() { return true, "", nil } case readWriteServiceAccountName: return true, "", nil } } } return false, fmt.Sprintf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()), nil }) // Set up admission plugin to auto-assign serviceaccounts to pods serviceAccountAdmission := serviceaccountadmission.NewServiceAccount() serviceAccountAdmission.SetInternalClientSet(internalRootClientset) masterConfig := framework.NewMasterConfig() masterConfig.GenericConfig.EnableIndex = true masterConfig.GenericConfig.Authenticator = authenticator masterConfig.GenericConfig.Authorizer = authorizer masterConfig.GenericConfig.AdmissionControl = serviceAccountAdmission framework.RunAMasterUsingServer(masterConfig, apiServer, h) // Start the service account and service account token controllers stopCh := make(chan struct{}) tokenController := serviceaccountcontroller.NewTokensController(rootClientset, serviceaccountcontroller.TokensControllerOptions{TokenGenerator: serviceaccount.JWTTokenGenerator(serviceAccountKey)}) go tokenController.Run(1, stopCh) informers := informers.NewSharedInformerFactory(rootClientset, nil, controller.NoResyncPeriodFunc()) serviceAccountController := serviceaccountcontroller.NewServiceAccountsController(informers.ServiceAccounts(), informers.Namespaces(), rootClientset, serviceaccountcontroller.DefaultServiceAccountsControllerOptions()) informers.Start(stopCh) go serviceAccountController.Run(5, stopCh) // Start the admission plugin reflectors serviceAccountAdmission.Run() stop := func() { close(stopCh) serviceAccountAdmission.Stop() apiServer.Close() } return rootClientset, clientConfig, stop }