diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index 0f29bb31c00c401d3444cef7ae71c6203a702704..0000000000000000000000000000000000000000 --- a/.golangci.yml +++ /dev/null @@ -1,23 +0,0 @@ -linters-settings: - govet: - check-shadowing: true - golint: - min-confidence: 0 - gocyclo: - min-complexity: 60 - maligned: - suggest-new: true - dupl: - threshold: 100 - goconst: - min-len: 2 - min-occurrences: 2 - -linters: - enable-all: true - disable: - - maligned - - unparam - - lll - - gochecknoinits - - gochecknoglobals diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d2d1522179535cafbbc3e844e3929e3f4dedad51..0000000000000000000000000000000000000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go - -matrix: - include: - - go: 1.12.x - env: GO111MODULE=on - - go: 1.11.x - env: GO111MODULE=on - -install: -- go get github.com/mattn/goveralls -- go get -u github.com/client9/misspell/cmd/misspell -script: -- make test -- if ([[ ${TRAVIS_BRANCH} == "master" ]] && [[ ${TRAVIS_EVENT_TYPE} == "push" ]]); then - go get github.com/mattn/goveralls; - goveralls -service=travis-ci; - make bench; - fi diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..299441727536515d8d779efbcdf622c2968108fb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM golang:alpine as go_builder + +RUN apk add --no-cache curl git gcc musl-dev +RUN curl https://glide.sh/get | sh + +WORKDIR /go/src/app +COPY *.go go.* ./ +RUN go mod download +RUN CGO_ENABLED=false go build -o app . + +FROM alpine:3.10 +RUN apk add --no-cache ca-certificates +WORKDIR / +COPY --from=go_builder /go/src/app/app /app +COPY templates /templates +ENTRYPOINT ["/app"] \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..c45b1b35a421e55c5352871855188c4d7fefb48d --- /dev/null +++ b/build.sh @@ -0,0 +1,9 @@ +#!/bin/sh +IMAGE=k8r.eu/justjanne/keycloak-proxy +TAGS=$(git describe --always --tags HEAD) + +docker build -t $IMAGE:$TAGS . +docker tag $IMAGE:$TAGS $IMAGE:latest +echo Successfully tagged $IMAGE:latest +docker push $IMAGE:$TAGS +docker push $IMAGE:latest \ No newline at end of file diff --git a/get-version.sh b/get-version.sh deleted file mode 100755 index a01326f386635ca6764ddd8ce1ca53e0d5166ce1..0000000000000000000000000000000000000000 --- a/get-version.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -e - -awk '/release.*=/ { print $3 }' doc.go | sed 's/"//g' diff --git a/go.mod b/go.mod index 6ac8067a53716b9967ab05e70e6dcc3d6791b1af..5ee3c434469a87fa095dea8e88a9fc825920a47f 100644 --- a/go.mod +++ b/go.mod @@ -35,3 +35,5 @@ require ( gopkg.in/resty.v1 v1.10.3 gopkg.in/yaml.v2 v2.2.2 ) + +go 1.13 diff --git a/middleware.go b/middleware.go index 7adcde95d9930c465d62b44227847dc6ab87d768..9b0d0ecd1422f611e0d8b10c1c92c0307a20d548 100644 --- a/middleware.go +++ b/middleware.go @@ -98,7 +98,7 @@ func (r *oauthProxy) loggingMiddleware(next http.Handler) http.Handler { } // authenticationMiddleware is responsible for verifying the access token -func (r *oauthProxy) authenticationMiddleware() func(http.Handler) http.Handler { +func (r *oauthProxy) authenticationMiddleware(whitelisted bool) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { clientIP := req.RemoteAddr @@ -106,6 +106,9 @@ func (r *oauthProxy) authenticationMiddleware() func(http.Handler) http.Handler user, err := r.getIdentity(req) if err != nil { r.log.Error("no session found in request, redirecting for authorization", zap.Error(err)) + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) return } @@ -123,6 +126,9 @@ func (r *oauthProxy) authenticationMiddleware() func(http.Handler) http.Handler zap.String("username", user.name), zap.String("expired_on", user.expiresAt.String())) + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) return } @@ -136,6 +142,9 @@ func (r *oauthProxy) authenticationMiddleware() func(http.Handler) http.Handler zap.String("client_ip", clientIP), zap.Error(err)) + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) return } @@ -147,6 +156,9 @@ func (r *oauthProxy) authenticationMiddleware() func(http.Handler) http.Handler zap.String("email", user.name), zap.String("expired_on", user.expiresAt.String())) + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) return } @@ -163,6 +175,9 @@ func (r *oauthProxy) authenticationMiddleware() func(http.Handler) http.Handler zap.String("email", user.email), zap.Error(err)) + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) return } @@ -187,6 +202,9 @@ func (r *oauthProxy) authenticationMiddleware() func(http.Handler) http.Handler default: r.log.Error("failed to refresh the access token", zap.Error(err)) } + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.redirectToAuthorization(w, req))) return @@ -316,7 +334,7 @@ func (r *oauthProxy) checkClaim(user *userContext, claimName string, match *rege } // admissionMiddleware is responsible checking the access token against the protected resource -func (r *oauthProxy) admissionMiddleware(resource *Resource) func(http.Handler) http.Handler { +func (r *oauthProxy) admissionMiddleware(whitelisted bool, resource *Resource) func(http.Handler) http.Handler { claimMatches := make(map[string]*regexp.Regexp) for k, v := range r.config.MatchClaims { claimMatches[k] = regexp.MustCompile(v) @@ -340,6 +358,9 @@ func (r *oauthProxy) admissionMiddleware(resource *Resource) func(http.Handler) zap.String("resource", resource.URL), zap.String("roles", resource.getRoles())) + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) return } @@ -352,6 +373,9 @@ func (r *oauthProxy) admissionMiddleware(resource *Resource) func(http.Handler) zap.String("resource", resource.URL), zap.String("groups", strings.Join(resource.Groups, ","))) + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) return } @@ -359,6 +383,9 @@ func (r *oauthProxy) admissionMiddleware(resource *Resource) func(http.Handler) // step: if we have any claim matching, lets validate the tokens has the claims for claimName, match := range claimMatches { if !r.checkClaim(user, claimName, match, resource.URL) { + if whitelisted { + return + } next.ServeHTTP(w, req.WithContext(r.accessForbidden(w, req))) return } diff --git a/release.sh b/release.sh deleted file mode 100755 index 28a6e2577b02a3832666c2e5cea8d9a2d87d6af0..0000000000000000000000000000000000000000 --- a/release.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -e -NAME="keycloak-gatekeeper" -PLATFORMS="darwin linux windows" -ARCHITECTURES="amd64" -GIT_SHA=$(git --no-pager describe --always --dirty) -BUILD_TIME=$(date '+%s') -LFLAGS="-X main.gitsha=$GIT_SHA -X main.compiled=$BUILD_TIME" - -DIR="$PWD" -VERSION=`./get-version.sh` -echo "Version: $VERSION" - -TMP=`mktemp -d` - -# Perform some clean up before building it -clean() { - rm -rf ./bin/* 2>/dev/null - rm -rf ./release/* 2>/dev/null -} - -release() { - mkdir -p release - for PLATFORM in $PLATFORMS; do - EXT="" - if [ "$PLATFORM" == "windows" ]; then - EXT=".exe" - fi - for ARCH in $ARCHITECTURES; do - env GOOS=$PLATFORM GOARCH=$ARCH CGO_ENABLED=0 go build -a -tags netgo -ldflags " -w $LFLAGS" -o bin/$NAME$EXT - tar -czvf release/"$NAME-$PLATFORM-$ARCH".tar.gz -C bin/ $NAME$EXT >/dev/null - sha1sum release/"$NAME-$PLATFORM-$ARCH".tar.gz | cut -d " " -f1 > release/"$NAME-$GOOS-$GOARCH".tar.gz.sha1 - # Test if tar file is not corrupted - if ! tar -tf release/"$NAME-$PLATFORM-$ARCH".tar.gz &>/dev/null;then - echo "Corrupted tar file" - exit 1 - fi - done - done -} - -echo "------------------------------------------------------------------------------------------------------------" -echo "Building: $NAME-$VERSION" -echo "" - -clean -release - -echo "------------------------------------------------------------------------------------------------------------" -echo "Upload to jboss.org:" -echo "" - -rsync -rv --protocol=28 $DIR/release/* keycloak@filemgmt.jboss.org:/downloads_htdocs/keycloak/$VERSION/gatekeeper/ - -echo "------------------------------------------------------------------------------------------------------------" -echo "Done" -echo "------------------------------------------------------------------------------------------------------------" diff --git a/server.go b/server.go index fa6d79ebccfb69d1348d5b176ad4e5c1e449180d..9f1ba00d0891e6a4e084465704c3d1e149bbf151 100644 --- a/server.go +++ b/server.go @@ -204,8 +204,8 @@ func (r *oauthProxy) createReverseProxy() error { e.Get(callbackURL, r.oauthCallbackHandler) e.Get(expiredURL, r.expirationHandler) e.Get(healthURL, r.healthHandler) - e.With(r.authenticationMiddleware()).Get(logoutURL, r.logoutHandler) - e.With(r.authenticationMiddleware()).Get(tokenURL, r.tokenHandler) + e.With(r.authenticationMiddleware(false)).Get(logoutURL, r.logoutHandler) + e.With(r.authenticationMiddleware(false)).Get(tokenURL, r.tokenHandler) e.Post(loginURL, r.loginHandler) if r.config.EnableMetrics { r.log.Info("enabled the service metrics middleware", zap.String("path", r.config.WithOAuthURI(metricsURL))) @@ -260,16 +260,21 @@ func (r *oauthProxy) createReverseProxy() error { for _, x := range r.config.Resources { r.log.Info("protecting resource", zap.String("resource", x.String())) e := engine.With( - r.authenticationMiddleware(), - r.admissionMiddleware(x), + r.authenticationMiddleware(false), + r.admissionMiddleware(false, x), + r.identityHeadersMiddleware(r.config.AddClaims)) + + w := engine.With( + r.authenticationMiddleware(true), + r.admissionMiddleware(true, x), r.identityHeadersMiddleware(r.config.AddClaims)) for _, m := range x.Methods { - if !x.WhiteListed { + if x.WhiteListed { + w.MethodFunc(m, x.URL, emptyHandler) + } else { e.MethodFunc(m, x.URL, emptyHandler) - continue } - engine.MethodFunc(m, x.URL, emptyHandler) } } diff --git a/set-version.sh b/set-version.sh deleted file mode 100755 index c7ba72906083b2681c3872ab7d36966a854f6afe..0000000000000000000000000000000000000000 --- a/set-version.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -e - -NEW_VERSION=$1 - -CURRENT=`awk '/release.*=/ { print $3 }' doc.go | sed 's/"//g'` -sed -i "s/$CURRENT/$NEW_VERSION/g" doc.go