github.com/richardwilkes/toolbox@v1.121.0/xio/network/xhttp/basic_auth.go (about)

     1  // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the Mozilla Public
     4  // License, version 2.0. If a copy of the MPL was not distributed with
     5  // this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  //
     7  // This Source Code Form is "Incompatible With Secondary Licenses", as
     8  // defined by the Mozilla Public License, version 2.0.
     9  
    10  // Package xhttp provides HTTP-related utilities.
    11  package xhttp
    12  
    13  import (
    14  	"crypto/subtle"
    15  	"fmt"
    16  	"net/http"
    17  )
    18  
    19  // BasicAuth provides basic HTTP authentication.
    20  type BasicAuth struct {
    21  	// Lookup provides a way to map a user in a realm to a password. The returned password should have already been
    22  	// passed through the Hasher function.
    23  	Lookup func(user, realm string) ([]byte, bool)
    24  	Hasher func(input string) []byte
    25  	Realm  string
    26  }
    27  
    28  // Wrap an http.Handler, requiring Basic Authentication.
    29  func (ba *BasicAuth) Wrap(handler http.Handler) http.Handler {
    30  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    31  		if user, pw, ok := r.BasicAuth(); ok {
    32  			stored, found := ba.Lookup(user, ba.Realm)
    33  			passwordMatch := subtle.ConstantTimeCompare(ba.Hasher(pw), stored) == 1
    34  			if found && passwordMatch {
    35  				if md := MetadataFromRequest(r); md != nil {
    36  					md.User = user
    37  					md.Logger = md.Logger.With("user", user)
    38  				}
    39  				handler.ServeHTTP(w, r)
    40  				return
    41  			}
    42  		}
    43  		w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm=%q, charset="UTF-8"`, ba.Realm))
    44  		ErrorStatus(w, http.StatusUnauthorized)
    45  	})
    46  }