mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 09:22:44 +00:00
Add basicauth and password authenticators
This commit is contained in:
parent
e82b88fed8
commit
3532be3c82
@ -31,11 +31,18 @@ type Token interface {
|
|||||||
|
|
||||||
// Request attempts to extract authentication information from a request and returns
|
// Request attempts to extract authentication information from a request and returns
|
||||||
// information about the current user and true if successful, false if not successful,
|
// information about the current user and true if successful, false if not successful,
|
||||||
// or an error if the token could not be checked.
|
// or an error if the request could not be checked.
|
||||||
type Request interface {
|
type Request interface {
|
||||||
AuthenticateRequest(req *http.Request) (user.Info, bool, error)
|
AuthenticateRequest(req *http.Request) (user.Info, 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
|
||||||
|
type Password interface {
|
||||||
|
AuthenticatePassword(user, password string) (user.Info, bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
// TokenFunc is a function that implements the Token interface.
|
// TokenFunc is a function that implements the Token interface.
|
||||||
type TokenFunc func(token string) (user.Info, bool, error)
|
type TokenFunc func(token string) (user.Info, bool, error)
|
||||||
|
|
||||||
@ -51,3 +58,11 @@ type RequestFunc func(req *http.Request) (user.Info, bool, error)
|
|||||||
func (f RequestFunc) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
func (f RequestFunc) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||||
return f(req)
|
return f(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PasswordFunc is a function that implements the Password interface.
|
||||||
|
type PasswordFunc func(user, password string) (user.Info, bool, error)
|
||||||
|
|
||||||
|
// AuthenticatePassword implements authenticator.Password.
|
||||||
|
func (f PasswordFunc) AuthenticatePassword(user, password string) (user.Info, bool, error) {
|
||||||
|
return f(user, password)
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||||||
|
|
||||||
package user
|
package user
|
||||||
|
|
||||||
// UserInfo describes a user that has been authenticated to the system.
|
// Info describes a user that has been authenticated to the system.
|
||||||
type Info interface {
|
type Info interface {
|
||||||
// GetName returns the name that uniquely identifies this user among all
|
// GetName returns the name that uniquely identifies this user among all
|
||||||
// other active users.
|
// other active users.
|
||||||
|
18
plugin/pkg/auth/authenticator/doc.go
Normal file
18
plugin/pkg/auth/authenticator/doc.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
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 contains implementations for pkg/auth/authenticator interfaces
|
||||||
|
package authenticator
|
38
plugin/pkg/auth/authenticator/password/allow/allow.go
Normal file
38
plugin/pkg/auth/authenticator/password/allow/allow.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
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 allow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type allowAuthenticator struct{}
|
||||||
|
|
||||||
|
// NewAllow returns a password authenticator that allows any non-empty username
|
||||||
|
func NewAllow() authenticator.Password {
|
||||||
|
return allowAuthenticator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticatePassword implements authenticator.Password to allow any non-empty username,
|
||||||
|
// using the specified username as the name and UID
|
||||||
|
func (allowAuthenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
|
||||||
|
if username == "" {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
return &user.DefaultInfo{Name: username, UID: username}, true, nil
|
||||||
|
}
|
47
plugin/pkg/auth/authenticator/password/allow/allow_test.go
Normal file
47
plugin/pkg/auth/authenticator/password/allow/allow_test.go
Normal file
@ -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 allow
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestAllowEmpty(t *testing.T) {
|
||||||
|
allow := NewAllow()
|
||||||
|
user, ok, err := allow.AuthenticatePassword("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
t.Fatalf("Unexpected success")
|
||||||
|
}
|
||||||
|
if user != nil {
|
||||||
|
t.Fatalf("Unexpected user: %v", user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllowPresent(t *testing.T) {
|
||||||
|
allow := NewAllow()
|
||||||
|
user, ok, err := allow.AuthenticatePassword("myuser", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Unexpected failure")
|
||||||
|
}
|
||||||
|
if user.GetName() != "myuser" || user.GetUID() != "myuser" {
|
||||||
|
t.Fatalf("Unexpected user name or uid: %v", user)
|
||||||
|
}
|
||||||
|
}
|
18
plugin/pkg/auth/authenticator/password/doc.go
Normal file
18
plugin/pkg/auth/authenticator/password/doc.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
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 password contains authenticator.Password implementations
|
||||||
|
package password
|
63
plugin/pkg/auth/authenticator/request/basicauth/basicauth.go
Normal file
63
plugin/pkg/auth/authenticator/request/basicauth/basicauth.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
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 basicauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Authenticator authenticates requests using basic auth
|
||||||
|
type Authenticator struct {
|
||||||
|
auth authenticator.Password
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a request authenticator that validates credentials using the provided password authenticator
|
||||||
|
func New(auth authenticator.Password) *Authenticator {
|
||||||
|
return &Authenticator{auth}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticateRequest authenticates the request using the "Authorization: Basic" header in the request
|
||||||
|
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]) != "basic" {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := base64.StdEncoding.DecodeString(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pair := strings.SplitN(string(payload), ":", 2)
|
||||||
|
if len(pair) != 2 {
|
||||||
|
return nil, false, errors.New("malformed basic auth header")
|
||||||
|
}
|
||||||
|
|
||||||
|
username := pair[0]
|
||||||
|
password := pair[1]
|
||||||
|
return a.auth.AuthenticatePassword(username, password)
|
||||||
|
}
|
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
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 basicauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testPassword struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Called bool
|
||||||
|
|
||||||
|
User user.Info
|
||||||
|
OK bool
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testPassword) AuthenticatePassword(user, password string) (user.Info, bool, error) {
|
||||||
|
t.Called = true
|
||||||
|
t.Username = user
|
||||||
|
t.Password = password
|
||||||
|
return t.User, t.OK, t.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBasicAuth(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
Header string
|
||||||
|
Password testPassword
|
||||||
|
|
||||||
|
ExpectedCalled bool
|
||||||
|
ExpectedUsername string
|
||||||
|
ExpectedPassword string
|
||||||
|
|
||||||
|
ExpectedUser string
|
||||||
|
ExpectedOK bool
|
||||||
|
ExpectedErr bool
|
||||||
|
}{
|
||||||
|
"no header": {
|
||||||
|
Header: "",
|
||||||
|
},
|
||||||
|
"non-basic header": {
|
||||||
|
Header: "Bearer foo",
|
||||||
|
},
|
||||||
|
"empty value basic header": {
|
||||||
|
Header: "Basic",
|
||||||
|
},
|
||||||
|
"whitespace value basic header": {
|
||||||
|
Header: "Basic ",
|
||||||
|
},
|
||||||
|
"non base-64 basic header": {
|
||||||
|
Header: "Basic !@#$",
|
||||||
|
ExpectedErr: true,
|
||||||
|
},
|
||||||
|
"malformed basic header": {
|
||||||
|
Header: "Basic " + base64.StdEncoding.EncodeToString([]byte("user_without_password")),
|
||||||
|
ExpectedErr: true,
|
||||||
|
},
|
||||||
|
"empty password basic header": {
|
||||||
|
Header: "Basic " + base64.StdEncoding.EncodeToString([]byte("user_with_empty_password:")),
|
||||||
|
ExpectedCalled: true,
|
||||||
|
ExpectedUsername: "user_with_empty_password",
|
||||||
|
ExpectedPassword: "",
|
||||||
|
},
|
||||||
|
"valid basic header": {
|
||||||
|
Header: "Basic " + base64.StdEncoding.EncodeToString([]byte("myuser:mypassword:withcolon")),
|
||||||
|
ExpectedCalled: true,
|
||||||
|
ExpectedUsername: "myuser",
|
||||||
|
ExpectedPassword: "mypassword:withcolon",
|
||||||
|
},
|
||||||
|
"password auth returned user": {
|
||||||
|
Header: "Basic " + base64.StdEncoding.EncodeToString([]byte("myuser:mypw")),
|
||||||
|
Password: testPassword{User: &user.DefaultInfo{Name: "returneduser"}, OK: true},
|
||||||
|
ExpectedCalled: true,
|
||||||
|
ExpectedUsername: "myuser",
|
||||||
|
ExpectedPassword: "mypw",
|
||||||
|
ExpectedUser: "returneduser",
|
||||||
|
ExpectedOK: true,
|
||||||
|
},
|
||||||
|
"password auth returned error": {
|
||||||
|
Header: "Basic " + base64.StdEncoding.EncodeToString([]byte("myuser:mypw")),
|
||||||
|
Password: testPassword{Err: errors.New("auth error")},
|
||||||
|
ExpectedCalled: true,
|
||||||
|
ExpectedUsername: "myuser",
|
||||||
|
ExpectedPassword: "mypw",
|
||||||
|
ExpectedErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, testCase := range testCases {
|
||||||
|
password := testCase.Password
|
||||||
|
auth := authenticator.Request(New(&password))
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", "/", nil)
|
||||||
|
if testCase.Header != "" {
|
||||||
|
req.Header.Set("Authorization", testCase.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, ok, err := auth.AuthenticateRequest(req)
|
||||||
|
|
||||||
|
if testCase.ExpectedCalled != password.Called {
|
||||||
|
t.Fatalf("%s: Expected called=%v, got %v", k, testCase.ExpectedCalled, password.Called)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if testCase.ExpectedUsername != password.Username {
|
||||||
|
t.Fatalf("%s: Expected called with username=%v, got %v", k, testCase.ExpectedUsername, password.Username)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if testCase.ExpectedPassword != password.Password {
|
||||||
|
t.Fatalf("%s: Expected called with password=%v, got %v", k, testCase.ExpectedPassword, password.Password)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if testCase.ExpectedErr != (err != nil) {
|
||||||
|
t.Fatalf("%s: Expected err=%v, got err=%v", k, testCase.ExpectedErr, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if testCase.ExpectedOK != ok {
|
||||||
|
t.Fatalf("%s: Expected ok=%v, got ok=%v", k, testCase.ExpectedOK, ok)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if testCase.ExpectedUser != "" && testCase.ExpectedUser != user.GetName() {
|
||||||
|
t.Fatalf("%s: Expected user.GetName()=%v, got %v", k, testCase.ExpectedUser, user.GetName())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
plugin/pkg/auth/doc.go
Normal file
18
plugin/pkg/auth/doc.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
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 auth contains implementations for interfaces in the pkg/auth package
|
||||||
|
package auth
|
Loading…
Reference in New Issue
Block a user