mirror of https://github.com/k3s-io/k3s
89 lines
2.1 KiB
Go
89 lines
2.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"crypto/sha1"
|
|
"encoding/base64"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
type BasicAuth struct {
|
|
Realm string
|
|
Secrets SecretProvider
|
|
}
|
|
|
|
/*
|
|
Checks the username/password combination from the request. Returns
|
|
either an empty string (authentication failed) or the name of the
|
|
authenticated user.
|
|
|
|
Supports MD5 and SHA1 password entries
|
|
*/
|
|
func (a *BasicAuth) CheckAuth(r *http.Request) string {
|
|
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
|
|
if len(s) != 2 || s[0] != "Basic" {
|
|
return ""
|
|
}
|
|
|
|
b, err := base64.StdEncoding.DecodeString(s[1])
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
pair := strings.SplitN(string(b), ":", 2)
|
|
if len(pair) != 2 {
|
|
return ""
|
|
}
|
|
passwd := a.Secrets(pair[0], a.Realm)
|
|
if passwd == "" {
|
|
return ""
|
|
}
|
|
if strings.HasPrefix(passwd, "{SHA}") {
|
|
d := sha1.New()
|
|
d.Write([]byte(pair[1]))
|
|
if passwd[5:] != base64.StdEncoding.EncodeToString(d.Sum(nil)) {
|
|
return ""
|
|
}
|
|
} else {
|
|
e := NewMD5Entry(passwd)
|
|
if e == nil {
|
|
return ""
|
|
}
|
|
if passwd != string(MD5Crypt([]byte(pair[1]), e.Salt, e.Magic)) {
|
|
return ""
|
|
}
|
|
}
|
|
return pair[0]
|
|
}
|
|
|
|
/*
|
|
http.Handler for BasicAuth which initiates the authentication process
|
|
(or requires reauthentication).
|
|
*/
|
|
func (a *BasicAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="`+a.Realm+`"`)
|
|
w.WriteHeader(401)
|
|
w.Write([]byte("401 Unauthorized\n"))
|
|
}
|
|
|
|
/*
|
|
BasicAuthenticator returns a function, which wraps an
|
|
AuthenticatedHandlerFunc converting it to http.HandlerFunc. This
|
|
wrapper function checks the authentication and either sends back
|
|
required authentication headers, or calls the wrapped function with
|
|
authenticated username in the AuthenticatedRequest.
|
|
*/
|
|
func (a *BasicAuth) Wrap(wrapped AuthenticatedHandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if username := a.CheckAuth(r); username == "" {
|
|
a.RequireAuth(w, r)
|
|
} else {
|
|
ar := &AuthenticatedRequest{Request: *r, Username: username}
|
|
wrapped(w, ar)
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewBasicAuthenticator(realm string, secrets SecretProvider) *BasicAuth {
|
|
return &BasicAuth{Realm: realm, Secrets: secrets}
|
|
}
|