depot/web/fup/fuphttp/auth.go

58 lines
1.2 KiB
Go

package fuphttp
import (
"crypto/subtle"
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func tokenFromRequest(r *http.Request) (token string, ok bool) {
// Check for a Fup-Token header.
v := r.Header.Get("Fup-Token")
if v != "" {
return v, true
}
// Check for basic auth.
_, v, ok = r.BasicAuth()
return v, ok
}
func TokenAuthMiddleware(token, realm string) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
if token == "" {
return next
}
tokenBytes := []byte(token)
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if !IsMutate(ctx) {
// Allow all access to public pages.
next.ServeHTTP(rw, r)
return
}
requestAuth := func(s string) {
rw.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q, charset=\"UTF-8\"", realm))
http.Error(rw, s, http.StatusUnauthorized)
}
pw, ok := tokenFromRequest(r)
switch {
case !ok:
requestAuth("unparsable or no credentials")
return
case subtle.ConstantTimeCompare([]byte(pw), tokenBytes) != 1:
requestAuth("bad credentials")
return
}
// Auth check passed, let's go.
next.ServeHTTP(rw, r)
return
})
}
}