mirror of
https://github.com/fosrl/badger.git
synced 2026-04-01 15:36:44 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67ad9b651e | ||
|
|
f220c75a52 | ||
|
|
d81af67db3 | ||
|
|
2902340f7b | ||
|
|
877363a686 | ||
|
|
e0a2d76844 | ||
|
|
be5015cc2a | ||
|
|
f00a92c7af |
14
README.md
14
README.md
@@ -70,20 +70,6 @@ trustip:
|
|||||||
customIPHeader: "X-Forwarded-For"
|
customIPHeader: "X-Forwarded-For"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration Options Reference
|
|
||||||
|
|
||||||
| Option | Type | Required\* | Default | Description |
|
|
||||||
| ----------------------------- | -------- | ---------- | ------- | ----------------------------------------------------------------------------------- |
|
|
||||||
| `disableForwardAuth` | bool | No | `false` | Disable forward auth; only IP handling is performed |
|
|
||||||
| `apiBaseUrl` | string | Yes\* | - | Base URL of the Pangolin API |
|
|
||||||
| `userSessionCookieName` | string | Yes\* | - | Cookie name for user sessions |
|
|
||||||
| `resourceSessionRequestParam` | string | Yes\* | - | Query parameter name for resource session requests |
|
|
||||||
| `trustip` | []string | No | `[]` | Array of trusted IP ranges in CIDR format |
|
|
||||||
| `disableDefaultCFIPs` | bool | No | `false` | Disable default Cloudflare IP ranges |
|
|
||||||
| `customIPHeader` | string | No | `""` | Custom header name to extract IP from (only used if request is from trusted source) |
|
|
||||||
|
|
||||||
\* Required only when `disableForwardAuth` is `false` (default)
|
|
||||||
|
|
||||||
## Updating Cloudflare IPs
|
## Updating Cloudflare IPs
|
||||||
|
|
||||||
To update the Cloudflare IP ranges, run:
|
To update the Cloudflare IP ranges, run:
|
||||||
|
|||||||
75
main.go
75
main.go
@@ -10,12 +10,16 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fosrl/badger/ips"
|
"github.com/fosrl/badger/ips"
|
||||||
|
"github.com/fosrl/badger/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
APIBaseUrl string `json:"apiBaseUrl,omitempty"`
|
APIBaseUrl string `json:"apiBaseUrl,omitempty"`
|
||||||
UserSessionCookieName string `json:"userSessionCookieName,omitempty"`
|
UserSessionCookieName string `json:"userSessionCookieName,omitempty"`
|
||||||
ResourceSessionRequestParam string `json:"resourceSessionRequestParam,omitempty"`
|
ResourceSessionRequestParam string `json:"resourceSessionRequestParam,omitempty"`
|
||||||
|
AccessTokenQueryParam string `json:"accessTokenQueryParam,omitempty"`
|
||||||
|
AccessTokenIDHeader string `json:"accessTokenIdHeader,omitempty"`
|
||||||
|
AccessTokenHeader string `json:"accessTokenHeader,omitempty"`
|
||||||
DisableForwardAuth bool `json:"disableForwardAuth,omitempty"`
|
DisableForwardAuth bool `json:"disableForwardAuth,omitempty"`
|
||||||
TrustIP []string `json:"trustip,omitempty"`
|
TrustIP []string `json:"trustip,omitempty"`
|
||||||
DisableDefaultCFIPs bool `json:"disableDefaultCFIPs,omitempty"`
|
DisableDefaultCFIPs bool `json:"disableDefaultCFIPs,omitempty"`
|
||||||
@@ -36,6 +40,9 @@ type Badger struct {
|
|||||||
apiBaseUrl string
|
apiBaseUrl string
|
||||||
userSessionCookieName string
|
userSessionCookieName string
|
||||||
resourceSessionRequestParam string
|
resourceSessionRequestParam string
|
||||||
|
accessTokenQueryParam string
|
||||||
|
accessTokenIDHeader string
|
||||||
|
accessTokenHeader string
|
||||||
disableForwardAuth bool
|
disableForwardAuth bool
|
||||||
trustIP []*net.IPNet
|
trustIP []*net.IPNet
|
||||||
customIPHeader string
|
customIPHeader string
|
||||||
@@ -52,6 +59,7 @@ type VerifyBody struct {
|
|||||||
RequestIP *string `json:"requestIp,omitempty"`
|
RequestIP *string `json:"requestIp,omitempty"`
|
||||||
Headers map[string]string `json:"headers,omitempty"`
|
Headers map[string]string `json:"headers,omitempty"`
|
||||||
Query map[string]string `json:"query,omitempty"`
|
Query map[string]string `json:"query,omitempty"`
|
||||||
|
BadgerVersion string `json:"badgerVersion,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerifyResponse struct {
|
type VerifyResponse struct {
|
||||||
@@ -64,6 +72,7 @@ type VerifyResponse struct {
|
|||||||
Name *string `json:"name,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
Role *string `json:"role,omitempty"`
|
Role *string `json:"role,omitempty"`
|
||||||
ResponseHeaders map[string]string `json:"responseHeaders,omitempty"`
|
ResponseHeaders map[string]string `json:"responseHeaders,omitempty"`
|
||||||
|
PangolinVersion *string `json:"pangolinVersion,omitempty"`
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +101,9 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h
|
|||||||
apiBaseUrl: config.APIBaseUrl,
|
apiBaseUrl: config.APIBaseUrl,
|
||||||
userSessionCookieName: config.UserSessionCookieName,
|
userSessionCookieName: config.UserSessionCookieName,
|
||||||
resourceSessionRequestParam: config.ResourceSessionRequestParam,
|
resourceSessionRequestParam: config.ResourceSessionRequestParam,
|
||||||
|
accessTokenQueryParam: config.AccessTokenQueryParam,
|
||||||
|
accessTokenIDHeader: config.AccessTokenIDHeader,
|
||||||
|
accessTokenHeader: config.AccessTokenHeader,
|
||||||
disableForwardAuth: config.DisableForwardAuth,
|
disableForwardAuth: config.DisableForwardAuth,
|
||||||
customIPHeader: config.CustomIPHeader,
|
customIPHeader: config.CustomIPHeader,
|
||||||
}
|
}
|
||||||
@@ -228,6 +240,7 @@ func (p *Badger) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
RequestIP: &realIP,
|
RequestIP: &realIP,
|
||||||
Headers: headers,
|
Headers: headers,
|
||||||
Query: queryParams,
|
Query: queryParams,
|
||||||
|
BadgerVersion: version.Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonData, err := json.Marshal(cookieData)
|
jsonData, err := json.Marshal(cookieData)
|
||||||
@@ -308,6 +321,10 @@ func (p *Badger) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
req.Header.Add("Remote-Role", *result.Data.Role)
|
req.Header.Add("Remote-Role", *result.Data.Role)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.stripSessionCookies(req)
|
||||||
|
p.stripSessionParam(req)
|
||||||
|
p.stripAccessTokenHeaders(req)
|
||||||
|
|
||||||
fmt.Println("Badger: Valid session")
|
fmt.Println("Badger: Valid session")
|
||||||
p.next.ServeHTTP(rw, req)
|
p.next.ServeHTTP(rw, req)
|
||||||
return
|
return
|
||||||
@@ -410,6 +427,64 @@ func (p *Badger) getRealIP(req *http.Request) string {
|
|||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Badger) stripSessionParam(req *http.Request) {
|
||||||
|
query := req.URL.Query()
|
||||||
|
modified := false
|
||||||
|
if query.Has(p.resourceSessionRequestParam) {
|
||||||
|
query.Del(p.resourceSessionRequestParam)
|
||||||
|
modified = true
|
||||||
|
}
|
||||||
|
if p.accessTokenQueryParam != "" && query.Has(p.accessTokenQueryParam) {
|
||||||
|
query.Del(p.accessTokenQueryParam)
|
||||||
|
modified = true
|
||||||
|
}
|
||||||
|
if modified {
|
||||||
|
req.URL.RawQuery = query.Encode()
|
||||||
|
req.RequestURI = req.URL.RequestURI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Badger) stripAccessTokenHeaders(req *http.Request) {
|
||||||
|
if p.accessTokenIDHeader != "" {
|
||||||
|
req.Header.Del(p.accessTokenIDHeader)
|
||||||
|
}
|
||||||
|
if p.accessTokenHeader != "" {
|
||||||
|
req.Header.Del(p.accessTokenHeader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stripSessionCookies removes session cookies from the request before forwarding to the backend.
|
||||||
|
// It processes raw Cookie header pairs so non-target cookies are preserved as-is.
|
||||||
|
func (p *Badger) stripSessionCookies(req *http.Request) {
|
||||||
|
cookieHeaders := req.Header.Values("Cookie")
|
||||||
|
if len(cookieHeaders) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var remainingPairs []string
|
||||||
|
for _, headerValue := range cookieHeaders {
|
||||||
|
for _, part := range strings.Split(headerValue, ";") {
|
||||||
|
part = strings.TrimSpace(part)
|
||||||
|
if part == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name, _, _ := strings.Cut(part, "=")
|
||||||
|
name = strings.TrimSpace(name)
|
||||||
|
if !strings.HasPrefix(name, p.userSessionCookieName) {
|
||||||
|
remainingPairs = append(remainingPairs, part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(remainingPairs) == 0 {
|
||||||
|
req.Header.Del("Cookie")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep a single canonical Cookie header while preserving surviving name=value pairs.
|
||||||
|
req.Header.Set("Cookie", strings.Join(remainingPairs, "; "))
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Badger) isTrustedIP(remoteAddr string) bool {
|
func (p *Badger) isTrustedIP(remoteAddr string) bool {
|
||||||
ipStr, _, err := net.SplitHostPort(remoteAddr)
|
ipStr, _, err := net.SplitHostPort(remoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
3
version/version.go
Normal file
3
version/version.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package version
|
||||||
|
|
||||||
|
const Version = "1.3.1"
|
||||||
Reference in New Issue
Block a user