mirror of https://github.com/k3s-io/k3s
Merge pull request #1529 from smarterclayton/add_auth_interfaces
Add simple Bearer authenticator filter for Kubepull/6/head
commit
5503e95c1d
|
@ -29,6 +29,9 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator/bearertoken"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator/tokenfile"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/handlers"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||
|
@ -51,6 +54,7 @@ var (
|
|||
minionPort = flag.Uint("minion_port", 10250, "The port at which kubelet will be listening on the minions.")
|
||||
healthCheckMinions = flag.Bool("health_check_minions", true, "If true, health check minions and filter unhealthy ones. Default true")
|
||||
minionCacheTTL = flag.Duration("minion_cache_ttl", 30*time.Second, "Duration of time to cache minion information. Default 30 seconds")
|
||||
tokenAuthFile = flag.String("token_auth_file", "", "If set, the file that will be used to secure the API server via token authentication")
|
||||
etcdServerList util.StringList
|
||||
machineList util.StringList
|
||||
corsAllowedOriginList util.StringList
|
||||
|
@ -172,6 +176,7 @@ func main() {
|
|||
ui.InstallSupport(mux)
|
||||
|
||||
handler := http.Handler(mux)
|
||||
|
||||
if len(corsAllowedOriginList) > 0 {
|
||||
allowedOriginRegexps, err := util.CompileRegexps(corsAllowedOriginList)
|
||||
if err != nil {
|
||||
|
@ -179,6 +184,16 @@ func main() {
|
|||
}
|
||||
handler = apiserver.CORS(handler, allowedOriginRegexps, nil, nil, "true")
|
||||
}
|
||||
|
||||
if len(*tokenAuthFile) != 0 {
|
||||
auth, err := tokenfile.New(*tokenAuthFile)
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to load the token authentication file '%s': %v", *tokenAuthFile, err)
|
||||
}
|
||||
userContexts := handlers.NewUserRequestContext()
|
||||
handler = handlers.NewRequestAuthenticator(userContexts, bearertoken.New(auth), handlers.Unauthorized, handler)
|
||||
}
|
||||
|
||||
handler = apiserver.RecoverPanics(handler)
|
||||
|
||||
s := &http.Server{
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package bearertoken
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||
)
|
||||
|
||||
type Authenticator struct {
|
||||
auth authenticator.Token
|
||||
}
|
||||
|
||||
func New(auth authenticator.Token) *Authenticator {
|
||||
return &Authenticator{auth}
|
||||
}
|
||||
|
||||
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||
auth := strings.TrimSpace(req.Header.Get("Authorization"))
|
||||
if auth == "" {
|
||||
return nil, false, nil
|
||||
}
|
||||
parts := strings.Split(auth, " ")
|
||||
if len(parts) < 2 || strings.ToLower(parts[0]) != "bearer" {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
token := parts[1]
|
||||
return a.auth.AuthenticateToken(token)
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package bearertoken
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||
)
|
||||
|
||||
func TestAuthenticateRequest(t *testing.T) {
|
||||
auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
|
||||
if token != "token" {
|
||||
t.Errorf("unexpected token: %s", token)
|
||||
}
|
||||
return &user.DefaultInfo{Name: "user"}, true, nil
|
||||
}))
|
||||
user, ok, err := auth.AuthenticateRequest(&http.Request{
|
||||
Header: http.Header{"Authorization": []string{"Bearer token"}},
|
||||
})
|
||||
if !ok || user == nil || err != nil {
|
||||
t.Errorf("expected valid user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthenticateRequestTokenInvalid(t *testing.T) {
|
||||
auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
|
||||
return nil, false, nil
|
||||
}))
|
||||
user, ok, err := auth.AuthenticateRequest(&http.Request{
|
||||
Header: http.Header{"Authorization": []string{"Bearer token"}},
|
||||
})
|
||||
if ok || user != nil || err != nil {
|
||||
t.Errorf("expected not authenticated user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthenticateRequestTokenError(t *testing.T) {
|
||||
auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
|
||||
return nil, false, errors.New("error")
|
||||
}))
|
||||
user, ok, err := auth.AuthenticateRequest(&http.Request{
|
||||
Header: http.Header{"Authorization": []string{"Bearer token"}},
|
||||
})
|
||||
if ok || user != nil || err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthenticateRequestBadValue(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Req *http.Request
|
||||
}{
|
||||
{Req: &http.Request{}},
|
||||
{Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer"}}}},
|
||||
{Req: &http.Request{Header: http.Header{"Authorization": []string{"bear token"}}}},
|
||||
{Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer: token"}}}},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
auth := New(authenticator.TokenFunc(func(token string) (user.Info, bool, error) {
|
||||
t.Errorf("authentication should not have been called")
|
||||
return nil, false, nil
|
||||
}))
|
||||
user, ok, err := auth.AuthenticateRequest(testCase.Req)
|
||||
if ok || user != nil || err != nil {
|
||||
t.Errorf("%d: expected not authenticated (no token)", i)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package authenticator
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/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.
|
||||
type Token interface {
|
||||
AuthenticateToken(token string) (user.Info, 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 token could not be checked.
|
||||
type Request interface {
|
||||
AuthenticateRequest(req *http.Request) (user.Info, bool, error)
|
||||
}
|
||||
|
||||
// TokenFunc is a function that implements the Token interface.
|
||||
type TokenFunc func(token string) (user.Info, bool, error)
|
||||
|
||||
// AuthenticateToken implements authenticator.Token.
|
||||
func (f TokenFunc) AuthenticateToken(token string) (user.Info, bool, error) {
|
||||
return f(token)
|
||||
}
|
||||
|
||||
// RequestFunc is a function that implements the Request interface.
|
||||
type RequestFunc func(req *http.Request) (user.Info, bool, error)
|
||||
|
||||
// AuthenticateRequest implements authenticator.Request.
|
||||
func (f RequestFunc) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||
return f(req)
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tokenfile
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||
)
|
||||
|
||||
type TokenAuthenticator struct {
|
||||
tokens map[string]*user.DefaultInfo
|
||||
}
|
||||
|
||||
func New(path string) (*TokenAuthenticator, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
tokens := make(map[string]*user.DefaultInfo)
|
||||
reader := csv.NewReader(file)
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(record) < 3 {
|
||||
return nil, fmt.Errorf("token file '%s' must have at least 3 columns (token, user name, user uid), found %d", path, len(record))
|
||||
}
|
||||
obj := &user.DefaultInfo{
|
||||
Name: record[1],
|
||||
UID: record[2],
|
||||
}
|
||||
tokens[record[0]] = obj
|
||||
}
|
||||
|
||||
return &TokenAuthenticator{
|
||||
tokens: tokens,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *TokenAuthenticator) AuthenticateToken(value string) (user.Info, bool, error) {
|
||||
user, ok := a.tokens[value]
|
||||
if !ok {
|
||||
return nil, false, nil
|
||||
}
|
||||
return user, true, nil
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tokenfile
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||
)
|
||||
|
||||
func TestTokenFile(t *testing.T) {
|
||||
auth, err := newWithContents(t, `
|
||||
token1,user1,uid1
|
||||
token2,user2,uid2
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to read tokenfile: %v", err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
Token string
|
||||
User *user.DefaultInfo
|
||||
Ok bool
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
Token: "token1",
|
||||
User: &user.DefaultInfo{Name: "user1", UID: "uid1"},
|
||||
Ok: true,
|
||||
},
|
||||
{
|
||||
Token: "token2",
|
||||
User: &user.DefaultInfo{Name: "user2", UID: "uid2"},
|
||||
Ok: true,
|
||||
},
|
||||
{
|
||||
Token: "token3",
|
||||
},
|
||||
{
|
||||
Token: "token4",
|
||||
},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
user, ok, err := auth.AuthenticateToken(testCase.Token)
|
||||
if testCase.User == nil {
|
||||
if user != nil {
|
||||
t.Errorf("%d: unexpected non-nil user %#v", i, user)
|
||||
}
|
||||
} else if !reflect.DeepEqual(testCase.User, user) {
|
||||
t.Errorf("%d: expected user %#v, got %#v", i, testCase.User, user)
|
||||
}
|
||||
if testCase.Ok != ok {
|
||||
t.Errorf("%d: expected auth %f, got %f", i, testCase.Ok, ok)
|
||||
}
|
||||
switch {
|
||||
case err == nil && testCase.Err:
|
||||
t.Errorf("%d: unexpected nil error", i)
|
||||
case err != nil && !testCase.Err:
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadTokenFile(t *testing.T) {
|
||||
_, err := newWithContents(t, `
|
||||
token1,user1,uid1
|
||||
token2,user2,uid2
|
||||
token3,user3
|
||||
token4
|
||||
`)
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsufficientColumnsTokenFile(t *testing.T) {
|
||||
_, err := newWithContents(t, "token4\n")
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non error")
|
||||
}
|
||||
}
|
||||
|
||||
func newWithContents(t *testing.T, contents string) (auth *TokenAuthenticator, err error) {
|
||||
f, err := ioutil.TempFile("", "tokenfile_test")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error creating tokenfile: %v", err)
|
||||
}
|
||||
f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
if err := ioutil.WriteFile(f.Name(), []byte(contents), 0700); err != nil {
|
||||
t.Fatalf("unexpected error writing tokenfile: %v", err)
|
||||
}
|
||||
|
||||
return New(f.Name())
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// RequestContext is the interface used to associate a user with an http Request.
|
||||
type RequestContext interface {
|
||||
Set(*http.Request, user.Info)
|
||||
Remove(*http.Request)
|
||||
}
|
||||
|
||||
// NewRequestAuthenticator creates an http handler that tries to authenticate the given request as a user, and then
|
||||
// stores any such user found onto the provided context for the request. If authentication fails or returns an error
|
||||
// the failed handler is used. On success, handler is invoked to serve the request.
|
||||
func NewRequestAuthenticator(context RequestContext, auth authenticator.Request, failed http.Handler, handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
user, 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)
|
||||
}
|
||||
failed.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
context.Set(req, user)
|
||||
defer context.Remove(req)
|
||||
|
||||
handler.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
|
||||
var Unauthorized http.HandlerFunc = unauthorized
|
||||
|
||||
// unauthorized serves an unauthorized message to clients.
|
||||
func unauthorized(w http.ResponseWriter, req *http.Request) {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
// UserRequestContext allows different levels of a call stack to store/retrieve info about the
|
||||
// current user associated with an http.Request.
|
||||
type UserRequestContext struct {
|
||||
requests map[*http.Request]user.Info
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// NewUserRequestContext provides a map for storing and retrieving users associated with requests.
|
||||
// Be sure to pair each `context.Set(req, user)` call with a `defer context.Remove(req)` call or
|
||||
// you will leak requests. It implements the RequestContext interface.
|
||||
func NewUserRequestContext() *UserRequestContext {
|
||||
return &UserRequestContext{
|
||||
requests: make(map[*http.Request]user.Info),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UserRequestContext) Get(req *http.Request) (user.Info, bool) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
user, ok := c.requests[req]
|
||||
return user, ok
|
||||
}
|
||||
|
||||
func (c *UserRequestContext) Set(req *http.Request, user user.Info) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
c.requests[req] = user
|
||||
}
|
||||
|
||||
func (c *UserRequestContext) Remove(req *http.Request) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
delete(c.requests, req)
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||
)
|
||||
|
||||
func TestAuthenticateRequest(t *testing.T) {
|
||||
success := make(chan struct{})
|
||||
context := NewUserRequestContext()
|
||||
auth := NewRequestAuthenticator(
|
||||
context,
|
||||
authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
|
||||
return &user.DefaultInfo{Name: "user"}, true, nil
|
||||
}),
|
||||
http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
t.Errorf("unexpected call to failed")
|
||||
}),
|
||||
http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {
|
||||
if user, ok := context.Get(req); user == nil || !ok {
|
||||
t.Errorf("no user stored on context: %#v", context)
|
||||
}
|
||||
close(success)
|
||||
}),
|
||||
)
|
||||
|
||||
auth.ServeHTTP(httptest.NewRecorder(), &http.Request{})
|
||||
|
||||
<-success
|
||||
if len(context.requests) > 0 {
|
||||
t.Errorf("context should have no stored requests", context)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthenticateRequestFailed(t *testing.T) {
|
||||
failed := make(chan struct{})
|
||||
context := NewUserRequestContext()
|
||||
auth := NewRequestAuthenticator(
|
||||
context,
|
||||
authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
|
||||
return nil, false, nil
|
||||
}),
|
||||
http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
close(failed)
|
||||
}),
|
||||
http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {
|
||||
t.Errorf("unexpected call to handler")
|
||||
}),
|
||||
)
|
||||
|
||||
auth.ServeHTTP(httptest.NewRecorder(), &http.Request{})
|
||||
|
||||
<-failed
|
||||
if len(context.requests) > 0 {
|
||||
t.Errorf("context should have no stored requests", context)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthenticateRequestError(t *testing.T) {
|
||||
failed := make(chan struct{})
|
||||
context := NewUserRequestContext()
|
||||
auth := NewRequestAuthenticator(
|
||||
context,
|
||||
authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
|
||||
return nil, false, errors.New("failure")
|
||||
}),
|
||||
http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
close(failed)
|
||||
}),
|
||||
http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {
|
||||
t.Errorf("unexpected call to handler")
|
||||
}),
|
||||
)
|
||||
|
||||
auth.ServeHTTP(httptest.NewRecorder(), &http.Request{})
|
||||
|
||||
<-failed
|
||||
if len(context.requests) > 0 {
|
||||
t.Errorf("context should have no stored requests", context)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package user contains utilities for dealing with simple user exchange in the auth
|
||||
// packages. The user.Info interface defines an interface for exchanging that info.
|
||||
package user
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package user
|
||||
|
||||
// UserInfo describes a user that has been authenticated to the system.
|
||||
type Info interface {
|
||||
// GetName returns the name that uniquely identifies this user among all
|
||||
// other active users.
|
||||
GetName() string
|
||||
// GetUID returns a unique value for a particular user that will change
|
||||
// if the user is removed from the system and another user is added with
|
||||
// the same name.
|
||||
GetUID() string
|
||||
}
|
||||
|
||||
// DefaultInfo provides a simple user information exchange object
|
||||
// for components that implement the UserInfo interface.
|
||||
type DefaultInfo struct {
|
||||
Name string
|
||||
UID string
|
||||
}
|
||||
|
||||
func (i *DefaultInfo) GetName() string {
|
||||
return i.Name
|
||||
}
|
||||
|
||||
func (i *DefaultInfo) GetUID() string {
|
||||
return i.UID
|
||||
}
|
Loading…
Reference in New Issue