mirror of
https://github.com/restic/rest-server.git
synced 2026-10-15 15:10:07 -07:00
Requests rejected by Basic authentication currently return 401 without WWW-Authenticate, preventing HTTP clients from prompting for credentials. Advertise the Basic scheme on the server and metrics auth paths while leaving proxy authentication unchanged.
136 lines
3.0 KiB
Go
136 lines
3.0 KiB
Go
package restserver
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestCheckAuth(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
server *Server
|
|
requestHeaders map[string]string
|
|
basicAuth bool
|
|
basicUser string
|
|
basicPassword string
|
|
expectedUser string
|
|
expectedOk bool
|
|
}{
|
|
{
|
|
name: "NoAuth enabled",
|
|
server: &Server{
|
|
NoAuth: true,
|
|
},
|
|
expectedOk: true,
|
|
},
|
|
{
|
|
name: "Proxy Auth successful",
|
|
server: &Server{
|
|
ProxyAuthUsername: "X-Remote-User",
|
|
},
|
|
requestHeaders: map[string]string{
|
|
"X-Remote-User": "restic",
|
|
},
|
|
expectedUser: "restic",
|
|
expectedOk: true,
|
|
},
|
|
{
|
|
name: "Proxy Auth empty header",
|
|
server: &Server{
|
|
ProxyAuthUsername: "X-Remote-User",
|
|
},
|
|
requestHeaders: map[string]string{
|
|
"X-Remote-User": "",
|
|
},
|
|
expectedOk: false,
|
|
},
|
|
{
|
|
name: "Proxy Auth missing header",
|
|
server: &Server{
|
|
ProxyAuthUsername: "X-Remote-User",
|
|
},
|
|
expectedOk: false,
|
|
},
|
|
{
|
|
name: "Proxy Auth send but not enabled",
|
|
server: &Server{},
|
|
requestHeaders: map[string]string{
|
|
"X-Remote-User": "restic",
|
|
},
|
|
expectedOk: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/", nil)
|
|
for header, value := range tt.requestHeaders {
|
|
req.Header.Set(header, value)
|
|
}
|
|
if tt.basicAuth {
|
|
req.SetBasicAuth(tt.basicUser, tt.basicPassword)
|
|
}
|
|
|
|
username, ok := tt.server.checkAuth(req)
|
|
if username != tt.expectedUser || ok != tt.expectedOk {
|
|
t.Errorf("expected (%v, %v), got (%v, %v)", tt.expectedUser, tt.expectedOk, username, ok)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnauthorizedResponsesIncludeBasicChallenge(t *testing.T) {
|
|
const challenge = `Basic realm="rest-server"`
|
|
|
|
tests := []struct {
|
|
name string
|
|
server *Server
|
|
metrics bool
|
|
wantChallenge string
|
|
}{
|
|
{
|
|
name: "server Basic authentication",
|
|
server: &Server{},
|
|
wantChallenge: challenge,
|
|
},
|
|
{
|
|
name: "server proxy authentication",
|
|
server: &Server{ProxyAuthUsername: "X-Remote-User"},
|
|
},
|
|
{
|
|
name: "metrics Basic authentication",
|
|
server: &Server{},
|
|
metrics: true,
|
|
wantChallenge: challenge,
|
|
},
|
|
{
|
|
name: "metrics proxy authentication",
|
|
server: &Server{ProxyAuthUsername: "X-Remote-User"},
|
|
metrics: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var handler http.HandlerFunc
|
|
if tt.metrics {
|
|
handler = tt.server.wrapMetricsAuth(func(http.ResponseWriter, *http.Request) {
|
|
t.Fatal("handler should not be called for an unauthorized request")
|
|
})
|
|
} else {
|
|
handler = tt.server.ServeHTTP
|
|
}
|
|
|
|
rec := httptest.NewRecorder()
|
|
handler(rec, httptest.NewRequest(http.MethodGet, "/", nil))
|
|
if rec.Code != http.StatusUnauthorized {
|
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusUnauthorized)
|
|
}
|
|
if got := rec.Header().Get("WWW-Authenticate"); got != tt.wantChallenge {
|
|
t.Errorf("WWW-Authenticate = %q, want %q", got, tt.wantChallenge)
|
|
}
|
|
})
|
|
}
|
|
}
|