fix(proxy): separate HTTP auth and method errors
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
4a0213e89f
commit
6f0f695054
2 changed files with 91 additions and 11 deletions
71
http_auth_test.go
Normal file
71
http_auth_test.go
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProxy_allowHTTP_Good(t *testing.T) {
|
||||
p := &Proxy{
|
||||
config: &Config{
|
||||
HTTP: HTTPConfig{
|
||||
Restricted: true,
|
||||
AccessToken: "secret",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
status, ok := p.allowHTTP(&http.Request{
|
||||
Method: http.MethodGet,
|
||||
Header: http.Header{
|
||||
"Authorization": []string{"Bearer secret"},
|
||||
},
|
||||
})
|
||||
if !ok {
|
||||
t.Fatalf("expected authorised request to pass, got status %d", status)
|
||||
}
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("expected status %d, got %d", http.StatusOK, status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxy_allowHTTP_Bad(t *testing.T) {
|
||||
p := &Proxy{
|
||||
config: &Config{
|
||||
HTTP: HTTPConfig{
|
||||
Restricted: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
status, ok := p.allowHTTP(&http.Request{Method: http.MethodPost})
|
||||
if ok {
|
||||
t.Fatal("expected non-GET request to be rejected")
|
||||
}
|
||||
if status != http.StatusMethodNotAllowed {
|
||||
t.Fatalf("expected status %d, got %d", http.StatusMethodNotAllowed, status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxy_allowHTTP_Ugly(t *testing.T) {
|
||||
p := &Proxy{
|
||||
config: &Config{
|
||||
HTTP: HTTPConfig{
|
||||
AccessToken: "secret",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
status, ok := p.allowHTTP(&http.Request{
|
||||
Method: http.MethodGet,
|
||||
Header: http.Header{
|
||||
"Authorization": []string{"Bearer wrong"},
|
||||
},
|
||||
})
|
||||
if ok {
|
||||
t.Fatal("expected invalid token to be rejected")
|
||||
}
|
||||
if status != http.StatusUnauthorized {
|
||||
t.Fatalf("expected status %d, got %d", http.StatusUnauthorized, status)
|
||||
}
|
||||
}
|
||||
|
|
@ -588,22 +588,31 @@ func parseTLSVersion(value string) uint16 {
|
|||
func (p *Proxy) startHTTP() {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/1/summary", func(w http.ResponseWriter, r *http.Request) {
|
||||
if !p.allowHTTP(r) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
if status, ok := p.allowHTTP(r); !ok {
|
||||
if status == http.StatusUnauthorized {
|
||||
w.Header().Set("WWW-Authenticate", "Bearer")
|
||||
}
|
||||
w.WriteHeader(status)
|
||||
return
|
||||
}
|
||||
p.writeJSON(w, p.summaryDocument())
|
||||
})
|
||||
mux.HandleFunc("/1/workers", func(w http.ResponseWriter, r *http.Request) {
|
||||
if !p.allowHTTP(r) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
if status, ok := p.allowHTTP(r); !ok {
|
||||
if status == http.StatusUnauthorized {
|
||||
w.Header().Set("WWW-Authenticate", "Bearer")
|
||||
}
|
||||
w.WriteHeader(status)
|
||||
return
|
||||
}
|
||||
p.writeJSON(w, p.workersDocument())
|
||||
})
|
||||
mux.HandleFunc("/1/miners", func(w http.ResponseWriter, r *http.Request) {
|
||||
if !p.allowHTTP(r) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
if status, ok := p.allowHTTP(r); !ok {
|
||||
if status == http.StatusUnauthorized {
|
||||
w.Header().Set("WWW-Authenticate", "Bearer")
|
||||
}
|
||||
w.WriteHeader(status)
|
||||
return
|
||||
}
|
||||
p.writeJSON(w, p.minersDocument())
|
||||
|
|
@ -615,20 +624,20 @@ func (p *Proxy) startHTTP() {
|
|||
}()
|
||||
}
|
||||
|
||||
func (p *Proxy) allowHTTP(r *http.Request) bool {
|
||||
func (p *Proxy) allowHTTP(r *http.Request) (int, bool) {
|
||||
if p == nil {
|
||||
return false
|
||||
return http.StatusServiceUnavailable, false
|
||||
}
|
||||
if p.config.HTTP.Restricted && r.Method != http.MethodGet {
|
||||
return false
|
||||
return http.StatusMethodNotAllowed, false
|
||||
}
|
||||
if token := p.config.HTTP.AccessToken; token != "" {
|
||||
parts := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
|
||||
if len(parts) != 2 || !strings.EqualFold(parts[0], "bearer") || parts[1] != token {
|
||||
return false
|
||||
return http.StatusUnauthorized, false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return http.StatusOK, true
|
||||
}
|
||||
|
||||
func (p *Proxy) writeJSON(w http.ResponseWriter, payload any) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue