Пример #1
0
func (impersonateAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
	user := a.GetUser()

	switch {
	case user.GetName() == "system:admin":
		return true, "", nil

	case user.GetName() == "tester":
		return false, "", fmt.Errorf("works on my machine")

	case user.GetName() == "deny-me":
		return false, "denied", nil
	}

	if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "wheel" && a.GetVerb() == "impersonate" && a.GetResource() == "users" {
		return true, "", nil
	}

	if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "sa-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "serviceaccounts" {
		return true, "", nil
	}

	if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "regular-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "users" {
		return true, "", nil
	}

	if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "group-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "groups" {
		return true, "", nil
	}

	if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-scopes" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" {
		return true, "", nil
	}

	if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-particular-scopes" &&
		a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" && a.GetName() == "scope-a" {
		return true, "", nil
	}

	if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-project" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "project" {
		return true, "", nil
	}

	return false, "deny by default", nil
}
Пример #2
0
// 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
}
Пример #3
0
func TestBasicAuth(t *testing.T) {
	testCases := map[string]struct {
		Header   string
		Password testPassword

		ExpectedCalled   bool
		ExpectedUsername string
		ExpectedPassword string

		ExpectedUser string
		ExpectedOK   bool
		ExpectedErr  bool
	}{
		"no auth": {},
		"empty password basic header": {
			ExpectedCalled:   true,
			ExpectedUsername: "******",
			ExpectedPassword: "",
		},
		"valid basic header": {
			ExpectedCalled:   true,
			ExpectedUsername: "******",
			ExpectedPassword: "******",
		},
		"password auth returned user": {
			Password:         testPassword{User: &user.DefaultInfo{Name: "returneduser"}, OK: true},
			ExpectedCalled:   true,
			ExpectedUsername: "******",
			ExpectedPassword: "******",
			ExpectedUser:     "******",
			ExpectedOK:       true,
		},
		"password auth returned error": {
			Password:         testPassword{Err: errors.New("auth error")},
			ExpectedCalled:   true,
			ExpectedUsername: "******",
			ExpectedPassword: "******",
			ExpectedErr:      true,
		},
	}

	for k, testCase := range testCases {
		password := testCase.Password
		auth := authenticator.Request(New(&password))

		req, _ := http.NewRequest("GET", "/", nil)
		if testCase.ExpectedUsername != "" || testCase.ExpectedPassword != "" {
			req.SetBasicAuth(testCase.ExpectedUsername, testCase.ExpectedPassword)
		}

		user, ok, err := auth.AuthenticateRequest(req)

		if testCase.ExpectedCalled != password.Called {
			t.Errorf("%s: Expected called=%v, got %v", k, testCase.ExpectedCalled, password.Called)
			continue
		}
		if testCase.ExpectedUsername != password.Username {
			t.Errorf("%s: Expected called with username=%v, got %v", k, testCase.ExpectedUsername, password.Username)
			continue
		}
		if testCase.ExpectedPassword != password.Password {
			t.Errorf("%s: Expected called with password=%v, got %v", k, testCase.ExpectedPassword, password.Password)
			continue
		}

		if testCase.ExpectedErr != (err != nil) {
			t.Errorf("%s: Expected err=%v, got err=%v", k, testCase.ExpectedErr, err)
			continue
		}
		if testCase.ExpectedOK != ok {
			t.Errorf("%s: Expected ok=%v, got ok=%v", k, testCase.ExpectedOK, ok)
			continue
		}
		if testCase.ExpectedUser != "" && testCase.ExpectedUser != user.GetName() {
			t.Errorf("%s: Expected user.GetName()=%v, got %v", k, testCase.ExpectedUser, user.GetName())
			continue
		}
	}
}
Пример #4
0
func TestTLSConfig(t *testing.T) {
	// Verify the cert/key pair works.
	cert1 := path.Join(os.TempDir(), "oidc-cert-1")
	key1 := path.Join(os.TempDir(), "oidc-key-1")
	cert2 := path.Join(os.TempDir(), "oidc-cert-2")
	key2 := path.Join(os.TempDir(), "oidc-key-2")

	defer os.Remove(cert1)
	defer os.Remove(key1)
	defer os.Remove(cert2)
	defer os.Remove(key2)

	oidctesting.GenerateSelfSignedCert(t, "127.0.0.1", cert1, key1)
	oidctesting.GenerateSelfSignedCert(t, "127.0.0.1", cert2, key2)

	tests := []struct {
		testCase string

		serverCertFile string
		serverKeyFile  string

		trustedCertFile string

		wantErr bool
	}{
		{
			testCase:       "provider using untrusted custom cert",
			serverCertFile: cert1,
			serverKeyFile:  key1,
			wantErr:        true,
		},
		{
			testCase:        "provider using untrusted cert",
			serverCertFile:  cert1,
			serverKeyFile:   key1,
			trustedCertFile: cert2,
			wantErr:         true,
		},
		{
			testCase:        "provider using trusted cert",
			serverCertFile:  cert1,
			serverKeyFile:   key1,
			trustedCertFile: cert1,
			wantErr:         false,
		},
	}

	for _, tc := range tests {
		func() {
			op := oidctesting.NewOIDCProvider(t, "")
			srv, err := op.ServeTLSWithKeyPair(tc.serverCertFile, tc.serverKeyFile)
			if err != nil {
				t.Errorf("%s: %v", tc.testCase, err)
				return
			}
			defer srv.Close()

			issuer := srv.URL
			clientID := "client-foo"

			options := OIDCOptions{
				IssuerURL:     srv.URL,
				ClientID:      clientID,
				CAFile:        tc.trustedCertFile,
				UsernameClaim: "email",
				GroupsClaim:   "groups",
			}

			authenticator, err := New(options)
			if err != nil {
				t.Errorf("%s: failed to initialize authenticator: %v", tc.testCase, err)
				return
			}
			defer authenticator.Close()

			email := "*****@*****.**"
			groups := []string{"group1", "group2"}
			sort.Strings(groups)

			token := generateGoodToken(t, op, issuer, "user-1", clientID, "email", email, "groups", groups)

			// Because this authenticator behaves differently for subsequent requests, run these
			// tests multiple times (but expect the same result).
			for i := 1; i < 4; i++ {

				user, ok, err := authenticator.AuthenticateToken(token)
				if err != nil {
					if !tc.wantErr {
						t.Errorf("%s (req #%d): failed to authenticate token: %v", tc.testCase, i, err)
					}
					continue
				}

				if tc.wantErr {
					t.Errorf("%s (req #%d): expected error authenticating", tc.testCase, i)
					continue
				}
				if !ok {
					t.Errorf("%s (req #%d): did not get user or error", tc.testCase, i)
					continue
				}

				if gotUsername := user.GetName(); email != gotUsername {
					t.Errorf("%s (req #%d): GetName() expected=%q got %q", tc.testCase, i, email, gotUsername)
				}
				gotGroups := user.GetGroups()
				sort.Strings(gotGroups)
				if !reflect.DeepEqual(gotGroups, groups) {
					t.Errorf("%s (req #%d): GetGroups() expected=%q got %q", tc.testCase, i, groups, gotGroups)
				}
			}
		}()
	}
}
Пример #5
0
func TestX509Verifier(t *testing.T) {
	multilevelOpts := DefaultVerifyOptions()
	multilevelOpts.Roots = x509.NewCertPool()
	multilevelOpts.Roots.AddCert(getCertsFromFile(t, "root")[0])

	testCases := map[string]struct {
		Insecure bool
		Certs    []*x509.Certificate

		Opts x509.VerifyOptions

		AllowedCNs sets.String

		ExpectOK  bool
		ExpectErr bool
	}{
		"non-tls": {
			Insecure: true,

			ExpectOK:  false,
			ExpectErr: false,
		},

		"tls, no certs": {
			ExpectOK:  false,
			ExpectErr: false,
		},

		"self signed": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, selfSignedCert),

			ExpectErr: true,
		},

		"server cert disallowed": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, serverCert),

			ExpectErr: true,
		},
		"server cert allowing non-client cert usages": {
			Opts:  x509.VerifyOptions{Roots: getRootCertPool(t)},
			Certs: getCerts(t, serverCert),

			ExpectOK:  true,
			ExpectErr: false,
		},

		"valid client cert": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, clientCNCert),

			ExpectOK:  true,
			ExpectErr: false,
		},
		"valid client cert with wrong CN": {
			Opts:       getDefaultVerifyOptions(t),
			AllowedCNs: sets.NewString("foo", "bar"),
			Certs:      getCerts(t, clientCNCert),

			ExpectOK:  false,
			ExpectErr: true,
		},
		"valid client cert with right CN": {
			Opts:       getDefaultVerifyOptions(t),
			AllowedCNs: sets.NewString("client_cn"),
			Certs:      getCerts(t, clientCNCert),

			ExpectOK:  true,
			ExpectErr: false,
		},

		"future cert": {
			Opts: x509.VerifyOptions{
				CurrentTime: time.Now().Add(-100 * time.Hour * 24 * 365),
				Roots:       getRootCertPool(t),
			},
			Certs: getCerts(t, clientCNCert),

			ExpectOK:  false,
			ExpectErr: true,
		},
		"expired cert": {
			Opts: x509.VerifyOptions{
				CurrentTime: time.Now().Add(100 * time.Hour * 24 * 365),
				Roots:       getRootCertPool(t),
			},
			Certs: getCerts(t, clientCNCert),

			ExpectOK:  false,
			ExpectErr: true,
		},

		"multi-level, valid": {
			Opts:  multilevelOpts,
			Certs: getCertsFromFile(t, "client-valid", "intermediate"),

			ExpectOK:  true,
			ExpectErr: false,
		},
		"multi-level, expired": {
			Opts:  multilevelOpts,
			Certs: getCertsFromFile(t, "client-expired", "intermediate"),

			ExpectOK:  false,
			ExpectErr: true,
		},
	}

	for k, testCase := range testCases {
		req, _ := http.NewRequest("GET", "/", nil)
		if !testCase.Insecure {
			req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs}
		}

		authCall := false
		auth := authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
			authCall = true
			return &user.DefaultInfo{Name: "innerauth"}, true, nil
		})

		a := NewVerifier(testCase.Opts, auth, testCase.AllowedCNs)

		user, ok, err := a.AuthenticateRequest(req)

		if testCase.ExpectErr && err == nil {
			t.Errorf("%s: Expected error, got none", k)
			continue
		}
		if !testCase.ExpectErr && err != nil {
			t.Errorf("%s: Got unexpected error: %v", k, err)
			continue
		}

		if testCase.ExpectOK != ok {
			t.Errorf("%s: Expected ok=%v, got %v", k, testCase.ExpectOK, ok)
			continue
		}

		if testCase.ExpectOK {
			if !authCall {
				t.Errorf("%s: Expected inner auth called, wasn't", k)
				continue
			}
			if "innerauth" != user.GetName() {
				t.Errorf("%s: Expected user.name=%v, got %v", k, "innerauth", user.GetName())
				continue
			}
		} else {
			if authCall {
				t.Errorf("%s: Expected inner auth not to be called, was", k)
				continue
			}
		}
	}
}
Пример #6
0
func TestX509(t *testing.T) {
	multilevelOpts := DefaultVerifyOptions()
	multilevelOpts.Roots = x509.NewCertPool()
	multilevelOpts.Roots.AddCert(getCertsFromFile(t, "root")[0])

	testCases := map[string]struct {
		Insecure bool
		Certs    []*x509.Certificate

		Opts x509.VerifyOptions
		User UserConversion

		ExpectUserName string
		ExpectGroups   []string
		ExpectOK       bool
		ExpectErr      bool
	}{
		"non-tls": {
			Insecure: true,

			ExpectOK:  false,
			ExpectErr: false,
		},

		"tls, no certs": {
			ExpectOK:  false,
			ExpectErr: false,
		},

		"self signed": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, selfSignedCert),
			User:  CommonNameUserConversion,

			ExpectErr: true,
		},

		"server cert": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, serverCert),
			User:  CommonNameUserConversion,

			ExpectErr: true,
		},
		"server cert allowing non-client cert usages": {
			Opts:  x509.VerifyOptions{Roots: getRootCertPool(t)},
			Certs: getCerts(t, serverCert),
			User:  CommonNameUserConversion,

			ExpectUserName: "******",
			ExpectGroups:   []string{"My Org"},
			ExpectOK:       true,
			ExpectErr:      false,
		},

		"common name": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, clientCNCert),
			User:  CommonNameUserConversion,

			ExpectUserName: "******",
			ExpectGroups:   []string{"My Org"},
			ExpectOK:       true,
			ExpectErr:      false,
		},
		"ca with multiple organizations": {
			Opts: x509.VerifyOptions{
				Roots: getRootCertPoolFor(t, caWithGroups),
			},
			Certs: getCerts(t, caWithGroups),
			User:  CommonNameUserConversion,

			ExpectUserName: "******",
			ExpectGroups:   []string{"My Org", "My Org 1", "My Org 2"},
			ExpectOK:       true,
			ExpectErr:      false,
		},
		"empty dns": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, clientCNCert),
			User:  DNSNameUserConversion,

			ExpectOK:  false,
			ExpectErr: false,
		},
		"dns": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, clientDNSCert),
			User:  DNSNameUserConversion,

			ExpectUserName: "******",
			ExpectOK:       true,
			ExpectErr:      false,
		},

		"empty email": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, clientCNCert),
			User:  EmailAddressUserConversion,

			ExpectOK:  false,
			ExpectErr: false,
		},
		"email": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, clientEmailCert),
			User:  EmailAddressUserConversion,

			ExpectUserName: "******",
			ExpectOK:       true,
			ExpectErr:      false,
		},

		"custom conversion error": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, clientCNCert),
			User: UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
				return nil, false, errors.New("custom error")
			}),

			ExpectOK:  false,
			ExpectErr: true,
		},
		"custom conversion success": {
			Opts:  getDefaultVerifyOptions(t),
			Certs: getCerts(t, clientCNCert),
			User: UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
				return &user.DefaultInfo{Name: "custom"}, true, nil
			}),

			ExpectUserName: "******",
			ExpectOK:       true,
			ExpectErr:      false,
		},

		"future cert": {
			Opts: x509.VerifyOptions{
				CurrentTime: time.Now().Add(time.Duration(-100 * time.Hour * 24 * 365)),
				Roots:       getRootCertPool(t),
			},
			Certs: getCerts(t, clientCNCert),
			User:  CommonNameUserConversion,

			ExpectOK:  false,
			ExpectErr: true,
		},
		"expired cert": {
			Opts: x509.VerifyOptions{
				CurrentTime: time.Now().Add(time.Duration(100 * time.Hour * 24 * 365)),
				Roots:       getRootCertPool(t),
			},
			Certs: getCerts(t, clientCNCert),
			User:  CommonNameUserConversion,

			ExpectOK:  false,
			ExpectErr: true,
		},

		"multi-level, valid": {
			Opts:  multilevelOpts,
			Certs: getCertsFromFile(t, "client-valid", "intermediate"),
			User:  CommonNameUserConversion,

			ExpectUserName: "******",
			ExpectOK:       true,
			ExpectErr:      false,
		},
		"multi-level, expired": {
			Opts:  multilevelOpts,
			Certs: getCertsFromFile(t, "client-expired", "intermediate"),
			User:  CommonNameUserConversion,

			ExpectOK:  false,
			ExpectErr: true,
		},
	}

	for k, testCase := range testCases {
		req, _ := http.NewRequest("GET", "/", nil)
		if !testCase.Insecure {
			req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs}
		}

		a := New(testCase.Opts, testCase.User)

		user, ok, err := a.AuthenticateRequest(req)

		if testCase.ExpectErr && err == nil {
			t.Errorf("%s: Expected error, got none", k)
			continue
		}
		if !testCase.ExpectErr && err != nil {
			t.Errorf("%s: Got unexpected error: %v", k, err)
			continue
		}

		if testCase.ExpectOK != ok {
			t.Errorf("%s: Expected ok=%v, got %v", k, testCase.ExpectOK, ok)
			continue
		}

		if testCase.ExpectOK {
			if testCase.ExpectUserName != user.GetName() {
				t.Errorf("%s: Expected user.name=%v, got %v", k, testCase.ExpectUserName, user.GetName())
			}

			groups := user.GetGroups()
			sort.Strings(testCase.ExpectGroups)
			sort.Strings(groups)
			if !reflect.DeepEqual(testCase.ExpectGroups, groups) {
				t.Errorf("%s: Expected user.groups=%v, got %v", k, testCase.ExpectGroups, groups)
			}
		}
	}
}