diff --git a/internal/bootstrap/app_bootstrap.go b/internal/bootstrap/app_bootstrap.go index 3879c05e..bc4d1894 100644 --- a/internal/bootstrap/app_bootstrap.go +++ b/internal/bootstrap/app_bootstrap.go @@ -104,7 +104,13 @@ func (app *BootstrapApp) Setup() error { } // Get cookie domain - cookieDomain, err := utils.GetCookieDomain(app.context.appUrl) + cookieDomainResolver := utils.GetCookieDomain + if !app.config.Auth.SubdomainsEnabled { + tlog.App.Info().Msg("Subdomains disabled, automatic authentication for proxied apps will not work") + cookieDomainResolver = utils.GetStandaloneCookieDomain + } + + cookieDomain, err := cookieDomainResolver(app.context.appUrl) if err != nil { return err diff --git a/internal/bootstrap/router_bootstrap.go b/internal/bootstrap/router_bootstrap.go index 91d36ac2..d1e213fb 100644 --- a/internal/bootstrap/router_bootstrap.go +++ b/internal/bootstrap/router_bootstrap.go @@ -83,6 +83,7 @@ func (app *BootstrapApp) setupRouter() (*gin.Engine, error) { RedirectCookieName: app.context.redirectCookieName, CookieDomain: app.context.cookieDomain, OAuthSessionCookieName: app.context.oauthSessionCookieName, + SubdomainsEnabled: app.config.Auth.SubdomainsEnabled, }, apiRouter, app.services.authService) oauthController.SetupRoutes() diff --git a/internal/bootstrap/service_bootstrap.go b/internal/bootstrap/service_bootstrap.go index 9c5806b9..c2e03b74 100644 --- a/internal/bootstrap/service_bootstrap.go +++ b/internal/bootstrap/service_bootstrap.go @@ -80,6 +80,7 @@ func (app *BootstrapApp) initServices(queries *repository.Queries) (Services, er SessionCookieName: app.context.sessionCookieName, IP: app.config.Auth.IP, LDAPGroupsCacheTTL: app.config.Ldap.GroupCacheTTL, + SubdomainsEnabled: app.config.Auth.SubdomainsEnabled, }, dockerService, services.ldapService, queries, services.oauthBrokerService) err = authService.Init() diff --git a/internal/config/config.go b/internal/config/config.go index 1bf64af4..3e05fff3 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -18,6 +18,7 @@ func NewDefaultConfiguration() *Config { Address: "0.0.0.0", }, Auth: AuthConfig{ + SubdomainsEnabled: true, SessionExpiry: 86400, // 1 day SessionMaxLifetime: 0, // disabled LoginTimeout: 300, // 5 minutes @@ -115,6 +116,7 @@ type ServerConfig struct { type AuthConfig struct { IP IPConfig `description:"IP whitelisting config options." yaml:"ip"` Users []string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"` + SubdomainsEnabled bool `description:"Enable subdomains support." yaml:"subdomainsEnabled"` UserAttributes map[string]UserAttributes `description:"Map of per-user OIDC attributes (username -> attributes)." yaml:"userAttributes"` UsersFile string `description:"Path to the users file." yaml:"usersFile"` SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie"` diff --git a/internal/controller/oauth_controller.go b/internal/controller/oauth_controller.go index 4133b849..614fa707 100644 --- a/internal/controller/oauth_controller.go +++ b/internal/controller/oauth_controller.go @@ -27,6 +27,7 @@ type OAuthControllerConfig struct { SecureCookie bool AppURL string CookieDomain string + SubdomainsEnabled bool } type OAuthController struct { @@ -106,7 +107,7 @@ func (controller *OAuthController) oauthURLHandler(c *gin.Context) { return } - c.SetCookie(controller.config.OAuthSessionCookieName, sessionId, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) + c.SetCookie(controller.config.OAuthSessionCookieName, sessionId, int(time.Hour.Seconds()), "/", controller.getCookieDomain(), controller.config.SecureCookie, true) c.JSON(200, gin.H{ "status": 200, @@ -136,7 +137,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) { return } - c.SetCookie(controller.config.OAuthSessionCookieName, "", -1, "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) + c.SetCookie(controller.config.OAuthSessionCookieName, "", -1, "/", controller.getCookieDomain(), controller.config.SecureCookie, true) oauthPendingSession, err := controller.auth.GetOAuthPendingSession(sessionIdCookie) @@ -282,3 +283,10 @@ func (controller *OAuthController) isOidcRequest(params service.OAuthURLParams) params.ClientID != "" && params.RedirectURI != "" } + +func (controller *OAuthController) getCookieDomain() string { + if controller.config.SubdomainsEnabled { + return "." + controller.config.CookieDomain + } + return controller.config.CookieDomain +} diff --git a/internal/service/auth_service.go b/internal/service/auth_service.go index 1d0d74d3..3b00e282 100644 --- a/internal/service/auth_service.go +++ b/internal/service/auth_service.go @@ -78,6 +78,7 @@ type AuthServiceConfig struct { SessionCookieName string IP config.IPConfig LDAPGroupsCacheTTL int + SubdomainsEnabled bool } type AuthService struct { @@ -327,7 +328,7 @@ func (auth *AuthService) CreateSessionCookie(c *gin.Context, data *repository.Se return err } - c.SetCookie(auth.config.SessionCookieName, session.UUID, expiry, "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) + c.SetCookie(auth.config.SessionCookieName, session.UUID, expiry, "/", auth.getCookieDomain(), auth.config.SecureCookie, true) return nil } @@ -378,7 +379,7 @@ func (auth *AuthService) RefreshSessionCookie(c *gin.Context) error { return err } - c.SetCookie(auth.config.SessionCookieName, cookie, int(newExpiry-currentTime), "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) + c.SetCookie(auth.config.SessionCookieName, cookie, int(newExpiry-currentTime), "/", auth.getCookieDomain(), auth.config.SecureCookie, true) tlog.App.Trace().Str("username", session.Username).Msg("Session cookie refreshed") return nil @@ -397,7 +398,7 @@ func (auth *AuthService) DeleteSessionCookie(c *gin.Context) error { return err } - c.SetCookie(auth.config.SessionCookieName, "", -1, "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) + c.SetCookie(auth.config.SessionCookieName, "", -1, "/", auth.getCookieDomain(), auth.config.SecureCookie, true) return nil } @@ -834,3 +835,10 @@ func (auth *AuthService) ClearRateLimitsTestingOnly() { } auth.loginMutex.Unlock() } + +func (auth *AuthService) getCookieDomain() string { + if auth.config.SubdomainsEnabled { + return "." + auth.config.CookieDomain + } + return auth.config.CookieDomain +} diff --git a/internal/utils/app_utils.go b/internal/utils/app_utils.go index 55665ee0..6b0ee834 100644 --- a/internal/utils/app_utils.go +++ b/internal/utils/app_utils.go @@ -49,6 +49,15 @@ func GetCookieDomain(u string) (string, error) { return domain, nil } +func GetStandaloneCookieDomain(u string) (string, error) { + parsed, err := url.Parse(u) + if err != nil { + return "", err + } + + return parsed.Hostname(), nil +} + func ParseFileToLine(content string) string { lines := strings.Split(content, "\n") users := make([]string, 0)