refactor: move BasicAuthenticator into RequestAuthenticator; Authenticate takes only *http.Request

Co-authored-by: coolaj86 <122831+coolaj86@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-02 07:43:09 +00:00
parent 780ad06089
commit 33960a5f2b
3 changed files with 11 additions and 3 deletions

View File

@ -17,6 +17,10 @@ var ErrNoCredentials = errors.New("no credentials provided")
// //
// Use NewRequestAuthenticator for sane defaults. // Use NewRequestAuthenticator for sane defaults.
type RequestAuthenticator struct { type RequestAuthenticator struct {
// Authenticator is the credential verifier called with the extracted
// username/password or token. Must be set before calling Authenticate.
Authenticator BasicAuthenticator
// AuthenticateBasic enables HTTP Basic Auth (Authorization: Basic …). // AuthenticateBasic enables HTTP Basic Auth (Authorization: Basic …).
AuthenticateBasic bool AuthenticateBasic bool
@ -53,7 +57,9 @@ func NewRequestAuthenticator() *RequestAuthenticator {
// 4. Query parameters (TokenQueryParams) // 4. Query parameters (TokenQueryParams)
// //
// Returns ErrNoCredentials if no credential form is present in the request. // Returns ErrNoCredentials if no credential form is present in the request.
func (ra *RequestAuthenticator) Authenticate(r *http.Request, a BasicAuthenticator) (BasicPrinciple, error) { func (ra *RequestAuthenticator) Authenticate(r *http.Request) (BasicPrinciple, error) {
a := ra.Authenticator
// 1. Basic Auth // 1. Basic Auth
if ra.AuthenticateBasic { if ra.AuthenticateBasic {
if username, password, ok := r.BasicAuth(); ok { if username, password, ok := r.BasicAuth(); ok {

View File

@ -594,11 +594,12 @@ func matchPattern(grant, rMethod, rHost, rPath string) bool {
func (cli *MainConfig) authenticate(r *http.Request) (auth.BasicPrinciple, error) { func (cli *MainConfig) authenticate(r *http.Request) (auth.BasicPrinciple, error) {
ra := auth.RequestAuthenticator{ ra := auth.RequestAuthenticator{
Authenticator: creds,
AuthorizationSchemes: cli.AuthorizationHeaderSchemes, AuthorizationSchemes: cli.AuthorizationHeaderSchemes,
TokenHeaders: cli.TokenHeaderNames, TokenHeaders: cli.TokenHeaderNames,
TokenQueryParams: cli.QueryParamNames, TokenQueryParams: cli.QueryParamNames,
} }
cred, err := ra.Authenticate(r, creds) cred, err := ra.Authenticate(r)
if errors.Is(err, auth.ErrNoCredentials) { if errors.Is(err, auth.ErrNoCredentials) {
return nil, ErrNoAuth return nil, ErrNoAuth
} }

View File

@ -102,6 +102,7 @@ func main() {
if err := smsAuth.LoadCSV(f, '\t'); err != nil { if err := smsAuth.LoadCSV(f, '\t'); err != nil {
log.Fatalf("failed to load credentials from %q: %v", credPath, err) log.Fatalf("failed to load credentials from %q: %v", credPath, err)
} }
smsRequestAuth.Authenticator = smsAuth
} else { } else {
log.Printf("Warning: credentials file %q not found; /api/smsgw routes will return 401: %v", credPath, err) log.Printf("Warning: credentials file %q not found; /api/smsgw routes will return 401: %v", credPath, err)
} }
@ -148,7 +149,7 @@ func requireSMSPermission(permission string) func(http.Handler) http.Handler {
http.Error(w, "Unauthorized", http.StatusUnauthorized) http.Error(w, "Unauthorized", http.StatusUnauthorized)
return return
} }
cred, err := smsRequestAuth.Authenticate(r, smsAuth) cred, err := smsRequestAuth.Authenticate(r)
if err != nil || !hasSMSPermission(cred.Permissions(), permission) { if err != nil || !hasSMSPermission(cred.Permissions(), permission) {
w.Header().Set("WWW-Authenticate", `Basic`) w.Header().Set("WWW-Authenticate", `Basic`)
http.Error(w, "Unauthorized", http.StatusUnauthorized) http.Error(w, "Unauthorized", http.StatusUnauthorized)