impl authelia I think

master
Bel LaPointe 2021-03-21 12:44:21 -05:00
parent 177e0d88da
commit cebb518e05
7 changed files with 125 additions and 16 deletions

BIN
config/.config.go.un~ Normal file

Binary file not shown.

BIN
config/.new.go.un~ Normal file

Binary file not shown.

View File

@ -25,6 +25,11 @@ func parseProxy(s string) (string, Proxy) {
return key, p
}
func GetAuthelia() (string, bool) {
authelia := conf.Get("authelia").GetString()
return authelia, authelia != ""
}
func GetBOAuthZ() (string, bool) {
boauthz := conf.Get("oauth").GetString()
return boauthz, boauthz != ""
@ -99,3 +104,7 @@ func GetNoPath(key string) bool {
_, ok := m[key]
return ok
}
func GetCompression() bool {
return conf.GetBool("compression")
}

View File

@ -3,6 +3,7 @@ package config
import (
"fmt"
"local/args"
"local/logb"
"log"
"os"
"strings"
@ -26,6 +27,7 @@ func Refresh() error {
return err
}
conf = as
logb.Set(logb.LevelFromString(as.GetString("level")))
return nil
}
@ -42,14 +44,17 @@ func parseArgs() (*args.ArgSet, error) {
as.Append(args.INT, "ap", "alt port for always http service", 51556)
as.Append(args.INT, "r", "rate per second for requests", 100)
as.Append(args.INT, "b", "burst requests", 100)
as.Append(args.BOOL, "compress", "enable compression", true)
as.Append(args.STRING, "crt", "path to crt for ssl", "")
as.Append(args.STRING, "key", "path to key for ssl", "")
as.Append(args.STRING, "tcp", "address for tcp only tunnel", "")
as.Append(args.DURATION, "timeout", "timeout for tunnel", time.Minute)
as.Append(args.STRING, "proxy", "double-comma separated (+ if oauth)from,scheme://to.tld:port,oauth,,", "")
as.Append(args.STRING, "proxy", "double-comma separated (+ if auth)from,scheme://to.tld:port,,", "")
as.Append(args.STRING, "oauth", "url for boauthz", "")
as.Append(args.STRING, "authelia", "url for authelia", "")
as.Append(args.STRING, "cors", "json dict key:true for keys to set CORS permissive headers, like {\"from\":true}", "{}")
as.Append(args.STRING, "nopath", "json dict key:true for keys to remove all path info from forwarded request, like -cors", "{}")
as.Append(args.STRING, "level", "log level", "info")
err := as.Parse()
return as, err

View File

@ -11,10 +11,13 @@ func New() *Server {
port := config.GetPort()
altport := config.GetAltPort()
r, b := config.GetRate()
return &Server{
server := &Server{
db: storage.NewMap(),
addr: port,
altaddr: altport,
limiter: rate.NewLimiter(rate.Limit(r), b),
}
_, server.auth.BOAuthZ = config.GetBOAuthZ()
_, server.auth.Authelia = config.GetAuthelia()
return server
}

View File

@ -49,7 +49,7 @@ func (s *Server) lookup(host string) (*url.URL, error) {
return v.URL(), err
}
func (s *Server) lookupBOAuthZ(host string) (bool, error) {
func (s *Server) lookupAuth(host string) (bool, error) {
v := packable.NewString()
err := s.db.Get(nsBOAuthZ, host, v)
return v.String() == "true", err

View File

@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"io"
"local/logb"
"local/oauth2/oauth2client"
"local/rproxy3/config"
"local/rproxy3/storage"
@ -52,6 +53,10 @@ type Server struct {
username string
password string
limiter *rate.Limiter
auth struct {
BOAuthZ bool
Authelia bool
}
}
func (s *Server) Route(src string, dst config.Proxy) error {
@ -99,19 +104,81 @@ func (s *Server) Run() error {
return errors.New("did not load server")
}
func (s *Server) doAuth(foo http.HandlerFunc) http.HandlerFunc {
func (s *Server) doAuthelia(foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
authelia, ok := config.GetAuthelia()
if !ok {
panic("howd i get here")
}
url, err := url.Parse(authelia)
if err != nil {
panic(fmt.Sprintf("bad config for authelia url: %v", err))
}
url.Path = "/api/verify"
req, err := http.NewRequest(http.MethodGet, url.String(), nil)
if err != nil {
panic(err.Error())
}
r2 := r.Clone(r.Context())
if r2.URL.Host == "" {
r2.URL.Host = r2.Host
}
r2.URL.Host, _, _ = net.SplitHostPort(r2.URL.Host)
if r2.URL.Scheme == "" {
r2.URL.Scheme = "https"
}
for _, httpreq := range []*http.Request{r, req} {
httpreq.Header.Set("X-Original-URL", r2.URL.String())
httpreq.Header.Set("X-Forwarded-Proto", r2.URL.Scheme)
httpreq.Header.Set("X-Forwarded-Host", r2.URL.Host)
httpreq.Header.Set("X-Forwarded-URI", r2.URL.String())
}
if cookie, err := r.Cookie("authelia_session"); err == nil {
req.AddCookie(cookie)
}
c := &http.Client{
Timeout: time.Minute,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
autheliaKey := mapKey(req.Host)
if strings.HasPrefix(r.Host, autheliaKey) {
logb.Debugf("no authelia for %s because it has prefix %s", r.Host, autheliaKey)
foo(w, r)
return
}
resp, err := c.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
logb.Debugf(
"authelia: %+v, %+v \n\t-> \n\t(%d) %+v, %+v",
req,
req.Cookies(),
resp.StatusCode,
resp.Header,
resp.Cookies(),
)
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
foo(w, r)
return
}
url.Path = ""
q := url.Query()
q.Set("rd", r2.URL.String())
url.RawQuery = q.Encode()
http.Redirect(w, r, url.String(), http.StatusFound)
}
}
func (s *Server) doBOAuthZ(foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
key := mapKey(r.Host)
if config.GetCORS(key) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "X-Auth-Token, content-type, Content-Type")
if r.Method == "OPTIONS" {
w.Header().Set("Content-Length", "0")
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, TRACE, PATCH, HEAD, DELETE")
return
}
}
rusr, rpwd, ok := config.GetAuth()
if ok {
usr, pwd, ok := r.BasicAuth()
@ -121,7 +188,7 @@ func (s *Server) doAuth(foo http.HandlerFunc) http.HandlerFunc {
return
}
}
ok, err := s.lookupBOAuthZ(key)
ok, err := s.lookupAuth(key)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
@ -177,7 +244,16 @@ func (s *Server) Pre(foo http.HandlerFunc) http.HandlerFunc {
w.WriteHeader(http.StatusTooManyRequests)
return
}
s.doAuth(foo)(w, r)
if did := s.doCORS(w, r); did {
return
}
if s.auth.BOAuthZ {
s.doBOAuthZ(foo)(w, r)
} else if s.auth.Authelia {
s.doAuthelia(foo)(w, r)
} else {
foo(w, r)
}
}
}
@ -185,6 +261,22 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.Pre(s.Proxy)(w, r)
}
func (s *Server) doCORS(w http.ResponseWriter, r *http.Request) bool {
key := mapKey(r.Host)
if !config.GetCORS(key) {
return false
}
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "X-Auth-Token, content-type, Content-Type")
if r.Method != "OPTIONS" {
return false
}
w.Header().Set("Content-Length", "0")
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, TRACE, PATCH, HEAD, DELETE")
return true
}
func getProxyAuth(r *http.Request) (string, string) {
proxyAuthHeader := r.Header.Get("Proxy-Authorization")
proxyAuthB64 := strings.TrimPrefix(proxyAuthHeader, "Basic ")