You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
47 lines
1.3 KiB
Go
47 lines
1.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"crypto/subtle"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
// BasicAuthConfig configures HTTP Basic authentication middleware.
|
|
type BasicAuthConfig struct {
|
|
Username string
|
|
Password string
|
|
Realm string
|
|
}
|
|
|
|
// BasicAuthMiddleware protects routes with HTTP Basic authentication.
|
|
// If credentials are not configured, all requests are denied.
|
|
func BasicAuthMiddleware(cfg BasicAuthConfig) func(http.Handler) http.Handler {
|
|
realm := cfg.Realm
|
|
if realm == "" {
|
|
realm = "Restricted"
|
|
}
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
username, password, ok := r.BasicAuth()
|
|
if !ok || !basicAuthCredentialsMatch(username, password, cfg.Username, cfg.Password) {
|
|
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s", charset="UTF-8"`, realm))
|
|
writeJSON(w, http.StatusUnauthorized, map[string]string{
|
|
"error": "unauthorized",
|
|
})
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|
|
|
|
func basicAuthCredentialsMatch(gotUser, gotPass, wantUser, wantPass string) bool {
|
|
if wantUser == "" || wantPass == "" {
|
|
return false
|
|
}
|
|
userOK := subtle.ConstantTimeCompare([]byte(gotUser), []byte(wantUser)) == 1
|
|
passOK := subtle.ConstantTimeCompare([]byte(gotPass), []byte(wantPass)) == 1
|
|
return userOK && passOK
|
|
}
|