diff --git a/cmd/jwtpxy.go b/cmd/jwtpxy.go index 5cffe8c..6ca646b 100644 --- a/cmd/jwtpxy.go +++ b/cmd/jwtpxy.go @@ -38,12 +38,13 @@ var ( backendEnv = getEnv("BACKEND", "http://localhost:8000") headerMappingsEnv = getEnv("HEADER_MAPPING", "From:preferred_username,Realm-Access:realm_access,Groups:groups") requireTokenModeEnv = getEnv("REQUIRE_TOKEN", "true") + allowCookieTokenEnv = getEnv("ALLOW_COOKIE_TOKEN", "false") + cookieTokenNameEnv = getEnv("COOKIE_TOKEN_NAME", "jwt") sigHeaderEnv = getEnv("SIG_HEADER", "shared_secret_change_me") ) var Version = "0.0.0" -// Realm info from Keycloak type RealmInfo struct { Realm string `json:"realm"` PublicKey string `json:"public_key"` @@ -85,6 +86,8 @@ func main() { sigHeader = flag.String("sigHeader", sigHeaderEnv, "Signature header / shared secret") requireTokenMode = flag.String("requireTokenMode", requireTokenModeEnv, "set to string \"false\" to allow un-authenticated pass-through.") headerMappings = flag.String("headerMappings", headerMappingsEnv, "Mapping HTTPS headers to token attributes.") + allowCookieToken = flag.String("allowCookieToken", allowCookieTokenEnv, "Allow cookie tokens.") + cookieTokenName = flag.String("cookieTokenName", cookieTokenNameEnv, "Cookie token name.") ) flag.Parse() @@ -200,6 +203,8 @@ func main() { RequireTokenMode: *requireTokenMode, TokenMappings: tknMappings, SigHeader: *sigHeader, + CookieTokenName: *cookieTokenName, + AllowCookieToken: *allowCookieToken, } // proxy mux diff --git a/proxy.go b/proxy.go index c89670e..fc2ee22 100644 --- a/proxy.go +++ b/proxy.go @@ -26,6 +26,8 @@ type Proxy struct { RequireTokenMode string SigHeader string TokenMappings []TokenMapping + AllowCookieToken string + CookieTokenName string } type JWTConfig struct { @@ -78,8 +80,16 @@ func (p *Proxy) Handle(w http.ResponseWriter, r *http.Request) { authHeader := r.Header.Get("Authorization") tokenString := strings.TrimPrefix(authHeader, "Bearer ") + // if Bearer token is empty and cookie token is true. + if tokenString != "" && p.AllowCookieToken == "true" { + tokenCookie, _ := r.Cookie(p.CookieTokenName) + if tokenCookie != nil && tokenCookie.Secure && tokenCookie.HttpOnly { + tokenString = tokenCookie.String() + } + } + if tokenString != "" { - err := p.ProxyTokenHandler(r) + err := p.ProxyTokenHandler(r, tokenString) if err != nil { // fail admit = false @@ -93,7 +103,7 @@ func (p *Proxy) Handle(w http.ResponseWriter, r *http.Request) { // is requireTokenMode is true then a token is required // return unauthorized - if tokenString == "" && requireTokenMode == "true" { + if admit && tokenString == "" && requireTokenMode == "true" { // fail admit = false diff --git a/token.go b/token.go index 9b60737..b42ea5c 100644 --- a/token.go +++ b/token.go @@ -6,7 +6,6 @@ import ( "fmt" "net/http" "reflect" - "strings" "github.com/dgrijalva/jwt-go" "go.uber.org/zap" @@ -18,11 +17,7 @@ type TokenMapping struct { TokenValue interface{} } -func (p *Proxy) ProxyTokenHandler(r *http.Request) error { - - // process JWT - authHeader := r.Header.Get("Authorization") - tokenString := strings.TrimPrefix(authHeader, "Bearer ") +func (p *Proxy) ProxyTokenHandler(r *http.Request, tokenString string) error { token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { // WARNING: always validate that the alg is what we expect