Files
gokrazy/authenticated.go
Tim H 1d4c6badf3 Always listen on gokrazy.HTTPUnixSocket (#296)
The change is made to allow other tools like breakglass or mkfs to
interact with the Gokrazy API when TLS is enabled. The tools currently
make HTTP requests to get system information or trigger reboots. When
TLS is enabled, these requests fail because Gokrazy redirects all HTTP
requests to HTTPS. While it is possible to configure the respective
clients to properly validate (self-signed) certificates, doing so is
cumbersome. Therefore, always listen on the Unix socket to avoid the
complexity of certificate validation. Username and password must still
be provided and will be validated.
2025-02-22 07:08:47 +01:00

53 lines
1.6 KiB
Go

package gokrazy
import (
"crypto/subtle"
"encoding/base64"
"fmt"
"net"
"net/http"
"strings"
)
func authenticated(w http.ResponseWriter, r *http.Request) {
// If httpPassword is empty, we only allow access via the unix socket. Out
// of paranoia, even though it should only be listening via the unix socket,
// verify that's where it came from.
//
// See https://github.com/gokrazy/gokrazy/issues/265
if httpPassword == "" {
addr, ok := r.Context().Value(http.LocalAddrContextKey).(*net.UnixAddr)
if ok && addr.Name == HTTPUnixSocket {
http.DefaultServeMux.ServeHTTP(w, r)
} else {
http.Error(w, "httpPassword not set and request from unexpected address", http.StatusInternalServerError)
}
return
}
kind, encoded, found := strings.Cut(r.Header.Get("Authorization"), " ")
if !found || kind != "Basic" {
w.Header().Set("WWW-Authenticate", `Basic realm="gokrazy"`)
http.Error(w, "no Basic Authorization header set", http.StatusUnauthorized)
return
}
b, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
w.Header().Set("WWW-Authenticate", `Basic realm="gokrazy"`)
http.Error(w, fmt.Sprintf("could not decode Authorization header as base64: %v", err), http.StatusUnauthorized)
return
}
username, password, found := strings.Cut(string(b), ":")
if !found ||
username != "gokrazy" ||
subtle.ConstantTimeCompare([]byte(password), []byte(httpPassword)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="gokrazy"`)
http.Error(w, "invalid username/password", http.StatusUnauthorized)
return
}
http.DefaultServeMux.ServeHTTP(w, r)
}