Merge pull request #714 from grnhse/redis-sentinel-password
Support Password & SentinelPassword in Redis session store
This commit is contained in:
		
						commit
						8515da3e91
					
				|  | @ -11,6 +11,7 @@ | ||||||
| 
 | 
 | ||||||
| ## Changes since v6.0.0 | ## Changes since v6.0.0 | ||||||
| 
 | 
 | ||||||
|  | - [#714](https://github.com/oauth2-proxy/oauth2-proxy/pull/714) Support passwords with Redis session stores (@NickMeves) | ||||||
| - [#719](https://github.com/oauth2-proxy/oauth2-proxy/pull/719) Add Gosec fixes to areas that are intermittently flagged on PRs (@NickMeves) | - [#719](https://github.com/oauth2-proxy/oauth2-proxy/pull/719) Add Gosec fixes to areas that are intermittently flagged on PRs (@NickMeves) | ||||||
| - [#718](https://github.com/oauth2-proxy/oauth2-proxy/pull/718) Allow Logging to stdout with separate Error Log Channel | - [#718](https://github.com/oauth2-proxy/oauth2-proxy/pull/718) Allow Logging to stdout with separate Error Log Channel | ||||||
| - [#690](https://github.com/oauth2-proxy/oauth2-proxy/pull/690) Address GoSec security findings & remediate (@NickMeves) | - [#690](https://github.com/oauth2-proxy/oauth2-proxy/pull/690) Address GoSec security findings & remediate (@NickMeves) | ||||||
|  |  | ||||||
|  | @ -99,6 +99,8 @@ An example [oauth2-proxy.cfg]({{ site.gitweb }}/contrib/oauth2-proxy.cfg.example | ||||||
| | `--redirect-url` | string | the OAuth Redirect URL, e.g. `"https://internalapp.yourcompany.com/oauth2/callback"` | | | | `--redirect-url` | string | the OAuth Redirect URL, e.g. `"https://internalapp.yourcompany.com/oauth2/callback"` | | | ||||||
| | `--redis-cluster-connection-urls` | string \| list | List of Redis cluster connection URLs (e.g. `redis://HOST[:PORT]`). Used in conjunction with `--redis-use-cluster` | | | | `--redis-cluster-connection-urls` | string \| list | List of Redis cluster connection URLs (e.g. `redis://HOST[:PORT]`). Used in conjunction with `--redis-use-cluster` | | | ||||||
| | `--redis-connection-url` | string | URL of redis server for redis session storage (e.g. `redis://HOST[:PORT]`) | | | | `--redis-connection-url` | string | URL of redis server for redis session storage (e.g. `redis://HOST[:PORT]`) | | | ||||||
|  | | `--redis-password` | string | Redis password. Applicable for all Redis configurations. Will override any password set in `--redis-connection-url` | | | ||||||
|  | | `--redis-sentinel-password` | string | Redis sentinel password. Used only for sentinel connection; any redis node passwords need to use `--redis-password` | | | ||||||
| | `--redis-sentinel-master-name` | string | Redis sentinel master name. Used in conjunction with `--redis-use-sentinel` | | | | `--redis-sentinel-master-name` | string | Redis sentinel master name. Used in conjunction with `--redis-use-sentinel` | | | ||||||
| | `--redis-sentinel-connection-urls` | string \| list | List of Redis sentinel connection URLs (e.g. `redis://HOST[:PORT]`). Used in conjunction with `--redis-use-sentinel` | | | | `--redis-sentinel-connection-urls` | string \| list | List of Redis sentinel connection URLs (e.g. `redis://HOST[:PORT]`). Used in conjunction with `--redis-use-sentinel` | | | ||||||
| | `--redis-use-cluster` | bool | Connect to redis cluster. Must set `--redis-cluster-connection-urls` to use this feature | false | | | `--redis-use-cluster` | bool | Connect to redis cluster. Must set `--redis-cluster-connection-urls` to use this feature | false | | ||||||
|  |  | ||||||
|  | @ -230,7 +230,9 @@ func NewFlagSet() *pflag.FlagSet { | ||||||
| 	flagSet.String("session-store-type", "cookie", "the session storage provider to use") | 	flagSet.String("session-store-type", "cookie", "the session storage provider to use") | ||||||
| 	flagSet.Bool("session-cookie-minimal", false, "strip OAuth tokens from cookie session stores if they aren't needed (cookie session store only)") | 	flagSet.Bool("session-cookie-minimal", false, "strip OAuth tokens from cookie session stores if they aren't needed (cookie session store only)") | ||||||
| 	flagSet.String("redis-connection-url", "", "URL of redis server for redis session storage (eg: redis://HOST[:PORT])") | 	flagSet.String("redis-connection-url", "", "URL of redis server for redis session storage (eg: redis://HOST[:PORT])") | ||||||
|  | 	flagSet.String("redis-password", "", "Redis password. Applicable for all Redis configurations. Will override any password set in `--redis-connection-url`") | ||||||
| 	flagSet.Bool("redis-use-sentinel", false, "Connect to redis via sentinels. Must set --redis-sentinel-master-name and --redis-sentinel-connection-urls to use this feature") | 	flagSet.Bool("redis-use-sentinel", false, "Connect to redis via sentinels. Must set --redis-sentinel-master-name and --redis-sentinel-connection-urls to use this feature") | ||||||
|  | 	flagSet.String("redis-sentinel-password", "", "Redis sentinel password. Used only for sentinel connection; any redis node passwords need to use `--redis-password`") | ||||||
| 	flagSet.String("redis-sentinel-master-name", "", "Redis sentinel master name. Used in conjunction with --redis-use-sentinel") | 	flagSet.String("redis-sentinel-master-name", "", "Redis sentinel master name. Used in conjunction with --redis-use-sentinel") | ||||||
| 	flagSet.String("redis-ca-path", "", "Redis custom CA path") | 	flagSet.String("redis-ca-path", "", "Redis custom CA path") | ||||||
| 	flagSet.Bool("redis-insecure-skip-tls-verify", false, "Use insecure TLS connection to redis") | 	flagSet.Bool("redis-insecure-skip-tls-verify", false, "Use insecure TLS connection to redis") | ||||||
|  |  | ||||||
|  | @ -23,7 +23,9 @@ type CookieStoreOptions struct { | ||||||
| // RedisStoreOptions contains configuration options for the RedisSessionStore.
 | // RedisStoreOptions contains configuration options for the RedisSessionStore.
 | ||||||
| type RedisStoreOptions struct { | type RedisStoreOptions struct { | ||||||
| 	ConnectionURL          string   `flag:"redis-connection-url" cfg:"redis_connection_url"` | 	ConnectionURL          string   `flag:"redis-connection-url" cfg:"redis_connection_url"` | ||||||
|  | 	Password               string   `flag:"redis-password" cfg:"redis_password"` | ||||||
| 	UseSentinel            bool     `flag:"redis-use-sentinel" cfg:"redis_use_sentinel"` | 	UseSentinel            bool     `flag:"redis-use-sentinel" cfg:"redis_use_sentinel"` | ||||||
|  | 	SentinelPassword       string   `flag:"redis-sentinel-password" cfg:"redis_sentinel_password"` | ||||||
| 	SentinelMasterName     string   `flag:"redis-sentinel-master-name" cfg:"redis_sentinel_master_name"` | 	SentinelMasterName     string   `flag:"redis-sentinel-master-name" cfg:"redis_sentinel_master_name"` | ||||||
| 	SentinelConnectionURLs []string `flag:"redis-sentinel-connection-urls" cfg:"redis_sentinel_connection_urls"` | 	SentinelConnectionURLs []string `flag:"redis-sentinel-connection-urls" cfg:"redis_sentinel_connection_urls"` | ||||||
| 	UseCluster             bool     `flag:"redis-use-cluster" cfg:"redis_use_cluster"` | 	UseCluster             bool     `flag:"redis-use-cluster" cfg:"redis_use_cluster"` | ||||||
|  |  | ||||||
|  | @ -90,6 +90,8 @@ func buildSentinelClient(opts options.RedisStoreOptions) (Client, error) { | ||||||
| 	client := redis.NewFailoverClient(&redis.FailoverOptions{ | 	client := redis.NewFailoverClient(&redis.FailoverOptions{ | ||||||
| 		MasterName:       opts.SentinelMasterName, | 		MasterName:       opts.SentinelMasterName, | ||||||
| 		SentinelAddrs:    addrs, | 		SentinelAddrs:    addrs, | ||||||
|  | 		SentinelPassword: opts.SentinelPassword, | ||||||
|  | 		Password:         opts.Password, | ||||||
| 	}) | 	}) | ||||||
| 	return newClient(client), nil | 	return newClient(client), nil | ||||||
| } | } | ||||||
|  | @ -102,6 +104,7 @@ func buildClusterClient(opts options.RedisStoreOptions) (Client, error) { | ||||||
| 	} | 	} | ||||||
| 	client := redis.NewClusterClient(&redis.ClusterOptions{ | 	client := redis.NewClusterClient(&redis.ClusterOptions{ | ||||||
| 		Addrs:    addrs, | 		Addrs:    addrs, | ||||||
|  | 		Password: opts.Password, | ||||||
| 	}) | 	}) | ||||||
| 	return newClusterClient(client), nil | 	return newClusterClient(client), nil | ||||||
| } | } | ||||||
|  | @ -114,6 +117,10 @@ func buildStandaloneClient(opts options.RedisStoreOptions) (Client, error) { | ||||||
| 		return nil, fmt.Errorf("unable to parse redis url: %s", err) | 		return nil, fmt.Errorf("unable to parse redis url: %s", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if opts.Password != "" { | ||||||
|  | 		opt.Password = opts.Password | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if opts.InsecureSkipTLSVerify { | 	if opts.InsecureSkipTLSVerify { | ||||||
| 		opt.TLSConfig.InsecureSkipVerify = true | 		opt.TLSConfig.InsecureSkipVerify = true | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -18,6 +18,8 @@ import ( | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | const redisPassword = "0123456789abcdefghijklmnopqrstuv" | ||||||
|  | 
 | ||||||
| func TestSessionStore(t *testing.T) { | func TestSessionStore(t *testing.T) { | ||||||
| 	logger.SetOutput(GinkgoWriter) | 	logger.SetOutput(GinkgoWriter) | ||||||
| 
 | 
 | ||||||
|  | @ -127,4 +129,87 @@ var _ = Describe("Redis SessionStore Tests", func() { | ||||||
| 			}, | 			}, | ||||||
| 		) | 		) | ||||||
| 	}) | 	}) | ||||||
|  | 
 | ||||||
|  | 	Context("with a redis password", func() { | ||||||
|  | 		BeforeEach(func() { | ||||||
|  | 			mr.RequireAuth(redisPassword) | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		AfterEach(func() { | ||||||
|  | 			mr.RequireAuth("") | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		tests.RunSessionStoreTests( | ||||||
|  | 			func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) { | ||||||
|  | 				// Set the connection URL
 | ||||||
|  | 				opts.Type = options.RedisSessionStoreType | ||||||
|  | 				opts.Redis.ConnectionURL = "redis://" + mr.Addr() | ||||||
|  | 				opts.Redis.Password = redisPassword | ||||||
|  | 
 | ||||||
|  | 				// Capture the session store so that we can close the client
 | ||||||
|  | 				var err error | ||||||
|  | 				ss, err = NewRedisSessionStore(opts, cookieOpts) | ||||||
|  | 				return ss, err | ||||||
|  | 			}, | ||||||
|  | 			func(d time.Duration) error { | ||||||
|  | 				mr.FastForward(d) | ||||||
|  | 				return nil | ||||||
|  | 			}, | ||||||
|  | 		) | ||||||
|  | 
 | ||||||
|  | 		Context("with sentinel", func() { | ||||||
|  | 			var ms *minisentinel.Sentinel | ||||||
|  | 
 | ||||||
|  | 			BeforeEach(func() { | ||||||
|  | 				ms = minisentinel.NewSentinel(mr) | ||||||
|  | 				Expect(ms.Start()).To(Succeed()) | ||||||
|  | 			}) | ||||||
|  | 
 | ||||||
|  | 			AfterEach(func() { | ||||||
|  | 				ms.Close() | ||||||
|  | 			}) | ||||||
|  | 
 | ||||||
|  | 			tests.RunSessionStoreTests( | ||||||
|  | 				func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) { | ||||||
|  | 					// Set the sentinel connection URL
 | ||||||
|  | 					sentinelAddr := "redis://" + ms.Addr() | ||||||
|  | 					opts.Type = options.RedisSessionStoreType | ||||||
|  | 					opts.Redis.SentinelConnectionURLs = []string{sentinelAddr} | ||||||
|  | 					opts.Redis.UseSentinel = true | ||||||
|  | 					opts.Redis.SentinelMasterName = ms.MasterInfo().Name | ||||||
|  | 					opts.Redis.Password = redisPassword | ||||||
|  | 
 | ||||||
|  | 					// Capture the session store so that we can close the client
 | ||||||
|  | 					var err error | ||||||
|  | 					ss, err = NewRedisSessionStore(opts, cookieOpts) | ||||||
|  | 					return ss, err | ||||||
|  | 				}, | ||||||
|  | 				func(d time.Duration) error { | ||||||
|  | 					mr.FastForward(d) | ||||||
|  | 					return nil | ||||||
|  | 				}, | ||||||
|  | 			) | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		Context("with cluster", func() { | ||||||
|  | 			tests.RunSessionStoreTests( | ||||||
|  | 				func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) { | ||||||
|  | 					clusterAddr := "redis://" + mr.Addr() | ||||||
|  | 					opts.Type = options.RedisSessionStoreType | ||||||
|  | 					opts.Redis.ClusterConnectionURLs = []string{clusterAddr} | ||||||
|  | 					opts.Redis.UseCluster = true | ||||||
|  | 					opts.Redis.Password = redisPassword | ||||||
|  | 
 | ||||||
|  | 					// Capture the session store so that we can close the client
 | ||||||
|  | 					var err error | ||||||
|  | 					ss, err = NewRedisSessionStore(opts, cookieOpts) | ||||||
|  | 					return ss, err | ||||||
|  | 				}, | ||||||
|  | 				func(d time.Duration) error { | ||||||
|  | 					mr.FastForward(d) | ||||||
|  | 					return nil | ||||||
|  | 				}, | ||||||
|  | 			) | ||||||
|  | 		}) | ||||||
|  | 	}) | ||||||
| }) | }) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue