From fee5a9232e5847dac63cefebfed8473b60c0d120 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Tue, 4 Nov 2025 17:09:51 +0100 Subject: [PATCH] Make secure cookie configurable Signed-off-by: Sacha Al Himdani --- cfg/dev.yaml | 1 + docs/CONFIGURATION.md | 6 ++++ docs/DOCKER_ENVIRONMENT_VARIABLES.md | 1 + pkg/probod/auth_config.go | 1 + pkg/probod/probod.go | 19 +++++++----- pkg/securecookie/securecookie.go | 4 +-- pkg/server/api/api.go | 13 ++++++--- pkg/server/api/console/v1/resolver.go | 2 ++ pkg/server/api/trust/v1/resolver.go | 4 ++- .../trust/v1/trust_center_access_handler.go | 5 ++-- pkg/server/auth/accept_invitation_handler.go | 5 ++-- pkg/server/auth/auth.go | 29 ++++++++++--------- pkg/server/auth/auth_middleware.go | 4 ++- pkg/server/auth/saml_acs_handler.go | 10 ++++--- pkg/server/auth/sign_in_handler.go | 7 +++-- pkg/server/auth/sign_out_handler.go | 8 +++-- pkg/server/auth/sign_up_handler.go | 5 ++-- .../auth/signup_from_invitation_handler.go | 5 ++-- pkg/server/server.go | 11 +++---- pkg/server/session/session.go | 11 ++++--- 20 files changed, 94 insertions(+), 57 deletions(-) diff --git a/cfg/dev.yaml b/cfg/dev.yaml index acd5fe00a..7b12d2ba0 100644 --- a/cfg/dev.yaml +++ b/cfg/dev.yaml @@ -34,6 +34,7 @@ probod: domain: "localhost" secret: "this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes" duration: 24 + secure: true password: pepper: "this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes" iterations: 1000000 diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 102bf7549..eca49c7dc 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -363,6 +363,12 @@ Secret key used for signing session cookies. Should be at least 32 bytes for sec Session cookie lifetime in hours. +#### `auth.cookie.secure` (boolean) + +**Default**: `true` + +Controls whether the Secure flag is set on session cookies. When true, cookies are only sent over HTTPS connections. + #### `auth.password.pepper` (string) **Default**: Auto-generated diff --git a/docs/DOCKER_ENVIRONMENT_VARIABLES.md b/docs/DOCKER_ENVIRONMENT_VARIABLES.md index fc8d388c8..5f5ec6b5e 100644 --- a/docs/DOCKER_ENVIRONMENT_VARIABLES.md +++ b/docs/DOCKER_ENVIRONMENT_VARIABLES.md @@ -68,6 +68,7 @@ This document provides a comprehensive reference for all environment variables u | `AUTH_COOKIE_DOMAIN` | Domain for the session cookie | `localhost` | No | | `AUTH_COOKIE_SECRET` | Secret key for signing session cookies (32+ bytes) | - | **Yes** | | `AUTH_COOKIE_DURATION` | Session cookie validity duration in hours | `24` | No | +| `AUTH_COOKIE_SECURE` | Set Secure flag on cookies (use false for HTTP) | `true` | No | ### Password Security diff --git a/pkg/probod/auth_config.go b/pkg/probod/auth_config.go index 045bbca85..9140debfd 100644 --- a/pkg/probod/auth_config.go +++ b/pkg/probod/auth_config.go @@ -44,6 +44,7 @@ type ( Secret string `json:"secret"` Duration int `json:"duration"` Name string `json:"name"` + Secure bool `json:"secure"` } passwordConfig struct { diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index 933feb89d..dcac7d0a8 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -27,6 +27,14 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/prometheus/client_golang/prometheus" + "go.gearno.de/kit/httpclient" + "go.gearno.de/kit/httpserver" + "go.gearno.de/kit/log" + "go.gearno.de/kit/migrator" + "go.gearno.de/kit/pg" + "go.gearno.de/kit/unit" + "go.opentelemetry.io/otel/trace" "go.probo.inc/probo/pkg/agents" "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/authz" @@ -48,14 +56,6 @@ import ( "go.probo.inc/probo/pkg/server/api" "go.probo.inc/probo/pkg/slack" "go.probo.inc/probo/pkg/trust" - "github.com/prometheus/client_golang/prometheus" - "go.gearno.de/kit/httpclient" - "go.gearno.de/kit/httpserver" - "go.gearno.de/kit/log" - "go.gearno.de/kit/migrator" - "go.gearno.de/kit/pg" - "go.gearno.de/kit/unit" - "go.opentelemetry.io/otel/trace" "golang.org/x/sync/errgroup" ) @@ -116,6 +116,7 @@ func New() *Implm { Secret: "this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes", Duration: 24, Domain: "localhost", + Secure: true, }, DisableSignup: false, InvitationConfirmationTokenValidity: 3600, @@ -402,6 +403,7 @@ func (impl *Implm) Run( CookieDomain: impl.cfg.Auth.Cookie.Domain, SessionDuration: time.Duration(impl.cfg.Auth.Cookie.Duration) * time.Hour, CookieSecret: impl.cfg.Auth.Cookie.Secret, + CookieSecure: impl.cfg.Auth.Cookie.Secure, }, TrustAuth: api.TrustAuthConfig{ CookieName: impl.cfg.TrustAuth.CookieName, @@ -412,6 +414,7 @@ func (impl *Implm) Run( TokenSecret: impl.cfg.TrustAuth.TokenSecret, Scope: impl.cfg.TrustAuth.Scope, TokenType: impl.cfg.TrustAuth.TokenType, + CookieSecure: impl.cfg.Auth.Cookie.Secure, }, }, ) diff --git a/pkg/securecookie/securecookie.go b/pkg/securecookie/securecookie.go index c2bdb90d0..6f8dacc4b 100644 --- a/pkg/securecookie/securecookie.go +++ b/pkg/securecookie/securecookie.go @@ -59,13 +59,13 @@ type Config struct { } // DefaultConfig returns a default secure cookie configuration -func DefaultConfig(name, secret string) Config { +func DefaultConfig(name, secret string, secure bool) Config { return Config{ Name: name, Secret: secret, Path: "/", MaxAge: 86400 * 30, // 30 days - Secure: true, + Secure: secure, HTTPOnly: true, SameSite: http.SameSiteNoneMode, // None mode required for SAML (cross-site POST from IdP) } diff --git a/pkg/server/api/api.go b/pkg/server/api/api.go index 474058773..76c760535 100644 --- a/pkg/server/api/api.go +++ b/pkg/server/api/api.go @@ -20,6 +20,10 @@ import ( "time" + "github.com/go-chi/chi/v5" + "github.com/go-chi/cors" + "go.gearno.de/kit/httpserver" + "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/authz" "go.probo.inc/probo/pkg/connector" @@ -28,10 +32,6 @@ import ( console_v1 "go.probo.inc/probo/pkg/server/api/console/v1" trust_v1 "go.probo.inc/probo/pkg/server/api/trust/v1" "go.probo.inc/probo/pkg/trust" - "github.com/go-chi/chi/v5" - "github.com/go-chi/cors" - "go.gearno.de/kit/httpserver" - "go.gearno.de/kit/log" ) type ( @@ -40,6 +40,7 @@ type ( CookieDomain string SessionDuration time.Duration CookieSecret string + CookieSecure bool } TrustAuthConfig struct { @@ -51,6 +52,7 @@ type ( TokenSecret string Scope string TokenType string + CookieSecure bool } Config struct { @@ -128,6 +130,7 @@ func NewServer(cfg Config) (*Server, error) { CookieDomain: cfg.ConsoleAuth.CookieDomain, SessionDuration: cfg.ConsoleAuth.SessionDuration, CookieSecret: cfg.ConsoleAuth.CookieSecret, + CookieSecure: cfg.ConsoleAuth.CookieSecure, }, trust_v1.TrustAuthConfig{ CookieName: cfg.TrustAuth.CookieName, @@ -138,6 +141,7 @@ func NewServer(cfg Config) (*Server, error) { TokenSecret: cfg.TrustAuth.TokenSecret, Scope: cfg.TrustAuth.Scope, TokenType: cfg.TrustAuth.TokenType, + CookieSecure: cfg.TrustAuth.CookieSecure, }, ) @@ -191,6 +195,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { CookieDomain: s.cfg.ConsoleAuth.CookieDomain, SessionDuration: s.cfg.ConsoleAuth.SessionDuration, CookieSecret: s.cfg.ConsoleAuth.CookieSecret, + CookieSecure: s.cfg.ConsoleAuth.CookieSecure, }, s.cfg.ConnectorRegistry, s.cfg.SafeRedirect, diff --git a/pkg/server/api/console/v1/resolver.go b/pkg/server/api/console/v1/resolver.go index 2bebced5f..dfb1a6f7b 100644 --- a/pkg/server/api/console/v1/resolver.go +++ b/pkg/server/api/console/v1/resolver.go @@ -54,6 +54,7 @@ type ( CookieDomain string SessionDuration time.Duration CookieSecret string + CookieSecure bool } Resolver struct { @@ -371,6 +372,7 @@ func WithSession(authSvc *auth.Service, authzSvc *authz.Service, authCfg AuthCon sessionAuthCfg := session.AuthConfig{ CookieName: authCfg.CookieName, CookieSecret: authCfg.CookieSecret, + CookieSecure: authCfg.CookieSecure, } errorHandler := session.ErrorHandler{ diff --git a/pkg/server/api/trust/v1/resolver.go b/pkg/server/api/trust/v1/resolver.go index 36d161ff8..b3c1f1b87 100644 --- a/pkg/server/api/trust/v1/resolver.go +++ b/pkg/server/api/trust/v1/resolver.go @@ -52,6 +52,7 @@ type ( TokenSecret string Scope string TokenType string + CookieSecure bool } Resolver struct { @@ -186,6 +187,7 @@ func trySessionAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, sessionAuthCfg := session.AuthConfig{ CookieName: authCfg.CookieName, CookieSecret: authCfg.CookieSecret, + CookieSecure: authCfg.CookieSecure, } errorHandler := session.ErrorHandler{ @@ -256,7 +258,7 @@ func clearTokenCookie(w http.ResponseWriter, trustAuthCfg TrustAuthConfig) { Domain: trustAuthCfg.CookieDomain, Path: "/", MaxAge: -1, - Secure: true, + Secure: trustAuthCfg.CookieSecure, HttpOnly: true, SameSite: http.SameSiteStrictMode, }) diff --git a/pkg/server/api/trust/v1/trust_center_access_handler.go b/pkg/server/api/trust/v1/trust_center_access_handler.go index 0f8b2ec2a..ab31e4c6c 100644 --- a/pkg/server/api/trust/v1/trust_center_access_handler.go +++ b/pkg/server/api/trust/v1/trust_center_access_handler.go @@ -110,7 +110,7 @@ func authTokenHandler(trustSvc *trust.Service, trustAuthCfg TrustAuthConfig) htt Domain: cookieDomain, Path: "/", MaxAge: int(trustAuthCfg.CookieDuration / time.Second), - Secure: true, + Secure: trustAuthCfg.CookieSecure, HttpOnly: true, SameSite: http.SameSiteStrictMode, } @@ -159,7 +159,7 @@ func trustCenterLogoutHandler(authCfg console_v1.AuthConfig, trustAuthCfg TrustA Domain: cookieDomain, Path: "/", MaxAge: -1, - Secure: true, + Secure: trustAuthCfg.CookieSecure, HttpOnly: true, SameSite: http.SameSiteStrictMode, }) @@ -167,6 +167,7 @@ func trustCenterLogoutHandler(authCfg console_v1.AuthConfig, trustAuthCfg TrustA session.ClearCookie(w, session.AuthConfig{ CookieName: authCfg.CookieName, CookieSecret: authCfg.CookieSecret, + CookieSecure: authCfg.CookieSecure, }) httpserver.RenderJSON(w, http.StatusOK, map[string]string{ diff --git a/pkg/server/auth/accept_invitation_handler.go b/pkg/server/auth/accept_invitation_handler.go index 2b04b0af8..f535fe85a 100644 --- a/pkg/server/auth/accept_invitation_handler.go +++ b/pkg/server/auth/accept_invitation_handler.go @@ -19,11 +19,11 @@ import ( "fmt" "net/http" + "go.gearno.de/kit/httpserver" authsvc "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/authz" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/server/session" - "go.gearno.de/kit/httpserver" ) type ( @@ -36,13 +36,14 @@ type ( } ) -func AcceptInvitationHandler(authSvc *authsvc.Service, authzSvc *authz.Service, cookieName string, cookieSecret string) http.HandlerFunc { +func AcceptInvitationHandler(authSvc *authsvc.Service, authzSvc *authz.Service, cookieName string, cookieSecret string, cookieSecure bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() sessionAuthCfg := session.AuthConfig{ CookieName: cookieName, CookieSecret: cookieSecret, + CookieSecure: cookieSecure, } errorHandler := session.ErrorHandler{ diff --git a/pkg/server/auth/auth.go b/pkg/server/auth/auth.go index 6f572d66c..bc6853a55 100644 --- a/pkg/server/auth/auth.go +++ b/pkg/server/auth/auth.go @@ -33,6 +33,7 @@ type Config struct { CookieDomain string SessionDuration time.Duration CookieSecret string + CookieSecure bool FileManager *filemanager.Service Logger *log.Logger } @@ -44,26 +45,26 @@ type Server struct { func NewServer(cfg Config) (*Server, error) { router := chi.NewRouter() - router.Post("/register", SignUpHandler(cfg.Auth, cfg.CookieName, cfg.CookieSecret)) - router.Post("/login", SignInHandler(cfg.Auth, cfg.CookieName, cfg.CookieSecret)) - router.Delete("/logout", SignOutHandler(cfg.Auth, cfg.CookieName, cfg.CookieSecret)) - router.Post("/signup-from-invitation", SignupFromInvitationHandler(cfg.Auth, cfg.CookieName, cfg.CookieSecret)) + router.Post("/register", SignUpHandler(cfg.Auth, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure)) + router.Post("/login", SignInHandler(cfg.Auth, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure)) + router.Delete("/logout", SignOutHandler(cfg.Auth, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure)) + router.Post("/signup-from-invitation", SignupFromInvitationHandler(cfg.Auth, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure)) router.Post("/forget-password", ForgetPasswordHandler(cfg.Auth)) router.Post("/reset-password", ResetPasswordHandler(cfg.Auth)) router.Post("/check-sso", SAMLCheckSSOHandler(cfg.Auth, cfg.Logger)) - router.Get("/organizations", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, ListOrganizationsHandler(cfg.Auth, cfg.Authz))) - router.Get("/organizations/{organizationID}/logo", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, OrganizationLogoHandler(cfg.Auth, cfg.FileManager))) - router.Get("/invitations", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, ListInvitationsHandler(cfg.Authz))) - router.Post("/invitations/accept", AcceptInvitationHandler(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret)) + router.Get("/organizations", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, ListOrganizationsHandler(cfg.Auth, cfg.Authz))) + router.Get("/organizations/{organizationID}/logo", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, OrganizationLogoHandler(cfg.Auth, cfg.FileManager))) + router.Get("/invitations", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, ListInvitationsHandler(cfg.Authz))) + router.Post("/invitations/accept", AcceptInvitationHandler(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure)) - router.Get("/api-keys", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, ListUserAPIKeysHandler(cfg.Auth, cfg.Authz))) - router.Post("/api-keys", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, CreateUserAPIKeyHandler(cfg.Auth))) - router.Get("/api-keys/{id}", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, GetUserAPIKeyHandler(cfg.Auth))) - router.Put("/api-keys", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, UpdateUserAPIKeyHandler(cfg.Auth))) - router.Delete("/api-keys", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, DeleteUserAPIKeyHandler(cfg.Auth))) + router.Get("/api-keys", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, ListUserAPIKeysHandler(cfg.Auth, cfg.Authz))) + router.Post("/api-keys", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, CreateUserAPIKeyHandler(cfg.Auth))) + router.Get("/api-keys/{id}", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, GetUserAPIKeyHandler(cfg.Auth))) + router.Put("/api-keys", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, UpdateUserAPIKeyHandler(cfg.Auth))) + router.Delete("/api-keys", RequireAuth(cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, DeleteUserAPIKeyHandler(cfg.Auth))) router.Get("/saml/login/{samlConfigID}", SAMLLoginHandler(cfg.SAML, cfg.Auth, cfg.Logger)) - router.Post("/saml/consume", SAMLACSHandler(cfg.SAML, cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.SessionDuration, cfg.Logger)) + router.Post("/saml/consume", SAMLACSHandler(cfg.SAML, cfg.Auth, cfg.Authz, cfg.CookieName, cfg.CookieSecret, cfg.CookieSecure, cfg.SessionDuration, cfg.Logger)) router.Get("/saml/metadata", SAMLMetadataHandler(cfg.SAML)) return &Server{ diff --git a/pkg/server/auth/auth_middleware.go b/pkg/server/auth/auth_middleware.go index 3c30cd6bb..eed8d1003 100644 --- a/pkg/server/auth/auth_middleware.go +++ b/pkg/server/auth/auth_middleware.go @@ -19,11 +19,11 @@ import ( "fmt" "net/http" + "go.gearno.de/kit/httpserver" authsvc "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/authz" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/server/session" - "go.gearno.de/kit/httpserver" ) type ctxKey struct{ name string } @@ -38,6 +38,7 @@ func RequireAuth( authzSvc *authz.Service, cookieName string, cookieSecret string, + cookieSecure bool, next http.HandlerFunc, ) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -46,6 +47,7 @@ func RequireAuth( sessionAuthCfg := session.AuthConfig{ CookieName: cookieName, CookieSecret: cookieSecret, + CookieSecure: cookieSecure, } errorHandler := session.ErrorHandler{ diff --git a/pkg/server/auth/saml_acs_handler.go b/pkg/server/auth/saml_acs_handler.go index 72f3b1a55..43ef0694c 100644 --- a/pkg/server/auth/saml_acs_handler.go +++ b/pkg/server/auth/saml_acs_handler.go @@ -20,20 +20,21 @@ import ( "net/http" "time" + "go.gearno.de/kit/log" authsvc "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/authz" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/securecookie" - "go.gearno.de/kit/log" ) -func getSessionIDFromCookie(r *http.Request, cookieName string, cookieSecret string) (gid.GID, error) { +func getSessionIDFromCookie(r *http.Request, cookieName string, cookieSecret string, cookieSecure bool) (gid.GID, error) { cookieValue, err := securecookie.Get( r, securecookie.DefaultConfig( cookieName, cookieSecret, + cookieSecure, ), ) if err != nil { @@ -43,7 +44,7 @@ func getSessionIDFromCookie(r *http.Request, cookieName string, cookieSecret str return gid.ParseGID(cookieValue) } -func SAMLACSHandler(samlSvc *authsvc.SAMLService, authSvc *authsvc.Service, authzSvc *authz.Service, cookieName string, cookieSecret string, sessionDuration time.Duration, logger *log.Logger) http.HandlerFunc { +func SAMLACSHandler(samlSvc *authsvc.SAMLService, authSvc *authsvc.Service, authzSvc *authz.Service, cookieName string, cookieSecret string, cookieSecure bool, sessionDuration time.Duration, logger *log.Logger) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -73,7 +74,7 @@ func SAMLACSHandler(samlSvc *authsvc.SAMLService, authSvc *authsvc.Service, auth } var existingSession *coredata.Session - if existingSessionID, err := getSessionIDFromCookie(r, cookieName, cookieSecret); err == nil { + if existingSessionID, err := getSessionIDFromCookie(r, cookieName, cookieSecret, cookieSecure); err == nil { if session, err := authSvc.GetSession(ctx, existingSessionID); err == nil { existingSession = session } @@ -114,6 +115,7 @@ func SAMLACSHandler(samlSvc *authsvc.SAMLService, authSvc *authsvc.Service, auth securecookie.DefaultConfig( cookieName, cookieSecret, + cookieSecure, ), session.ID.String(), ) diff --git a/pkg/server/auth/sign_in_handler.go b/pkg/server/auth/sign_in_handler.go index 6d01ab6b4..9ac9ed1a5 100644 --- a/pkg/server/auth/sign_in_handler.go +++ b/pkg/server/auth/sign_in_handler.go @@ -21,11 +21,11 @@ import ( "net/http" "time" + "go.gearno.de/kit/httpserver" authsvc "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/securecookie" - "go.gearno.de/kit/httpserver" ) type ( @@ -47,7 +47,7 @@ type ( } ) -func SignInHandler(authSvc *authsvc.Service, cookieName string, cookieSecret string) http.HandlerFunc { +func SignInHandler(authSvc *authsvc.Service, cookieName string, cookieSecret string, cookieSecure bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req SignInRequest @@ -57,7 +57,7 @@ func SignInHandler(authSvc *authsvc.Service, cookieName string, cookieSecret str } var existingSession *coredata.Session - if existingSessionID, err := getSessionIDFromCookie(r, cookieName, cookieSecret); err == nil { + if existingSessionID, err := getSessionIDFromCookie(r, cookieName, cookieSecret, cookieSecure); err == nil { if session, err := authSvc.GetSession(r.Context(), existingSessionID); err == nil { existingSession = session } @@ -79,6 +79,7 @@ func SignInHandler(authSvc *authsvc.Service, cookieName string, cookieSecret str securecookie.DefaultConfig( cookieName, cookieSecret, + cookieSecure, ), session.ID.String(), ) diff --git a/pkg/server/auth/sign_out_handler.go b/pkg/server/auth/sign_out_handler.go index 98688e0a9..e69774db5 100644 --- a/pkg/server/auth/sign_out_handler.go +++ b/pkg/server/auth/sign_out_handler.go @@ -18,18 +18,19 @@ import ( "fmt" "net/http" + "go.gearno.de/kit/httpserver" + authsvc "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/securecookie" - authsvc "go.probo.inc/probo/pkg/auth" - "go.gearno.de/kit/httpserver" ) -func SignOutHandler(authSvc *authsvc.Service, cookieName string, cookieSecret string) http.HandlerFunc { +func SignOutHandler(authSvc *authsvc.Service, cookieName string, cookieSecret string, cookieSecure bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { sessionID, err := securecookie.Get(r, securecookie.DefaultConfig( cookieName, cookieSecret, + cookieSecure, )) if err != nil { httpserver.RenderError(w, http.StatusBadRequest, err) @@ -50,6 +51,7 @@ func SignOutHandler(authSvc *authsvc.Service, cookieName string, cookieSecret st securecookie.Clear(w, securecookie.DefaultConfig( cookieName, cookieSecret, + cookieSecure, )) w.Header().Set("Clear-Site-Data", "*") diff --git a/pkg/server/auth/sign_up_handler.go b/pkg/server/auth/sign_up_handler.go index 2f6fa2ac1..dc7cf5aab 100644 --- a/pkg/server/auth/sign_up_handler.go +++ b/pkg/server/auth/sign_up_handler.go @@ -20,9 +20,9 @@ import ( "fmt" "net/http" + "go.gearno.de/kit/httpserver" authsvc "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/securecookie" - "go.gearno.de/kit/httpserver" ) type ( @@ -37,7 +37,7 @@ type ( } ) -func SignUpHandler(authSvc *authsvc.Service, cookieName string, cookieSecret string) http.HandlerFunc { +func SignUpHandler(authSvc *authsvc.Service, cookieName string, cookieSecret string, cookieSecure bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req SignUpRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { @@ -72,6 +72,7 @@ func SignUpHandler(authSvc *authsvc.Service, cookieName string, cookieSecret str securecookie.DefaultConfig( cookieName, cookieSecret, + cookieSecure, ), session.ID.String(), ) diff --git a/pkg/server/auth/signup_from_invitation_handler.go b/pkg/server/auth/signup_from_invitation_handler.go index 0870ad554..a06c694d3 100644 --- a/pkg/server/auth/signup_from_invitation_handler.go +++ b/pkg/server/auth/signup_from_invitation_handler.go @@ -19,9 +19,9 @@ import ( "fmt" "net/http" + "go.gearno.de/kit/httpserver" authsvc "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/securecookie" - "go.gearno.de/kit/httpserver" ) type ( @@ -35,7 +35,7 @@ type ( } ) -func SignupFromInvitationHandler(authSvc *authsvc.Service, cookieName string, cookieSecret string) http.HandlerFunc { +func SignupFromInvitationHandler(authSvc *authsvc.Service, cookieName string, cookieSecret string, cookieSecure bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req SignupFromInvitationRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { @@ -54,6 +54,7 @@ func SignupFromInvitationHandler(authSvc *authsvc.Service, cookieName string, co securecookie.DefaultConfig( cookieName, cookieSecret, + cookieSecure, ), session.ID.String(), ) diff --git a/pkg/server/server.go b/pkg/server/server.go index e8d804803..8800dc223 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -20,6 +20,10 @@ import ( "net/http" "strings" + "github.com/go-chi/chi/v5" + "go.gearno.de/kit/httpserver" + "go.gearno.de/kit/log" + "go.gearno.de/kit/pg" "go.probo.inc/probo/pkg/agents" "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/authz" @@ -29,15 +33,11 @@ import ( "go.probo.inc/probo/pkg/probo" "go.probo.inc/probo/pkg/saferedirect" "go.probo.inc/probo/pkg/server/api" - auth_server "go.probo.inc/probo/pkg/server/auth" trust_v1 "go.probo.inc/probo/pkg/server/api/trust/v1" + auth_server "go.probo.inc/probo/pkg/server/auth" "go.probo.inc/probo/pkg/server/trust" "go.probo.inc/probo/pkg/server/web" trust_pkg "go.probo.inc/probo/pkg/trust" - "github.com/go-chi/chi/v5" - "go.gearno.de/kit/httpserver" - "go.gearno.de/kit/log" - "go.gearno.de/kit/pg" ) type Config struct { @@ -108,6 +108,7 @@ func NewServer(cfg Config) (*Server, error) { CookieDomain: cfg.ConsoleAuth.CookieDomain, SessionDuration: cfg.ConsoleAuth.SessionDuration, CookieSecret: cfg.ConsoleAuth.CookieSecret, + CookieSecure: cfg.ConsoleAuth.CookieSecure, FileManager: cfg.FileManager, Logger: cfg.Logger.Named("auth"), }) diff --git a/pkg/server/session/session.go b/pkg/server/session/session.go index 8e9d81adf..303905069 100644 --- a/pkg/server/session/session.go +++ b/pkg/server/session/session.go @@ -19,16 +19,17 @@ import ( "errors" "net/http" + "go.probo.inc/probo/pkg/auth" "go.probo.inc/probo/pkg/authz" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/securecookie" - "go.probo.inc/probo/pkg/auth" ) type AuthConfig struct { CookieName string CookieSecret string + CookieSecure bool } type AuthResult struct { @@ -58,6 +59,7 @@ func TryAuth( cookieValue, err := securecookie.Get(r, securecookie.DefaultConfig( authCfg.CookieName, authCfg.CookieSecret, + authCfg.CookieSecure, )) if err != nil { if !errors.Is(err, securecookie.ErrCookieNotFound) && errorHandler.OnCookieError != nil { @@ -131,9 +133,9 @@ func TryAuth( } return &AuthResult{ - Session: session, - User: user, - TenantIDs: allowedTenantIDs, + Session: session, + User: user, + TenantIDs: allowedTenantIDs, AuthErrors: authErrors, } } @@ -142,5 +144,6 @@ func ClearCookie(w http.ResponseWriter, authCfg AuthConfig) { securecookie.Clear(w, securecookie.DefaultConfig( authCfg.CookieName, authCfg.CookieSecret, + authCfg.CookieSecure, )) }