summaryrefslogtreecommitdiffhomepage
path: root/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'server.go')
-rw-r--r--server.go67
1 files changed, 52 insertions, 15 deletions
diff --git a/server.go b/server.go
index 830a6e4..f971d45 100644
--- a/server.go
+++ b/server.go
@@ -8,6 +8,7 @@ import (
"net/http"
"net/http/httputil"
"net/url"
+ "os"
"strings"
)
@@ -19,7 +20,7 @@ type rewriteRule struct {
fromHost string
fromPath string
toUrl *url.URL
- proxy *httputil.ReverseProxy
+ proxy http.Handler
}
func (r *rewriteRule) matches(host, path string) bool {
@@ -33,29 +34,62 @@ func (r *rewriteRule) matches(host, path string) bool {
return ret
}
-func newMultipleReverseProxyServer(ps []ProxyConfig) *multipleReverseProxyServer {
+func basicAuthHandler(handler http.Handler, realm, username, passwordHash string) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ inputUsername, inputPassword, ok := r.BasicAuth()
+ if !ok || inputUsername != username || !VerifyPassword(inputPassword, passwordHash) {
+ w.Header().Set(
+ "WWW-Authenticate",
+ fmt.Sprintf("Basic realm=\"%s\"", realm),
+ )
+ http.Error(w, "401 unauthorized", http.StatusUnauthorized)
+ return
+ }
+ handler.ServeHTTP(w, r)
+ })
+}
+
+func newMultipleReverseProxyServer(ps []ProxyConfig) (*multipleReverseProxyServer, error) {
var rules []rewriteRule
for _, p := range ps {
targetUrl, err := url.Parse(fmt.Sprintf("http://%s:%d", p.To.Host, p.To.Port))
if err != nil {
- // This setting should be validated when loading config.
- panic(err)
+ return nil, err
+ }
+ var proxy http.Handler = &httputil.ReverseProxy{
+ Rewrite: func(r *httputil.ProxyRequest) {
+ r.SetURL(targetUrl)
+ r.SetXForwarded()
+ },
+ }
+ if p.BasicAuth != nil {
+ credentialFileContent, err := os.ReadFile(p.BasicAuth.CredentialFile)
+ if err != nil {
+ return nil, err
+ }
+ usernameAndPasswordHash := strings.Split(strings.TrimSuffix(string(credentialFileContent), "\n"), ":")
+ if len(usernameAndPasswordHash) != 2 {
+ return nil, fmt.Errorf("invalid credential file format")
+ }
+ username := usernameAndPasswordHash[0]
+ passwordHash := usernameAndPasswordHash[1]
+ proxy = basicAuthHandler(
+ proxy,
+ p.BasicAuth.Realm,
+ username,
+ passwordHash,
+ )
}
rules = append(rules, rewriteRule{
fromHost: p.From.Host,
fromPath: p.From.Path,
toUrl: targetUrl,
- proxy: &httputil.ReverseProxy{
- Rewrite: func(r *httputil.ProxyRequest) {
- r.SetURL(targetUrl)
- r.SetXForwarded()
- },
- },
+ proxy: proxy,
})
}
return &multipleReverseProxyServer{
rules: rules,
- }
+ }, nil
}
func (s *multipleReverseProxyServer) tryServeHTTP(
@@ -77,7 +111,7 @@ type Server struct {
tlsEnabled bool
}
-func NewServer(cfg *ServerConfig) *Server {
+func NewServer(cfg *ServerConfig) (*Server, error) {
h := http.NewServeMux()
if cfg.ACMEChallenge != nil {
@@ -95,7 +129,10 @@ func NewServer(cfg *ServerConfig) *Server {
http.Redirect(w, r, target.String(), http.StatusMovedPermanently)
})
} else {
- reverseProxyServer := newMultipleReverseProxyServer(cfg.Proxies)
+ reverseProxyServer, err := newMultipleReverseProxyServer(cfg.Proxies)
+ if err != nil {
+ return nil, err
+ }
h.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// r.Host may have ":port" part.
hostWithoutPort, _, err := net.SplitHostPort(r.Host)
@@ -114,7 +151,7 @@ func NewServer(cfg *ServerConfig) *Server {
if cfg.TLSCertFile != "" && cfg.TLSKeyFile != "" {
cert, err := tls.LoadX509KeyPair(cfg.TLSCertFile, cfg.TLSKeyFile)
if err != nil {
- panic(err)
+ return nil, err
}
tlsConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
@@ -128,7 +165,7 @@ func NewServer(cfg *ServerConfig) *Server {
Handler: h,
TLSConfig: tlsConfig,
},
- }
+ }, nil
}
func (s *Server) Label() string {