From e1640301197b743a0021d99ea3f7abef80f7e5bd Mon Sep 17 00:00:00 2001 From: ThetaDev Date: Thu, 2 May 2024 02:35:02 +0200 Subject: [PATCH 1/2] feat: add group-based access control --- Dockerfile | 2 +- pkg/forwardauth/forwardauth.go | 23 ++++++++++++++--------- pkg/httphandler/handler.go | 24 ++++++++++++++---------- pkg/httphandler/root.go | 21 ++++++++++++++++++++- pkg/options/options.go | 1 + 5 files changed, 50 insertions(+), 21 deletions(-) diff --git a/Dockerfile b/Dockerfile index 32e2d75..fad88cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,7 +55,7 @@ ARG VCS_REF # Good docker practice LABEL org.opencontainers.image.created=$BUILD_DATE \ org.opencontainers.image.authors="StiviiK" \ - org.opencontainers.image.source="https://github.com/StiviiK/oidc-forward-auth.git" \ + org.opencontainers.image.source="https://code.thetadev.de/ThetaDev/oidc-forward-auth" \ org.opencontainers.image.revision=$VCS_REF ENTRYPOINT ["/go/bin/oidc-forward-auth"] \ No newline at end of file diff --git a/pkg/forwardauth/forwardauth.go b/pkg/forwardauth/forwardauth.go index 99a7c23..b10c563 100644 --- a/pkg/forwardauth/forwardauth.go +++ b/pkg/forwardauth/forwardauth.go @@ -7,6 +7,7 @@ package forwardauth import ( "context" "fmt" + "strings" "github.com/StiviiK/keycloak-traefik-forward-auth/pkg/options" "github.com/StiviiK/keycloak-traefik-forward-auth/pkg/utils" @@ -28,14 +29,15 @@ type Claims struct { IssuedAt utils.Time `json:"iat"` Expiration utils.Time `json:"exp"` - Name string `json:"name"` - GivenName string `json:"given_name"` - FamilyName string `json:"family_name"` - Email string `json:"email"` - VerifiedMail bool `json:"email_verified"` - Picture string `json:"picture"` - Locale string `json:"locale"` - PreferedUsername string `json:"preferred_username"` + Name string `json:"name"` + GivenName string `json:"given_name"` + FamilyName string `json:"family_name"` + Email string `json:"email"` + VerifiedMail bool `json:"email_verified"` + Picture string `json:"picture"` + Locale string `json:"locale"` + PreferedUsername string `json:"preferred_username"` + Groups []string `json:"groups"` } // Create creates a new fw auth client from our options @@ -49,6 +51,9 @@ func Create(ctx context.Context, options *options.Options) (*ForwardAuth, error) ClientID: options.ClientID, }) + scopes := []string{oidc.ScopeOpenID, "profile", "email"} + scopes = append(scopes, strings.Split(options.Scopes, " ")...) + return &ForwardAuth{ OidcProvider: provider, OAuth2Config: oauth2.Config{ @@ -60,7 +65,7 @@ func Create(ctx context.Context, options *options.Options) (*ForwardAuth, error) Endpoint: provider.Endpoint(), // "openid" is a required scope for OpenID Connect flows. - Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, + Scopes: scopes, }, OidcVefifier: verifier, }, nil diff --git a/pkg/httphandler/handler.go b/pkg/httphandler/handler.go index 06a70df..35d6f66 100644 --- a/pkg/httphandler/handler.go +++ b/pkg/httphandler/handler.go @@ -27,18 +27,22 @@ func Create(fw *forwardauth.ForwardAuth, options *options.Options) *HttpHandler func (h *HttpHandler) Entrypoint() func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { uri, err := url.Parse(r.Header.Get("X-Forwarded-Uri")) - switch { - case err != nil: + host := r.Header.Get("X-Forwarded-Host") + + if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return - - case uri.Path == h.options.RedirectURL: - h.callbackHandler(w, r, uri) - return - - default: - h.rootHandler(w, r, uri) - return } + + if host == h.options.AuthDomain { + // Handles OIDC callback + if uri.Path == h.options.RedirectURL { + h.callbackHandler(w, r, uri) + return + } + } + + // Handles forward auth + h.rootHandler(w, r, uri, r.URL) } } diff --git a/pkg/httphandler/root.go b/pkg/httphandler/root.go index 1c87f82..7e153c3 100644 --- a/pkg/httphandler/root.go +++ b/pkg/httphandler/root.go @@ -5,6 +5,7 @@ This code is licensed under MIT license (see LICENSE for details) package httphandler import ( + "fmt" "net/http" "net/url" @@ -13,7 +14,7 @@ import ( ) // RootHandler returns a handler function which handles all requests to the root -func (root *HttpHandler) rootHandler(w http.ResponseWriter, r *http.Request, forwardedURI *url.URL) { +func (root *HttpHandler) rootHandler(w http.ResponseWriter, r *http.Request, forwardedURI *url.URL, queryURI *url.URL) { logger := logrus.WithFields(logrus.Fields{ "SourceIP": r.Header.Get("X-Forwarded-For"), "RequestTarget": root.forwardAuth.GetReturnUri(r), @@ -34,6 +35,24 @@ func (root *HttpHandler) rootHandler(w http.ResponseWriter, r *http.Request, for return } + // Check group + group := queryURI.Query().Get("group") + if len(group) > 0 { + if !contains(claims.Groups, group) { + logger.Warnf("User %s not member of group %s", claims.PreferedUsername, group) + http.Error(w, fmt.Sprintf("You need to be a member of the group '%s' to access this site", group), http.StatusForbidden) + } + } + w.Header().Set("X-Forwarded-User", claims.Email) w.WriteHeader(200) } + +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/pkg/options/options.go b/pkg/options/options.go index 12a677a..0dd15d8 100644 --- a/pkg/options/options.go +++ b/pkg/options/options.go @@ -18,6 +18,7 @@ type Options struct { CookieDomain string `env:"COOKIE_DOMAIN"` Port int `env:"PORT" envDefault:"4181"` RedirectURL string `env:"REDIRECT_URL" envDefault:"/auth/resp"` + Scopes string `env:"SCOPES"` } // LoadOptions parses the environment vars and the options From 0c133ff09d5d60c7f653fa22a5322c87bb81e602 Mon Sep 17 00:00:00 2001 From: ThetaDev Date: Thu, 2 May 2024 03:01:26 +0200 Subject: [PATCH 2/2] dockerfile: enable cross build --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fad88cf..1c1dc20 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,7 +31,7 @@ RUN go mod download RUN go mod verify # Build the binary. -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -ldflags="-w -s" -o /go/bin/oidc-forward-auth +RUN CGO_ENABLED=0 go build -a -installsuffix cgo -ldflags="-w -s" -o /go/bin/oidc-forward-auth # Runner FROM scratch