Fix multiauth

This commit is contained in:
Mygod 2023-04-26 16:35:55 -04:00
parent a7059fa9b0
commit 44bd8c758f
3 changed files with 32 additions and 34 deletions

View file

@ -1,6 +1,7 @@
package forwardproxy
import (
"encoding/base64"
"log"
"strconv"
"strings"
@ -45,13 +46,14 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if strings.Contains(args[0], ":") {
return d.Err("character ':' in usernames is not allowed")
}
// TODO: Support multiple basicauths.
// TODO: Actually, just try to use Caddy 2's existing basicauth module.
if h.BasicauthUser != "" || h.BasicauthPass != "" {
return d.Err("Multi-user basicauth is not supported")
if h.AuthCredentials == nil {
h.AuthCredentials = [][]byte{}
}
h.BasicauthUser = args[0]
h.BasicauthPass = args[1]
// base64-encode credentials
buf := make([]byte, base64.StdEncoding.EncodedLen(len(args[0])+1+len(args[1])))
base64.StdEncoding.Encode(buf, []byte(args[0]+":"+args[1]))
h.AuthCredentials = append(h.AuthCredentials, buf)
h.AuthRequired = true
case "hosts":
if len(args) == 0 {
return d.ArgErr()

View file

@ -3,6 +3,7 @@ package forwardproxy
import (
"context"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
@ -190,6 +191,9 @@ func TestMain(m *testing.M) {
},
}
buf := make([]byte, base64.StdEncoding.EncodedLen(9))
base64.StdEncoding.Encode(buf, []byte("test:pass"))
caddyForwardProxyAuth = caddyTestServer{
addr: "127.0.0.1:4891",
root: "./test/forwardproxy",
@ -197,8 +201,8 @@ func TestMain(m *testing.M) {
proxyHandler: &Handler{
PACPath: defaultPACPath,
ACL: []ACLRule{{Subjects: []string{"all"}, Allow: true}},
BasicauthUser: "test",
BasicauthPass: "pass",
AuthCredentials: [][]byte{buf},
AuthRequired: true,
},
}
@ -208,8 +212,8 @@ func TestMain(m *testing.M) {
proxyHandler: &Handler{
PACPath: defaultPACPath,
ACL: []ACLRule{{Subjects: []string{"all"}, Allow: true}},
BasicauthUser: "test",
BasicauthPass: "pass",
AuthCredentials: [][]byte{buf},
AuthRequired: true,
},
}
@ -221,8 +225,8 @@ func TestMain(m *testing.M) {
PACPath: "/superhiddenfile.pac",
ACL: []ACLRule{{Subjects: []string{"all"}, Allow: true}},
ProbeResistance: &ProbeResistance{Domain: "test.localhost"},
BasicauthUser: "test",
BasicauthPass: "pass",
AuthCredentials: [][]byte{buf},
AuthRequired: true,
},
httpRedirPort: "8880",
}
@ -250,8 +254,8 @@ func TestMain(m *testing.M) {
tls: true,
proxyHandler: &Handler{
Upstream: "https://test:pass@127.0.0.1:4891",
BasicauthUser: "upstreamtest",
BasicauthPass: "upstreampass",
AuthCredentials: [][]byte{buf},
AuthRequired: true,
},
}

View file

@ -93,8 +93,8 @@ type Handler struct {
// TODO: temporary/deprecated - we should try to reuse existing authentication modules instead!
BasicauthUser string `json:"auth_user_deprecated,omitempty"`
BasicauthPass string `json:"auth_pass_deprecated,omitempty"`
authRequired bool
authCredentials [][]byte // slice with base64-encoded credentials
AuthRequired bool `json:"auth_required,omitempty"`
AuthCredentials [][]byte `json:"auth_credentials,omitempty"` // slice with base64-encoded credentials
}
// CaddyModule returns the Caddy module information.
@ -120,14 +120,6 @@ func (h *Handler) Provision(ctx caddy.Context) error {
TLSHandshakeTimeout: 10 * time.Second,
}
// TODO: temporary, in an effort to get the tests to pass
if h.BasicauthUser != "" && h.BasicauthPass != "" {
basicAuthBuf := make([]byte, base64.StdEncoding.EncodedLen(len(h.BasicauthUser)+1+len(h.BasicauthPass)))
base64.StdEncoding.Encode(basicAuthBuf, []byte(h.BasicauthUser+":"+h.BasicauthPass))
h.authRequired = true
h.authCredentials = [][]byte{basicAuthBuf}
}
// access control lists
for _, rule := range h.ACL {
for _, subj := range rule.Subjects {
@ -155,7 +147,7 @@ func (h *Handler) Provision(ctx caddy.Context) error {
h.aclRules = append(h.aclRules, &aclAllRule{allow: true})
if h.ProbeResistance != nil {
if !h.authRequired {
if !h.AuthRequired {
return fmt.Errorf("probe resistance requires authentication")
}
if len(h.ProbeResistance.Domain) > 0 {
@ -237,7 +229,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
}
var authErr error
if h.authRequired {
if h.AuthRequired {
authErr = h.checkCredentials(r)
}
if h.ProbeResistance != nil && len(h.ProbeResistance.Domain) > 0 && reqHost == h.ProbeResistance.Domain {
@ -418,7 +410,7 @@ func (h Handler) checkCredentials(r *http.Request) error {
if strings.ToLower(pa[0]) != "basic" {
return errors.New("Auth type is not supported")
}
for _, creds := range h.authCredentials {
for _, creds := range h.AuthCredentials {
if subtle.ConstantTimeCompare(creds, []byte(pa[1])) == 1 {
// Please do not consider this to be timing-attack-safe code. Simple equality is almost
// mindlessly substituted with constant time algo and there ARE known issues with this code,