forked from Nixius/authelia
66 lines
1.7 KiB
Go
66 lines
1.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
)
|
|
|
|
// instanceUsernamePattern matches valid instance slugs.
|
|
var instanceUsernamePattern = regexp.MustCompile(`^[a-z0-9-]+$`)
|
|
|
|
// handleInstanceProxy enforces account ownership for /i/<slug>, then
|
|
// reverse-proxies to that customer stack's web service.
|
|
func (a *App) handleInstanceProxy(w http.ResponseWriter, r *http.Request) {
|
|
slug := chi.URLParam(r, "username")
|
|
if slug == "" {
|
|
http.Error(w, "forbidden", http.StatusForbidden)
|
|
return
|
|
}
|
|
if !instanceUsernamePattern.MatchString(slug) {
|
|
http.Error(w, "forbidden", http.StatusForbidden)
|
|
return
|
|
}
|
|
acct, identity, err := a.currentAccount(r)
|
|
if err != nil || acct == nil {
|
|
http.Redirect(w, r, a.cfg.IdentityURL, http.StatusSeeOther)
|
|
return
|
|
}
|
|
inst, err := a.accounts.InstanceBySlug(r.Context(), slug)
|
|
if err != nil || inst.AccountID != acct.ID {
|
|
log.Printf("instance proxy: denied %s access to /i/%s", accountDisplay(acct, identity), slug)
|
|
http.Error(w, "forbidden", http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
backendHost := fmt.Sprintf("web.%s", inst.StackName)
|
|
backendURL := &url.URL{
|
|
Scheme: "http",
|
|
Host: backendHost + ":3001",
|
|
Path: "/",
|
|
}
|
|
prefix := "/i/" + slug
|
|
pathSuffix := strings.TrimPrefix(r.URL.Path, prefix)
|
|
if pathSuffix == "" {
|
|
pathSuffix = "/"
|
|
}
|
|
if !strings.HasPrefix(pathSuffix, "/") {
|
|
pathSuffix = "/" + pathSuffix
|
|
}
|
|
|
|
proxy := httputil.NewSingleHostReverseProxy(backendURL)
|
|
proxy.Director = func(req *http.Request) {
|
|
req.URL.Scheme = backendURL.Scheme
|
|
req.URL.Host = backendURL.Host
|
|
req.URL.Path = pathSuffix
|
|
req.Host = backendURL.Host
|
|
}
|
|
proxy.ServeHTTP(w, r)
|
|
}
|