120
vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go
generated
vendored
Normal file
120
vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 authenticatorfactory
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/group"
|
||||
"k8s.io/apiserver/pkg/authentication/request/anonymous"
|
||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
||||
"k8s.io/apiserver/pkg/authentication/request/headerrequest"
|
||||
unionauth "k8s.io/apiserver/pkg/authentication/request/union"
|
||||
"k8s.io/apiserver/pkg/authentication/request/websocket"
|
||||
"k8s.io/apiserver/pkg/authentication/request/x509"
|
||||
"k8s.io/apiserver/pkg/authentication/token/cache"
|
||||
webhooktoken "k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
|
||||
authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1"
|
||||
"k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
// DelegatingAuthenticatorConfig is the minimal configuration needed to create an authenticator
|
||||
// built to delegate authentication to a kube API server
|
||||
type DelegatingAuthenticatorConfig struct {
|
||||
Anonymous bool
|
||||
|
||||
// TokenAccessReviewClient is a client to do token review. It can be nil. Then every token is ignored.
|
||||
TokenAccessReviewClient authenticationclient.TokenReviewInterface
|
||||
|
||||
// CacheTTL is the length of time that a token authentication answer will be cached.
|
||||
CacheTTL time.Duration
|
||||
|
||||
// ClientCAFile is the CA bundle file used to authenticate client certificates
|
||||
ClientCAFile string
|
||||
|
||||
APIAudiences authenticator.Audiences
|
||||
|
||||
RequestHeaderConfig *RequestHeaderConfig
|
||||
}
|
||||
|
||||
func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDefinitions, error) {
|
||||
authenticators := []authenticator.Request{}
|
||||
securityDefinitions := spec.SecurityDefinitions{}
|
||||
|
||||
// front-proxy first, then remote
|
||||
// Add the front proxy authenticator if requested
|
||||
if c.RequestHeaderConfig != nil {
|
||||
requestHeaderAuthenticator, err := headerrequest.NewSecure(
|
||||
c.RequestHeaderConfig.ClientCA,
|
||||
c.RequestHeaderConfig.AllowedClientNames,
|
||||
c.RequestHeaderConfig.UsernameHeaders,
|
||||
c.RequestHeaderConfig.GroupHeaders,
|
||||
c.RequestHeaderConfig.ExtraHeaderPrefixes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
authenticators = append(authenticators, requestHeaderAuthenticator)
|
||||
}
|
||||
|
||||
// x509 client cert auth
|
||||
if len(c.ClientCAFile) > 0 {
|
||||
clientCAs, err := cert.NewPool(c.ClientCAFile)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to load client CA file %s: %v", c.ClientCAFile, err)
|
||||
}
|
||||
verifyOpts := x509.DefaultVerifyOptions()
|
||||
verifyOpts.Roots = clientCAs
|
||||
authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion))
|
||||
}
|
||||
|
||||
if c.TokenAccessReviewClient != nil {
|
||||
tokenAuth, err := webhooktoken.NewFromInterface(c.TokenAccessReviewClient, c.APIAudiences)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cachingTokenAuth := cache.New(tokenAuth, false, c.CacheTTL, c.CacheTTL)
|
||||
authenticators = append(authenticators, bearertoken.New(cachingTokenAuth), websocket.NewProtocolAuthenticator(cachingTokenAuth))
|
||||
|
||||
securityDefinitions["BearerToken"] = &spec.SecurityScheme{
|
||||
SecuritySchemeProps: spec.SecuritySchemeProps{
|
||||
Type: "apiKey",
|
||||
Name: "authorization",
|
||||
In: "header",
|
||||
Description: "Bearer Token authentication",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if len(authenticators) == 0 {
|
||||
if c.Anonymous {
|
||||
return anonymous.NewAuthenticator(), &securityDefinitions, nil
|
||||
}
|
||||
return nil, nil, errors.New("No authentication method configured")
|
||||
}
|
||||
|
||||
authenticator := group.NewAuthenticatedGroupAdder(unionauth.New(authenticators...))
|
||||
if c.Anonymous {
|
||||
authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
|
||||
}
|
||||
return authenticator, &securityDefinitions, nil
|
||||
}
|
||||
29
vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/loopback.go
generated
vendored
Normal file
29
vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/loopback.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 authenticatorfactory
|
||||
|
||||
import (
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
||||
"k8s.io/apiserver/pkg/authentication/token/tokenfile"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
// NewFromTokens returns an authenticator.Request or an error
|
||||
func NewFromTokens(tokens map[string]*user.DefaultInfo) authenticator.Request {
|
||||
return bearertoken.New(tokenfile.New(tokens))
|
||||
}
|
||||
31
vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go
generated
vendored
Normal file
31
vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
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 authenticatorfactory
|
||||
|
||||
type RequestHeaderConfig struct {
|
||||
// UsernameHeaders are the headers to check (in order, case-insensitively) for an identity. The first header with a value wins.
|
||||
UsernameHeaders []string
|
||||
// GroupHeaders are the headers to check (case-insensitively) for a group names. All values will be used.
|
||||
GroupHeaders []string
|
||||
// ExtraHeaderPrefixes are the head prefixes to check (case-insentively) for filling in
|
||||
// the user.Info.Extra. All values of all matching headers will be added.
|
||||
ExtraHeaderPrefixes []string
|
||||
// ClientCA points to CA bundle file which is used verify the identity of the front proxy
|
||||
ClientCA string
|
||||
// AllowedClientNames is a list of common names that may be presented by the authenticating front proxy. Empty means: accept any.
|
||||
AllowedClientNames []string
|
||||
}
|
||||
61
vendor/k8s.io/apiserver/pkg/authentication/group/authenticated_group_adder.go
generated
vendored
Normal file
61
vendor/k8s.io/apiserver/pkg/authentication/group/authenticated_group_adder.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 group
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
// AuthenticatedGroupAdder adds system:authenticated group when appropriate
|
||||
type AuthenticatedGroupAdder struct {
|
||||
// Authenticator is delegated to make the authentication decision
|
||||
Authenticator authenticator.Request
|
||||
}
|
||||
|
||||
// NewAuthenticatedGroupAdder wraps a request authenticator, and adds the system:authenticated group when appropriate.
|
||||
// Authentication must succeed, the user must not be system:anonymous, the groups system:authenticated or system:unauthenticated must
|
||||
// not be present
|
||||
func NewAuthenticatedGroupAdder(auth authenticator.Request) authenticator.Request {
|
||||
return &AuthenticatedGroupAdder{auth}
|
||||
}
|
||||
|
||||
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 r.User.GetName() == user.Anonymous {
|
||||
return r, true, nil
|
||||
}
|
||||
for _, group := range r.User.GetGroups() {
|
||||
if group == user.AllAuthenticated || group == user.AllUnauthenticated {
|
||||
return r, 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
|
||||
}
|
||||
51
vendor/k8s.io/apiserver/pkg/authentication/group/group_adder.go
generated
vendored
Normal file
51
vendor/k8s.io/apiserver/pkg/authentication/group/group_adder.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 group
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
// GroupAdder adds groups to an authenticated user.Info
|
||||
type GroupAdder struct {
|
||||
// Authenticator is delegated to make the authentication decision
|
||||
Authenticator authenticator.Request
|
||||
// Groups are additional groups to add to the user.Info from a successful authentication
|
||||
Groups []string
|
||||
}
|
||||
|
||||
// NewGroupAdder wraps a request authenticator, and adds the specified groups to the returned user when authentication succeeds
|
||||
func NewGroupAdder(auth authenticator.Request, groups []string) authenticator.Request {
|
||||
return &GroupAdder{auth, groups}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
51
vendor/k8s.io/apiserver/pkg/authentication/group/token_group_adder.go
generated
vendored
Normal file
51
vendor/k8s.io/apiserver/pkg/authentication/group/token_group_adder.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 group
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
// TokenGroupAdder adds groups to an authenticated user.Info
|
||||
type TokenGroupAdder struct {
|
||||
// Authenticator is delegated to make the authentication decision
|
||||
Authenticator authenticator.Token
|
||||
// Groups are additional groups to add to the user.Info from a successful authentication
|
||||
Groups []string
|
||||
}
|
||||
|
||||
// NewTokenGroupAdder wraps a token authenticator, and adds the specified groups to the returned user when authentication succeeds
|
||||
func NewTokenGroupAdder(auth authenticator.Token, groups []string) authenticator.Token {
|
||||
return &TokenGroupAdder{auth, groups}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
43
vendor/k8s.io/apiserver/pkg/authentication/request/anonymous/anonymous.go
generated
vendored
Normal file
43
vendor/k8s.io/apiserver/pkg/authentication/request/anonymous/anonymous.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 anonymous
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
const (
|
||||
anonymousUser = user.Anonymous
|
||||
|
||||
unauthenticatedGroup = user.AllUnauthenticated
|
||||
)
|
||||
|
||||
func NewAuthenticator() authenticator.Request {
|
||||
return authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
|
||||
auds, _ := authenticator.AudiencesFrom(req.Context())
|
||||
return &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: anonymousUser,
|
||||
Groups: []string{unauthenticatedGroup},
|
||||
},
|
||||
Audiences: auds,
|
||||
}, true, nil
|
||||
})
|
||||
}
|
||||
67
vendor/k8s.io/apiserver/pkg/authentication/request/bearertoken/bearertoken.go
generated
vendored
Normal file
67
vendor/k8s.io/apiserver/pkg/authentication/request/bearertoken/bearertoken.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
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"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
)
|
||||
|
||||
type Authenticator struct {
|
||||
auth authenticator.Token
|
||||
}
|
||||
|
||||
func New(auth authenticator.Token) *Authenticator {
|
||||
return &Authenticator{auth}
|
||||
}
|
||||
|
||||
var invalidToken = errors.New("invalid bearer token")
|
||||
|
||||
func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, 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]
|
||||
|
||||
// Empty bearer tokens aren't valid
|
||||
if len(token) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
req.Header.Del("Authorization")
|
||||
}
|
||||
|
||||
// If the token authenticator didn't error, provide a default error
|
||||
if !ok && err == nil {
|
||||
err = invalidToken
|
||||
}
|
||||
|
||||
return resp, ok, err
|
||||
}
|
||||
190
vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go
generated
vendored
Normal file
190
vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 headerrequest
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
x509request "k8s.io/apiserver/pkg/authentication/request/x509"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
utilcert "k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
type requestHeaderAuthRequestHandler struct {
|
||||
// nameHeaders are the headers to check (in order, case-insensitively) for an identity. The first header with a value wins.
|
||||
nameHeaders []string
|
||||
|
||||
// groupHeaders are the headers to check (case-insensitively) for group membership. All values of all headers will be added.
|
||||
groupHeaders []string
|
||||
|
||||
// extraHeaderPrefixes are the head prefixes to check (case-insensitively) for filling in
|
||||
// the user.Info.Extra. All values of all matching headers will be added.
|
||||
extraHeaderPrefixes []string
|
||||
}
|
||||
|
||||
func New(nameHeaders []string, groupHeaders []string, extraHeaderPrefixes []string) (authenticator.Request, error) {
|
||||
trimmedNameHeaders, err := trimHeaders(nameHeaders...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trimmedGroupHeaders, err := trimHeaders(groupHeaders...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trimmedExtraHeaderPrefixes, err := trimHeaders(extraHeaderPrefixes...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &requestHeaderAuthRequestHandler{
|
||||
nameHeaders: trimmedNameHeaders,
|
||||
groupHeaders: trimmedGroupHeaders,
|
||||
extraHeaderPrefixes: trimmedExtraHeaderPrefixes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func trimHeaders(headerNames ...string) ([]string, error) {
|
||||
ret := []string{}
|
||||
for _, headerName := range headerNames {
|
||||
trimmedHeader := strings.TrimSpace(headerName)
|
||||
if len(trimmedHeader) == 0 {
|
||||
return nil, fmt.Errorf("empty header %q", headerName)
|
||||
}
|
||||
ret = append(ret, trimmedHeader)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func NewSecure(clientCA string, proxyClientNames []string, nameHeaders []string, groupHeaders []string, extraHeaderPrefixes []string) (authenticator.Request, error) {
|
||||
headerAuthenticator, err := New(nameHeaders, groupHeaders, extraHeaderPrefixes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(clientCA) == 0 {
|
||||
return nil, fmt.Errorf("missing clientCA file")
|
||||
}
|
||||
|
||||
// Wrap with an x509 verifier
|
||||
caData, err := ioutil.ReadFile(clientCA)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %v", clientCA, err)
|
||||
}
|
||||
opts := x509request.DefaultVerifyOptions()
|
||||
opts.Roots = x509.NewCertPool()
|
||||
certs, err := utilcert.ParseCertsPEM(caData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading certs from %s: %v", clientCA, err)
|
||||
}
|
||||
for _, cert := range certs {
|
||||
opts.Roots.AddCert(cert)
|
||||
}
|
||||
|
||||
return x509request.NewVerifier(opts, headerAuthenticator, sets.NewString(proxyClientNames...)), nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
groups := allHeaderValues(req.Header, a.groupHeaders)
|
||||
extra := newExtra(req.Header, a.extraHeaderPrefixes)
|
||||
|
||||
// clear headers used for authentication
|
||||
for _, headerName := range a.nameHeaders {
|
||||
req.Header.Del(headerName)
|
||||
}
|
||||
for _, headerName := range a.groupHeaders {
|
||||
req.Header.Del(headerName)
|
||||
}
|
||||
for k := range extra {
|
||||
for _, prefix := range a.extraHeaderPrefixes {
|
||||
req.Header.Del(prefix + k)
|
||||
}
|
||||
}
|
||||
|
||||
return &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: name,
|
||||
Groups: groups,
|
||||
Extra: extra,
|
||||
},
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
func headerValue(h http.Header, headerNames []string) string {
|
||||
for _, headerName := range headerNames {
|
||||
headerValue := h.Get(headerName)
|
||||
if len(headerValue) > 0 {
|
||||
return headerValue
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func allHeaderValues(h http.Header, headerNames []string) []string {
|
||||
ret := []string{}
|
||||
for _, headerName := range headerNames {
|
||||
headerKey := http.CanonicalHeaderKey(headerName)
|
||||
values, ok := h[headerKey]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, headerValue := range values {
|
||||
if len(headerValue) > 0 {
|
||||
ret = append(ret, headerValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func unescapeExtraKey(encodedKey string) string {
|
||||
key, err := url.PathUnescape(encodedKey) // Decode %-encoded bytes.
|
||||
if err != nil {
|
||||
return encodedKey // Always record extra strings, even if malformed/unencoded.
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func newExtra(h http.Header, headerPrefixes []string) map[string][]string {
|
||||
ret := map[string][]string{}
|
||||
|
||||
// we have to iterate over prefixes first in order to have proper ordering inside the value slices
|
||||
for _, prefix := range headerPrefixes {
|
||||
for headerName, vv := range h {
|
||||
if !strings.HasPrefix(strings.ToLower(headerName), strings.ToLower(prefix)) {
|
||||
continue
|
||||
}
|
||||
|
||||
extraKey := unescapeExtraKey(strings.ToLower(headerName[len(prefix):]))
|
||||
ret[extraKey] = append(ret[extraKey], vv...)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
71
vendor/k8s.io/apiserver/pkg/authentication/request/union/union.go
generated
vendored
Normal file
71
vendor/k8s.io/apiserver/pkg/authentication/request/union/union.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
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 union
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
)
|
||||
|
||||
// unionAuthRequestHandler authenticates requests using a chain of authenticator.Requests
|
||||
type unionAuthRequestHandler struct {
|
||||
// Handlers is a chain of request authenticators to delegate to
|
||||
Handlers []authenticator.Request
|
||||
// FailOnError determines whether an error returns short-circuits the chain
|
||||
FailOnError bool
|
||||
}
|
||||
|
||||
// New returns a request authenticator that validates credentials using a chain of authenticator.Request objects.
|
||||
// The entire chain is tried until one succeeds. If all fail, an aggregate error is returned.
|
||||
func New(authRequestHandlers ...authenticator.Request) authenticator.Request {
|
||||
if len(authRequestHandlers) == 1 {
|
||||
return authRequestHandlers[0]
|
||||
}
|
||||
return &unionAuthRequestHandler{Handlers: authRequestHandlers, FailOnError: false}
|
||||
}
|
||||
|
||||
// NewFailOnError returns a request authenticator that validates credentials using a chain of authenticator.Request objects.
|
||||
// The first error short-circuits the chain.
|
||||
func NewFailOnError(authRequestHandlers ...authenticator.Request) authenticator.Request {
|
||||
if len(authRequestHandlers) == 1 {
|
||||
return authRequestHandlers[0]
|
||||
}
|
||||
return &unionAuthRequestHandler{Handlers: authRequestHandlers, FailOnError: true}
|
||||
}
|
||||
|
||||
// AuthenticateRequest authenticates the request using a chain of authenticator.Request objects.
|
||||
func (authHandler *unionAuthRequestHandler) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
|
||||
var errlist []error
|
||||
for _, currAuthRequestHandler := range authHandler.Handlers {
|
||||
resp, ok, err := currAuthRequestHandler.AuthenticateRequest(req)
|
||||
if err != nil {
|
||||
if authHandler.FailOnError {
|
||||
return resp, ok, err
|
||||
}
|
||||
errlist = append(errlist, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if ok {
|
||||
return resp, ok, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false, utilerrors.NewAggregate(errlist)
|
||||
}
|
||||
108
vendor/k8s.io/apiserver/pkg/authentication/request/websocket/protocol.go
generated
vendored
Normal file
108
vendor/k8s.io/apiserver/pkg/authentication/request/websocket/protocol.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 websocket
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/util/wsstream"
|
||||
)
|
||||
|
||||
const bearerProtocolPrefix = "base64url.bearer.authorization.k8s.io."
|
||||
|
||||
var protocolHeader = textproto.CanonicalMIMEHeaderKey("Sec-WebSocket-Protocol")
|
||||
|
||||
var errInvalidToken = errors.New("invalid bearer token")
|
||||
|
||||
// ProtocolAuthenticator allows a websocket connection to provide a bearer token as a subprotocol
|
||||
// in the format "base64url.bearer.authorization.<base64url-without-padding(bearer-token)>"
|
||||
type ProtocolAuthenticator struct {
|
||||
// auth is the token authenticator to use to validate the token
|
||||
auth authenticator.Token
|
||||
}
|
||||
|
||||
func NewProtocolAuthenticator(auth authenticator.Token) *ProtocolAuthenticator {
|
||||
return &ProtocolAuthenticator{auth}
|
||||
}
|
||||
|
||||
func (a *ProtocolAuthenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
|
||||
// Only accept websocket connections
|
||||
if !wsstream.IsWebSocketRequest(req) {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
token := ""
|
||||
sawTokenProtocol := false
|
||||
filteredProtocols := []string{}
|
||||
for _, protocolHeader := range req.Header[protocolHeader] {
|
||||
for _, protocol := range strings.Split(protocolHeader, ",") {
|
||||
protocol = strings.TrimSpace(protocol)
|
||||
|
||||
if !strings.HasPrefix(protocol, bearerProtocolPrefix) {
|
||||
filteredProtocols = append(filteredProtocols, protocol)
|
||||
continue
|
||||
}
|
||||
|
||||
if sawTokenProtocol {
|
||||
return nil, false, errors.New("multiple base64.bearer.authorization tokens specified")
|
||||
}
|
||||
sawTokenProtocol = true
|
||||
|
||||
encodedToken := strings.TrimPrefix(protocol, bearerProtocolPrefix)
|
||||
decodedToken, err := base64.RawURLEncoding.DecodeString(encodedToken)
|
||||
if err != nil {
|
||||
return nil, false, errors.New("invalid base64.bearer.authorization token encoding")
|
||||
}
|
||||
if !utf8.Valid(decodedToken) {
|
||||
return nil, false, errors.New("invalid base64.bearer.authorization token")
|
||||
}
|
||||
token = string(decodedToken)
|
||||
}
|
||||
}
|
||||
|
||||
// Must pass at least one other subprotocol so that we can remove the one containing the bearer token,
|
||||
// and there is at least one to echo back to the client
|
||||
if len(token) > 0 && len(filteredProtocols) == 0 {
|
||||
return nil, false, errors.New("missing additional subprotocol")
|
||||
}
|
||||
|
||||
if len(token) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
resp, ok, err := a.auth.AuthenticateToken(req.Context(), token)
|
||||
|
||||
// on success, remove the protocol with the token
|
||||
if ok {
|
||||
// https://tools.ietf.org/html/rfc6455#section-11.3.4 indicates the Sec-WebSocket-Protocol header may appear multiple times
|
||||
// in a request, and is logically the same as a single Sec-WebSocket-Protocol header field that contains all values
|
||||
req.Header.Set(protocolHeader, strings.Join(filteredProtocols, ","))
|
||||
}
|
||||
|
||||
// If the token authenticator didn't error, provide a default error
|
||||
if !ok && err == nil {
|
||||
err = errInvalidToken
|
||||
}
|
||||
|
||||
return resp, ok, err
|
||||
}
|
||||
7
vendor/k8s.io/apiserver/pkg/authentication/request/x509/OWNERS
generated
vendored
Normal file
7
vendor/k8s.io/apiserver/pkg/authentication/request/x509/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
approvers:
|
||||
- sig-auth-certificates-approvers
|
||||
reviewers:
|
||||
- sig-auth-certificates-reviewers
|
||||
labels:
|
||||
- sig/auth
|
||||
|
||||
19
vendor/k8s.io/apiserver/pkg/authentication/request/x509/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/apiserver/pkg/authentication/request/x509/doc.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
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 x509 provides a request authenticator that validates and
|
||||
// extracts user information from client certificates
|
||||
package x509 // import "k8s.io/apiserver/pkg/authentication/request/x509"
|
||||
192
vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go
generated
vendored
Normal file
192
vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
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 x509
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
var clientCertificateExpirationHistogram = prometheus.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Namespace: "apiserver",
|
||||
Subsystem: "client",
|
||||
Name: "certificate_expiration_seconds",
|
||||
Help: "Distribution of the remaining lifetime on the certificate used to authenticate a request.",
|
||||
Buckets: []float64{
|
||||
0,
|
||||
(6 * time.Hour).Seconds(),
|
||||
(12 * time.Hour).Seconds(),
|
||||
(24 * time.Hour).Seconds(),
|
||||
(2 * 24 * time.Hour).Seconds(),
|
||||
(4 * 24 * time.Hour).Seconds(),
|
||||
(7 * 24 * time.Hour).Seconds(),
|
||||
(30 * 24 * time.Hour).Seconds(),
|
||||
(3 * 30 * 24 * time.Hour).Seconds(),
|
||||
(6 * 30 * 24 * time.Hour).Seconds(),
|
||||
(12 * 30 * 24 * time.Hour).Seconds(),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
func init() {
|
||||
prometheus.MustRegister(clientCertificateExpirationHistogram)
|
||||
}
|
||||
|
||||
// UserConversion defines an interface for extracting user info from a client certificate chain
|
||||
type UserConversion interface {
|
||||
User(chain []*x509.Certificate) (*authenticator.Response, bool, error)
|
||||
}
|
||||
|
||||
// UserConversionFunc is a function that implements the UserConversion interface.
|
||||
type UserConversionFunc func(chain []*x509.Certificate) (*authenticator.Response, bool, error)
|
||||
|
||||
// User implements x509.UserConversion
|
||||
func (f UserConversionFunc) User(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
|
||||
return f(chain)
|
||||
}
|
||||
|
||||
// Authenticator implements request.Authenticator by extracting user info from verified client certificates
|
||||
type Authenticator struct {
|
||||
opts x509.VerifyOptions
|
||||
user UserConversion
|
||||
}
|
||||
|
||||
// New returns a request.Authenticator that verifies client certificates using the provided
|
||||
// VerifyOptions, and converts valid certificate chains into user.Info using the provided UserConversion
|
||||
func New(opts x509.VerifyOptions, user UserConversion) *Authenticator {
|
||||
return &Authenticator{opts, user}
|
||||
}
|
||||
|
||||
// AuthenticateRequest authenticates the request using presented client certificates
|
||||
func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
|
||||
if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
// Use intermediates, if provided
|
||||
optsCopy := a.opts
|
||||
if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
|
||||
optsCopy.Intermediates = x509.NewCertPool()
|
||||
for _, intermediate := range req.TLS.PeerCertificates[1:] {
|
||||
optsCopy.Intermediates.AddCert(intermediate)
|
||||
}
|
||||
}
|
||||
|
||||
remaining := req.TLS.PeerCertificates[0].NotAfter.Sub(time.Now())
|
||||
clientCertificateExpirationHistogram.Observe(remaining.Seconds())
|
||||
chains, err := req.TLS.PeerCertificates[0].Verify(optsCopy)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
var errlist []error
|
||||
for _, chain := range chains {
|
||||
user, ok, err := a.user.User(chain)
|
||||
if err != nil {
|
||||
errlist = append(errlist, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if ok {
|
||||
return user, ok, err
|
||||
}
|
||||
}
|
||||
return nil, false, utilerrors.NewAggregate(errlist)
|
||||
}
|
||||
|
||||
// Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
|
||||
type Verifier struct {
|
||||
opts x509.VerifyOptions
|
||||
auth authenticator.Request
|
||||
|
||||
// allowedCommonNames contains the common names which a verified certificate is allowed to have.
|
||||
// If empty, all verified certificates are allowed.
|
||||
allowedCommonNames sets.String
|
||||
}
|
||||
|
||||
// NewVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
|
||||
func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCommonNames sets.String) authenticator.Request {
|
||||
return &Verifier{opts, auth, allowedCommonNames}
|
||||
}
|
||||
|
||||
// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth
|
||||
func (a *Verifier) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
|
||||
if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
// Use intermediates, if provided
|
||||
optsCopy := a.opts
|
||||
if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
|
||||
optsCopy.Intermediates = x509.NewCertPool()
|
||||
for _, intermediate := range req.TLS.PeerCertificates[1:] {
|
||||
optsCopy.Intermediates.AddCert(intermediate)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := req.TLS.PeerCertificates[0].Verify(optsCopy); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if err := a.verifySubject(req.TLS.PeerCertificates[0].Subject); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return a.auth.AuthenticateRequest(req)
|
||||
}
|
||||
|
||||
func (a *Verifier) verifySubject(subject pkix.Name) error {
|
||||
// No CN restrictions
|
||||
if len(a.allowedCommonNames) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Enforce CN restrictions
|
||||
if a.allowedCommonNames.Has(subject.CommonName) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("x509: subject with cn=%s is not in the allowed list", subject.CommonName)
|
||||
}
|
||||
|
||||
// DefaultVerifyOptions returns VerifyOptions that use the system root certificates, current time,
|
||||
// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth)
|
||||
func DefaultVerifyOptions() x509.VerifyOptions {
|
||||
return x509.VerifyOptions{
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
}
|
||||
|
||||
// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
|
||||
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
|
||||
if len(chain[0].Subject.CommonName) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
return &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: chain[0].Subject.CommonName,
|
||||
Groups: chain[0].Subject.Organization,
|
||||
},
|
||||
}, true, nil
|
||||
})
|
||||
49
vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_simple.go
generated
vendored
Normal file
49
vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_simple.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
lrucache "k8s.io/apimachinery/pkg/util/cache"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
)
|
||||
|
||||
type simpleCache struct {
|
||||
lru *lrucache.LRUExpireCache
|
||||
}
|
||||
|
||||
func newSimpleCache(size int, clock clock.Clock) cache {
|
||||
return &simpleCache{lru: lrucache.NewLRUExpireCacheWithClock(size, clock)}
|
||||
}
|
||||
|
||||
func (c *simpleCache) get(key string) (*cacheRecord, bool) {
|
||||
record, ok := c.lru.Get(key)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
value, ok := record.(*cacheRecord)
|
||||
return value, ok
|
||||
}
|
||||
|
||||
func (c *simpleCache) set(key string, value *cacheRecord, ttl time.Duration) {
|
||||
c.lru.Add(key, value, ttl)
|
||||
}
|
||||
|
||||
func (c *simpleCache) remove(key string) {
|
||||
c.lru.Remove(key)
|
||||
}
|
||||
60
vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_striped.go
generated
vendored
Normal file
60
vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_striped.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 cache
|
||||
|
||||
import (
|
||||
"hash/fnv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// split cache lookups across N striped caches
|
||||
type stripedCache struct {
|
||||
stripeCount uint32
|
||||
hashFunc func(string) uint32
|
||||
caches []cache
|
||||
}
|
||||
|
||||
type hashFunc func(string) uint32
|
||||
type newCacheFunc func() 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),
|
||||
hashFunc: hash,
|
||||
caches: caches,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *stripedCache) get(key string) (*cacheRecord, bool) {
|
||||
return c.caches[c.hashFunc(key)%c.stripeCount].get(key)
|
||||
}
|
||||
func (c *stripedCache) set(key string, value *cacheRecord, ttl time.Duration) {
|
||||
c.caches[c.hashFunc(key)%c.stripeCount].set(key, value, ttl)
|
||||
}
|
||||
func (c *stripedCache) remove(key string) {
|
||||
c.caches[c.hashFunc(key)%c.stripeCount].remove(key)
|
||||
}
|
||||
|
||||
func fnvHashFunc(key string) uint32 {
|
||||
f := fnv.New32()
|
||||
f.Write([]byte(key))
|
||||
return f.Sum32()
|
||||
}
|
||||
95
vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go
generated
vendored
Normal file
95
vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
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 cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
utilclock "k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
)
|
||||
|
||||
// cacheRecord holds the three return values of the authenticator.Token AuthenticateToken method
|
||||
type cacheRecord struct {
|
||||
resp *authenticator.Response
|
||||
ok bool
|
||||
err error
|
||||
}
|
||||
|
||||
type cachedTokenAuthenticator struct {
|
||||
authenticator authenticator.Token
|
||||
|
||||
cacheErrs bool
|
||||
successTTL time.Duration
|
||||
failureTTL time.Duration
|
||||
|
||||
cache cache
|
||||
}
|
||||
|
||||
type cache interface {
|
||||
// given a key, return the record, and whether or not it existed
|
||||
get(key string) (value *cacheRecord, exists bool)
|
||||
// caches the record for the key
|
||||
set(key string, value *cacheRecord, ttl time.Duration)
|
||||
// removes the record for the key
|
||||
remove(key string)
|
||||
}
|
||||
|
||||
// New returns a token authenticator that caches the results of the specified authenticator. A ttl of 0 bypasses the cache.
|
||||
func New(authenticator authenticator.Token, cacheErrs bool, successTTL, failureTTL time.Duration) authenticator.Token {
|
||||
return newWithClock(authenticator, cacheErrs, successTTL, failureTTL, utilclock.RealClock{})
|
||||
}
|
||||
|
||||
func newWithClock(authenticator authenticator.Token, cacheErrs bool, successTTL, failureTTL time.Duration, clock utilclock.Clock) authenticator.Token {
|
||||
return &cachedTokenAuthenticator{
|
||||
authenticator: authenticator,
|
||||
cacheErrs: cacheErrs,
|
||||
successTTL: successTTL,
|
||||
failureTTL: failureTTL,
|
||||
cache: newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(128, clock) }),
|
||||
}
|
||||
}
|
||||
|
||||
// AuthenticateToken implements authenticator.Token
|
||||
func (a *cachedTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
|
||||
auds, _ := authenticator.AudiencesFrom(ctx)
|
||||
|
||||
key := keyFunc(auds, token)
|
||||
if record, ok := a.cache.get(key); ok {
|
||||
return record.resp, record.ok, record.err
|
||||
}
|
||||
|
||||
resp, ok, err := a.authenticator.AuthenticateToken(ctx, token)
|
||||
if !a.cacheErrs && err != nil {
|
||||
return resp, ok, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case ok && a.successTTL > 0:
|
||||
a.cache.set(key, &cacheRecord{resp: resp, ok: ok, err: err}, a.successTTL)
|
||||
case !ok && a.failureTTL > 0:
|
||||
a.cache.set(key, &cacheRecord{resp: resp, ok: ok, err: err}, a.failureTTL)
|
||||
}
|
||||
|
||||
return resp, ok, err
|
||||
}
|
||||
|
||||
func keyFunc(auds []string, token string) string {
|
||||
return fmt.Sprintf("%#v|%v", auds, token)
|
||||
}
|
||||
99
vendor/k8s.io/apiserver/pkg/authentication/token/tokenfile/tokenfile.go
generated
vendored
Normal file
99
vendor/k8s.io/apiserver/pkg/authentication/token/tokenfile/tokenfile.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
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 (
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
type TokenAuthenticator struct {
|
||||
tokens map[string]*user.DefaultInfo
|
||||
}
|
||||
|
||||
// New returns a TokenAuthenticator for a single token
|
||||
func New(tokens map[string]*user.DefaultInfo) *TokenAuthenticator {
|
||||
return &TokenAuthenticator{
|
||||
tokens: tokens,
|
||||
}
|
||||
}
|
||||
|
||||
// NewCSV returns a TokenAuthenticator, populated from a CSV file.
|
||||
// The CSV file must contain records in the format "token,username,useruid"
|
||||
func NewCSV(path string) (*TokenAuthenticator, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
recordNum := 0
|
||||
tokens := make(map[string]*user.DefaultInfo)
|
||||
reader := csv.NewReader(file)
|
||||
reader.FieldsPerRecord = -1
|
||||
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))
|
||||
}
|
||||
|
||||
recordNum++
|
||||
if record[0] == "" {
|
||||
klog.Warningf("empty token has been found in token file '%s', record number '%d'", path, recordNum)
|
||||
continue
|
||||
}
|
||||
|
||||
obj := &user.DefaultInfo{
|
||||
Name: record[1],
|
||||
UID: record[2],
|
||||
}
|
||||
if _, exist := tokens[record[0]]; exist {
|
||||
klog.Warningf("duplicate token has been found in token file '%s', record number '%d'", path, recordNum)
|
||||
}
|
||||
tokens[record[0]] = obj
|
||||
|
||||
if len(record) >= 4 {
|
||||
obj.Groups = strings.Split(record[3], ",")
|
||||
}
|
||||
}
|
||||
|
||||
return &TokenAuthenticator{
|
||||
tokens: tokens,
|
||||
}, nil
|
||||
}
|
||||
|
||||
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 &authenticator.Response{User: user}, true, nil
|
||||
}
|
||||
Reference in New Issue
Block a user