-
Notifications
You must be signed in to change notification settings - Fork 188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redis sessions #224
base: main
Are you sure you want to change the base?
Redis sessions #224
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,15 +14,18 @@ import ( | |
|
||
// DefaultAuthConfig specifies all the defaults used to configure sso-auth | ||
// All configuration can be set using environment variables. Below is a list of | ||
// configuration variables via their envivronment configuration | ||
// configuration variables via their environment configuration | ||
// | ||
// SESSION COOKIE_NAME | ||
// SESSION_COOKIE_NAME | ||
// SESSION_COOKIE_SECRET | ||
// SESSION_COOKIE_EXPIRE | ||
// SESSION_COOKIE_DOMAIN | ||
// SESSION_COOKIE_REFRESH | ||
// SESSION_COOKIE_SECURE | ||
// SESSION_COOKIE_HTTPONLY | ||
// SESSION_REDIS_CONNECTION | ||
// SESSION_REDIS_SENTINEL | ||
// SESSION_REDIS_MASTER | ||
// SESSION_LIFETIME | ||
// SESSION_KEY | ||
// | ||
|
@@ -35,6 +38,9 @@ import ( | |
// PROVIDER_*_CLIENT_SECRET | ||
// PROVIDER_*_SCOPE | ||
// | ||
// PROVIDER_*_AZURE_TENANT | ||
// PROVIDER_*_AZURE_PROMPT | ||
// | ||
// PROVIDER_*_GOOGLE_CREDENTIALS | ||
// PROVIDER_*_GOOGLE_IMPERSONATE | ||
// | ||
|
@@ -84,6 +90,9 @@ func DefaultAuthConfig() Configuration { | |
Secure: true, | ||
HTTPOnly: true, | ||
}, | ||
RedisConfig: RedisConfig{ | ||
UseSentinel: false, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To clarify: is this just included for explicitness around this setting? (Unless I'm mistaken, it's not strictly required, right?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's correct. It's been awhile but I think it might fail if the |
||
}, | ||
}, | ||
LoggingConfig: LoggingConfig{ | ||
Enable: true, | ||
|
@@ -275,8 +284,34 @@ func (gcc GroupCacheConfig) Validate() error { | |
return nil | ||
} | ||
|
||
type RedisConfig struct { | ||
ConnectionURLs []string `mapstructure:"connection"` | ||
UseSentinel bool `mapstructure:"sentinel"` | ||
SentinelMasterName string `mapstructure:"master"` | ||
} | ||
|
||
func (rc RedisConfig) Enabled() bool { | ||
// If redis connection URL is missing, use normal cookie sessions | ||
return rc.UseSentinel || len(rc.ConnectionURLs) >= 1 | ||
} | ||
|
||
func (rc RedisConfig) Validate() error { | ||
if rc.UseSentinel { | ||
if rc.SentinelMasterName == "" { | ||
return xerrors.New("no sentinel master is configured") | ||
} else if len(rc.ConnectionURLs) == 0 { | ||
return xerrors.New("no sentinel connection URLs are configured") | ||
} | ||
} else if len(rc.ConnectionURLs) > 1 { | ||
return xerrors.New("only one connection URL should be set unless sentinel enabled") | ||
} | ||
// If redis connection URL is missing, use normal cookie sessions | ||
return nil | ||
} | ||
|
||
type SessionConfig struct { | ||
CookieConfig CookieConfig `mapstructure:"cookie"` | ||
RedisConfig RedisConfig `mapstructure:"redis"` | ||
|
||
SessionLifetimeTTL time.Duration `mapstructure:"lifetime"` | ||
Key string `mapstructure:"key"` | ||
|
@@ -298,6 +333,9 @@ func (sc SessionConfig) Validate() error { | |
if err := sc.CookieConfig.Validate(); err != nil { | ||
return xerrors.Errorf("invalid session.cookie config: %w", err) | ||
} | ||
if err := sc.RedisConfig.Validate(); err != nil { | ||
return xerrors.Errorf("invalid session.redis config: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -130,6 +130,57 @@ func TestEnvironmentOverridesConfiguration(t *testing.T) { | |
assertEq("foo-client-id", foo.ClientConfig.ID, t) | ||
}, | ||
}, | ||
{ | ||
Name: "Test Sessions", | ||
EnvOverrides: map[string]string{ | ||
"SESSION_LIFETIME": "1h", | ||
"SESSION_KEY": "abcdefg", | ||
}, | ||
CheckFunc: func(c Configuration, t *testing.T) { | ||
assertEq(1*time.Hour, c.SessionConfig.SessionLifetimeTTL, t) | ||
assertEq("abcdefg", c.SessionConfig.Key, t) | ||
}, | ||
}, | ||
{ | ||
Name: "Test Redis Sessions", | ||
EnvOverrides: map[string]string{ | ||
"SESSION_REDIS_CONNECTION": "redis://master.example.com:6379", | ||
}, | ||
CheckFunc: func(c Configuration, t *testing.T) { | ||
redisConf := c.SessionConfig.RedisConfig | ||
assertEq([]string{"redis://master.example.com:6379"}, redisConf.ConnectionURLs, t) | ||
}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if it's also worth adding in a call to |
||
}, | ||
{ | ||
Name: "Test Redis Sentinel Sessions", | ||
EnvOverrides: map[string]string{ | ||
"SESSION_REDIS_SENTINEL": "true", | ||
"SESSION_REDIS_MASTER": "redis://master.example.com:6379", | ||
"SESSION_REDIS_CONNECTION": "redis://instance-001.example.com:6379,redis://instance-002.example.com:6379,redis://instance-003.example.com:6379", | ||
}, | ||
CheckFunc: func(c Configuration, t *testing.T) { | ||
redisConf := c.SessionConfig.RedisConfig | ||
assertEq(true, redisConf.UseSentinel, t) | ||
assertEq("redis://master.example.com:6379", redisConf.SentinelMasterName, t) | ||
assertEq([]string{ | ||
"redis://instance-001.example.com:6379", | ||
"redis://instance-002.example.com:6379", | ||
"redis://instance-003.example.com:6379", | ||
}, redisConf.ConnectionURLs, t) | ||
}, | ||
}, | ||
{ | ||
Name: "Test Cookie Sessions", | ||
EnvOverrides: map[string]string{ | ||
"SESSION_COOKIE_NAME": "sso_auth_test", | ||
"SESSION_COOKIE_SECRET": "s3kr1t", | ||
}, | ||
CheckFunc: func(c Configuration, t *testing.T) { | ||
cookieConf := c.SessionConfig.CookieConfig | ||
assertEq("sso_auth_test", cookieConf.Name, t) | ||
assertEq("s3kr1t", cookieConf.Secret, t) | ||
}, | ||
}, | ||
{ | ||
Name: "Test Multiple Providers", | ||
EnvOverrides: map[string]string{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,13 +37,19 @@ func NewAuthenticatorMux(config Configuration, statsdClient *statsd.Client) (*Au | |
} | ||
|
||
idpSlug := idp.Data().ProviderSlug | ||
authenticator, err := NewAuthenticator(config, | ||
opts := []func(*Authenticator) error{ | ||
SetValidator(validator), | ||
SetProvider(idp), | ||
SetCookieStore(config.SessionConfig, idpSlug), | ||
SetStatsdClient(statsdClient), | ||
SetRedirectURL(config.ServerConfig, idpSlug), | ||
) | ||
} | ||
|
||
if config.SessionConfig.RedisConfig.Enabled() { | ||
opts = append(opts, SetRedisStore(config.SessionConfig, idpSlug)) | ||
} else { | ||
opts = append(opts, SetCookieStore(config.SessionConfig, idpSlug)) | ||
} | ||
authenticator, err := NewAuthenticator(config, opts...) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about maybe creating a new Which either essentially calls the above, or returns one of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. However, this kind of pattern is used elsewhere in the codebase! 🤔 |
||
if err != nil { | ||
logger.Error(err, "error creating new Authenticator") | ||
return nil, err | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This snuck in somehow, not sure how critical it is to keep this isolated since this PR is the main blocker for Azure, but I can remove if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely not critical to remove, but I think I'd personally prefer if it was pulled back into the Azure PR and removed here, if that's ok!