Skip to content
Snippets Groups Projects
Verified Commit 6cbb7582 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Fix header injection bug

parent ee5c21ff
Branches
Tags
No related merge requests found
NAME=keycloak-gatekeeper
AUTHOR=keycloak
REGISTRY=docker.io
GOVERSION ?= 1.10.2
ROOT_DIR=${PWD}
HARDWARE=$(shell uname -m)
GIT_SHA=$(shell git --no-pager describe --always --dirty)
BUILD_TIME=$(shell date '+%s')
VERSION ?= $(shell awk '/release.*=/ { print $$3 }' doc.go | sed 's/"//g')
DEPS=$(shell go list -f '{{range .TestImports}}{{.}} {{end}}' ./...)
PACKAGES=$(shell go list ./...)
LFLAGS ?= -X main.gitsha=${GIT_SHA} -X main.compiled=${BUILD_TIME}
VETARGS ?= -asmdecl -atomic -bool -buildtags -copylocks -methods -nilfunc -printf -rangeloops -shift -unsafeptr
PLATFORMS=darwin linux windows
ARCHITECTURES=amd64
.PHONY: test authors changelog build docker static release lint cover vet glide-install
default: build
golang:
@echo "--> Go Version"
@go version
build: golang
@echo "--> Compiling the project"
@mkdir -p bin
go build -ldflags "${LFLAGS}" -o bin/${NAME}
static: golang
@echo "--> Compiling the static binary"
@mkdir -p bin
CGO_ENABLED=0 GOOS=linux go build -a -tags netgo -ldflags "-w ${LFLAGS}" -o bin/${NAME}
docker-build:
@echo "--> Compiling the project"
docker run --rm \
-v ${ROOT_DIR}:/go/src/github.com/${AUTHOR}/${NAME} \
-w /go/src/github.com/${AUTHOR}/${NAME} \
-e GOOS=linux golang:${GOVERSION} \
make static
docker-test:
@echo "--> Running the docker test"
docker run --rm -ti -p 3000:3000 \
-v ${ROOT_DIR}/config.yml:/etc/keycloak/config.yml:ro \
-v ${ROOT_DIR}/tests:/opt/tests:ro \
${REGISTRY}/${AUTHOR}/${NAME}:${VERSION} --config /etc/keycloak/config.yml
docker-release:
@echo "--> Building a release image"
@$(MAKE) static
@$(MAKE) docker
@docker push ${REGISTRY}/${AUTHOR}/${NAME}:${VERSION}
docker:
@echo "--> Building the docker image"
docker build -t ${REGISTRY}/${AUTHOR}/${NAME}:${VERSION} .
certs:
@echo "--> Generating the root CA"
@cfssl gencert -initca tests/ca-csr.json | cfssljson -bare tests/ca
@echo "--> Generating the Test Certs"
cfssl gencert \
-ca=tests/ca.pem \
-ca-key=tests/ca-key.pem \
-config=tests/ca-config.json \
-profile=server \
tests/proxy-csr.json | cfssljson -bare tests/proxy
clean:
rm -rf ./bin/* 2>/dev/null
rm -rf ./release/* 2>/dev/null
authors:
@echo "--> Updating the AUTHORS"
git log --format='%aN <%aE>' | sort -u > AUTHORS
vet:
@echo "--> Running go vet $(VETARGS) ."
@go vet 2>/dev/null ; if [ $$? -eq 3 ]; then \
go get golang.org/x/tools/cmd/vet; \
fi
# This is required due to break of API compatibility in go vet between version 1.11 and 1.12
@go version | grep '1.11' 2>/dev/null ; if [[ $$? -eq 0 ]]; then \
go vet $(VETARGS) -structtags *.go; \
fi
@go version | grep '1.12' 2>/dev/null ; if [[ $$? -eq 0 ]]; then \
go vet $(VETARGS) -structtag *.go; \
fi
lint:
@echo "--> Running golangci-lint"
@which golangci-lint 2>/dev/null ; if [ $$? -eq 1 ]; then \
go get -u github.com/golangci/golangci-lint/cmd/golangci-lint; \
fi
@golint .
gofmt:
@echo "--> Running gofmt check"
@gofmt -s -l *.go \
| grep -q \.go ; if [ $$? -eq 0 ]; then \
echo "You need to runn the make format, we have file unformatted"; \
gofmt -s -l *.go; \
exit 1; \
fi
verify:
@echo "--> Verifying the code"
golangci-lint run
format:
@echo "--> Running go fmt"
@gofmt -s -w *.go
bench:
@echo "--> Running go bench"
@go test -bench=. -benchmem
coverage:
@echo "--> Running go coverage"
@go test -coverprofile cover.out
@go tool cover -html=cover.out -o cover.html
cover:
@echo "--> Running go cover"
@go test --cover
spelling:
@echo "--> Checking the spelling"
@which misspell 2>/dev/null ; if [ $$? -eq 1 ]; then \
go get -u github.com/client9/misspell/cmd/misspell; \
fi
@misspell -error *.go
@misspell -error *.md
test:
@echo "--> Running the tests"
@go test -v
@$(MAKE) golang
@$(MAKE) gofmt
@$(MAKE) spelling
@$(MAKE) vet
@$(MAKE) cover
all: test
echo "--> Performing all tests"
@${MAKE} verify
@$(MAKE) bench
@$(MAKE) coverage
changelog: release
git log $(shell git tag | tail -n1)..HEAD --no-merges --format=%B > changelog
...@@ -113,7 +113,7 @@ func (r *oauthProxy) requestHeaderSanitizingMiddleware() func(http.Handler) http ...@@ -113,7 +113,7 @@ func (r *oauthProxy) requestHeaderSanitizingMiddleware() func(http.Handler) http
} }
// authenticationMiddleware is responsible for verifying the access token // authenticationMiddleware is responsible for verifying the access token
func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handler) http.Handler { func (r *oauthProxy) authenticationMiddleware(loginOptional bool) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
clientIP := req.RemoteAddr clientIP := req.RemoteAddr
...@@ -121,7 +121,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle ...@@ -121,7 +121,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle
user, err := r.getIdentity(req) user, err := r.getIdentity(req)
if err != nil { if err != nil {
r.log.Error("no session found in request, redirecting for authorization", zap.Error(err)) r.log.Error("no session found in request, redirecting for authorization", zap.Error(err))
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req)))
...@@ -141,7 +141,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle ...@@ -141,7 +141,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle
zap.String("username", user.name), zap.String("username", user.name),
zap.String("expired_on", user.expiresAt.String())) zap.String("expired_on", user.expiresAt.String()))
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req)))
...@@ -157,7 +157,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle ...@@ -157,7 +157,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle
zap.String("client_ip", clientIP), zap.String("client_ip", clientIP),
zap.Error(err)) zap.Error(err))
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req)))
...@@ -171,7 +171,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle ...@@ -171,7 +171,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle
zap.String("email", user.name), zap.String("email", user.name),
zap.String("expired_on", user.expiresAt.String())) zap.String("expired_on", user.expiresAt.String()))
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req)))
...@@ -190,7 +190,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle ...@@ -190,7 +190,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle
zap.String("email", user.email), zap.String("email", user.email),
zap.Error(err)) zap.Error(err))
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req)))
...@@ -217,7 +217,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle ...@@ -217,7 +217,7 @@ func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handle
default: default:
r.log.Error("failed to refresh the access token", zap.Error(err)) r.log.Error("failed to refresh the access token", zap.Error(err))
} }
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req)))
...@@ -349,7 +349,7 @@ func (r *oauthProxy) checkClaim(user *userContext, claimName string, match *rege ...@@ -349,7 +349,7 @@ func (r *oauthProxy) checkClaim(user *userContext, claimName string, match *rege
} }
// admissionMiddleware is responsible checking the access token against the protected resource // admissionMiddleware is responsible checking the access token against the protected resource
func (r *oauthProxy) admissionMiddleware(whitelisted bool, resource *Resource) func(http.Handler) http.Handler { func (r *oauthProxy) admissionMiddleware(loginOptional bool, resource *Resource) func(http.Handler) http.Handler {
claimMatches := make(map[string]*regexp.Regexp) claimMatches := make(map[string]*regexp.Regexp)
for k, v := range r.config.MatchClaims { for k, v := range r.config.MatchClaims {
claimMatches[k] = regexp.MustCompile(v) claimMatches[k] = regexp.MustCompile(v)
...@@ -373,7 +373,7 @@ func (r *oauthProxy) admissionMiddleware(whitelisted bool, resource *Resource) f ...@@ -373,7 +373,7 @@ func (r *oauthProxy) admissionMiddleware(whitelisted bool, resource *Resource) f
zap.String("resource", resource.URL), zap.String("resource", resource.URL),
zap.String("roles", resource.getRoles())) zap.String("roles", resource.getRoles()))
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req)))
...@@ -388,7 +388,7 @@ func (r *oauthProxy) admissionMiddleware(whitelisted bool, resource *Resource) f ...@@ -388,7 +388,7 @@ func (r *oauthProxy) admissionMiddleware(whitelisted bool, resource *Resource) f
zap.String("resource", resource.URL), zap.String("resource", resource.URL),
zap.String("groups", strings.Join(resource.Groups, ","))) zap.String("groups", strings.Join(resource.Groups, ",")))
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req)))
...@@ -398,7 +398,7 @@ func (r *oauthProxy) admissionMiddleware(whitelisted bool, resource *Resource) f ...@@ -398,7 +398,7 @@ func (r *oauthProxy) admissionMiddleware(whitelisted bool, resource *Resource) f
// step: if we have any claim matching, lets validate the tokens has the claims // step: if we have any claim matching, lets validate the tokens has the claims
for claimName, match := range claimMatches { for claimName, match := range claimMatches {
if !r.checkClaim(user, claimName, match, resource.URL) { if !r.checkClaim(user, claimName, match, resource.URL) {
if whitelisted { if loginOptional {
return return
} }
next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req)))
...@@ -482,7 +482,7 @@ func (r *oauthProxy) identityHeadersMiddleware(custom []string) func(http.Handle ...@@ -482,7 +482,7 @@ func (r *oauthProxy) identityHeadersMiddleware(custom []string) func(http.Handle
// securityMiddleware performs numerous security checks on the request // securityMiddleware performs numerous security checks on the request
func (r *oauthProxy) securityMiddleware(next http.Handler) http.Handler { func (r *oauthProxy) securityMiddleware(next http.Handler) http.Handler {
r.log.Info("enabling the security filter middleware") r.log.Info("enabling the security filter middleware")
secure := secure.New(secure.Options{ secureFilter := secure.New(secure.Options{
AllowedHosts: r.config.Hostnames, AllowedHosts: r.config.Hostnames,
BrowserXssFilter: r.config.EnableBrowserXSSFilter, BrowserXssFilter: r.config.EnableBrowserXSSFilter,
ContentSecurityPolicy: r.config.ContentSecurityPolicy, ContentSecurityPolicy: r.config.ContentSecurityPolicy,
...@@ -493,7 +493,7 @@ func (r *oauthProxy) securityMiddleware(next http.Handler) http.Handler { ...@@ -493,7 +493,7 @@ func (r *oauthProxy) securityMiddleware(next http.Handler) http.Handler {
}) })
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if err := secure.Process(w, req); err != nil { if err := secureFilter.Process(w, req); err != nil {
r.log.Warn("failed security middleware", zap.Error(err)) r.log.Warn("failed security middleware", zap.Error(err))
next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req)))
return return
......
...@@ -265,6 +265,7 @@ func (r *oauthProxy) createReverseProxy() error { ...@@ -265,6 +265,7 @@ func (r *oauthProxy) createReverseProxy() error {
r.identityHeadersMiddleware(r.config.AddClaims)) r.identityHeadersMiddleware(r.config.AddClaims))
o := engine.With( o := engine.With(
r.requestHeaderSanitizingMiddleware(),
r.authenticationMiddleware(true), r.authenticationMiddleware(true),
r.admissionMiddleware(true, x), r.admissionMiddleware(true, x),
r.identityHeadersMiddleware(r.config.AddClaims)) r.identityHeadersMiddleware(r.config.AddClaims))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment