mirror of
https://github.com/therootcompany/golib.git
synced 2026-03-02 23:57:59 +00:00
78 lines
2.5 KiB
Go
78 lines
2.5 KiB
Go
package auth
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
// ErrNoCredentials is returned by RequestAuthenticator.Authenticate when the
|
|
// request contains no recognizable form of credentials.
|
|
var ErrNoCredentials = errors.New("no credentials provided")
|
|
|
|
// RequestAuthenticator extracts credentials from an HTTP request and delegates
|
|
// verification to a BasicAuthenticator. It supports Basic Auth, Authorization
|
|
// header tokens, custom token headers, and query-parameter tokens.
|
|
type RequestAuthenticator struct {
|
|
// AuthorizationSchemes lists accepted schemes for "Authorization: <scheme> <token>".
|
|
// nil accepts any scheme; a non-nil empty slice skips the Authorization header
|
|
// entirely; ["*"] also accepts any scheme; ["Bearer", "Token"] restricts to those.
|
|
AuthorizationSchemes []string
|
|
|
|
// TokenHeaders lists header names checked for bearer tokens,
|
|
// e.g. []string{"API-Key", "X-API-Key"}.
|
|
TokenHeaders []string
|
|
|
|
// TokenQueryParams lists query parameter names checked for tokens,
|
|
// e.g. []string{"access_token", "token"}.
|
|
TokenQueryParams []string
|
|
}
|
|
|
|
// Authenticate extracts credentials from r in this order:
|
|
// 1. Basic Auth (Authorization: Basic …)
|
|
// 2. Authorization: <scheme> <token> (filtered by AuthorizationSchemes)
|
|
// 3. Token headers (TokenHeaders)
|
|
// 4. Query parameters (TokenQueryParams)
|
|
//
|
|
// Returns ErrNoCredentials if no credential form is present in the request.
|
|
func (ra *RequestAuthenticator) Authenticate(r *http.Request, a BasicAuthenticator) (BasicPrinciple, error) {
|
|
// 1. Basic Auth
|
|
if username, password, ok := r.BasicAuth(); ok {
|
|
return a.Authenticate(username, password)
|
|
}
|
|
|
|
// 2. Authorization: <scheme> <token>
|
|
// nil AuthorizationSchemes accepts any scheme; a non-nil empty slice skips.
|
|
if ra.AuthorizationSchemes == nil || len(ra.AuthorizationSchemes) > 0 {
|
|
if authHeader := r.Header.Get("Authorization"); authHeader != "" {
|
|
parts := strings.SplitN(authHeader, " ", 2)
|
|
if len(parts) == 2 {
|
|
scheme, token := parts[0], strings.TrimSpace(parts[1])
|
|
if ra.AuthorizationSchemes == nil ||
|
|
ra.AuthorizationSchemes[0] == "*" ||
|
|
slices.Contains(ra.AuthorizationSchemes, scheme) {
|
|
return a.Authenticate("", token)
|
|
}
|
|
}
|
|
return nil, ErrNoCredentials
|
|
}
|
|
}
|
|
|
|
// 3. Token headers
|
|
for _, h := range ra.TokenHeaders {
|
|
if token := r.Header.Get(h); token != "" {
|
|
return a.Authenticate("", token)
|
|
}
|
|
}
|
|
|
|
// 4. Query parameters
|
|
for _, p := range ra.TokenQueryParams {
|
|
if token := r.URL.Query().Get(p); token != "" {
|
|
return a.Authenticate("", token)
|
|
}
|
|
}
|
|
|
|
return nil, ErrNoCredentials
|
|
}
|