mirror of
https://github.com/dredx/prole.git
synced 2026-09-27 16:24:30 +00:00
80 lines
2.4 KiB
Go
80 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
|
|
goidentity "github.com/jcmturner/goidentity/v6"
|
|
"github.com/jcmturner/gokrb5/v8/keytab"
|
|
"github.com/jcmturner/gokrb5/v8/spnego"
|
|
)
|
|
|
|
const (
|
|
upstreamURL = "http://gitea-http.gitea.svc.cluster.local:3000"
|
|
listenAddr = ":4000"
|
|
)
|
|
|
|
func main() {
|
|
keytabPath := os.Getenv("KRB5_KTNAME")
|
|
if keytabPath == "" {
|
|
keytabPath = "/etc/krb5/http.keytab"
|
|
}
|
|
|
|
kt, err := keytab.Load(keytabPath)
|
|
if err != nil {
|
|
log.Fatalf("failed to load keytab %s: %v", keytabPath, err)
|
|
}
|
|
|
|
upstream, _ := url.Parse(upstreamURL)
|
|
proxy := httputil.NewSingleHostReverseProxy(upstream)
|
|
proxy.Director = func(req *http.Request) {
|
|
req.URL.Scheme = upstream.Scheme
|
|
req.URL.Host = upstream.Host
|
|
if _, ok := req.Header["User-Agent"]; !ok {
|
|
req.Header.Set("User-Agent", "")
|
|
}
|
|
}
|
|
|
|
// authedInner runs only when SPNEGO negotiation succeeds.
|
|
// It extracts the client username from the request context and injects
|
|
// X-WEBAUTH-USER for Gitea reverse-proxy auto-login.
|
|
authedInner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// goidentity.AddToHTTPRequestContext is called by SPNEGOKRB5Authenticate on success.
|
|
// FromHTTPRequestContext retrieves the identity set there.
|
|
if id := goidentity.FromHTTPRequestContext(r); id != nil {
|
|
username := strings.SplitN(id.UserName(), "@", 2)[0]
|
|
r.Header.Set("X-WEBAUTH-USER", username)
|
|
log.Printf("SPNEGO auth OK: %s -> %s", id.UserName(), username)
|
|
}
|
|
proxy.ServeHTTP(w, r)
|
|
})
|
|
|
|
spnegoHandler := spnego.SPNEGOKRB5Authenticate(authedInner, kt)
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
mux.HandleFunc("/_healthz", func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = w.Write([]byte("ok"))
|
|
})
|
|
|
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
if strings.HasPrefix(r.Header.Get("Authorization"), "Negotiate ") {
|
|
// Client is presenting a Kerberos ticket — run full SPNEGO negotiation.
|
|
// On success: X-WEBAUTH-USER is set by authedInner, Gitea auto-logs in.
|
|
// On failure: gokrb5 returns 401 (invalid ticket — correct to reject).
|
|
spnegoHandler.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
// No Kerberos ticket — pass through so Gitea can show its own login page.
|
|
proxy.ServeHTTP(w, r)
|
|
})
|
|
|
|
log.Printf("spnego-proxy listening on %s, upstream %s", listenAddr, upstreamURL)
|
|
log.Fatal(http.ListenAndServe(listenAddr, mux))
|
|
}
|