Beispiel #1
0
func TestGroupAdder(t *testing.T) {
	adder := authenticator.Request(
		NewGroupAdder(
			authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
				return &user.DefaultInfo{Name: "user", Groups: []string{"original"}}, true, nil
			}),
			[]string{"added"},
		),
	)

	user, _, _ := adder.AuthenticateRequest(nil)
	if !reflect.DeepEqual(user.GetGroups(), []string{"original", "added"}) {
		t.Errorf("Expected original,added groups, got %#v", user.GetGroups())
	}
}
Beispiel #2
0
func (impersonateAuthorizer) Authorize(ctx kapi.Context, a authorizer.AuthorizationAttributes) (allowed bool, reason string, err error) {
	user, exists := kapi.UserFrom(ctx)
	if !exists {
		return false, "missing user", nil
	}

	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()) == 1 && user.GetGroups()[0] == "wheel" && a.GetVerb() == "impersonate" && a.GetResource() == "systemusers" {
		return true, "", nil
	}

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

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

	return false, "deny by default", nil
}
Beispiel #3
0
func TestRoundTrip(t *testing.T) {
	// Start with origin attributes
	oattrs := oauthorizer.DefaultAuthorizationAttributes{
		Verb:              "get",
		APIVersion:        "av",
		APIGroup:          "ag",
		Resource:          "r",
		ResourceName:      "rn",
		RequestAttributes: "ra",
		NonResourceURL:    true,
		URL:               "/123",
	}

	// Convert to kube attributes
	kattrs := KubernetesAuthorizerAttributes("ns", &user.DefaultInfo{Name: "myuser", Groups: []string{"mygroup"}}, oattrs)
	if kattrs.GetUser().GetName() != "myuser" {
		t.Errorf("Expected %v, got %v", "myuser", kattrs.GetUser().GetName())
	}
	if !reflect.DeepEqual(kattrs.GetUser().GetGroups(), []string{"mygroup"}) {
		t.Errorf("Expected %v, got %v", []string{"mygroup"}, kattrs.GetUser().GetGroups())
	}
	if kattrs.GetVerb() != "get" {
		t.Errorf("Expected %v, got %v", "get", kattrs.GetVerb())
	}
	if kattrs.IsReadOnly() != true {
		t.Errorf("Expected %v, got %v", true, kattrs.IsReadOnly())
	}
	if kattrs.GetNamespace() != "ns" {
		t.Errorf("Expected %v, got %v", "ns", kattrs.GetNamespace())
	}
	if kattrs.GetResource() != "r" {
		t.Errorf("Expected %v, got %v", "", kattrs.GetResource())
	}
	if kattrs.IsResourceRequest() != false {
		t.Errorf("Expected %v, got %v", false, kattrs.IsResourceRequest())
	}
	if kattrs.GetPath() != "/123" {
		t.Errorf("Expected %v, got %v", "/123", kattrs.GetPath())
	}

	// Convert back to context+origin attributes
	ctx, oattrs2 := OriginAuthorizerAttributes(kattrs)

	// Ensure namespace/user info is preserved
	if user, ok := kapi.UserFrom(ctx); !ok {
		t.Errorf("No user in context")
	} else if user.GetName() != "myuser" {
		t.Errorf("Expected %v, got %v", "myuser", user.GetName())
	} else if !reflect.DeepEqual(user.GetGroups(), []string{"mygroup"}) {
		t.Errorf("Expected %v, got %v", []string{"mygroup"}, user.GetGroups())
	}

	// Ensure common attribute info is preserved
	if oattrs.GetVerb() != oattrs2.GetVerb() {
		t.Errorf("Expected %v, got %v", oattrs.GetVerb(), oattrs2.GetVerb())
	}
	if oattrs.GetResource() != oattrs2.GetResource() {
		t.Errorf("Expected %v, got %v", oattrs.GetResource(), oattrs2.GetResource())
	}

	// Ensure origin-specific info is preserved
	if oattrs.GetAPIVersion() != oattrs2.GetAPIVersion() {
		t.Errorf("Expected %v, got %v", oattrs.GetAPIVersion(), oattrs2.GetAPIVersion())
	}
	if oattrs.GetAPIGroup() != oattrs2.GetAPIGroup() {
		t.Errorf("Expected %v, got %v", oattrs.GetAPIGroup(), oattrs2.GetAPIGroup())
	}
	if oattrs.GetResourceName() != oattrs2.GetResourceName() {
		t.Errorf("Expected %v, got %v", oattrs.GetResourceName(), oattrs2.GetResourceName())
	}
	if oattrs.GetRequestAttributes() != oattrs2.GetRequestAttributes() {
		t.Errorf("Expected %v, got %v", oattrs.GetRequestAttributes(), oattrs2.GetRequestAttributes())
	}
	if oattrs.IsNonResourceURL() != oattrs2.IsNonResourceURL() {
		t.Errorf("Expected %v, got %v", oattrs.IsNonResourceURL(), oattrs2.IsNonResourceURL())
	}
	if oattrs.GetURL() != oattrs2.GetURL() {
		t.Errorf("Expected %v, got %v", oattrs.GetURL(), oattrs2.GetURL())
	}
}
Beispiel #4
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)
			}
		}
	}
}
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
}
Beispiel #6
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)
				}
			}
		}()
	}
}