Merge pull request #69582 from mikedanese/trev7

tokenreview: authenticator interface changes
pull/58/head
k8s-ci-robot 2018-10-22 23:59:04 -07:00 committed by GitHub
commit baa8d800ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 491 additions and 369 deletions

View File

@ -77,6 +77,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/util/httpstream:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/httpstream/spdy:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",

View File

@ -221,7 +221,7 @@ func NewServer(
func (s *Server) InstallAuthFilter() {
s.restfulCont.Filter(func(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
// Authenticate
u, ok, err := s.auth.AuthenticateRequest(req.Request)
info, ok, err := s.auth.AuthenticateRequest(req.Request)
if err != nil {
glog.Errorf("Unable to authenticate the request due to an error: %v", err)
resp.WriteErrorString(http.StatusUnauthorized, "Unauthorized")
@ -233,18 +233,18 @@ func (s *Server) InstallAuthFilter() {
}
// Get authorization attributes
attrs := s.auth.GetRequestAttributes(u, req.Request)
attrs := s.auth.GetRequestAttributes(info.User, req.Request)
// Authorize
decision, _, err := s.auth.Authorize(attrs)
if err != nil {
msg := fmt.Sprintf("Authorization error (user=%s, verb=%s, resource=%s, subresource=%s)", u.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
msg := fmt.Sprintf("Authorization error (user=%s, verb=%s, resource=%s, subresource=%s)", attrs.GetUser().GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
glog.Errorf(msg, err)
resp.WriteErrorString(http.StatusInternalServerError, msg)
return
}
if decision != authorizer.DecisionAllow {
msg := fmt.Sprintf("Forbidden (user=%s, verb=%s, resource=%s, subresource=%s)", u.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
msg := fmt.Sprintf("Forbidden (user=%s, verb=%s, resource=%s, subresource=%s)", attrs.GetUser().GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
glog.V(2).Info(msg)
resp.WriteErrorString(http.StatusForbidden, msg)
return

View File

@ -44,6 +44,7 @@ import (
"k8s.io/apimachinery/pkg/util/httpstream"
"k8s.io/apimachinery/pkg/util/httpstream/spdy"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/client-go/tools/remotecommand"
@ -269,12 +270,12 @@ func (_ *fakeKubelet) GetCgroupCPUAndMemoryStats(cgroupName string, updateStats
}
type fakeAuth struct {
authenticateFunc func(*http.Request) (user.Info, bool, error)
authenticateFunc func(*http.Request) (*authenticator.Response, bool, error)
attributesFunc func(user.Info, *http.Request) authorizer.Attributes
authorizeFunc func(authorizer.Attributes) (authorized authorizer.Decision, reason string, err error)
}
func (f *fakeAuth) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (f *fakeAuth) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
return f.authenticateFunc(req)
}
func (f *fakeAuth) GetRequestAttributes(u user.Info, req *http.Request) authorizer.Attributes {
@ -317,8 +318,8 @@ func newServerTestWithDebug(enableDebugging, redirectContainerStreaming bool, st
streamingRuntime: streamingServer,
}
fw.fakeAuth = &fakeAuth{
authenticateFunc: func(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{Name: "test"}, true, nil
authenticateFunc: func(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: &user.DefaultInfo{Name: "test"}}, true, nil
},
attributesFunc: func(u user.Info, req *http.Request) authorizer.Attributes {
return &authorizer.AttributesRecord{User: u}
@ -768,9 +769,9 @@ Otherwise, add it to the expected list of paths that map to the "proxy" subresou
calledAttributes = false
)
fw.fakeAuth.authenticateFunc = func(req *http.Request) (user.Info, bool, error) {
fw.fakeAuth.authenticateFunc = func(req *http.Request) (*authenticator.Response, bool, error) {
calledAuthenticate = true
return expectedUser, true, nil
return &authenticator.Response{User: expectedUser}, true, nil
}
fw.fakeAuth.attributesFunc = func(u user.Info, req *http.Request) authorizer.Attributes {
calledAttributes = true
@ -830,9 +831,9 @@ func TestAuthenticationError(t *testing.T) {
fw := newServerTest()
defer fw.testHTTPServer.Close()
fw.fakeAuth.authenticateFunc = func(req *http.Request) (user.Info, bool, error) {
fw.fakeAuth.authenticateFunc = func(req *http.Request) (*authenticator.Response, bool, error) {
calledAuthenticate = true
return expectedUser, true, nil
return &authenticator.Response{User: expectedUser}, true, nil
}
fw.fakeAuth.attributesFunc = func(u user.Info, req *http.Request) authorizer.Attributes {
calledAttributes = true
@ -868,7 +869,7 @@ func TestAuthenticationFailure(t *testing.T) {
fw := newServerTest()
defer fw.testHTTPServer.Close()
fw.fakeAuth.authenticateFunc = func(req *http.Request) (user.Info, bool, error) {
fw.fakeAuth.authenticateFunc = func(req *http.Request) (*authenticator.Response, bool, error) {
calledAuthenticate = true
return nil, false, nil
}
@ -906,9 +907,9 @@ func TestAuthorizationSuccess(t *testing.T) {
fw := newServerTest()
defer fw.testHTTPServer.Close()
fw.fakeAuth.authenticateFunc = func(req *http.Request) (user.Info, bool, error) {
fw.fakeAuth.authenticateFunc = func(req *http.Request) (*authenticator.Response, bool, error) {
calledAuthenticate = true
return expectedUser, true, nil
return &authenticator.Response{User: expectedUser}, true, nil
}
fw.fakeAuth.attributesFunc = func(u user.Info, req *http.Request) authorizer.Attributes {
calledAttributes = true

View File

@ -68,19 +68,23 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
fakeReq := &http.Request{Header: http.Header{}}
fakeReq.Header.Add("Authorization", "Bearer "+tokenReview.Spec.Token)
tokenUser, ok, err := r.tokenAuthenticator.AuthenticateRequest(fakeReq)
resp, ok, err := r.tokenAuthenticator.AuthenticateRequest(fakeReq)
tokenReview.Status.Authenticated = ok
if err != nil {
tokenReview.Status.Error = err.Error()
}
if tokenUser != nil {
// TODO(mikedanese): verify the response audience matches one of apiAuds if
// non-empty
if resp != nil && resp.User != nil {
tokenReview.Status.User = authentication.UserInfo{
Username: tokenUser.GetName(),
UID: tokenUser.GetUID(),
Groups: tokenUser.GetGroups(),
Username: resp.User.GetName(),
UID: resp.User.GetUID(),
Groups: resp.User.GetGroups(),
Extra: map[string]authentication.ExtraValue{},
}
for k, v := range tokenUser.GetExtra() {
for k, v := range resp.User.GetExtra() {
tokenReview.Status.User.Extra[k] = authentication.ExtraValue(v)
}
}

View File

@ -22,10 +22,10 @@ import (
"time"
"github.com/golang/glog"
"gopkg.in/square/go-jose.v2/jwt"
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/kubernetes/pkg/apis/core"
"gopkg.in/square/go-jose.v2/jwt"
)
// time.Now stubbed out to allow testing

View File

@ -22,10 +22,10 @@ import (
"testing"
"time"
"gopkg.in/square/go-jose.v2/jwt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/apis/core"
"gopkg.in/square/go-jose.v2/jwt"
)
func init() {

View File

@ -17,6 +17,7 @@ limitations under the License.
package serviceaccount
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
@ -25,13 +26,12 @@ import (
"fmt"
"strings"
jose "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
"k8s.io/api/core/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
jose "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)
// ServiceAccountTokenGetter defines functions to retrieve a named service account and secret
@ -140,7 +140,7 @@ type Validator interface {
NewPrivateClaims() interface{}
}
func (j *jwtTokenAuthenticator) AuthenticateToken(tokenData string) (user.Info, bool, error) {
func (j *jwtTokenAuthenticator) AuthenticateToken(ctx context.Context, tokenData string) (*authenticator.Response, bool, error) {
if !j.hasCorrectIssuer(tokenData) {
return nil, false, nil
}
@ -177,7 +177,7 @@ func (j *jwtTokenAuthenticator) AuthenticateToken(tokenData string) (user.Info,
return nil, false, err
}
return sa.UserInfo(), true, nil
return &authenticator.Response{User: sa.UserInfo()}, true, nil
}
// hasCorrectIssuer returns true if tokenData is a valid JWT in compact

View File

@ -17,6 +17,7 @@ limitations under the License.
package serviceaccount_test
import (
"context"
"reflect"
"testing"
@ -278,12 +279,12 @@ func TestTokenGenerateAndValidate(t *testing.T) {
authenticator := serviceaccount.JWTTokenAuthenticator(serviceaccount.LegacyIssuer, tc.Keys, serviceaccount.NewLegacyValidator(tc.Client != nil, getter))
// An invalid, non-JWT token should always fail
if _, ok, err := authenticator.AuthenticateToken("invalid token"); err != nil || ok {
if _, ok, err := authenticator.AuthenticateToken(context.Background(), "invalid token"); err != nil || ok {
t.Errorf("%s: Expected err=nil, ok=false for non-JWT token", k)
continue
}
user, ok, err := authenticator.AuthenticateToken(tc.Token)
resp, ok, err := authenticator.AuthenticateToken(context.Background(), tc.Token)
if (err != nil) != tc.ExpectedErr {
t.Errorf("%s: Expected error=%v, got %v", k, tc.ExpectedErr, err)
continue
@ -298,16 +299,16 @@ func TestTokenGenerateAndValidate(t *testing.T) {
continue
}
if user.GetName() != tc.ExpectedUserName {
t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, user.GetName())
if resp.User.GetName() != tc.ExpectedUserName {
t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, resp.User.GetName())
continue
}
if user.GetUID() != tc.ExpectedUserUID {
t.Errorf("%s: Expected userUID=%v, got %v", k, tc.ExpectedUserUID, user.GetUID())
if resp.User.GetUID() != tc.ExpectedUserUID {
t.Errorf("%s: Expected userUID=%v, got %v", k, tc.ExpectedUserUID, resp.User.GetUID())
continue
}
if !reflect.DeepEqual(user.GetGroups(), tc.ExpectedGroups) {
t.Errorf("%s: Expected groups=%v, got %v", k, tc.ExpectedGroups, user.GetGroups())
if !reflect.DeepEqual(resp.User.GetGroups(), tc.ExpectedGroups) {
t.Errorf("%s: Expected groups=%v, got %v", k, tc.ExpectedGroups, resp.User.GetGroups())
continue
}
}

View File

@ -21,11 +21,11 @@ import (
"errors"
"fmt"
"k8s.io/api/core/v1"
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
"github.com/golang/glog"
"gopkg.in/square/go-jose.v2/jwt"
"k8s.io/api/core/v1"
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
)
func LegacyClaims(serviceAccount v1.ServiceAccount, secret v1.Secret) (*jwt.Claims, interface{}) {

View File

@ -30,6 +30,7 @@ go_library(
"//pkg/client/listers/core/internalversion:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//staging/src/k8s.io/cluster-bootstrap/token/api:go_default_library",
"//staging/src/k8s.io/cluster-bootstrap/token/util:go_default_library",

View File

@ -20,6 +20,7 @@ Package bootstrap provides a token authenticator for TLS bootstrap secrets.
package bootstrap
import (
"context"
"crypto/subtle"
"fmt"
"regexp"
@ -30,6 +31,7 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
bootstraputil "k8s.io/cluster-bootstrap/token/util"
@ -89,7 +91,7 @@ func tokenErrorf(s *api.Secret, format string, i ...interface{}) {
//
// ( token-id ).( token-secret )
//
func (t *TokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, error) {
func (t *TokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
tokenID, tokenSecret, err := parseToken(token)
if err != nil {
// Token isn't of the correct form, ignore it.
@ -144,9 +146,11 @@ func (t *TokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, e
return nil, false, nil
}
return &user.DefaultInfo{
Name: bootstrapapi.BootstrapUserPrefix + string(id),
Groups: groups,
return &authenticator.Response{
User: &user.DefaultInfo{
Name: bootstrapapi.BootstrapUserPrefix + string(id),
Groups: groups,
},
}, true, nil
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package bootstrap
import (
"context"
"reflect"
"testing"
@ -262,7 +263,7 @@ func TestTokenAuthenticator(t *testing.T) {
for _, test := range tests {
func() {
a := NewTokenAuthenticator(&lister{test.secrets})
u, found, err := a.AuthenticateToken(test.token)
resp, found, err := a.AuthenticateToken(context.Background(), test.token)
if err != nil {
t.Errorf("test %q returned an error: %v", test.name, err)
return
@ -280,8 +281,7 @@ func TestTokenAuthenticator(t *testing.T) {
return
}
gotUser := u.(*user.DefaultInfo)
gotUser := resp.User.(*user.DefaultInfo)
if !reflect.DeepEqual(gotUser, test.wantUser) {
t.Errorf("test %q want user=%#v, got=%#v", test.name, test.wantUser, gotUser)
}

View File

@ -17,52 +17,64 @@ limitations under the License.
package authenticator
import (
"context"
"net/http"
"k8s.io/apiserver/pkg/authentication/user"
)
// Token checks a string value against a backing authentication store and returns
// information about the current user and true if successful, false if not successful,
// or an error if the token could not be checked.
// Token checks a string value against a backing authentication store and
// returns a Response or an error if the token could not be checked.
type Token interface {
AuthenticateToken(token string) (user.Info, bool, error)
AuthenticateToken(ctx context.Context, token string) (*Response, bool, error)
}
// Request attempts to extract authentication information from a request and returns
// information about the current user and true if successful, false if not successful,
// or an error if the request could not be checked.
// Request attempts to extract authentication information from a request and
// returns a Response or an error if the request could not be checked.
type Request interface {
AuthenticateRequest(req *http.Request) (user.Info, bool, error)
AuthenticateRequest(req *http.Request) (*Response, bool, error)
}
// Password checks a username and password against a backing authentication store and
// returns information about the user and true if successful, false if not successful,
// or an error if the username and password could not be checked
// Password checks a username and password against a backing authentication
// store and returns a Response or an error if the password could not be
// checked.
type Password interface {
AuthenticatePassword(user, password string) (user.Info, bool, error)
AuthenticatePassword(ctx context.Context, user, password string) (*Response, bool, error)
}
// TokenFunc is a function that implements the Token interface.
type TokenFunc func(token string) (user.Info, bool, error)
type TokenFunc func(ctx context.Context, token string) (*Response, bool, error)
// AuthenticateToken implements authenticator.Token.
func (f TokenFunc) AuthenticateToken(token string) (user.Info, bool, error) {
return f(token)
func (f TokenFunc) AuthenticateToken(ctx context.Context, token string) (*Response, bool, error) {
return f(ctx, token)
}
// RequestFunc is a function that implements the Request interface.
type RequestFunc func(req *http.Request) (user.Info, bool, error)
type RequestFunc func(req *http.Request) (*Response, bool, error)
// AuthenticateRequest implements authenticator.Request.
func (f RequestFunc) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (f RequestFunc) AuthenticateRequest(req *http.Request) (*Response, bool, error) {
return f(req)
}
// PasswordFunc is a function that implements the Password interface.
type PasswordFunc func(user, password string) (user.Info, bool, error)
type PasswordFunc func(ctx context.Context, user, password string) (*Response, bool, error)
// AuthenticatePassword implements authenticator.Password.
func (f PasswordFunc) AuthenticatePassword(user, password string) (user.Info, bool, error) {
return f(user, password)
func (f PasswordFunc) AuthenticatePassword(ctx context.Context, user, password string) (*Response, bool, error) {
return f(ctx, user, password)
}
// Response is the struct returned by authenticator interfaces upon successful
// authentication. It contains information about whether the authenticator
// authenticated the request, information about the context of the
// authentication, and information about the authenticated user.
type Response struct {
// Audiences is the set of audiences the authenticator was able to validate
// the token against. If the authenticator is not audience aware, this field
// will be empty.
Audiences Audiences
// User is the UserInfo associated with the authentication context.
User user.Info
}

View File

@ -36,25 +36,26 @@ func NewAuthenticatedGroupAdder(auth authenticator.Request) authenticator.Reques
return &AuthenticatedGroupAdder{auth}
}
func (g *AuthenticatedGroupAdder) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
u, ok, err := g.Authenticator.AuthenticateRequest(req)
func (g *AuthenticatedGroupAdder) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
r, ok, err := g.Authenticator.AuthenticateRequest(req)
if err != nil || !ok {
return nil, ok, err
}
if u.GetName() == user.Anonymous {
return u, true, nil
if r.User.GetName() == user.Anonymous {
return r, true, nil
}
for _, group := range u.GetGroups() {
for _, group := range r.User.GetGroups() {
if group == user.AllAuthenticated || group == user.AllUnauthenticated {
return u, true, nil
return r, true, nil
}
}
return &user.DefaultInfo{
Name: u.GetName(),
UID: u.GetUID(),
Groups: append(u.GetGroups(), user.AllAuthenticated),
Extra: u.GetExtra(),
}, true, nil
r.User = &user.DefaultInfo{
Name: r.User.GetName(),
UID: r.User.GetUID(),
Groups: append(r.User.GetGroups(), user.AllAuthenticated),
Extra: r.User.GetExtra(),
}
return r, true, nil
}

View File

@ -36,15 +36,16 @@ func NewGroupAdder(auth authenticator.Request, groups []string) authenticator.Re
return &GroupAdder{auth, groups}
}
func (g *GroupAdder) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
u, ok, err := g.Authenticator.AuthenticateRequest(req)
func (g *GroupAdder) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
r, ok, err := g.Authenticator.AuthenticateRequest(req)
if err != nil || !ok {
return nil, ok, err
}
return &user.DefaultInfo{
Name: u.GetName(),
UID: u.GetUID(),
Groups: append(u.GetGroups(), g.Groups...),
Extra: u.GetExtra(),
}, true, nil
r.User = &user.DefaultInfo{
Name: r.User.GetName(),
UID: r.User.GetUID(),
Groups: append(r.User.GetGroups(), g.Groups...),
Extra: r.User.GetExtra(),
}
return r, true, nil
}

View File

@ -28,16 +28,16 @@ import (
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
authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: &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())
r, _, _ := adder.AuthenticateRequest(nil)
if want := []string{"original", "added"}; !reflect.DeepEqual(r.User.GetGroups(), want) {
t.Errorf("Unexpected groups\ngot:\t%#v\nwant:\t%#v", r.User.GetGroups(), want)
}
}
@ -96,15 +96,15 @@ func TestAuthenticatedGroupAdder(t *testing.T) {
for _, test := range tests {
adder := authenticator.Request(
NewAuthenticatedGroupAdder(
authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
return test.inputUser, true, nil
authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: test.inputUser}, true, nil
}),
),
)
user, _, _ := adder.AuthenticateRequest(nil)
if !reflect.DeepEqual(user, test.expectedUser) {
t.Errorf("got %#v", user)
r, _, _ := adder.AuthenticateRequest(nil)
if !reflect.DeepEqual(r.User, test.expectedUser) {
t.Errorf("Unexpected user\ngot:\t%#v\nwant:\t%#v", r.User, test.expectedUser)
}
}

View File

@ -17,6 +17,8 @@ limitations under the License.
package group
import (
"context"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
@ -34,15 +36,16 @@ func NewTokenGroupAdder(auth authenticator.Token, groups []string) authenticator
return &TokenGroupAdder{auth, groups}
}
func (g *TokenGroupAdder) AuthenticateToken(token string) (user.Info, bool, error) {
u, ok, err := g.Authenticator.AuthenticateToken(token)
func (g *TokenGroupAdder) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
r, ok, err := g.Authenticator.AuthenticateToken(ctx, token)
if err != nil || !ok {
return nil, ok, err
}
return &user.DefaultInfo{
Name: u.GetName(),
UID: u.GetUID(),
Groups: append(u.GetGroups(), g.Groups...),
Extra: u.GetExtra(),
}, true, nil
r.User = &user.DefaultInfo{
Name: r.User.GetName(),
UID: r.User.GetUID(),
Groups: append(r.User.GetGroups(), g.Groups...),
Extra: r.User.GetExtra(),
}
return r, true, nil
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package group
import (
"context"
"reflect"
"testing"
@ -27,15 +28,15 @@ import (
func TestTokenGroupAdder(t *testing.T) {
adder := authenticator.Token(
NewTokenGroupAdder(
authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
return &user.DefaultInfo{Name: "user", Groups: []string{"original"}}, true, nil
authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: &user.DefaultInfo{Name: "user", Groups: []string{"original"}}}, true, nil
}),
[]string{"added"},
),
)
user, _, _ := adder.AuthenticateToken("")
if !reflect.DeepEqual(user.GetGroups(), []string{"original", "added"}) {
t.Errorf("Expected original,added groups, got %#v", user.GetGroups())
r, _, _ := adder.AuthenticateToken(context.Background(), "")
if !reflect.DeepEqual(r.User.GetGroups(), []string{"original", "added"}) {
t.Errorf("Expected original,added groups, got %#v", r.User.GetGroups())
}
}

View File

@ -30,7 +30,12 @@ const (
)
func NewAuthenticator() authenticator.Request {
return authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{Name: anonymousUser, Groups: []string{unauthenticatedGroup}}, true, nil
return authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{
User: &user.DefaultInfo{
Name: anonymousUser,
Groups: []string{unauthenticatedGroup},
},
}, true, nil
})
}

View File

@ -26,17 +26,17 @@ import (
func TestAnonymous(t *testing.T) {
var a authenticator.Request = NewAuthenticator()
u, ok, err := a.AuthenticateRequest(nil)
r, ok, err := a.AuthenticateRequest(nil)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if !ok {
t.Fatalf("Unexpectedly unauthenticated")
}
if u.GetName() != user.Anonymous {
t.Fatalf("Expected username %s, got %s", user.Anonymous, u.GetName())
if r.User.GetName() != user.Anonymous {
t.Fatalf("Expected username %s, got %s", user.Anonymous, r.User.GetName())
}
if !sets.NewString(u.GetGroups()...).Equal(sets.NewString(user.AllUnauthenticated)) {
t.Fatalf("Expected group %s, got %v", user.AllUnauthenticated, u.GetGroups())
if !sets.NewString(r.User.GetGroups()...).Equal(sets.NewString(user.AllUnauthenticated)) {
t.Fatalf("Expected group %s, got %v", user.AllUnauthenticated, r.User.GetGroups())
}
}

View File

@ -21,10 +21,7 @@ go_library(
srcs = ["bearertoken.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/authentication/request/bearertoken",
importpath = "k8s.io/apiserver/pkg/authentication/request/bearertoken",
deps = [
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
],
deps = ["//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library"],
)
filegroup(

View File

@ -22,7 +22,6 @@ import (
"strings"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
type Authenticator struct {
@ -35,7 +34,7 @@ func New(auth authenticator.Token) *Authenticator {
var invalidToken = errors.New("invalid bearer token")
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
auth := strings.TrimSpace(req.Header.Get("Authorization"))
if auth == "" {
return nil, false, nil
@ -52,7 +51,7 @@ func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool,
return nil, false, nil
}
user, ok, err := a.auth.AuthenticateToken(token)
resp, ok, err := a.auth.AuthenticateToken(req.Context(), token)
// if we authenticated successfully, go ahead and remove the bearer token so that no one
// is ever tempted to use it inside of the API server
if ok {
@ -64,5 +63,5 @@ func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool,
err = invalidToken
}
return user, ok, err
return resp, ok, err
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package bearertoken
import (
"context"
"errors"
"net/http"
"reflect"
@ -27,28 +28,28 @@ import (
)
func TestAuthenticateRequest(t *testing.T) {
auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
if token != "token" {
t.Errorf("unexpected token: %s", token)
}
return &user.DefaultInfo{Name: "user"}, true, nil
return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}}, true, nil
}))
user, ok, err := auth.AuthenticateRequest(&http.Request{
resp, ok, err := auth.AuthenticateRequest(&http.Request{
Header: http.Header{"Authorization": []string{"Bearer token"}},
})
if !ok || user == nil || err != nil {
if !ok || resp == nil || err != nil {
t.Errorf("expected valid user")
}
}
func TestAuthenticateRequestTokenInvalid(t *testing.T) {
auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
return nil, false, nil
}))
user, ok, err := auth.AuthenticateRequest(&http.Request{
resp, ok, err := auth.AuthenticateRequest(&http.Request{
Header: http.Header{"Authorization": []string{"Bearer token"}},
})
if ok || user != nil {
if ok || resp != nil {
t.Errorf("expected not authenticated user")
}
if err != invalidToken {
@ -58,13 +59,13 @@ func TestAuthenticateRequestTokenInvalid(t *testing.T) {
func TestAuthenticateRequestTokenInvalidCustomError(t *testing.T) {
customError := errors.New("custom")
auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
return nil, false, customError
}))
user, ok, err := auth.AuthenticateRequest(&http.Request{
resp, ok, err := auth.AuthenticateRequest(&http.Request{
Header: http.Header{"Authorization": []string{"Bearer token"}},
})
if ok || user != nil {
if ok || resp != nil {
t.Errorf("expected not authenticated user")
}
if err != customError {
@ -73,13 +74,13 @@ func TestAuthenticateRequestTokenInvalidCustomError(t *testing.T) {
}
func TestAuthenticateRequestTokenError(t *testing.T) {
auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
return nil, false, errors.New("error")
}))
user, ok, err := auth.AuthenticateRequest(&http.Request{
resp, ok, err := auth.AuthenticateRequest(&http.Request{
Header: http.Header{"Authorization": []string{"Bearer token"}},
})
if ok || user != nil || err == nil {
if ok || resp != nil || err == nil {
t.Errorf("expected error")
}
}
@ -94,7 +95,7 @@ func TestAuthenticateRequestBadValue(t *testing.T) {
{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) {
auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
t.Errorf("authentication should not have been called")
return nil, false, nil
}))
@ -144,8 +145,10 @@ func TestBearerToken(t *testing.T) {
ExpectedAuthorizationHeaders: []string{"Bearer "},
},
"valid bearer token removing header": {
AuthorizationHeaders: []string{"Bearer 123"},
TokenAuth: authenticator.TokenFunc(func(t string) (user.Info, bool, error) { return &user.DefaultInfo{Name: "myuser"}, true, nil }),
AuthorizationHeaders: []string{"Bearer 123"},
TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: &user.DefaultInfo{Name: "myuser"}}, true, nil
}),
ExpectedUserName: "myuser",
ExpectedOK: true,
ExpectedErr: false,
@ -153,15 +156,17 @@ func TestBearerToken(t *testing.T) {
},
"invalid bearer token": {
AuthorizationHeaders: []string{"Bearer 123"},
TokenAuth: authenticator.TokenFunc(func(t string) (user.Info, bool, error) { return nil, false, nil }),
TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) { return nil, false, nil }),
ExpectedUserName: "",
ExpectedOK: false,
ExpectedErr: true,
ExpectedAuthorizationHeaders: []string{"Bearer 123"},
},
"error bearer token": {
AuthorizationHeaders: []string{"Bearer 123"},
TokenAuth: authenticator.TokenFunc(func(t string) (user.Info, bool, error) { return nil, false, errors.New("error") }),
AuthorizationHeaders: []string{"Bearer 123"},
TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) {
return nil, false, errors.New("error")
}),
ExpectedUserName: "",
ExpectedOK: false,
ExpectedErr: true,
@ -176,7 +181,7 @@ func TestBearerToken(t *testing.T) {
}
bearerAuth := New(tc.TokenAuth)
u, ok, err := bearerAuth.AuthenticateRequest(req)
resp, ok, err := bearerAuth.AuthenticateRequest(req)
if tc.ExpectedErr != (err != nil) {
t.Errorf("%s: Expected err=%v, got %v", k, tc.ExpectedErr, err)
continue
@ -185,8 +190,8 @@ func TestBearerToken(t *testing.T) {
t.Errorf("%s: Expected ok=%v, got %v", k, tc.ExpectedOK, ok)
continue
}
if ok && u.GetName() != tc.ExpectedUserName {
t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, u.GetName())
if ok && resp.User.GetName() != tc.ExpectedUserName {
t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, resp.User.GetName())
continue
}
if !reflect.DeepEqual(req.Header["Authorization"], tc.ExpectedAuthorizationHeaders) {

View File

@ -105,7 +105,7 @@ func NewSecure(clientCA string, proxyClientNames []string, nameHeaders []string,
return x509request.NewVerifier(opts, headerAuthenticator, sets.NewString(proxyClientNames...)), nil
}
func (a *requestHeaderAuthRequestHandler) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (a *requestHeaderAuthRequestHandler) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
name := headerValue(req.Header, a.nameHeaders)
if len(name) == 0 {
return nil, false, nil
@ -126,10 +126,12 @@ func (a *requestHeaderAuthRequestHandler) AuthenticateRequest(req *http.Request)
}
}
return &user.DefaultInfo{
Name: name,
Groups: groups,
Extra: extra,
return &authenticator.Response{
User: &user.DefaultInfo{
Name: name,
Groups: groups,
Extra: extra,
},
}, true, nil
}

View File

@ -186,19 +186,23 @@ func TestRequestHeader(t *testing.T) {
}
for k, testcase := range testcases {
auth, err := New(testcase.nameHeaders, testcase.groupHeaders, testcase.extraPrefixHeaders)
if err != nil {
t.Fatal(err)
}
req := &http.Request{Header: testcase.requestHeaders}
t.Run(k, func(t *testing.T) {
auth, err := New(testcase.nameHeaders, testcase.groupHeaders, testcase.extraPrefixHeaders)
if err != nil {
t.Fatal(err)
}
req := &http.Request{Header: testcase.requestHeaders}
user, ok, _ := auth.AuthenticateRequest(req)
if testcase.expectedOk != ok {
t.Errorf("%v: expected %v, got %v", k, testcase.expectedOk, ok)
}
if e, a := testcase.expectedUser, user; !reflect.DeepEqual(e, a) {
t.Errorf("%v: expected %#v, got %#v", k, e, a)
}
resp, ok, _ := auth.AuthenticateRequest(req)
if testcase.expectedOk != ok {
t.Errorf("%v: expected %v, got %v", k, testcase.expectedOk, ok)
}
if !ok {
return
}
if e, a := testcase.expectedUser, resp.User; !reflect.DeepEqual(e, a) {
t.Errorf("%v: expected %#v, got %#v", k, e, a)
}
})
}
}

View File

@ -10,7 +10,10 @@ go_test(
name = "go_default_test",
srcs = ["unionauth_test.go"],
embed = [":go_default_library"],
deps = ["//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library"],
deps = [
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
],
)
go_library(
@ -21,7 +24,6 @@ go_library(
deps = [
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
],
)

View File

@ -21,7 +21,6 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
// unionAuthRequestHandler authenticates requests using a chain of authenticator.Requests
@ -51,20 +50,20 @@ func NewFailOnError(authRequestHandlers ...authenticator.Request) authenticator.
}
// AuthenticateRequest authenticates the request using a chain of authenticator.Request objects.
func (authHandler *unionAuthRequestHandler) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (authHandler *unionAuthRequestHandler) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
var errlist []error
for _, currAuthRequestHandler := range authHandler.Handlers {
info, ok, err := currAuthRequestHandler.AuthenticateRequest(req)
resp, ok, err := currAuthRequestHandler.AuthenticateRequest(req)
if err != nil {
if authHandler.FailOnError {
return info, ok, err
return resp, ok, err
}
errlist = append(errlist, err)
continue
}
if ok {
return info, ok, err
return resp, ok, err
}
}

View File

@ -23,6 +23,7 @@ import (
"strings"
"testing"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
@ -37,8 +38,8 @@ var (
user2 = &user.DefaultInfo{Name: "elegant_sheep", UID: "bravo"}
)
func (mock *mockAuthRequestHandler) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
return mock.returnUser, mock.isAuthenticated, mock.err
func (mock *mockAuthRequestHandler) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: mock.returnUser}, mock.isAuthenticated, mock.err
}
func TestAuthenticateRequestSecondPasses(t *testing.T) {
@ -47,15 +48,15 @@ func TestAuthenticateRequestSecondPasses(t *testing.T) {
authRequestHandler := New(handler1, handler2)
req, _ := http.NewRequest("GET", "http://example.org", nil)
authenticatedUser, isAuthenticated, err := authRequestHandler.AuthenticateRequest(req)
resp, isAuthenticated, err := authRequestHandler.AuthenticateRequest(req)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !isAuthenticated {
t.Errorf("Unexpectedly unauthenticated: %v", isAuthenticated)
}
if !reflect.DeepEqual(user2, authenticatedUser) {
t.Errorf("Expected %v, got %v", user2, authenticatedUser)
if !reflect.DeepEqual(user2, resp.User) {
t.Errorf("Expected %v, got %v", user2, resp.User)
}
}
@ -65,15 +66,15 @@ func TestAuthenticateRequestFirstPasses(t *testing.T) {
authRequestHandler := New(handler1, handler2)
req, _ := http.NewRequest("GET", "http://example.org", nil)
authenticatedUser, isAuthenticated, err := authRequestHandler.AuthenticateRequest(req)
resp, isAuthenticated, err := authRequestHandler.AuthenticateRequest(req)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !isAuthenticated {
t.Errorf("Unexpectedly unauthenticated: %v", isAuthenticated)
}
if !reflect.DeepEqual(user1, authenticatedUser) {
t.Errorf("Expected %v, got %v", user1, authenticatedUser)
if !reflect.DeepEqual(user1, resp.User) {
t.Errorf("Expected %v, got %v", user2, resp.User)
}
}
@ -96,15 +97,15 @@ func TestAuthenticateRequestNoAuthenticators(t *testing.T) {
authRequestHandler := New()
req, _ := http.NewRequest("GET", "http://example.org", nil)
authenticatedUser, isAuthenticated, err := authRequestHandler.AuthenticateRequest(req)
resp, isAuthenticated, err := authRequestHandler.AuthenticateRequest(req)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if isAuthenticated {
t.Errorf("Unexpectedly authenticated: %v", isAuthenticated)
}
if authenticatedUser != nil {
t.Errorf("Unexpected authenticatedUser: %v", authenticatedUser)
if resp != nil {
t.Errorf("Unexpected authenticatedUser: %v", resp)
}
}

View File

@ -13,7 +13,6 @@ go_library(
importpath = "k8s.io/apiserver/pkg/authentication/request/websocket",
deps = [
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/wsstream:go_default_library",
],
)

View File

@ -25,7 +25,6 @@ import (
"unicode/utf8"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/util/wsstream"
)
@ -46,7 +45,7 @@ func NewProtocolAuthenticator(auth authenticator.Token) *ProtocolAuthenticator {
return &ProtocolAuthenticator{auth}
}
func (a *ProtocolAuthenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (a *ProtocolAuthenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
// Only accept websocket connections
if !wsstream.IsWebSocketRequest(req) {
return nil, false, nil
@ -91,7 +90,7 @@ func (a *ProtocolAuthenticator) AuthenticateRequest(req *http.Request) (user.Inf
return nil, false, nil
}
user, ok, err := a.auth.AuthenticateToken(token)
resp, ok, err := a.auth.AuthenticateToken(req.Context(), token)
// on success, remove the protocol with the token
if ok {
@ -105,5 +104,5 @@ func (a *ProtocolAuthenticator) AuthenticateRequest(req *http.Request) (user.Inf
err = errInvalidToken
}
return user, ok, err
return resp, ok, err
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package websocket
import (
"context"
"errors"
"net/http"
"reflect"
@ -27,36 +28,36 @@ import (
)
func TestAuthenticateRequest(t *testing.T) {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
if token != "token" {
t.Errorf("unexpected token: %s", token)
}
return &user.DefaultInfo{Name: "user"}, true, nil
return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}}, true, nil
}))
user, ok, err := auth.AuthenticateRequest(&http.Request{
resp, ok, err := auth.AuthenticateRequest(&http.Request{
Header: http.Header{
"Connection": []string{"upgrade"},
"Upgrade": []string{"websocket"},
"Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"},
},
})
if !ok || user == nil || err != nil {
if !ok || resp == nil || err != nil {
t.Errorf("expected valid user")
}
}
func TestAuthenticateRequestTokenInvalid(t *testing.T) {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
return nil, false, nil
}))
user, ok, err := auth.AuthenticateRequest(&http.Request{
resp, ok, err := auth.AuthenticateRequest(&http.Request{
Header: http.Header{
"Connection": []string{"upgrade"},
"Upgrade": []string{"websocket"},
"Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"},
},
})
if ok || user != nil {
if ok || resp != nil {
t.Errorf("expected not authenticated user")
}
if err != errInvalidToken {
@ -66,17 +67,17 @@ func TestAuthenticateRequestTokenInvalid(t *testing.T) {
func TestAuthenticateRequestTokenInvalidCustomError(t *testing.T) {
customError := errors.New("custom")
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
return nil, false, customError
}))
user, ok, err := auth.AuthenticateRequest(&http.Request{
resp, ok, err := auth.AuthenticateRequest(&http.Request{
Header: http.Header{
"Connection": []string{"upgrade"},
"Upgrade": []string{"websocket"},
"Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"},
},
})
if ok || user != nil {
if ok || resp != nil {
t.Errorf("expected not authenticated user")
}
if err != customError {
@ -85,17 +86,17 @@ func TestAuthenticateRequestTokenInvalidCustomError(t *testing.T) {
}
func TestAuthenticateRequestTokenError(t *testing.T) {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
return nil, false, errors.New("error")
}))
user, ok, err := auth.AuthenticateRequest(&http.Request{
resp, ok, err := auth.AuthenticateRequest(&http.Request{
Header: http.Header{
"Connection": []string{"upgrade"},
"Upgrade": []string{"websocket"},
"Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"},
},
})
if ok || user != nil || err == nil {
if ok || resp != nil || err == nil {
t.Errorf("expected error")
}
}
@ -117,12 +118,12 @@ func TestAuthenticateRequestBadValue(t *testing.T) {
},
}
for i, testCase := range testCases {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, 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 {
resp, ok, err := auth.AuthenticateRequest(testCase.Req)
if ok || resp != nil || err != nil {
t.Errorf("%d: expected not authenticated (no token)", i)
}
}
@ -167,8 +168,10 @@ func TestBearerToken(t *testing.T) {
ExpectedProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io."},
},
"valid bearer token removing header": {
ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4", "dummy, dummy2"},
TokenAuth: authenticator.TokenFunc(func(t string) (user.Info, bool, error) { return &user.DefaultInfo{Name: "myuser"}, true, nil }),
ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4", "dummy, dummy2"},
TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: &user.DefaultInfo{Name: "myuser"}}, true, nil
}),
ExpectedUserName: "myuser",
ExpectedOK: true,
ExpectedErr: false,
@ -176,15 +179,17 @@ func TestBearerToken(t *testing.T) {
},
"invalid bearer token": {
ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"},
TokenAuth: authenticator.TokenFunc(func(t string) (user.Info, bool, error) { return nil, false, nil }),
TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) { return nil, false, nil }),
ExpectedUserName: "",
ExpectedOK: false,
ExpectedErr: true,
ExpectedProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"},
},
"error bearer token": {
ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"},
TokenAuth: authenticator.TokenFunc(func(t string) (user.Info, bool, error) { return nil, false, errors.New("error") }),
ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"},
TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) {
return nil, false, errors.New("error")
}),
ExpectedUserName: "",
ExpectedOK: false,
ExpectedErr: true,
@ -201,7 +206,7 @@ func TestBearerToken(t *testing.T) {
}
bearerAuth := NewProtocolAuthenticator(tc.TokenAuth)
u, ok, err := bearerAuth.AuthenticateRequest(req)
resp, ok, err := bearerAuth.AuthenticateRequest(req)
if tc.ExpectedErr != (err != nil) {
t.Errorf("%s: Expected err=%v, got %v", k, tc.ExpectedErr, err)
continue
@ -210,8 +215,8 @@ func TestBearerToken(t *testing.T) {
t.Errorf("%s: Expected ok=%v, got %v", k, tc.ExpectedOK, ok)
continue
}
if ok && u.GetName() != tc.ExpectedUserName {
t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, u.GetName())
if ok && resp.User.GetName() != tc.ExpectedUserName {
t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, resp.User.GetName())
continue
}
if !reflect.DeepEqual(req.Header["Sec-Websocket-Protocol"], tc.ExpectedProtocolHeaders) {

View File

@ -59,14 +59,14 @@ func init() {
// UserConversion defines an interface for extracting user info from a client certificate chain
type UserConversion interface {
User(chain []*x509.Certificate) (user.Info, bool, error)
User(chain []*x509.Certificate) (*authenticator.Response, bool, error)
}
// UserConversionFunc is a function that implements the UserConversion interface.
type UserConversionFunc func(chain []*x509.Certificate) (user.Info, bool, error)
type UserConversionFunc func(chain []*x509.Certificate) (*authenticator.Response, bool, error)
// User implements x509.UserConversion
func (f UserConversionFunc) User(chain []*x509.Certificate) (user.Info, bool, error) {
func (f UserConversionFunc) User(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
return f(chain)
}
@ -83,7 +83,7 @@ func New(opts x509.VerifyOptions, user UserConversion) *Authenticator {
}
// AuthenticateRequest authenticates the request using presented client certificates
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
return nil, false, nil
}
@ -135,7 +135,7 @@ func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCom
}
// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth
func (a *Verifier) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (a *Verifier) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
return nil, false, nil
}
@ -179,12 +179,14 @@ func DefaultVerifyOptions() x509.VerifyOptions {
}
// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
if len(chain[0].Subject.CommonName) == 0 {
return nil, false, nil
}
return &user.DefaultInfo{
Name: chain[0].Subject.CommonName,
Groups: chain[0].Subject.Organization,
return &authenticator.Response{
User: &user.DefaultInfo{
Name: chain[0].Subject.CommonName,
Groups: chain[0].Subject.Organization,
},
}, true, nil
})

View File

@ -590,7 +590,7 @@ func TestX509(t *testing.T) {
"custom conversion error": {
Opts: getDefaultVerifyOptions(t),
Certs: getCerts(t, clientCNCert),
User: UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
User: UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
return nil, false, errors.New("custom error")
}),
@ -600,8 +600,8 @@ func TestX509(t *testing.T) {
"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
User: UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: &user.DefaultInfo{Name: "custom"}}, true, nil
}),
ExpectUserName: "custom",
@ -659,7 +659,7 @@ func TestX509(t *testing.T) {
a := New(testCase.Opts, testCase.User)
user, ok, err := a.AuthenticateRequest(req)
resp, ok, err := a.AuthenticateRequest(req)
if testCase.ExpectErr && err == nil {
t.Errorf("%s: Expected error, got none", k)
@ -676,11 +676,11 @@ func TestX509(t *testing.T) {
}
if testCase.ExpectOK {
if testCase.ExpectUserName != user.GetName() {
t.Errorf("%s: Expected user.name=%v, got %v", k, testCase.ExpectUserName, user.GetName())
if testCase.ExpectUserName != resp.User.GetName() {
t.Errorf("%s: Expected user.name=%v, got %v", k, testCase.ExpectUserName, resp.User.GetName())
}
groups := user.GetGroups()
groups := resp.User.GetGroups()
sort.Strings(testCase.ExpectGroups)
sort.Strings(groups)
if !reflect.DeepEqual(testCase.ExpectGroups, groups) {
@ -807,14 +807,14 @@ func TestX509Verifier(t *testing.T) {
}
authCall := false
auth := authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
auth := authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
authCall = true
return &user.DefaultInfo{Name: "innerauth"}, true, nil
return &authenticator.Response{User: &user.DefaultInfo{Name: "innerauth"}}, true, nil
})
a := NewVerifier(testCase.Opts, auth, testCase.AllowedCNs)
user, ok, err := a.AuthenticateRequest(req)
resp, ok, err := a.AuthenticateRequest(req)
if testCase.ExpectErr && err == nil {
t.Errorf("%s: Expected error, got none", k)
@ -835,8 +835,8 @@ func TestX509Verifier(t *testing.T) {
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())
if "innerauth" != resp.User.GetName() {
t.Errorf("%s: Expected user.name=%v, got %v", k, "innerauth", resp.User.GetName())
continue
}
} else {

View File

@ -17,6 +17,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/github.com/pborman/uuid:go_default_library",
],
)
@ -34,7 +35,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/util/cache:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
],
)

View File

@ -24,36 +24,36 @@ import (
// split cache lookups across N striped caches
type stripedCache struct {
stripeCount uint32
keyFunc func(string) uint32
hashFunc func(string) uint32
caches []cache
}
type keyFunc func(string) uint32
type hashFunc func(string) uint32
type newCacheFunc func() cache
func newStripedCache(stripeCount int, keyFunc keyFunc, newCacheFunc newCacheFunc) cache {
func newStripedCache(stripeCount int, hash hashFunc, newCacheFunc newCacheFunc) cache {
caches := []cache{}
for i := 0; i < stripeCount; i++ {
caches = append(caches, newCacheFunc())
}
return &stripedCache{
stripeCount: uint32(stripeCount),
keyFunc: keyFunc,
hashFunc: hash,
caches: caches,
}
}
func (c *stripedCache) get(key string) (*cacheRecord, bool) {
return c.caches[c.keyFunc(key)%c.stripeCount].get(key)
return c.caches[c.hashFunc(key)%c.stripeCount].get(key)
}
func (c *stripedCache) set(key string, value *cacheRecord, ttl time.Duration) {
c.caches[c.keyFunc(key)%c.stripeCount].set(key, value, ttl)
c.caches[c.hashFunc(key)%c.stripeCount].set(key, value, ttl)
}
func (c *stripedCache) remove(key string) {
c.caches[c.keyFunc(key)%c.stripeCount].remove(key)
c.caches[c.hashFunc(key)%c.stripeCount].remove(key)
}
func fnvKeyFunc(key string) uint32 {
func fnvHashFunc(key string) uint32 {
f := fnv.New32()
f.Write([]byte(key))
return f.Sum32()

View File

@ -21,10 +21,11 @@ import (
"testing"
"time"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apiserver/pkg/authentication/user"
"github.com/pborman/uuid"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
func TestSimpleCache(t *testing.T) {
@ -36,11 +37,11 @@ func BenchmarkSimpleCache(b *testing.B) {
}
func TestStripedCache(t *testing.T) {
testCache(newStripedCache(32, fnvKeyFunc, func() cache { return newSimpleCache(128, clock.RealClock{}) }), t)
testCache(newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(128, clock.RealClock{}) }), t)
}
func BenchmarkStripedCache(b *testing.B) {
benchmarkCache(newStripedCache(32, fnvKeyFunc, func() cache { return newSimpleCache(128, clock.RealClock{}) }), b)
benchmarkCache(newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(128, clock.RealClock{}) }), b)
}
func benchmarkCache(cache cache, b *testing.B) {
@ -71,8 +72,8 @@ func testCache(cache cache, t *testing.T) {
t.Errorf("Expected null, false, got %#v, %v", result, ok)
}
record1 := &cacheRecord{user: &user.DefaultInfo{Name: "bob"}}
record2 := &cacheRecord{user: &user.DefaultInfo{Name: "alice"}}
record1 := &cacheRecord{resp: &authenticator.Response{User: &user.DefaultInfo{Name: "bob"}}}
record2 := &cacheRecord{resp: &authenticator.Response{User: &user.DefaultInfo{Name: "alice"}}}
// when empty, record is stored
cache.set("foo", record1, time.Hour)

View File

@ -17,16 +17,18 @@ limitations under the License.
package cache
import (
"context"
"fmt"
"time"
utilclock "k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/endpoints/request"
)
// cacheRecord holds the three return values of the authenticator.Token AuthenticateToken method
type cacheRecord struct {
user user.Info
resp *authenticator.Response
ok bool
err error
}
@ -59,24 +61,31 @@ func newWithClock(authenticator authenticator.Token, successTTL, failureTTL time
authenticator: authenticator,
successTTL: successTTL,
failureTTL: failureTTL,
cache: newStripedCache(32, fnvKeyFunc, func() cache { return newSimpleCache(128, clock) }),
cache: newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(128, clock) }),
}
}
// AuthenticateToken implements authenticator.Token
func (a *cachedTokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, error) {
if record, ok := a.cache.get(token); ok {
return record.user, record.ok, record.err
func (a *cachedTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
auds, _ := request.AudiencesFrom(ctx)
key := keyFunc(auds, token)
if record, ok := a.cache.get(key); ok {
return record.resp, record.ok, record.err
}
user, ok, err := a.authenticator.AuthenticateToken(token)
resp, ok, err := a.authenticator.AuthenticateToken(ctx, token)
switch {
case ok && a.successTTL > 0:
a.cache.set(token, &cacheRecord{user: user, ok: ok, err: err}, a.successTTL)
a.cache.set(key, &cacheRecord{resp: resp, ok: ok, err: err}, a.successTTL)
case !ok && a.failureTTL > 0:
a.cache.set(token, &cacheRecord{user: user, ok: ok, err: err}, a.failureTTL)
a.cache.set(key, &cacheRecord{resp: resp, ok: ok, err: err}, a.failureTTL)
}
return user, ok, err
return resp, ok, err
}
func keyFunc(auds []string, token string) string {
return fmt.Sprintf("%#v|%v", auds, token)
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package cache
import (
"context"
"reflect"
"testing"
"time"
@ -24,6 +25,7 @@ import (
utilclock "k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/endpoints/request"
)
func TestCachedTokenAuthenticator(t *testing.T) {
@ -34,21 +36,21 @@ func TestCachedTokenAuthenticator(t *testing.T) {
resultOk bool
resultErr error
)
fakeAuth := authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
fakeAuth := authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
calledWithToken = append(calledWithToken, token)
return resultUsers[token], resultOk, resultErr
return &authenticator.Response{User: resultUsers[token]}, resultOk, resultErr
})
fakeClock := utilclock.NewFakeClock(time.Now())
a := newWithClock(fakeAuth, time.Minute, 0, fakeClock)
calledWithToken, resultUsers, resultOk, resultErr = []string{}, nil, false, nil
a.AuthenticateToken("bad1")
a.AuthenticateToken("bad2")
a.AuthenticateToken("bad3")
a.AuthenticateToken("bad1")
a.AuthenticateToken("bad2")
a.AuthenticateToken("bad3")
a.AuthenticateToken(context.Background(), "bad1")
a.AuthenticateToken(context.Background(), "bad2")
a.AuthenticateToken(context.Background(), "bad3")
a.AuthenticateToken(context.Background(), "bad1")
a.AuthenticateToken(context.Background(), "bad2")
a.AuthenticateToken(context.Background(), "bad3")
if !reflect.DeepEqual(calledWithToken, []string{"bad1", "bad2", "bad3", "bad1", "bad2", "bad3"}) {
t.Errorf("Expected failing calls to bypass cache, got %v", calledWithToken)
}
@ -61,13 +63,13 @@ func TestCachedTokenAuthenticator(t *testing.T) {
resultUsers["usertoken3"] = &user.DefaultInfo{Name: "user3"}
// populate cache
if user, ok, err := a.AuthenticateToken("usertoken1"); err != nil || !ok || user.GetName() != "user1" {
if resp, ok, err := a.AuthenticateToken(context.Background(), "usertoken1"); err != nil || !ok || resp.User.GetName() != "user1" {
t.Errorf("Expected user1")
}
if user, ok, err := a.AuthenticateToken("usertoken2"); err != nil || !ok || user.GetName() != "user2" {
if resp, ok, err := a.AuthenticateToken(context.Background(), "usertoken2"); err != nil || !ok || resp.User.GetName() != "user2" {
t.Errorf("Expected user2")
}
if user, ok, err := a.AuthenticateToken("usertoken3"); err != nil || !ok || user.GetName() != "user3" {
if resp, ok, err := a.AuthenticateToken(context.Background(), "usertoken3"); err != nil || !ok || resp.User.GetName() != "user3" {
t.Errorf("Expected user3")
}
if !reflect.DeepEqual(calledWithToken, []string{"usertoken1", "usertoken2", "usertoken3"}) {
@ -79,13 +81,13 @@ func TestCachedTokenAuthenticator(t *testing.T) {
resultUsers, resultOk, resultErr = nil, false, nil
// authenticate calls still succeed and backend is not hit
if user, ok, err := a.AuthenticateToken("usertoken1"); err != nil || !ok || user.GetName() != "user1" {
if resp, ok, err := a.AuthenticateToken(context.Background(), "usertoken1"); err != nil || !ok || resp.User.GetName() != "user1" {
t.Errorf("Expected user1")
}
if user, ok, err := a.AuthenticateToken("usertoken2"); err != nil || !ok || user.GetName() != "user2" {
if resp, ok, err := a.AuthenticateToken(context.Background(), "usertoken2"); err != nil || !ok || resp.User.GetName() != "user2" {
t.Errorf("Expected user2")
}
if user, ok, err := a.AuthenticateToken("usertoken3"); err != nil || !ok || user.GetName() != "user3" {
if resp, ok, err := a.AuthenticateToken(context.Background(), "usertoken3"); err != nil || !ok || resp.User.GetName() != "user3" {
t.Errorf("Expected user3")
}
if !reflect.DeepEqual(calledWithToken, []string{}) {
@ -96,10 +98,31 @@ func TestCachedTokenAuthenticator(t *testing.T) {
fakeClock.Step(2 * time.Minute)
// backend is consulted again and fails
a.AuthenticateToken("usertoken1")
a.AuthenticateToken("usertoken2")
a.AuthenticateToken("usertoken3")
a.AuthenticateToken(context.Background(), "usertoken1")
a.AuthenticateToken(context.Background(), "usertoken2")
a.AuthenticateToken(context.Background(), "usertoken3")
if !reflect.DeepEqual(calledWithToken, []string{"usertoken1", "usertoken2", "usertoken3"}) {
t.Errorf("Expected token calls, got %v", calledWithToken)
}
}
func TestCachedTokenAuthenticatorWithAudiences(t *testing.T) {
resultUsers := make(map[string]user.Info)
fakeAuth := authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
auds, _ := request.AudiencesFrom(ctx)
return &authenticator.Response{User: resultUsers[auds[0]+token]}, true, nil
})
fakeClock := utilclock.NewFakeClock(time.Now())
a := newWithClock(fakeAuth, time.Minute, 0, fakeClock)
resultUsers["audAusertoken1"] = &user.DefaultInfo{Name: "user1"}
resultUsers["audBusertoken1"] = &user.DefaultInfo{Name: "user1-different"}
if u, ok, _ := a.AuthenticateToken(request.WithAudiences(context.Background(), []string{"audA"}), "usertoken1"); !ok || u.User.GetName() != "user1" {
t.Errorf("Expected user1")
}
if u, ok, _ := a.AuthenticateToken(request.WithAudiences(context.Background(), []string{"audB"}), "usertoken1"); !ok || u.User.GetName() != "user1-different" {
t.Errorf("Expected user1-different")
}
}

View File

@ -19,6 +19,7 @@ go_library(
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/authentication/token/tokenfile",
importpath = "k8s.io/apiserver/pkg/authentication/token/tokenfile",
deps = [
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
],

View File

@ -17,6 +17,7 @@ limitations under the License.
package tokenfile
import (
"context"
"encoding/csv"
"fmt"
"io"
@ -24,6 +25,7 @@ import (
"strings"
"github.com/golang/glog"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
@ -88,10 +90,10 @@ func NewCSV(path string) (*TokenAuthenticator, error) {
}, nil
}
func (a *TokenAuthenticator) AuthenticateToken(value string) (user.Info, bool, error) {
func (a *TokenAuthenticator) AuthenticateToken(ctx context.Context, value string) (*authenticator.Response, bool, error) {
user, ok := a.tokens[value]
if !ok {
return nil, false, nil
}
return user, true, nil
return &authenticator.Response{User: user}, true, nil
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package tokenfile
import (
"context"
"io/ioutil"
"os"
"reflect"
@ -85,13 +86,13 @@ token7,user7,uid7,"group1,group2",otherdata
},
}
for i, testCase := range testCases {
user, ok, err := auth.AuthenticateToken(testCase.Token)
resp, ok, err := auth.AuthenticateToken(context.Background(), testCase.Token)
if testCase.User == nil {
if user != nil {
t.Errorf("%d: unexpected non-nil user %#v", i, user)
if resp != nil {
t.Errorf("%d: unexpected non-nil user %#v", i, resp.User)
}
} else if !reflect.DeepEqual(testCase.User, user) {
t.Errorf("%d: expected user %#v, got %#v", i, testCase.User, user)
} else if !reflect.DeepEqual(testCase.User, resp.User) {
t.Errorf("%d: expected user %#v, got %#v", i, testCase.User, resp.User)
}
if testCase.Ok != ok {

View File

@ -10,7 +10,10 @@ go_test(
name = "go_default_test",
srcs = ["unionauth_test.go"],
embed = [":go_default_library"],
deps = ["//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library"],
deps = [
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
],
)
go_library(
@ -21,7 +24,6 @@ go_library(
deps = [
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
],
)

View File

@ -17,9 +17,10 @@ limitations under the License.
package union
import (
"context"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
// unionAuthTokenHandler authenticates tokens using a chain of authenticator.Token objects
@ -49,10 +50,10 @@ func NewFailOnError(authTokenHandlers ...authenticator.Token) authenticator.Toke
}
// AuthenticateToken authenticates the token using a chain of authenticator.Token objects.
func (authHandler *unionAuthTokenHandler) AuthenticateToken(token string) (user.Info, bool, error) {
func (authHandler *unionAuthTokenHandler) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
var errlist []error
for _, currAuthRequestHandler := range authHandler.Handlers {
info, ok, err := currAuthRequestHandler.AuthenticateToken(token)
info, ok, err := currAuthRequestHandler.AuthenticateToken(ctx, token)
if err != nil {
if authHandler.FailOnError {
return info, ok, err

View File

@ -17,11 +17,13 @@ limitations under the License.
package union
import (
"context"
"errors"
"reflect"
"strings"
"testing"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
@ -36,8 +38,8 @@ var (
user2 = &user.DefaultInfo{Name: "elegant_sheep", UID: "bravo"}
)
func (mock *mockAuthRequestHandler) AuthenticateToken(token string) (user.Info, bool, error) {
return mock.returnUser, mock.isAuthenticated, mock.err
func (mock *mockAuthRequestHandler) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
return &authenticator.Response{User: mock.returnUser}, mock.isAuthenticated, mock.err
}
func TestAuthenticateTokenSecondPasses(t *testing.T) {
@ -45,15 +47,15 @@ func TestAuthenticateTokenSecondPasses(t *testing.T) {
handler2 := &mockAuthRequestHandler{returnUser: user2, isAuthenticated: true}
authRequestHandler := New(handler1, handler2)
authenticatedUser, isAuthenticated, err := authRequestHandler.AuthenticateToken("foo")
resp, isAuthenticated, err := authRequestHandler.AuthenticateToken(context.Background(), "foo")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !isAuthenticated {
t.Errorf("Unexpectedly unauthenticated: %v", isAuthenticated)
}
if !reflect.DeepEqual(user2, authenticatedUser) {
t.Errorf("Expected %v, got %v", user2, authenticatedUser)
if !reflect.DeepEqual(user2, resp.User) {
t.Errorf("Expected %v, got %v", user2, resp.User)
}
}
@ -62,15 +64,15 @@ func TestAuthenticateTokenFirstPasses(t *testing.T) {
handler2 := &mockAuthRequestHandler{returnUser: user2}
authRequestHandler := New(handler1, handler2)
authenticatedUser, isAuthenticated, err := authRequestHandler.AuthenticateToken("foo")
resp, isAuthenticated, err := authRequestHandler.AuthenticateToken(context.Background(), "foo")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !isAuthenticated {
t.Errorf("Unexpectedly unauthenticated: %v", isAuthenticated)
}
if !reflect.DeepEqual(user1, authenticatedUser) {
t.Errorf("Expected %v, got %v", user1, authenticatedUser)
if !reflect.DeepEqual(user1, resp.User) {
t.Errorf("Expected %v, got %v", user1, resp.User)
}
}
@ -79,7 +81,7 @@ func TestAuthenticateTokenSuppressUnnecessaryErrors(t *testing.T) {
handler2 := &mockAuthRequestHandler{isAuthenticated: true}
authRequestHandler := New(handler1, handler2)
_, isAuthenticated, err := authRequestHandler.AuthenticateToken("foo")
_, isAuthenticated, err := authRequestHandler.AuthenticateToken(context.Background(), "foo")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
@ -91,15 +93,15 @@ func TestAuthenticateTokenSuppressUnnecessaryErrors(t *testing.T) {
func TestAuthenticateTokenNoAuthenticators(t *testing.T) {
authRequestHandler := New()
authenticatedUser, isAuthenticated, err := authRequestHandler.AuthenticateToken("foo")
resp, isAuthenticated, err := authRequestHandler.AuthenticateToken(context.Background(), "foo")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if isAuthenticated {
t.Errorf("Unexpectedly authenticated: %v", isAuthenticated)
}
if authenticatedUser != nil {
t.Errorf("Unexpected authenticatedUser: %v", authenticatedUser)
if resp != nil {
t.Errorf("Unexpected authenticatedUser: %v", resp)
}
}
@ -108,7 +110,7 @@ func TestAuthenticateTokenNonePass(t *testing.T) {
handler2 := &mockAuthRequestHandler{}
authRequestHandler := New(handler1, handler2)
_, isAuthenticated, err := authRequestHandler.AuthenticateToken("foo")
_, isAuthenticated, err := authRequestHandler.AuthenticateToken(context.Background(), "foo")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
@ -122,7 +124,7 @@ func TestAuthenticateTokenAdditiveErrors(t *testing.T) {
handler2 := &mockAuthRequestHandler{err: errors.New("second")}
authRequestHandler := New(handler1, handler2)
_, isAuthenticated, err := authRequestHandler.AuthenticateToken("foo")
_, isAuthenticated, err := authRequestHandler.AuthenticateToken(context.Background(), "foo")
if err == nil {
t.Errorf("Expected an error")
}
@ -142,7 +144,7 @@ func TestAuthenticateTokenFailEarly(t *testing.T) {
handler2 := &mockAuthRequestHandler{err: errors.New("second")}
authRequestHandler := NewFailOnError(handler1, handler2)
_, isAuthenticated, err := authRequestHandler.AuthenticateToken("foo")
_, isAuthenticated, err := authRequestHandler.AuthenticateToken(context.Background(), "foo")
if err == nil {
t.Errorf("Expected an error")
}

View File

@ -59,7 +59,7 @@ func WithAuthentication(handler http.Handler, auth authenticator.Request, failed
if len(apiAuds) > 0 {
req = req.WithContext(genericapirequest.WithAudiences(req.Context(), apiAuds))
}
user, ok, err := auth.AuthenticateRequest(req)
resp, ok, err := auth.AuthenticateRequest(req)
if err != nil || !ok {
if err != nil {
glog.Errorf("Unable to authenticate the request due to an error: %v", err)
@ -68,12 +68,15 @@ func WithAuthentication(handler http.Handler, auth authenticator.Request, failed
return
}
// TODO(mikedanese): verify the response audience matches one of apiAuds if
// non-empty
// authorization header is not required anymore in case of a successful authentication.
req.Header.Del("Authorization")
req = req.WithContext(genericapirequest.WithUser(req.Context(), user))
req = req.WithContext(genericapirequest.WithUser(req.Context(), resp.User))
authenticatedUserCounter.WithLabelValues(compressUsername(user.GetName())).Inc()
authenticatedUserCounter.WithLabelValues(compressUsername(resp.User.GetName())).Inc()
handler.ServeHTTP(w, req)
})

View File

@ -41,9 +41,9 @@ func TestAuthenticateRequest(t *testing.T) {
}
close(success)
}),
authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
if req.Header.Get("Authorization") == "Something" {
return &user.DefaultInfo{Name: "user"}, true, nil
return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}}, true, nil
}
return nil, false, errors.New("Authorization header is missing.")
}),
@ -64,7 +64,7 @@ func TestAuthenticateRequestFailed(t *testing.T) {
http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {
t.Errorf("unexpected call to handler")
}),
authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
return nil, false, nil
}),
http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
@ -84,7 +84,7 @@ func TestAuthenticateRequestError(t *testing.T) {
http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {
t.Errorf("unexpected call to handler")
}),
authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
return nil, false, errors.New("failure")
}),
http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {

View File

@ -23,6 +23,7 @@ import (
"github.com/golang/glog"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/client-go/rest"
)
@ -77,9 +78,11 @@ func (s *DeprecatedInsecureServingInfo) NewLoopbackClientConfig() (*rest.Config,
// but allows apiserver code to stop special-casing a nil user to skip authorization checks.
type InsecureSuperuser struct{}
func (InsecureSuperuser) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{
Name: "system:unsecured",
Groups: []string{user.SystemPrivilegedGroup, user.AllAuthenticated},
func (InsecureSuperuser) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{
User: &user.DefaultInfo{
Name: "system:unsecured",
Groups: []string{user.SystemPrivilegedGroup, user.AllAuthenticated},
},
}, true, nil
}

View File

@ -19,6 +19,7 @@ go_library(
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile",
importpath = "k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile",
deps = [
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
],

View File

@ -17,6 +17,7 @@ limitations under the License.
package passwordfile
import (
"context"
"encoding/csv"
"fmt"
"io"
@ -25,6 +26,7 @@ import (
"github.com/golang/glog"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
@ -78,7 +80,7 @@ func NewCSV(path string) (*PasswordAuthenticator, error) {
return &PasswordAuthenticator{users}, nil
}
func (a *PasswordAuthenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
func (a *PasswordAuthenticator) AuthenticatePassword(ctx context.Context, username, password string) (*authenticator.Response, bool, error) {
user, ok := a.users[username]
if !ok {
return nil, false, nil
@ -86,5 +88,5 @@ func (a *PasswordAuthenticator) AuthenticatePassword(username, password string)
if user.password != password {
return nil, false, nil
}
return user.info, true, nil
return &authenticator.Response{User: user.info}, true, nil
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package passwordfile
import (
"context"
"io/ioutil"
"os"
"reflect"
@ -110,16 +111,16 @@ password7,user7,uid7,"group1,group2",otherdata
},
}
for i, testCase := range testCases {
user, ok, err := auth.AuthenticatePassword(testCase.Username, testCase.Password)
resp, ok, err := auth.AuthenticatePassword(context.Background(), testCase.Username, testCase.Password)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
}
if testCase.User == nil {
if user != nil {
t.Errorf("%d: unexpected non-nil user %#v", i, user)
if resp != nil {
t.Errorf("%d: unexpected non-nil user %#v", i, resp.User)
}
} else if !reflect.DeepEqual(testCase.User, user) {
t.Errorf("%d: expected user %#v, got %#v", i, testCase.User, user)
} else if !reflect.DeepEqual(testCase.User, resp.User) {
t.Errorf("%d: expected user %#v, got %#v", i, testCase.User, resp.User)
}
if testCase.Ok != ok {
t.Errorf("%d: expected auth %v, got %v", i, testCase.Ok, ok)

View File

@ -21,10 +21,7 @@ go_library(
srcs = ["basicauth.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth",
importpath = "k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth",
deps = [
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
],
deps = ["//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library"],
)
filegroup(

View File

@ -21,7 +21,6 @@ import (
"net/http"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
// Authenticator authenticates requests using basic auth
@ -37,18 +36,18 @@ func New(auth authenticator.Password) *Authenticator {
var errInvalidAuth = errors.New("invalid username/password combination")
// AuthenticateRequest authenticates the request using the "Authorization: Basic" header in the request
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
username, password, found := req.BasicAuth()
if !found {
return nil, false, nil
}
user, ok, err := a.auth.AuthenticatePassword(username, password)
resp, ok, err := a.auth.AuthenticatePassword(req.Context(), username, password)
// If the password authenticator didn't error, provide a default error
if !ok && err == nil {
err = errInvalidAuth
}
return user, ok, err
return resp, ok, err
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package basicauth
import (
"context"
"errors"
"net/http"
"testing"
@ -35,11 +36,11 @@ type testPassword struct {
Err error
}
func (t *testPassword) AuthenticatePassword(user, password string) (user.Info, bool, error) {
func (t *testPassword) AuthenticatePassword(ctx context.Context, user, password string) (*authenticator.Response, bool, error) {
t.Called = true
t.Username = user
t.Password = password
return t.User, t.OK, t.Err
return &authenticator.Response{User: t.User}, t.OK, t.Err
}
func TestBasicAuth(t *testing.T) {
@ -94,7 +95,7 @@ func TestBasicAuth(t *testing.T) {
req.SetBasicAuth(testCase.ExpectedUsername, testCase.ExpectedPassword)
}
user, ok, err := auth.AuthenticateRequest(req)
resp, ok, err := auth.AuthenticateRequest(req)
if testCase.ExpectedCalled != password.Called {
t.Errorf("%s: Expected called=%v, got %v", k, testCase.ExpectedCalled, password.Called)
@ -117,8 +118,8 @@ func TestBasicAuth(t *testing.T) {
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())
if testCase.ExpectedUser != "" && testCase.ExpectedUser != resp.User.GetName() {
t.Errorf("%s: Expected user.GetName()=%v, got %v", k, testCase.ExpectedUser, resp.User.GetName())
continue
}
}

View File

@ -28,6 +28,7 @@ go_library(
deps = [
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
"//vendor/github.com/coreos/go-oidc:go_default_library",

View File

@ -44,8 +44,10 @@ import (
oidc "github.com/coreos/go-oidc"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
certutil "k8s.io/client-go/util/cert"
)
@ -529,7 +531,7 @@ func (r *claimResolver) resolve(endpoint endpoint, allClaims claims) error {
return nil
}
func (a *Authenticator) AuthenticateToken(token string) (user.Info, bool, error) {
func (a *Authenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
if !hasCorrectIssuer(a.issuerURL, token) {
return nil, false, nil
}
@ -539,7 +541,6 @@ func (a *Authenticator) AuthenticateToken(token string) (user.Info, bool, error)
return nil, false, fmt.Errorf("oidc: authenticator not initialized")
}
ctx := context.Background()
idToken, err := verifier.Verify(ctx, token)
if err != nil {
return nil, false, fmt.Errorf("oidc: verify token: %v", err)
@ -617,7 +618,7 @@ func (a *Authenticator) AuthenticateToken(token string) (user.Info, bool, error)
}
}
return info, true, nil
return &authenticator.Response{User: info}, true, nil
}
// getClaimJWT gets a distributed claim JWT from url, using the supplied access

View File

@ -296,7 +296,8 @@ func (c *claimsTest) run(t *testing.T) {
t.Fatalf("serialize token: %v", err)
}
got, ok, err := a.AuthenticateToken(token)
got, ok, err := a.AuthenticateToken(context.Background(), token)
if err != nil {
if !c.wantErr {
t.Fatalf("authenticate token: %v", err)
@ -318,7 +319,7 @@ func (c *claimsTest) run(t *testing.T) {
t.Fatalf("expected authenticator to skip token")
}
gotUser := got.(*user.DefaultInfo)
gotUser := got.User.(*user.DefaultInfo)
if !reflect.DeepEqual(gotUser, c.want) {
t.Fatalf("wanted user=%#v, got=%#v", c.want, gotUser)
}

View File

@ -11,7 +11,10 @@ go_library(
srcs = ["tokentest.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest",
importpath = "k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest",
deps = ["//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library"],
deps = [
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
],
)
filegroup(

View File

@ -16,7 +16,12 @@ limitations under the License.
package tokentest
import "k8s.io/apiserver/pkg/authentication/user"
import (
"context"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
type TokenAuthenticator struct {
Tokens map[string]*user.DefaultInfo
@ -27,10 +32,11 @@ func New() *TokenAuthenticator {
Tokens: make(map[string]*user.DefaultInfo),
}
}
func (a *TokenAuthenticator) AuthenticateToken(value string) (user.Info, bool, error) {
func (a *TokenAuthenticator) AuthenticateToken(ctx context.Context, value string) (*authenticator.Response, bool, error) {
user, ok := a.Tokens[value]
if !ok {
return nil, false, nil
}
return user, true, nil
return &authenticator.Response{User: user}, true, nil
}

View File

@ -18,6 +18,7 @@ limitations under the License.
package webhook
import (
"context"
"time"
"github.com/golang/glog"
@ -69,7 +70,7 @@ func newWithBackoff(tokenReview authenticationclient.TokenReviewInterface, ttl,
}
// AuthenticateToken implements the authenticator.Token interface.
func (w *WebhookTokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, error) {
func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
r := &authentication.TokenReview{
Spec: authentication.TokenReviewSpec{Token: token},
}
@ -104,11 +105,13 @@ func (w *WebhookTokenAuthenticator) AuthenticateToken(token string) (user.Info,
}
}
return &user.DefaultInfo{
Name: r.Status.User.Username,
UID: r.Status.User.UID,
Groups: r.Status.User.Groups,
Extra: extra,
return &authenticator.Response{
User: &user.DefaultInfo{
Name: r.Status.User.Username,
UID: r.Status.User.UID,
Groups: r.Status.User.Groups,
Extra: extra,
},
}, true, nil
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package webhook
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
@ -257,7 +258,7 @@ func TestTLSConfig(t *testing.T) {
// Allow all and see if we get an error.
service.Allow()
_, authenticated, err := wh.AuthenticateToken("t0k3n")
_, authenticated, err := wh.AuthenticateToken(context.Background(), "t0k3n")
if tt.wantErr {
if err == nil {
t.Errorf("expected error making authorization request: %v", err)
@ -270,7 +271,7 @@ func TestTLSConfig(t *testing.T) {
}
service.Deny()
_, authenticated, err = wh.AuthenticateToken("t0k3n")
_, authenticated, err = wh.AuthenticateToken(context.Background(), "t0k3n")
if err != nil {
t.Errorf("%s: unexpectedly failed AuthenticateToken", tt.test)
}
@ -374,7 +375,7 @@ func TestWebhookTokenAuthenticator(t *testing.T) {
token := "my-s3cr3t-t0ken"
for i, tt := range tests {
serv.response = tt.serverResponse
user, authenticated, err := wh.AuthenticateToken(token)
resp, authenticated, err := wh.AuthenticateToken(context.Background(), token)
if err != nil {
t.Errorf("case %d: authentication failed: %v", i, err)
continue
@ -391,9 +392,9 @@ func TestWebhookTokenAuthenticator(t *testing.T) {
t.Errorf("case %d: Plugin returned incorrect authentication response. Got %t, expected %t.",
i, authenticated, tt.expectedAuthenticated)
}
if user != nil && tt.expectedUser != nil && !reflect.DeepEqual(user, tt.expectedUser) {
if resp != nil && tt.expectedUser != nil && !reflect.DeepEqual(resp.User, tt.expectedUser) {
t.Errorf("case %d: Plugin returned incorrect user. Got %#v, expected %#v",
i, user, tt.expectedUser)
i, resp.User, tt.expectedUser)
}
}
}
@ -540,12 +541,12 @@ func TestWebhookCacheAndRetry(t *testing.T) {
}
for _, testcase := range testcases {
func() {
t.Run(testcase.description, func(t *testing.T) {
serv.allow = testcase.allow
serv.statusCode = testcase.code
serv.called = 0
_, ok, err := wh.AuthenticateToken(testcase.token)
_, ok, err := wh.AuthenticateToken(context.Background(), testcase.token)
hasError := err != nil
if hasError != testcase.expectError {
t.Log(testcase.description)
@ -559,6 +560,6 @@ func TestWebhookCacheAndRetry(t *testing.T) {
t.Log(testcase.description)
t.Errorf("Expected ok=%v, got %v", testcase.expectOk, ok)
}
}()
})
}
}

View File

@ -46,9 +46,11 @@ func (sarAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, st
return authorizer.DecisionAllow, "you're not dave", nil
}
func alwaysAlice(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{
Name: "alice",
func alwaysAlice(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{
User: &user.DefaultInfo{
Name: "alice",
},
}, true, nil
}
@ -145,8 +147,10 @@ func TestSubjectAccessReview(t *testing.T) {
func TestSelfSubjectAccessReview(t *testing.T) {
username := "alice"
masterConfig := framework.NewIntegrationTestMasterConfig()
masterConfig.GenericConfig.Authentication.Authenticator = authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{Name: username}, true, nil
masterConfig.GenericConfig.Authentication.Authenticator = authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{
User: &user.DefaultInfo{Name: username},
}, true, nil
})
masterConfig.GenericConfig.Authorization.Authorizer = sarAuthorizer{}
_, s, closeFn := framework.RunAMaster(masterConfig)

View File

@ -83,9 +83,11 @@ func (alwaysAllow) Authorize(requestAttributes authorizer.Attributes) (authorize
}
// alwaysEmpty simulates "no authentication" for old tests
func alwaysEmpty(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{
Name: "",
func alwaysEmpty(req *http.Request) (*authauthenticator.Response, bool, error) {
return &authauthenticator.Response{
User: &user.DefaultInfo{
Name: "",
},
}, true, nil
}

View File

@ -21,6 +21,7 @@ package serviceaccount
// to work for any client of the HTTP interface.
import (
"context"
"crypto/rand"
"crypto/rsa"
"fmt"
@ -365,9 +366,9 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
// 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) {
rootTokenAuth := authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
if token == rootToken {
return &user.DefaultInfo{Name: rootUserName}, true, nil
return &authenticator.Response{User: &user.DefaultInfo{Name: rootUserName}}, true, nil
}
return nil, false, nil
})