123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- package server
- import (
- "crypto/sha256"
- "crypto/subtle"
- "net/http"
- )
- func (app *Application) BasicAuth(next http.HandlerFunc) http.HandlerFunc {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- // Extract the username and password from the request Authorization header.
- // If no Authentication header is present, or if the header value is
- // invalid, then the 'ok' return value will be false.
- username, password, ok := r.BasicAuth()
- if ok {
- // Calculate SHA-256 hashes for the provided and expected usernames
- // and passwords in order to have constant length values.
- actualUsernameHash := sha256.Sum256([]byte(username))
- actualPasswordHash := sha256.Sum256([]byte(password))
- expectedUsernameHash := sha256.Sum256([]byte(app.Username))
- expectedPasswordHash := sha256.Sum256([]byte(app.Password))
- // Use the subtle.ConstantTimeCompare() function to check if the
- // provided username and password hashes equal the expected
- // username and password hashes.
- // ConstantTimeCompare will return 1 if the values are equal, or 0 otherwise.
- // Importantly, we should do the work to evaluate both the username
- // and password before checking the return values, to avoid leaking information.
- usernameMatch := 1 == subtle.ConstantTimeCompare(actualUsernameHash[:], expectedUsernameHash[:])
- passwordMatch := 1 == subtle.ConstantTimeCompare(actualPasswordHash[:], expectedPasswordHash[:])
- // If the username and password are correct, then call the next
- // handler in the chain. Make sure to return afterwards, so that
- // none of the code below is run.
- if usernameMatch && passwordMatch {
- next.ServeHTTP(w, r)
- return
- }
- }
- // If the Authentication header is not present, is invalid, or the
- // username or password is wrong, then set a WWW-Authenticate header
- // to inform the client that we expect them to use basic authentication
- // and send a 401 Unauthorized response.
- w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
- http.Error(w, "Please provide an authorization", http.StatusUnauthorized)
- })
- }
|