mirror of
https://github.com/rancher/steve.git
synced 2025-09-03 16:35:25 +00:00
Refactor
This commit is contained in:
146
pkg/auth/filter.go
Normal file
146
pkg/auth/filter.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/token/cache"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
||||
type Authenticator interface {
|
||||
Authenticate(req *http.Request) (user.Info, bool, error)
|
||||
}
|
||||
|
||||
type AuthenticatorFunc func(req *http.Request) (user.Info, bool, error)
|
||||
|
||||
func (a AuthenticatorFunc) Authenticate(req *http.Request) (user.Info, bool, error) {
|
||||
return a(req)
|
||||
}
|
||||
|
||||
type Middleware func(http.ResponseWriter, *http.Request, http.Handler)
|
||||
|
||||
func (m Middleware) Wrap(handler http.Handler) http.Handler {
|
||||
if m == nil {
|
||||
return handler
|
||||
}
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
m(rw, req, handler)
|
||||
})
|
||||
}
|
||||
|
||||
func WebhookConfigForURL(url string) (string, error) {
|
||||
config := clientcmdapi.Config{
|
||||
Clusters: map[string]*clientcmdapi.Cluster{
|
||||
"local": {
|
||||
Server: url,
|
||||
InsecureSkipTLSVerify: true,
|
||||
},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"Default": {
|
||||
Cluster: "local",
|
||||
AuthInfo: "user",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"user": {},
|
||||
},
|
||||
CurrentContext: "Default",
|
||||
}
|
||||
|
||||
tmpFile, err := ioutil.TempFile("", "webhook-config")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tmpFile.Name(), clientcmd.WriteToFile(config, tmpFile.Name())
|
||||
}
|
||||
|
||||
func NewWebhookAuthenticator(cacheTTL time.Duration, kubeConfigFile string) (Authenticator, error) {
|
||||
wh, err := webhook.New(kubeConfigFile, "v1", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cacheTTL > 0 {
|
||||
return &webhookAuth{
|
||||
auth: cache.New(wh, false, cacheTTL, cacheTTL),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &webhookAuth{
|
||||
auth: wh,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewWebhookMiddleware(cacheTTL time.Duration, kubeConfigFile string) (Middleware, error) {
|
||||
auth, err := NewWebhookAuthenticator(cacheTTL, kubeConfigFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToMiddleware(auth), nil
|
||||
}
|
||||
|
||||
type webhookAuth struct {
|
||||
auth authenticator.Token
|
||||
}
|
||||
|
||||
func (w *webhookAuth) Authenticate(req *http.Request) (user.Info, bool, error) {
|
||||
token := req.Header.Get("Authorization")
|
||||
if strings.HasPrefix(token, "Bearer ") {
|
||||
token = strings.TrimPrefix(token, "Bearer ")
|
||||
} else {
|
||||
token = ""
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
cookie, err := req.Cookie("R_SESS")
|
||||
if err != nil && err != http.ErrNoCookie {
|
||||
return nil, false, err
|
||||
} else if err != http.ErrNoCookie && len(cookie.Value) > 0 {
|
||||
token = "cookie://" + cookie.Value
|
||||
}
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
resp, ok, err := w.auth.AuthenticateToken(req.Context(), token)
|
||||
if resp == nil {
|
||||
return nil, ok, err
|
||||
}
|
||||
return resp.User, ok, err
|
||||
}
|
||||
|
||||
func ToMiddleware(auth Authenticator) func(rw http.ResponseWriter, req *http.Request, next http.Handler) {
|
||||
return func(rw http.ResponseWriter, req *http.Request, next http.Handler) {
|
||||
info, ok, err := auth.Authenticate(req)
|
||||
if err != nil {
|
||||
rw.WriteHeader(http.StatusServiceUnavailable)
|
||||
rw.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !ok {
|
||||
rw.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := request.WithUser(req.Context(), info)
|
||||
req = req.WithContext(ctx)
|
||||
next.ServeHTTP(rw, req)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user