git.iko.soy/typeable/oauth2-proxy
on master help sign in
Merge pull request #484 from oauth2-proxy/cookie-options-rename

Replace configuration loading with Viper

commiteae652d986bda65677c2f2fa30b867609645d67d authorJoel Speed <Joel.speed@hotmail.co.uk> dateSun 3 May 2020, 12:14 (6 years ago) parent842d76400fed1a
18 files changed+738−298
CHANGELOG.md+6−2 env_options.go−54 env_options_test.go−46 go.mod+3−2 go.sum+112−2 main.go+11−13 oauthproxy.go+15−15 oauthproxy_test.go+24−24 options.go+30−33 options_test.go+20−20 pkg/apis/options/cookie.go+9−9 pkg/apis/options/load.go+134 pkg/apis/options/load_test.go+300 pkg/apis/options/sessions.go+6−10 pkg/cookies/cookies.go+7−7 pkg/sessions/cookie/session_store.go+7−7 pkg/sessions/redis/redis_store.go+23−23 pkg/sessions/session_store_test.go+31−31
CHANGELOG.md+6−2
@@ -11,14 +11,18 @@
1111- Migration from Pusher to independent org may have introduced breaking changes for your environment.
1212 - See the changes listed below for PR [#464](https://github.com/oauth2-proxy/oauth2-proxy/pull/464) for full details
1313 - Binaries renamed from `oauth2_proxy` to `oauth2-proxy`
14−
1514- [#440](https://github.com/oauth2-proxy/oauth2-proxy/pull/440) Switch Azure AD Graph API to Microsoft Graph API (@johejo)
16− - The Azure AD Graph API has been [deprecated](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api) and is being replaced by the Microsoft Graph API.
15+ - The Azure AD Graph API has been [deprecated](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api) and is being replaced by the Microsoft Graph API.
1716 If your application relies on the access token being passed to it to access the Azure AD Graph API, you should migrate your application to use the Microsoft Graph API.
1817 Existing behaviour can be retained by setting `-resource=https://graph.windows.net`.
18+- [#484](https://github.com/oauth2-proxy/oauth2-proxy/pull/484) Configuration loading has been replaced with Viper and PFlag
19+ - Flags now require a `--` prefix before the option
20+ - Previously flags allowed either `-` or `--` to prefix the option name
21+ - Eg `-provider` must now be `--provider`
1922
2023## Changes since v5.1.0
2124
25+- [#484](https://github.com/oauth2-proxy/oauth2-proxy/pull/484) Replace configuration loading with Viper (@JoelSpeed)
2226- [#499](https://github.com/oauth2-proxy/oauth2-proxy/pull/469) Add `-user-id-claim` to support generic claims in addition to email
2327- [#486](https://github.com/oauth2-proxy/oauth2-proxy/pull/486) Add new linters (@johejo)
2428- [#440](https://github.com/oauth2-proxy/oauth2-proxy/pull/440) Switch Azure AD Graph API to Microsoft Graph API (@johejo)
env_options.godeleted−54
@@ -1,54 +0,0 @@
1−package main
2−
3−import (
4− "os"
5− "reflect"
6− "strings"
7−)
8−
9−// EnvOptions holds program options loaded from the process environment
10−type EnvOptions map[string]interface{}
11−
12−// LoadEnvForStruct loads environment variables for each field in an options
13−// struct passed into it.
14−//
15−// Fields in the options struct must have an `env` and `cfg` tag to be read
16−// from the environment
17−func (cfg EnvOptions) LoadEnvForStruct(options interface{}) {
18− val := reflect.ValueOf(options)
19− var typ reflect.Type
20− if val.Kind() == reflect.Ptr {
21− typ = val.Elem().Type()
22− } else {
23− typ = val.Type()
24− }
25−
26− for i := 0; i < typ.NumField(); i++ {
27− // pull out the struct tags:
28− // flag - the name of the command line flag
29− // deprecated - (optional) the name of the deprecated command line flag
30− // cfg - (optional, defaults to underscored flag) the name of the config file option
31− field := typ.Field(i)
32− fieldV := reflect.Indirect(val).Field(i)
33−
34− if field.Type.Kind() == reflect.Struct && field.Anonymous {
35− cfg.LoadEnvForStruct(fieldV.Interface())
36− continue
37− }
38−
39− flagName := field.Tag.Get("flag")
40− envName := field.Tag.Get("env")
41− cfgName := field.Tag.Get("cfg")
42− if cfgName == "" && flagName != "" {
43− cfgName = strings.ReplaceAll(flagName, "-", "_")
44− }
45− if envName == "" || cfgName == "" {
46− // resolvable fields must have the `env` and `cfg` struct tag
47− continue
48− }
49− v := os.Getenv(envName)
50− if v != "" {
51− cfg[cfgName] = v
52− }
53− }
54−}
env_options_test.godeleted−46
@@ -1,46 +0,0 @@
1−package main_test
2−
3−import (
4− "os"
5− "testing"
6−
7− proxy "github.com/oauth2-proxy/oauth2-proxy"
8− "github.com/stretchr/testify/assert"
9−)
10−
11−type EnvTest struct {
12− TestField string `cfg:"target_field" env:"TEST_ENV_FIELD"`
13− EnvTestEmbed
14−}
15−
16−type EnvTestEmbed struct {
17− TestFieldEmbed string `cfg:"target_field_embed" env:"TEST_ENV_FIELD_EMBED"`
18−}
19−
20−func TestLoadEnvForStruct(t *testing.T) {
21−
22− cfg := make(proxy.EnvOptions)
23− cfg.LoadEnvForStruct(&EnvTest{})
24−
25− _, ok := cfg["target_field"]
26− assert.Equal(t, ok, false)
27−
28− os.Setenv("TEST_ENV_FIELD", "1234abcd")
29− cfg.LoadEnvForStruct(&EnvTest{})
30− v := cfg["target_field"]
31− assert.Equal(t, v, "1234abcd")
32−}
33−
34−func TestLoadEnvForStructWithEmbeddedFields(t *testing.T) {
35−
36− cfg := make(proxy.EnvOptions)
37− cfg.LoadEnvForStruct(&EnvTest{})
38−
39− _, ok := cfg["target_field_embed"]
40− assert.Equal(t, ok, false)
41−
42− os.Setenv("TEST_ENV_FIELD_EMBED", "1234abcd")
43− cfg.LoadEnvForStruct(&EnvTest{})
44− v := cfg["target_field_embed"]
45− assert.Equal(t, v, "1234abcd")
46−}
go.mod+3−2
@@ -3,7 +3,6 @@ module github.com/oauth2-proxy/oauth2-proxy
33go 1.14
44
55require (
6− github.com/BurntSushi/toml v0.3.1
76 github.com/alicebob/miniredis/v2 v2.11.2
87 github.com/bitly/go-simplejson v0.5.0
98 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
@@ -13,10 +12,12 @@ require (
1312 github.com/go-redis/redis/v7 v7.2.0
1413 github.com/kr/pretty v0.2.0 // indirect
1514 github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa
16− github.com/mreiferson/go-options v1.0.0
15+ github.com/mitchellh/mapstructure v1.1.2
1716 github.com/onsi/ginkgo v1.12.0
1817 github.com/onsi/gomega v1.9.0
1918 github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
19+ github.com/spf13/pflag v1.0.3
20+ github.com/spf13/viper v1.6.3
2021 github.com/stretchr/testify v1.5.1
2122 github.com/yhat/wsutil v0.0.0-20170731153501-1d66fa95c997
2223 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
go.sum+112−2
@@ -4,67 +4,118 @@ cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
44cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
55github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
66github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
7+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
8+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
9+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
710github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U=
811github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
912github.com/alicebob/miniredis/v2 v2.11.2 h1:OtWO7akm5otuhssnE/sNfsWxG4gZ8DbGhShDtRrByJs=
1013github.com/alicebob/miniredis/v2 v2.11.2/go.mod h1:VL3UDEfAH59bSa7MuHMuFToxkqyHh69s/WUbYlOAuyg=
14+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
15+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
16+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
1117github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
1218github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
1319github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
1420github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
1521github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
22+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
1623github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
1724github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
1825github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
1926github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
27+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
28+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
2029github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
2130github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
31+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
32+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
33+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
2234github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2335github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
36+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
37+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2438github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
2539github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
40+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
2641github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
2742github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
2843github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
2944github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
3045github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
3146github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
47+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
48+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
49+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
50+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
3251github.com/go-redis/redis/v7 v7.2.0 h1:CrCexy/jYWZjW0AyVoHlcJUeZN19VWlbepTh1Vq6dJs=
3352github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
53+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
54+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
55+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
3456github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
3557github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
58+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
3659github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
3760github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
3861github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
62+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
3963github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
4064github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
4165github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3 h1:6amM4HsNPOvMLVc2ZnyqrjeQ92YAVWn7T4WBKK87inY=
4266github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
4367github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
68+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
4469github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
4570github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
4671github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
72+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
4773github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
4874github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
4975github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
5076github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
5177github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
78+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
79+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
80+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
81+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
82+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
83+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
5284github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
5385github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
5486github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
87+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
88+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
5589github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
5690github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
91+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
92+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
5793github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
94+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
95+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
96+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
97+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
98+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
99+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
100+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
58101github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
59102github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
60103github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
61104github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
62105github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
63106github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
107+github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
108+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
109+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
64110github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa h1:hI1uC2A3vJFjwvBn0G0a7QBRdBUp6Y048BtLAHRTKPo=
65111github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa/go.mod h1:8vxFeeg++MqgCHwehSuwTlYCF0ALyDJbYJ1JsKi7v6s=
66−github.com/mreiferson/go-options v1.0.0 h1:RMLidydGlDWpL+lQTXo0bVIf/XT2CTq7AEJMoz5/VWs=
67−github.com/mreiferson/go-options v1.0.0/go.mod h1:zHtCks/HQvOt8ATyfwVe3JJq2PPuImzXINPRTC03+9w=
112+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
113+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
114+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
115+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
116+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
117+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
118+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
68119github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
69120github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
70121github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
@@ -73,20 +124,63 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
73124github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
74125github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
75126github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
127+github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
128+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
129+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
76130github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
77131github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
78132github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
79133github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
134+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
135+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
136+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
137+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
80138github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
139+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
140+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
141+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
142+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
143+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
144+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
145+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
146+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
147+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
148+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
149+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
150+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
151+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
152+github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
153+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
154+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
155+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
156+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
157+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
158+github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
159+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
160+github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
161+github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
81162github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
163+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
164+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
165+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
82166github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
83167github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
168+github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
169+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
170+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
171+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
172+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
84173github.com/yhat/wsutil v0.0.0-20170731153501-1d66fa95c997 h1:1+FQ4Ns+UZtUiQ4lP0sTCyKSQ0EXoiwAdHZB0Pd5t9Q=
85174github.com/yhat/wsutil v0.0.0-20170731153501-1d66fa95c997/go.mod h1:DIGbh/f5XMAessMV/uaIik81gkDVjUeQ9ApdaU7wRKE=
86175github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
87176github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
177+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
88178go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
89179go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
180+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
181+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
182+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
183+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
90184golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
91185golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
92186golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -98,11 +192,14 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl
98192golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
99193golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
100194golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
195+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
196+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
101197golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
102198golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
103199golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
104200golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
105201golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
202+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
106203golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
107204golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
108205golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -117,7 +214,10 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
117214golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
118215golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
119216golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
217+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
120218golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
219+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
220+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
121221golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
122222golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
123223golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
@@ -131,11 +231,14 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
131231golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
132232golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
133233golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
234+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
235+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
134236golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
135237golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
136238golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
137239golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
138240golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
241+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
139242golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
140243golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
141244golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -152,21 +255,28 @@ google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRn
152255google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
153256google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
154257google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
258+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
155259google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
156260google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
157261google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
262+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
158263gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
159264gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
265+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
160266gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
161267gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
162268gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
163269gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
270+gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
271+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
164272gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
165273gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
274+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
166275gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y=
167276gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
168277gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
169278gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
279+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
170280gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
171281gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
172282gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
main.go+11−13
@@ -12,9 +12,9 @@ import (
1212 "syscall"
1313 "time"
1414
15− "github.com/BurntSushi/toml"
16− options "github.com/mreiferson/go-options"
15+ "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
1716 "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
17+ "github.com/spf13/pflag"
1818)
1919
2020func main() {
@@ -149,7 +149,10 @@ func main() {
149149
150150 flagSet.String("user-id-claim", "email", "which claim contains the user ID")
151151
152− flagSet.Parse(os.Args[1:])
152+ pflagSet := pflag.NewFlagSet("oauth2-proxy", pflag.ExitOnError)
153+ pflagSet.AddGoFlagSet(flagSet)
154+
155+ pflagSet.Parse(os.Args[1:])
153156
154157 if *showVersion {
155158 fmt.Printf("oauth2-proxy %s (built with %s)\n", VERSION, runtime.Version())
@@ -157,18 +160,13 @@ func main() {
157160 }
158161
159162 opts := NewOptions()
160−
161− cfg := make(EnvOptions)
162− if *config != "" {
163− _, err := toml.DecodeFile(*config, &cfg)
164− if err != nil {
165− logger.Fatalf("ERROR: failed to load config file %s - %s", *config, err)
166− }
163+ err := options.Load(*config, pflagSet, opts)
164+ if err != nil {
165+ logger.Printf("ERROR: Failed to load config: %v", err)
166+ os.Exit(1)
167167 }
168− cfg.LoadEnvForStruct(opts)
169− options.Resolve(opts, flagSet, cfg)
170168
171− err := opts.Validate()
169+ err = opts.Validate()
172170 if err != nil {
173171 logger.Printf("%s", err)
174172 os.Exit(1)
oauthproxy.go+15−15
@@ -247,7 +247,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
247247 panic(fmt.Sprintf("unknown upstream protocol %s", u.Scheme))
248248 }
249249 }
250− for _, u := range opts.CompiledRegex {
250+ for _, u := range opts.compiledRegex {
251251 logger.Printf("compiled skip-auth-regex => %q", u)
252252 }
253253
@@ -264,23 +264,23 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
264264
265265 logger.Printf("OAuthProxy configured for %s Client ID: %s", opts.provider.Data().ProviderName, opts.ClientID)
266266 refresh := "disabled"
267− if opts.CookieRefresh != time.Duration(0) {
268− refresh = fmt.Sprintf("after %s", opts.CookieRefresh)
267+ if opts.Cookie.Refresh != time.Duration(0) {
268+ refresh = fmt.Sprintf("after %s", opts.Cookie.Refresh)
269269 }
270270
271− logger.Printf("Cookie settings: name:%s secure(https):%v httponly:%v expiry:%s domains:%s path:%s samesite:%s refresh:%s", opts.CookieName, opts.CookieSecure, opts.CookieHTTPOnly, opts.CookieExpire, strings.Join(opts.CookieDomains, ","), opts.CookiePath, opts.CookieSameSite, refresh)
271+ logger.Printf("Cookie settings: name:%s secure(https):%v httponly:%v expiry:%s domains:%s path:%s samesite:%s refresh:%s", opts.Cookie.Name, opts.Cookie.Secure, opts.Cookie.HTTPOnly, opts.Cookie.Expire, strings.Join(opts.Cookie.Domains, ","), opts.Cookie.Path, opts.Cookie.SameSite, refresh)
272272
273273 return &OAuthProxy{
274− CookieName: opts.CookieName,
275− CSRFCookieName: fmt.Sprintf("%v_%v", opts.CookieName, "csrf"),
276− CookieSeed: opts.CookieSecret,
277− CookieDomains: opts.CookieDomains,
278− CookiePath: opts.CookiePath,
279− CookieSecure: opts.CookieSecure,
280− CookieHTTPOnly: opts.CookieHTTPOnly,
281− CookieExpire: opts.CookieExpire,
282− CookieRefresh: opts.CookieRefresh,
283− CookieSameSite: opts.CookieSameSite,
274+ CookieName: opts.Cookie.Name,
275+ CSRFCookieName: fmt.Sprintf("%v_%v", opts.Cookie.Name, "csrf"),
276+ CookieSeed: opts.Cookie.Secret,
277+ CookieDomains: opts.Cookie.Domains,
278+ CookiePath: opts.Cookie.Path,
279+ CookieSecure: opts.Cookie.Secure,
280+ CookieHTTPOnly: opts.Cookie.HTTPOnly,
281+ CookieExpire: opts.Cookie.Expire,
282+ CookieRefresh: opts.Cookie.Refresh,
283+ CookieSameSite: opts.Cookie.SameSite,
284284 Validator: validator,
285285
286286 RobotsPath: "/robots.txt",
@@ -303,7 +303,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
303303 skipAuthPreflight: opts.SkipAuthPreflight,
304304 skipJwtBearerTokens: opts.SkipJwtBearerTokens,
305305 jwtBearerVerifiers: opts.jwtBearerVerifiers,
306− compiledRegex: opts.CompiledRegex,
306+ compiledRegex: opts.compiledRegex,
307307 SetXAuthRequest: opts.SetXAuthRequest,
308308 PassBasicAuth: opts.PassBasicAuth,
309309 SetBasicAuth: opts.SetBasicAuth,
oauthproxy_test.go+24−24
@@ -164,7 +164,7 @@ func TestRobotsTxt(t *testing.T) {
164164 opts := NewOptions()
165165 opts.ClientID = "asdlkjx"
166166 opts.ClientSecret = "alkgks"
167− opts.CookieSecret = "asdkugkj"
167+ opts.Cookie.Secret = "asdkugkj"
168168 opts.Validate()
169169
170170 proxy := NewOAuthProxy(opts, func(string) bool { return true })
@@ -179,7 +179,7 @@ func TestIsValidRedirect(t *testing.T) {
179179 opts := NewOptions()
180180 opts.ClientID = "skdlfj"
181181 opts.ClientSecret = "fgkdsgj"
182− opts.CookieSecret = "ljgiogbj"
182+ opts.Cookie.Secret = "ljgiogbj"
183183 // Should match domains that are exactly foo.bar and any subdomain of bar.foo
184184 opts.WhitelistDomains = []string{
185185 "foo.bar",
@@ -398,10 +398,10 @@ func TestBasicAuthPassword(t *testing.T) {
398398 opts.Upstreams = append(opts.Upstreams, providerServer.URL)
399399 // The CookieSecret must be 32 bytes in order to create the AES
400400 // cipher.
401− opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
401+ opts.Cookie.Secret = "xyzzyplughxyzzyplughxyzzyplughxp"
402402 opts.ClientID = "dlgkj"
403403 opts.ClientSecret = "alkgret"
404− opts.CookieSecure = false
404+ opts.Cookie.Secure = false
405405 opts.PassBasicAuth = true
406406 opts.SetBasicAuth = true
407407 opts.PassUserHeaders = true
@@ -582,10 +582,10 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTes
582582 }
583583 // The CookieSecret must be 32 bytes in order to create the AES
584584 // cipher.
585− t.opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
585+ t.opts.Cookie.Secret = "xyzzyplughxyzzyplughxyzzyplughxp"
586586 t.opts.ClientID = "slgkj"
587587 t.opts.ClientSecret = "gfjgojl"
588− t.opts.CookieSecure = false
588+ t.opts.Cookie.Secure = false
589589 t.opts.PassAccessToken = opts.PassAccessToken
590590 t.opts.Validate()
591591
@@ -735,7 +735,7 @@ func NewSignInPageTest(skipProvider bool) *SignInPageTest {
735735 var sipTest SignInPageTest
736736
737737 sipTest.opts = NewOptions()
738− sipTest.opts.CookieSecret = "adklsj2"
738+ sipTest.opts.Cookie.Secret = "adklsj2"
739739 sipTest.opts.ClientID = "lkdgj"
740740 sipTest.opts.ClientSecret = "sgiufgoi"
741741 sipTest.opts.SkipProviderButton = skipProvider
@@ -841,10 +841,10 @@ func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifi
841841 }
842842 pcTest.opts.ClientID = "asdfljk"
843843 pcTest.opts.ClientSecret = "lkjfdsig"
844− pcTest.opts.CookieSecret = "0123456789abcdefabcd"
844+ pcTest.opts.Cookie.Secret = "0123456789abcdefabcd"
845845 // First, set the CookieRefresh option so proxy.AesCipher is created,
846846 // needed to encrypt the access_token.
847− pcTest.opts.CookieRefresh = time.Hour
847+ pcTest.opts.Cookie.Refresh = time.Hour
848848 pcTest.opts.Validate()
849849
850850 pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
@@ -915,7 +915,7 @@ func TestProcessCookieNoCookieError(t *testing.T) {
915915
916916func TestProcessCookieRefreshNotSet(t *testing.T) {
917917 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
918− opts.CookieExpire = time.Duration(23) * time.Hour
918+ opts.Cookie.Expire = time.Duration(23) * time.Hour
919919 })
920920 reference := time.Now().Add(time.Duration(-2) * time.Hour)
921921
@@ -932,7 +932,7 @@ func TestProcessCookieRefreshNotSet(t *testing.T) {
932932
933933func TestProcessCookieFailIfCookieExpired(t *testing.T) {
934934 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
935− opts.CookieExpire = time.Duration(24) * time.Hour
935+ opts.Cookie.Expire = time.Duration(24) * time.Hour
936936 })
937937 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
938938 startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
@@ -947,7 +947,7 @@ func TestProcessCookieFailIfCookieExpired(t *testing.T) {
947947
948948func TestProcessCookieFailIfRefreshSetAndCookieExpired(t *testing.T) {
949949 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
950− opts.CookieExpire = time.Duration(24) * time.Hour
950+ opts.Cookie.Expire = time.Duration(24) * time.Hour
951951 })
952952 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
953953 startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
@@ -1017,7 +1017,7 @@ func TestAuthOnlyEndpointUnauthorizedOnNoCookieSetError(t *testing.T) {
10171017
10181018func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
10191019 test := NewAuthOnlyEndpointTest(func(opts *Options) {
1020− opts.CookieExpire = time.Duration(24) * time.Hour
1020+ opts.Cookie.Expire = time.Duration(24) * time.Hour
10211021 })
10221022 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
10231023 startSession := &sessions.SessionState{
@@ -1149,7 +1149,7 @@ func TestAuthSkippedForPreflightRequests(t *testing.T) {
11491149 opts.Upstreams = append(opts.Upstreams, upstream.URL)
11501150 opts.ClientID = "aljsal"
11511151 opts.ClientSecret = "jglkfsdgj"
1152− opts.CookieSecret = "dkfjgdls"
1152+ opts.Cookie.Secret = "dkfjgdls"
11531153 opts.SkipAuthPreflight = true
11541154 opts.Validate()
11551155
@@ -1196,7 +1196,7 @@ type SignatureTest struct {
11961196
11971197func NewSignatureTest() *SignatureTest {
11981198 opts := NewOptions()
1199− opts.CookieSecret = "cookie secret"
1199+ opts.Cookie.Secret = "cookie secret"
12001200 opts.ClientID = "client ID"
12011201 opts.ClientSecret = "client secret"
12021202 opts.EmailDomains = []string{"acm.org"}
@@ -1343,7 +1343,7 @@ type ajaxRequestTest struct {
13431343func newAjaxRequestTest() *ajaxRequestTest {
13441344 test := &ajaxRequestTest{}
13451345 test.opts = NewOptions()
1346− test.opts.CookieSecret = "sdflsw"
1346+ test.opts.Cookie.Secret = "sdflsw"
13471347 test.opts.ClientID = "gkljfdl"
13481348 test.opts.ClientSecret = "sdflkjs"
13491349 test.opts.Validate()
@@ -1401,11 +1401,11 @@ func TestAjaxForbiddendRequest(t *testing.T) {
14011401
14021402func TestClearSplitCookie(t *testing.T) {
14031403 opts := NewOptions()
1404− opts.CookieName = "oauth2"
1405− opts.CookieDomains = []string{"abc"}
1406− store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.CookieOptions)
1404+ opts.Cookie.Name = "oauth2"
1405+ opts.Cookie.Domains = []string{"abc"}
1406+ store, err := cookie.NewCookieSessionStore(&opts.Session, &opts.Cookie)
14071407 assert.Equal(t, err, nil)
1408− p := OAuthProxy{CookieName: opts.CookieName, CookieDomains: opts.CookieDomains, sessionStore: store}
1408+ p := OAuthProxy{CookieName: opts.Cookie.Name, CookieDomains: opts.Cookie.Domains, sessionStore: store}
14091409 var rw = httptest.NewRecorder()
14101410 req := httptest.NewRequest("get", "/", nil)
14111411
@@ -1430,11 +1430,11 @@ func TestClearSplitCookie(t *testing.T) {
14301430
14311431func TestClearSingleCookie(t *testing.T) {
14321432 opts := NewOptions()
1433− opts.CookieName = "oauth2"
1434− opts.CookieDomains = []string{"abc"}
1435− store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.CookieOptions)
1433+ opts.Cookie.Name = "oauth2"
1434+ opts.Cookie.Domains = []string{"abc"}
1435+ store, err := cookie.NewCookieSessionStore(&opts.Session, &opts.Cookie)
14361436 assert.Equal(t, err, nil)
1437− p := OAuthProxy{CookieName: opts.CookieName, CookieDomains: opts.CookieDomains, sessionStore: store}
1437+ p := OAuthProxy{CookieName: opts.Cookie.Name, CookieDomains: opts.Cookie.Domains, sessionStore: store}
14381438 var rw = httptest.NewRecorder()
14391439 req := httptest.NewRequest("get", "/", nil)
14401440
options.go+30−33
@@ -64,11 +64,8 @@ type Options struct {
6464 Banner string `flag:"banner" cfg:"banner" env:"OAUTH2_PROXY_BANNER"`
6565 Footer string `flag:"footer" cfg:"footer" env:"OAUTH2_PROXY_FOOTER"`
6666
67− // Embed CookieOptions
68− options.CookieOptions
69−
70− // Embed SessionOptions
71− options.SessionOptions
67+ Cookie options.CookieOptions `cfg:",squash"`
68+ Session options.SessionOptions `cfg:",squash"`
7269
7370 Upstreams []string `flag:"upstream" cfg:"upstreams" env:"OAUTH2_PROXY_UPSTREAMS"`
7471 SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex" env:"OAUTH2_PROXY_SKIP_AUTH_REGEX"`
@@ -134,7 +131,7 @@ type Options struct {
134131 // internal values that are set after config validation
135132 redirectURL *url.URL
136133 proxyURLs []*url.URL
137− CompiledRegex []*regexp.Regexp
134+ compiledRegex []*regexp.Regexp
138135 provider providers.Provider
139136 sessionStore sessionsapi.SessionStore
140137 signatureData *SignatureData
@@ -158,14 +155,14 @@ func NewOptions() *Options {
158155 HTTPSAddress: ":443",
159156 ForceHTTPS: false,
160157 DisplayHtpasswdForm: true,
161− CookieOptions: options.CookieOptions{
162− CookieName: "_oauth2_proxy",
163− CookieSecure: true,
164− CookieHTTPOnly: true,
165− CookieExpire: time.Duration(168) * time.Hour,
166− CookieRefresh: time.Duration(0),
158+ Cookie: options.CookieOptions{
159+ Name: "_oauth2_proxy",
160+ Secure: true,
161+ HTTPOnly: true,
162+ Expire: time.Duration(168) * time.Hour,
163+ Refresh: time.Duration(0),
167164 },
168− SessionOptions: options.SessionOptions{
165+ Session: options.SessionOptions{
169166 Type: "cookie",
170167 },
171168 SetXAuthRequest: false,
@@ -227,7 +224,7 @@ func (o *Options) Validate() error {
227224 }
228225
229226 msgs := make([]string, 0)
230− if o.CookieSecret == "" {
227+ if o.Cookie.Secret == "" {
231228 msgs = append(msgs, "missing setting: cookie-secret")
232229 }
233230 if o.ClientID == "" {
@@ -372,61 +369,61 @@ func (o *Options) Validate() error {
372369 }
373370
374371 for _, u := range o.SkipAuthRegex {
375− CompiledRegex, err := regexp.Compile(u)
372+ compiledRegex, err := regexp.Compile(u)
376373 if err != nil {
377374 msgs = append(msgs, fmt.Sprintf("error compiling regex=%q %s", u, err))
378375 continue
379376 }
380− o.CompiledRegex = append(o.CompiledRegex, CompiledRegex)
377+ o.compiledRegex = append(o.compiledRegex, compiledRegex)
381378 }
382379 msgs = parseProviderInfo(o, msgs)
383380
384381 var cipher *encryption.Cipher
385− if o.PassAccessToken || o.SetAuthorization || o.PassAuthorization || (o.CookieRefresh != time.Duration(0)) {
382+ if o.PassAccessToken || o.SetAuthorization || o.PassAuthorization || (o.Cookie.Refresh != time.Duration(0)) {
386383 validCookieSecretSize := false
387384 for _, i := range []int{16, 24, 32} {
388− if len(secretBytes(o.CookieSecret)) == i {
385+ if len(secretBytes(o.Cookie.Secret)) == i {
389386 validCookieSecretSize = true
390387 }
391388 }
392389 var decoded bool
393− if string(secretBytes(o.CookieSecret)) != o.CookieSecret {
390+ if string(secretBytes(o.Cookie.Secret)) != o.Cookie.Secret {
394391 decoded = true
395392 }
396393 if !validCookieSecretSize {
397394 var suffix string
398395 if decoded {
399− suffix = fmt.Sprintf(" note: cookie secret was base64 decoded from %q", o.CookieSecret)
396+ suffix = fmt.Sprintf(" note: cookie secret was base64 decoded from %q", o.Cookie.Secret)
400397 }
401398 msgs = append(msgs, fmt.Sprintf(
402399 "cookie_secret must be 16, 24, or 32 bytes "+
403400 "to create an AES cipher when "+
404401 "pass_access_token == true or "+
405402 "cookie_refresh != 0, but is %d bytes.%s",
406− len(secretBytes(o.CookieSecret)), suffix))
403+ len(secretBytes(o.Cookie.Secret)), suffix))
407404 } else {
408405 var err error
409− cipher, err = encryption.NewCipher(secretBytes(o.CookieSecret))
406+ cipher, err = encryption.NewCipher(secretBytes(o.Cookie.Secret))
410407 if err != nil {
411408 msgs = append(msgs, fmt.Sprintf("cookie-secret error: %v", err))
412409 }
413410 }
414411 }
415412
416− o.SessionOptions.Cipher = cipher
417− sessionStore, err := sessions.NewSessionStore(&o.SessionOptions, &o.CookieOptions)
413+ o.Session.Cipher = cipher
414+ sessionStore, err := sessions.NewSessionStore(&o.Session, &o.Cookie)
418415 if err != nil {
419416 msgs = append(msgs, fmt.Sprintf("error initialising session storage: %v", err))
420417 } else {
421418 o.sessionStore = sessionStore
422419 }
423420
424− if o.CookieRefresh >= o.CookieExpire {
421+ if o.Cookie.Refresh >= o.Cookie.Expire {
425422 msgs = append(msgs, fmt.Sprintf(
426423 "cookie_refresh (%s) must be less than "+
427424 "cookie_expire (%s)",
428− o.CookieRefresh.String(),
429− o.CookieExpire.String()))
425+ o.Cookie.Refresh.String(),
426+ o.Cookie.Expire.String()))
430427 }
431428
432429 if len(o.GoogleGroups) > 0 || o.GoogleAdminEmail != "" || o.GoogleServiceAccountJSON != "" {
@@ -441,16 +438,16 @@ func (o *Options) Validate() error {
441438 }
442439 }
443440
444− switch o.CookieSameSite {
441+ switch o.Cookie.SameSite {
445442 case "", "none", "lax", "strict":
446443 default:
447− msgs = append(msgs, fmt.Sprintf("cookie_samesite (%s) must be one of ['', 'lax', 'strict', 'none']", o.CookieSameSite))
444+ msgs = append(msgs, fmt.Sprintf("cookie_samesite (%s) must be one of ['', 'lax', 'strict', 'none']", o.Cookie.SameSite))
448445 }
449446
450447 // Sort cookie domains by length, so that we try longer (and more specific)
451448 // domains first
452− sort.Slice(o.CookieDomains, func(i, j int) bool {
453− return len(o.CookieDomains[i]) > len(o.CookieDomains[j])
449+ sort.Slice(o.Cookie.Domains, func(i, j int) bool {
450+ return len(o.Cookie.Domains[i]) > len(o.Cookie.Domains[j])
454451 })
455452
456453 msgs = parseSignatureKey(o, msgs)
@@ -627,9 +624,9 @@ func newVerifierFromJwtIssuer(jwtIssuer jwtIssuer) (*oidc.IDTokenVerifier, error
627624}
628625
629626func validateCookieName(o *Options, msgs []string) []string {
630− cookie := &http.Cookie{Name: o.CookieName}
627+ cookie := &http.Cookie{Name: o.Cookie.Name}
631628 if cookie.String() == "" {
632− return append(msgs, fmt.Sprintf("invalid cookie name: %q", o.CookieName))
629+ return append(msgs, fmt.Sprintf("invalid cookie name: %q", o.Cookie.Name))
633630 }
634631 return msgs
635632}
options_test.go+20−20
@@ -22,7 +22,7 @@ const (
2222func testOptions() *Options {
2323 o := NewOptions()
2424 o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8080/")
25− o.CookieSecret = cookieSecret
25+ o.Cookie.Secret = cookieSecret
2626 o.ClientID = clientID
2727 o.ClientSecret = clientSecret
2828 o.EmailDomains = []string{"*"}
@@ -51,7 +51,7 @@ func TestNewOptions(t *testing.T) {
5151
5252func TestClientSecretFileOptionFails(t *testing.T) {
5353 o := NewOptions()
54− o.CookieSecret = cookieSecret
54+ o.Cookie.Secret = cookieSecret
5555 o.ClientID = clientID
5656 o.ClientSecretFile = clientSecret
5757 o.EmailDomains = []string{"*"}
@@ -81,7 +81,7 @@ func TestClientSecretFileOption(t *testing.T) {
8181 defer os.Remove(clientSecretFileName)
8282
8383 o := NewOptions()
84− o.CookieSecret = cookieSecret
84+ o.Cookie.Secret = cookieSecret
8585 o.ClientID = clientID
8686 o.ClientSecretFile = clientSecretFileName
8787 o.EmailDomains = []string{"*"}
@@ -165,7 +165,7 @@ func TestCompiledRegex(t *testing.T) {
165165 o.SkipAuthRegex = regexps
166166 assert.Equal(t, nil, o.Validate())
167167 actual := make([]string, 0)
168− for _, regex := range o.CompiledRegex {
168+ for _, regex := range o.compiledRegex {
169169 actual = append(actual, regex.String())
170170 }
171171 assert.Equal(t, regexps, actual)
@@ -212,20 +212,20 @@ func TestPassAccessTokenRequiresSpecificCookieSecretLengths(t *testing.T) {
212212
213213 assert.Equal(t, false, o.PassAccessToken)
214214 o.PassAccessToken = true
215− o.CookieSecret = "cookie of invalid length-"
215+ o.Cookie.Secret = "cookie of invalid length-"
216216 assert.NotEqual(t, nil, o.Validate())
217217
218218 o.PassAccessToken = false
219− o.CookieRefresh = time.Duration(24) * time.Hour
219+ o.Cookie.Refresh = time.Duration(24) * time.Hour
220220 assert.NotEqual(t, nil, o.Validate())
221221
222− o.CookieSecret = "16 bytes AES-128"
222+ o.Cookie.Secret = "16 bytes AES-128"
223223 assert.Equal(t, nil, o.Validate())
224224
225− o.CookieSecret = "24 byte secret AES-192--"
225+ o.Cookie.Secret = "24 byte secret AES-192--"
226226 assert.Equal(t, nil, o.Validate())
227227
228− o.CookieSecret = "32 byte secret for AES-256------"
228+ o.Cookie.Secret = "32 byte secret for AES-256------"
229229 assert.Equal(t, nil, o.Validate())
230230}
231231
@@ -233,11 +233,11 @@ func TestCookieRefreshMustBeLessThanCookieExpire(t *testing.T) {
233233 o := testOptions()
234234 assert.Equal(t, nil, o.Validate())
235235
236− o.CookieSecret = "0123456789abcdefabcd"
237− o.CookieRefresh = o.CookieExpire
236+ o.Cookie.Secret = "0123456789abcdefabcd"
237+ o.Cookie.Refresh = o.Cookie.Expire
238238 assert.NotEqual(t, nil, o.Validate())
239239
240− o.CookieRefresh -= time.Duration(1)
240+ o.Cookie.Refresh -= time.Duration(1)
241241 assert.Equal(t, nil, o.Validate())
242242}
243243
@@ -246,23 +246,23 @@ func TestBase64CookieSecret(t *testing.T) {
246246 assert.Equal(t, nil, o.Validate())
247247
248248 // 32 byte, base64 (urlsafe) encoded key
249− o.CookieSecret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ="
249+ o.Cookie.Secret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ="
250250 assert.Equal(t, nil, o.Validate())
251251
252252 // 32 byte, base64 (urlsafe) encoded key, w/o padding
253− o.CookieSecret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ"
253+ o.Cookie.Secret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ"
254254 assert.Equal(t, nil, o.Validate())
255255
256256 // 24 byte, base64 (urlsafe) encoded key
257− o.CookieSecret = "Kp33Gj-GQmYtz4zZUyUDdqQKx5_Hgkv3"
257+ o.Cookie.Secret = "Kp33Gj-GQmYtz4zZUyUDdqQKx5_Hgkv3"
258258 assert.Equal(t, nil, o.Validate())
259259
260260 // 16 byte, base64 (urlsafe) encoded key
261− o.CookieSecret = "LFEqZYvYUwKwzn0tEuTpLA=="
261+ o.Cookie.Secret = "LFEqZYvYUwKwzn0tEuTpLA=="
262262 assert.Equal(t, nil, o.Validate())
263263
264264 // 16 byte, base64 (urlsafe) encoded key, w/o padding
265− o.CookieSecret = "LFEqZYvYUwKwzn0tEuTpLA"
265+ o.Cookie.Secret = "LFEqZYvYUwKwzn0tEuTpLA"
266266 assert.Equal(t, nil, o.Validate())
267267}
268268
@@ -292,16 +292,16 @@ func TestValidateSignatureKeyUnsupportedAlgorithm(t *testing.T) {
292292
293293func TestValidateCookie(t *testing.T) {
294294 o := testOptions()
295− o.CookieName = "_valid_cookie_name"
295+ o.Cookie.Name = "_valid_cookie_name"
296296 assert.Equal(t, nil, o.Validate())
297297}
298298
299299func TestValidateCookieBadName(t *testing.T) {
300300 o := testOptions()
301− o.CookieName = "_bad_cookie_name{}"
301+ o.Cookie.Name = "_bad_cookie_name{}"
302302 err := o.Validate()
303303 assert.Equal(t, err.Error(), "invalid configuration:\n"+
304− fmt.Sprintf(" invalid cookie name: %q", o.CookieName))
304+ fmt.Sprintf(" invalid cookie name: %q", o.Cookie.Name))
305305}
306306
307307func TestSkipOIDCDiscovery(t *testing.T) {
pkg/apis/options/cookie.go+9−9
@@ -4,13 +4,13 @@ import "time"
44
55// CookieOptions contains configuration options relating to Cookie configuration
66type CookieOptions struct {
7− CookieName string `flag:"cookie-name" cfg:"cookie_name" env:"OAUTH2_PROXY_COOKIE_NAME"`
8− CookieSecret string `flag:"cookie-secret" cfg:"cookie_secret" env:"OAUTH2_PROXY_COOKIE_SECRET"`
9− CookieDomains []string `flag:"cookie-domain" cfg:"cookie_domain" env:"OAUTH2_PROXY_COOKIE_DOMAIN"`
10− CookiePath string `flag:"cookie-path" cfg:"cookie_path" env:"OAUTH2_PROXY_COOKIE_PATH"`
11− CookieExpire time.Duration `flag:"cookie-expire" cfg:"cookie_expire" env:"OAUTH2_PROXY_COOKIE_EXPIRE"`
12− CookieRefresh time.Duration `flag:"cookie-refresh" cfg:"cookie_refresh" env:"OAUTH2_PROXY_COOKIE_REFRESH"`
13− CookieSecure bool `flag:"cookie-secure" cfg:"cookie_secure" env:"OAUTH2_PROXY_COOKIE_SECURE"`
14− CookieHTTPOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly" env:"OAUTH2_PROXY_COOKIE_HTTPONLY"`
15− CookieSameSite string `flag:"cookie-samesite" cfg:"cookie_samesite" env:"OAUTH2_PROXY_COOKIE_SAMESITE"`
7+ Name string `flag:"cookie-name" cfg:"cookie_name" env:"OAUTH2_PROXY_COOKIE_NAME"`
8+ Secret string `flag:"cookie-secret" cfg:"cookie_secret" env:"OAUTH2_PROXY_COOKIE_SECRET"`
9+ Domains []string `flag:"cookie-domain" cfg:"cookie_domain" env:"OAUTH2_PROXY_COOKIE_DOMAIN"`
10+ Path string `flag:"cookie-path" cfg:"cookie_path" env:"OAUTH2_PROXY_COOKIE_PATH"`
11+ Expire time.Duration `flag:"cookie-expire" cfg:"cookie_expire" env:"OAUTH2_PROXY_COOKIE_EXPIRE"`
12+ Refresh time.Duration `flag:"cookie-refresh" cfg:"cookie_refresh" env:"OAUTH2_PROXY_COOKIE_REFRESH"`
13+ Secure bool `flag:"cookie-secure" cfg:"cookie_secure" env:"OAUTH2_PROXY_COOKIE_SECURE"`
14+ HTTPOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly" env:"OAUTH2_PROXY_COOKIE_HTTPONLY"`
15+ SameSite string `flag:"cookie-samesite" cfg:"cookie_samesite" env:"OAUTH2_PROXY_COOKIE_SAMESITE"`
1616}
pkg/apis/options/load.gonew file+134
@@ -0,0 +1,134 @@
1+package options
2+
3+import (
4+ "fmt"
5+ "reflect"
6+ "strings"
7+
8+ "github.com/mitchellh/mapstructure"
9+ "github.com/spf13/pflag"
10+ "github.com/spf13/viper"
11+)
12+
13+// Load reads in the config file at the path given, then merges in environment
14+// variables (prefixed with `OAUTH2_PROXY`) and finally merges in flags from the flagSet.
15+// If a config value is unset and the flag has a non-zero value default, this default will be used.
16+// Eg. A field defined:
17+// FooBar `cfg:"foo_bar" flag:"foo-bar"`
18+// Can be set in the config file as `foo_bar="baz"`, in the environment as `OAUTH2_PROXY_FOO_BAR=baz`,
19+// or via the command line flag `--foo-bar=baz`.
20+func Load(configFileName string, flagSet *pflag.FlagSet, into interface{}) error {
21+ v := viper.New()
22+ v.SetConfigFile(configFileName)
23+ v.SetConfigType("toml") // Config is in toml format
24+ v.SetEnvPrefix("OAUTH2_PROXY")
25+ v.AutomaticEnv()
26+ v.SetTypeByDefaultValue(true)
27+
28+ if configFileName != "" {
29+ err := v.ReadInConfig()
30+ if err != nil {
31+ return fmt.Errorf("unable to load config file: %w", err)
32+ }
33+ }
34+
35+ err := registerFlags(v, "", flagSet, into)
36+ if err != nil {
37+ // This should only happen if there is a programming error
38+ return fmt.Errorf("unable to register flags: %w", err)
39+ }
40+
41+ // UnmarhsalExact will return an error if the config includes options that are
42+ // not mapped to felds of the into struct
43+ err = v.UnmarshalExact(into, decodeFromCfgTag)
44+ if err != nil {
45+ return fmt.Errorf("error unmarshalling config: %w", err)
46+ }
47+
48+ return nil
49+}
50+
51+// registerFlags uses `cfg` and `flag` tags to associate flags in the flagSet
52+// to the fields in the options interface provided.
53+// Each exported field in the options must have a `cfg` tag otherwise an error will occur.
54+// - For fields, set `cfg` and `flag` so that `flag` is the name of the flag associated to this config option
55+// - For exported fields that are not user facing, set the `cfg` to `,internal`
56+// - For structs containing user facing fields, set the `cfg` to `,squash`
57+func registerFlags(v *viper.Viper, prefix string, flagSet *pflag.FlagSet, options interface{}) error {
58+ val := reflect.ValueOf(options)
59+ var typ reflect.Type
60+ if val.Kind() == reflect.Ptr {
61+ typ = val.Elem().Type()
62+ } else {
63+ typ = val.Type()
64+ }
65+
66+ for i := 0; i < typ.NumField(); i++ {
67+ // pull out the struct tags:
68+ // flag - the name of the command line flag
69+ // cfg - the name of the config file option
70+ field := typ.Field(i)
71+ fieldV := reflect.Indirect(val).Field(i)
72+ fieldName := strings.Join([]string{prefix, field.Name}, ".")
73+
74+ cfgName := field.Tag.Get("cfg")
75+ if cfgName == ",internal" {
76+ // Public but internal types that should not be exposed to users, skip them
77+ continue
78+ }
79+
80+ if isUnexported(field.Name) {
81+ // Unexported fields cannot be set by a user, so won't have tags or flags, skip them
82+ continue
83+ }
84+
85+ if field.Type.Kind() == reflect.Struct {
86+ if cfgName != ",squash" {
87+ return fmt.Errorf("field %q does not have required cfg tag: `,squash`", fieldName)
88+ }
89+ err := registerFlags(v, fieldName, flagSet, fieldV.Interface())
90+ if err != nil {
91+ return err
92+ }
93+ continue
94+ }
95+
96+ flagName := field.Tag.Get("flag")
97+ if flagName == "" || cfgName == "" {
98+ return fmt.Errorf("field %q does not have required tags (cfg, flag)", fieldName)
99+ }
100+
101+ if flagSet == nil {
102+ return fmt.Errorf("flagset cannot be nil")
103+ }
104+
105+ f := flagSet.Lookup(flagName)
106+ if f == nil {
107+ return fmt.Errorf("field %q does not have a registered flag", flagName)
108+ }
109+ err := v.BindPFlag(cfgName, f)
110+ if err != nil {
111+ return fmt.Errorf("error binding flag for field %q: %w", fieldName, err)
112+ }
113+ }
114+
115+ return nil
116+}
117+
118+// decodeFromCfgTag sets the Viper decoder to read the names from the `cfg` tag
119+// on each struct entry.
120+func decodeFromCfgTag(c *mapstructure.DecoderConfig) {
121+ c.TagName = "cfg"
122+}
123+
124+// isUnexported checks if a field name starts with a lowercase letter and therefore
125+// if it is unexported.
126+func isUnexported(name string) bool {
127+ if len(name) == 0 {
128+ // This should never happen
129+ panic("field name has len 0")
130+ }
131+
132+ first := string(name[0])
133+ return first == strings.ToLower(first)
134+}
pkg/apis/options/load_test.gonew file+300
@@ -0,0 +1,300 @@
1+package options
2+
3+import (
4+ "fmt"
5+ "io/ioutil"
6+ "os"
7+ "testing"
8+
9+ . "github.com/onsi/ginkgo"
10+ . "github.com/onsi/ginkgo/extensions/table"
11+ . "github.com/onsi/gomega"
12+ "github.com/spf13/pflag"
13+)
14+
15+func TestOptionsSuite(t *testing.T) {
16+ RegisterFailHandler(Fail)
17+ RunSpecs(t, "Options Suite")
18+}
19+
20+var _ = Describe("Load", func() {
21+ Context("with a testOptions structure", func() {
22+ type TestOptionSubStruct struct {
23+ StringSliceOption []string `flag:"string-slice-option" cfg:"string_slice_option"`
24+ }
25+
26+ type TestOptions struct {
27+ StringOption string `flag:"string-option" cfg:"string_option"`
28+ Sub TestOptionSubStruct `cfg:",squash"`
29+ // Check exported but internal fields do not break loading
30+ Internal *string `cfg:",internal"`
31+ // Check unexported fields do not break loading
32+ unexported string
33+ }
34+
35+ type MissingSquashTestOptions struct {
36+ StringOption string `flag:"string-option" cfg:"string_option"`
37+ Sub TestOptionSubStruct
38+ }
39+
40+ type MissingCfgTestOptions struct {
41+ StringOption string `flag:"string-option"`
42+ Sub TestOptionSubStruct `cfg:",squash"`
43+ }
44+
45+ type MissingFlagTestOptions struct {
46+ StringOption string `cfg:"string_option"`
47+ Sub TestOptionSubStruct `cfg:",squash"`
48+ }
49+
50+ var testOptionsConfigBytes = []byte(`
51+ string_option="foo"
52+ string_slice_option="a,b,c,d"
53+ `)
54+
55+ var testOptionsFlagSet *pflag.FlagSet
56+
57+ type testOptionsTableInput struct {
58+ env map[string]string
59+ args []string
60+ configFile []byte
61+ flagSet func() *pflag.FlagSet
62+ expectedErr error
63+ input interface{}
64+ expectedOutput interface{}
65+ }
66+
67+ BeforeEach(func() {
68+ testOptionsFlagSet = pflag.NewFlagSet("testFlagSet", pflag.ExitOnError)
69+ testOptionsFlagSet.String("string-option", "default", "")
70+ testOptionsFlagSet.StringSlice("string-slice-option", []string{"a", "b"}, "")
71+ })
72+
73+ DescribeTable("Load",
74+ func(o *testOptionsTableInput) {
75+ var configFileName string
76+
77+ if o.configFile != nil {
78+ By("Creating a config file")
79+ configFile, err := ioutil.TempFile("", "oauth2-proxy-test-legacy-config-file")
80+ Expect(err).ToNot(HaveOccurred())
81+ defer configFile.Close()
82+
83+ _, err = configFile.Write(o.configFile)
84+ Expect(err).ToNot(HaveOccurred())
85+ defer os.Remove(configFile.Name())
86+
87+ configFileName = configFile.Name()
88+ }
89+
90+ if len(o.env) > 0 {
91+ By("Setting environment variables")
92+ for k, v := range o.env {
93+ os.Setenv(k, v)
94+ defer os.Unsetenv(k)
95+ }
96+ }
97+
98+ Expect(o.flagSet).ToNot(BeNil())
99+ flagSet := o.flagSet()
100+ Expect(flagSet).ToNot(BeNil())
101+
102+ if len(o.args) > 0 {
103+ By("Parsing flag arguments")
104+ Expect(flagSet.Parse(o.args)).To(Succeed())
105+ }
106+
107+ var input interface{}
108+ if o.input != nil {
109+ input = o.input
110+ } else {
111+ input = &TestOptions{}
112+ }
113+ err := Load(configFileName, flagSet, input)
114+ if o.expectedErr != nil {
115+ Expect(err).To(MatchError(o.expectedErr.Error()))
116+ } else {
117+ Expect(err).ToNot(HaveOccurred())
118+ }
119+ Expect(input).To(Equal(o.expectedOutput))
120+ },
121+ Entry("with just a config file", &testOptionsTableInput{
122+ configFile: testOptionsConfigBytes,
123+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
124+ expectedOutput: &TestOptions{
125+ StringOption: "foo",
126+ Sub: TestOptionSubStruct{
127+ StringSliceOption: []string{"a", "b", "c", "d"},
128+ },
129+ },
130+ }),
131+ Entry("when setting env variables", &testOptionsTableInput{
132+ configFile: testOptionsConfigBytes,
133+ env: map[string]string{
134+ "OAUTH2_PROXY_STRING_OPTION": "bar",
135+ "OAUTH2_PROXY_STRING_SLICE_OPTION": "a,b,c",
136+ },
137+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
138+ expectedOutput: &TestOptions{
139+ StringOption: "bar",
140+ Sub: TestOptionSubStruct{
141+ StringSliceOption: []string{"a", "b", "c"},
142+ },
143+ },
144+ }),
145+ Entry("when setting flags", &testOptionsTableInput{
146+ configFile: testOptionsConfigBytes,
147+ env: map[string]string{
148+ "OAUTH2_PROXY_STRING_OPTION": "bar",
149+ "OAUTH2_PROXY_STRING_SLICE_OPTION": "a,b,c",
150+ },
151+ args: []string{
152+ "--string-option", "baz",
153+ "--string-slice-option", "a,b,c,d,e",
154+ },
155+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
156+ expectedOutput: &TestOptions{
157+ StringOption: "baz",
158+ Sub: TestOptionSubStruct{
159+ StringSliceOption: []string{"a", "b", "c", "d", "e"},
160+ },
161+ },
162+ }),
163+ Entry("when setting flags multiple times", &testOptionsTableInput{
164+ configFile: testOptionsConfigBytes,
165+ env: map[string]string{
166+ "OAUTH2_PROXY_STRING_OPTION": "bar",
167+ "OAUTH2_PROXY_STRING_SLICE_OPTION": "a,b,c",
168+ },
169+ args: []string{
170+ "--string-option", "baz",
171+ "--string-slice-option", "x",
172+ "--string-slice-option", "y",
173+ "--string-slice-option", "z",
174+ },
175+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
176+ expectedOutput: &TestOptions{
177+ StringOption: "baz",
178+ Sub: TestOptionSubStruct{
179+ StringSliceOption: []string{"x", "y", "z"},
180+ },
181+ },
182+ }),
183+ Entry("when setting env variables without a config file", &testOptionsTableInput{
184+ env: map[string]string{
185+ "OAUTH2_PROXY_STRING_OPTION": "bar",
186+ "OAUTH2_PROXY_STRING_SLICE_OPTION": "a,b,c",
187+ },
188+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
189+ expectedOutput: &TestOptions{
190+ StringOption: "bar",
191+ Sub: TestOptionSubStruct{
192+ StringSliceOption: []string{"a", "b", "c"},
193+ },
194+ },
195+ }),
196+ Entry("when setting flags without a config file", &testOptionsTableInput{
197+ env: map[string]string{
198+ "OAUTH2_PROXY_STRING_OPTION": "bar",
199+ "OAUTH2_PROXY_STRING_SLICE_OPTION": "a,b,c",
200+ },
201+ args: []string{
202+ "--string-option", "baz",
203+ "--string-slice-option", "a,b,c,d,e",
204+ },
205+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
206+ expectedOutput: &TestOptions{
207+ StringOption: "baz",
208+ Sub: TestOptionSubStruct{
209+ StringSliceOption: []string{"a", "b", "c", "d", "e"},
210+ },
211+ },
212+ }),
213+ Entry("when setting flags without a config file", &testOptionsTableInput{
214+ env: map[string]string{
215+ "OAUTH2_PROXY_STRING_OPTION": "bar",
216+ "OAUTH2_PROXY_STRING_SLICE_OPTION": "a,b,c",
217+ },
218+ args: []string{
219+ "--string-option", "baz",
220+ "--string-slice-option", "a,b,c,d,e",
221+ },
222+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
223+ expectedOutput: &TestOptions{
224+ StringOption: "baz",
225+ Sub: TestOptionSubStruct{
226+ StringSliceOption: []string{"a", "b", "c", "d", "e"},
227+ },
228+ },
229+ }),
230+ Entry("when nothing is set it should use flag defaults", &testOptionsTableInput{
231+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
232+ expectedOutput: &TestOptions{
233+ StringOption: "default",
234+ Sub: TestOptionSubStruct{
235+ StringSliceOption: []string{"a", "b"},
236+ },
237+ },
238+ }),
239+ Entry("with an invalid config file", &testOptionsTableInput{
240+ configFile: []byte(`slice_option = foo`),
241+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
242+ expectedErr: fmt.Errorf("unable to load config file: While parsing config: (1, 16): never reached"),
243+ expectedOutput: &TestOptions{},
244+ }),
245+ Entry("with an invalid flagset", &testOptionsTableInput{
246+ flagSet: func() *pflag.FlagSet {
247+ // Missing a flag
248+ f := pflag.NewFlagSet("testFlagSet", pflag.ExitOnError)
249+ f.String("string-option", "default", "")
250+ return f
251+ },
252+ expectedErr: fmt.Errorf("unable to register flags: field \"string-slice-option\" does not have a registered flag"),
253+ expectedOutput: &TestOptions{},
254+ }),
255+ Entry("with an struct is missing the squash tag", &testOptionsTableInput{
256+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
257+ expectedErr: fmt.Errorf("unable to register flags: field \".Sub\" does not have required cfg tag: `,squash`"),
258+ input: &MissingSquashTestOptions{},
259+ expectedOutput: &MissingSquashTestOptions{},
260+ }),
261+ Entry("with a field is missing the cfg tag", &testOptionsTableInput{
262+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
263+ expectedErr: fmt.Errorf("unable to register flags: field \".StringOption\" does not have required tags (cfg, flag)"),
264+ input: &MissingCfgTestOptions{},
265+ expectedOutput: &MissingCfgTestOptions{},
266+ }),
267+ Entry("with a field is missing the flag tag", &testOptionsTableInput{
268+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
269+ expectedErr: fmt.Errorf("unable to register flags: field \".StringOption\" does not have required tags (cfg, flag)"),
270+ input: &MissingFlagTestOptions{},
271+ expectedOutput: &MissingFlagTestOptions{},
272+ }),
273+ Entry("with existing unexported fields", &testOptionsTableInput{
274+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
275+ input: &TestOptions{
276+ unexported: "unexported",
277+ },
278+ expectedOutput: &TestOptions{
279+ StringOption: "default",
280+ Sub: TestOptionSubStruct{
281+ StringSliceOption: []string{"a", "b"},
282+ },
283+ unexported: "unexported",
284+ },
285+ }),
286+ Entry("with an unknown option in the config file", &testOptionsTableInput{
287+ configFile: []byte(`unknown_option="foo"`),
288+ flagSet: func() *pflag.FlagSet { return testOptionsFlagSet },
289+ expectedErr: fmt.Errorf("error unmarshalling config: 1 error(s) decoding:\n\n* '' has invalid keys: unknown_option"),
290+ // Viper will unmarshal before returning the error, so this is the default output
291+ expectedOutput: &TestOptions{
292+ StringOption: "default",
293+ Sub: TestOptionSubStruct{
294+ StringSliceOption: []string{"a", "b"},
295+ },
296+ },
297+ }),
298+ )
299+ })
300+})
pkg/apis/options/sessions.go+6−10
@@ -4,31 +4,27 @@ import "github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
44
55// SessionOptions contains configuration options for the SessionStore providers.
66type SessionOptions struct {
7− Type string `flag:"session-store-type" cfg:"session_store_type" env:"OAUTH2_PROXY_SESSION_STORE_TYPE"`
8− Cipher *encryption.Cipher
9− CookieStoreOptions
10− RedisStoreOptions
7+ Type string `flag:"session-store-type" cfg:"session_store_type" env:"OAUTH2_PROXY_SESSION_STORE_TYPE"`
8+ Cipher *encryption.Cipher `cfg:",internal"`
9+ Redis RedisStoreOptions `cfg:",squash"`
1110}
1211
1312// CookieSessionStoreType is used to indicate the CookieSessionStore should be
1413// used for storing sessions.
1514var CookieSessionStoreType = "cookie"
1615
17−// CookieStoreOptions contains configuration options for the CookieSessionStore.
18−type CookieStoreOptions struct{}
19−
2016// RedisSessionStoreType is used to indicate the RedisSessionStore should be
2117// used for storing sessions.
2218var RedisSessionStoreType = "redis"
2319
2420// RedisStoreOptions contains configuration options for the RedisSessionStore.
2521type RedisStoreOptions struct {
26− RedisConnectionURL string `flag:"redis-connection-url" cfg:"redis_connection_url" env:"OAUTH2_PROXY_REDIS_CONNECTION_URL"`
22+ ConnectionURL string `flag:"redis-connection-url" cfg:"redis_connection_url" env:"OAUTH2_PROXY_REDIS_CONNECTION_URL"`
2723 UseSentinel bool `flag:"redis-use-sentinel" cfg:"redis_use_sentinel" env:"OAUTH2_PROXY_REDIS_USE_SENTINEL"`
2824 SentinelMasterName string `flag:"redis-sentinel-master-name" cfg:"redis_sentinel_master_name" env:"OAUTH2_PROXY_REDIS_SENTINEL_MASTER_NAME"`
2925 SentinelConnectionURLs []string `flag:"redis-sentinel-connection-urls" cfg:"redis_sentinel_connection_urls" env:"OAUTH2_PROXY_REDIS_SENTINEL_CONNECTION_URLS"`
3026 UseCluster bool `flag:"redis-use-cluster" cfg:"redis_use_cluster" env:"OAUTH2_PROXY_REDIS_USE_CLUSTER"`
3127 ClusterConnectionURLs []string `flag:"redis-cluster-connection-urls" cfg:"redis_cluster_connection_urls" env:"OAUTH2_PROXY_REDIS_CLUSTER_CONNECTION_URLS"`
32− RedisCAPath string `flag:"redis-ca-path" cfg:"redis_ca_path" env:"OAUTH2_PROXY_REDIS_CA_PATH"`
33− RedisInsecureTLS bool `flag:"redis-insecure-skip-tls-verify" cfg:"redis_insecure_skip_tls_verify" env:"OAUTH2_PROXY_REDIS_INSECURE_SKIP_TLS_VERIFY"`
28+ CAPath string `flag:"redis-ca-path" cfg:"redis_ca_path" env:"OAUTH2_PROXY_REDIS_CA_PATH"`
29+ InsecureSkipTLSVerify bool `flag:"redis-insecure-skip-tls-verify" cfg:"redis_insecure_skip_tls_verify" env:"OAUTH2_PROXY_REDIS_INSECURE_SKIP_TLS_VERIFY"`
3430}
pkg/cookies/cookies.go+7−7
@@ -38,19 +38,19 @@ func MakeCookie(req *http.Request, name string, value string, path string, domai
3838
3939// MakeCookieFromOptions constructs a cookie based on the given *options.CookieOptions,
4040// value and creation time
41−func MakeCookieFromOptions(req *http.Request, name string, value string, opts *options.CookieOptions, expiration time.Duration, now time.Time) *http.Cookie {
42− domain := GetCookieDomain(req, opts.CookieDomains)
41+func MakeCookieFromOptions(req *http.Request, name string, value string, cookieOpts *options.CookieOptions, expiration time.Duration, now time.Time) *http.Cookie {
42+ domain := GetCookieDomain(req, cookieOpts.Domains)
4343
4444 if domain != "" {
45− return MakeCookie(req, name, value, opts.CookiePath, domain, opts.CookieHTTPOnly, opts.CookieSecure, expiration, now, ParseSameSite(opts.CookieSameSite))
45+ return MakeCookie(req, name, value, cookieOpts.Path, domain, cookieOpts.HTTPOnly, cookieOpts.Secure, expiration, now, ParseSameSite(cookieOpts.SameSite))
4646 }
4747 // If nothing matches, create the cookie with the shortest domain
48− logger.Printf("Warning: request host %q did not match any of the specific cookie domains of %q", GetRequestHost(req), strings.Join(opts.CookieDomains, ","))
48+ logger.Printf("Warning: request host %q did not match any of the specific cookie domains of %q", GetRequestHost(req), strings.Join(cookieOpts.Domains, ","))
4949 defaultDomain := ""
50− if len(opts.CookieDomains) > 0 {
51− defaultDomain = opts.CookieDomains[len(opts.CookieDomains)-1]
50+ if len(cookieOpts.Domains) > 0 {
51+ defaultDomain = cookieOpts.Domains[len(cookieOpts.Domains)-1]
5252 }
53− return MakeCookie(req, name, value, opts.CookiePath, defaultDomain, opts.CookieHTTPOnly, opts.CookieSecure, expiration, now, ParseSameSite(opts.CookieSameSite))
53+ return MakeCookie(req, name, value, cookieOpts.Path, defaultDomain, cookieOpts.HTTPOnly, cookieOpts.Secure, expiration, now, ParseSameSite(cookieOpts.SameSite))
5454}
5555
5656// GetCookieDomain returns the correct cookie domain given a list of domains
pkg/sessions/cookie/session_store.go+7−7
@@ -49,12 +49,12 @@ func (s *SessionStore) Save(rw http.ResponseWriter, req *http.Request, ss *sessi
4949// Load reads sessions.SessionState information from Cookies within the
5050// HTTP request object
5151func (s *SessionStore) Load(req *http.Request) (*sessions.SessionState, error) {
52− c, err := loadCookie(req, s.CookieOptions.CookieName)
52+ c, err := loadCookie(req, s.CookieOptions.Name)
5353 if err != nil {
5454 // always http.ErrNoCookie
55− return nil, fmt.Errorf("cookie %q not present", s.CookieOptions.CookieName)
55+ return nil, fmt.Errorf("cookie %q not present", s.CookieOptions.Name)
5656 }
57− val, _, ok := encryption.Validate(c, s.CookieOptions.CookieSecret, s.CookieOptions.CookieExpire)
57+ val, _, ok := encryption.Validate(c, s.CookieOptions.Secret, s.CookieOptions.Expire)
5858 if !ok {
5959 return nil, errors.New("cookie signature not valid")
6060 }
@@ -70,7 +70,7 @@ func (s *SessionStore) Load(req *http.Request) (*sessions.SessionState, error) {
7070// clear the session
7171func (s *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) error {
7272 // matches CookieName, CookieName_<number>
73− var cookieNameRegex = regexp.MustCompile(fmt.Sprintf("^%s(_\\d+)?$", s.CookieOptions.CookieName))
73+ var cookieNameRegex = regexp.MustCompile(fmt.Sprintf("^%s(_\\d+)?$", s.CookieOptions.Name))
7474
7575 for _, c := range req.Cookies() {
7676 if cookieNameRegex.MatchString(c.Name) {
@@ -94,10 +94,10 @@ func (s *SessionStore) setSessionCookie(rw http.ResponseWriter, req *http.Reques
9494// authentication details
9595func (s *SessionStore) makeSessionCookie(req *http.Request, value string, now time.Time) []*http.Cookie {
9696 if value != "" {
97− value = encryption.SignedValue(s.CookieOptions.CookieSecret, s.CookieOptions.CookieName, value, now)
97+ value = encryption.SignedValue(s.CookieOptions.Secret, s.CookieOptions.Name, value, now)
9898 }
99− c := s.makeCookie(req, s.CookieOptions.CookieName, value, s.CookieOptions.CookieExpire, now)
100− if len(c.Value) > 4096-len(s.CookieOptions.CookieName) {
99+ c := s.makeCookie(req, s.CookieOptions.Name, value, s.CookieOptions.Expire, now)
100+ if len(c.Value) > 4096-len(s.CookieOptions.Name) {
101101 return splitCookie(c)
102102 }
103103 return []*http.Cookie{c}
pkg/sessions/redis/redis_store.go+23−23
@@ -40,7 +40,7 @@ type SessionStore struct {
4040// NewRedisSessionStore initialises a new instance of the SessionStore from
4141// the configuration given
4242func NewRedisSessionStore(opts *options.SessionOptions, cookieOpts *options.CookieOptions) (sessions.SessionStore, error) {
43− client, err := newRedisCmdable(opts.RedisStoreOptions)
43+ client, err := newRedisCmdable(opts.Redis)
4444 if err != nil {
4545 return nil, fmt.Errorf("error constructing redis client: %v", err)
4646 }
@@ -74,16 +74,16 @@ func newRedisCmdable(opts options.RedisStoreOptions) (Client, error) {
7474 return newClusterClient(client), nil
7575 }
7676
77− opt, err := redis.ParseURL(opts.RedisConnectionURL)
77+ opt, err := redis.ParseURL(opts.ConnectionURL)
7878 if err != nil {
7979 return nil, fmt.Errorf("unable to parse redis url: %s", err)
8080 }
8181
82− if opts.RedisInsecureTLS {
82+ if opts.InsecureSkipTLSVerify {
8383 opt.TLSConfig.InsecureSkipVerify = true
8484 }
8585
86− if opts.RedisCAPath != "" {
86+ if opts.CAPath != "" {
8787 rootCAs, err := x509.SystemCertPool()
8888 if err != nil {
8989 logger.Printf("failed to load system cert pool for redis connection, falling back to empty cert pool")
@@ -91,9 +91,9 @@ func newRedisCmdable(opts options.RedisStoreOptions) (Client, error) {
9191 if rootCAs == nil {
9292 rootCAs = x509.NewCertPool()
9393 }
94− certs, err := ioutil.ReadFile(opts.RedisCAPath)
94+ certs, err := ioutil.ReadFile(opts.CAPath)
9595 if err != nil {
96− return nil, fmt.Errorf("failed to load %q, %v", opts.RedisCAPath, err)
96+ return nil, fmt.Errorf("failed to load %q, %v", opts.CAPath, err)
9797 }
9898
9999 // Append our cert to the system pool
@@ -117,13 +117,13 @@ func (store *SessionStore) Save(rw http.ResponseWriter, req *http.Request, s *se
117117
118118 // Old sessions that we are refreshing would have a request cookie
119119 // New sessions don't, so we ignore the error. storeValue will check requestCookie
120− requestCookie, _ := req.Cookie(store.CookieOptions.CookieName)
120+ requestCookie, _ := req.Cookie(store.CookieOptions.Name)
121121 value, err := s.EncodeSessionState(store.CookieCipher)
122122 if err != nil {
123123 return err
124124 }
125125 ctx := req.Context()
126− ticketString, err := store.storeValue(ctx, value, store.CookieOptions.CookieExpire, requestCookie)
126+ ticketString, err := store.storeValue(ctx, value, store.CookieOptions.Expire, requestCookie)
127127 if err != nil {
128128 return err
129129 }
@@ -131,7 +131,7 @@ func (store *SessionStore) Save(rw http.ResponseWriter, req *http.Request, s *se
131131 ticketCookie := store.makeCookie(
132132 req,
133133 ticketString,
134− store.CookieOptions.CookieExpire,
134+ store.CookieOptions.Expire,
135135 s.CreatedAt,
136136 )
137137
@@ -142,12 +142,12 @@ func (store *SessionStore) Save(rw http.ResponseWriter, req *http.Request, s *se
142142// Load reads sessions.SessionState information from a ticket
143143// cookie within the HTTP request object
144144func (store *SessionStore) Load(req *http.Request) (*sessions.SessionState, error) {
145− requestCookie, err := req.Cookie(store.CookieOptions.CookieName)
145+ requestCookie, err := req.Cookie(store.CookieOptions.Name)
146146 if err != nil {
147147 return nil, fmt.Errorf("error loading session: %s", err)
148148 }
149149
150− val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.CookieSecret, store.CookieOptions.CookieExpire)
150+ val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.Secret, store.CookieOptions.Expire)
151151 if !ok {
152152 return nil, fmt.Errorf("cookie signature not valid")
153153 }
@@ -161,12 +161,12 @@ func (store *SessionStore) Load(req *http.Request) (*sessions.SessionState, erro
161161
162162// loadSessionFromString loads the session based on the ticket value
163163func (store *SessionStore) loadSessionFromString(ctx context.Context, value string) (*sessions.SessionState, error) {
164− ticket, err := decodeTicket(store.CookieOptions.CookieName, value)
164+ ticket, err := decodeTicket(store.CookieOptions.Name, value)
165165 if err != nil {
166166 return nil, err
167167 }
168168
169− resultBytes, err := store.Client.Get(ctx, ticket.asHandle(store.CookieOptions.CookieName))
169+ resultBytes, err := store.Client.Get(ctx, ticket.asHandle(store.CookieOptions.Name))
170170 if err != nil {
171171 return nil, err
172172 }
@@ -199,7 +199,7 @@ func (store *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) erro
199199 http.SetCookie(rw, clearCookie)
200200
201201 // If there was an existing cookie we should clear the session in redis
202− requestCookie, err := req.Cookie(store.CookieOptions.CookieName)
202+ requestCookie, err := req.Cookie(store.CookieOptions.Name)
203203 if err != nil && err == http.ErrNoCookie {
204204 // No existing cookie so can't clear redis
205205 return nil
@@ -207,17 +207,17 @@ func (store *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) erro
207207 return fmt.Errorf("error retrieving cookie: %v", err)
208208 }
209209
210− val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.CookieSecret, store.CookieOptions.CookieExpire)
210+ val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.Secret, store.CookieOptions.Expire)
211211 if !ok {
212212 return fmt.Errorf("cookie signature not valid")
213213 }
214214
215215 // We only return an error if we had an issue with redis
216216 // If there's an issue decoding the ticket, ignore it
217− ticket, _ := decodeTicket(store.CookieOptions.CookieName, val)
217+ ticket, _ := decodeTicket(store.CookieOptions.Name, val)
218218 if ticket != nil {
219219 ctx := req.Context()
220− err := store.Client.Del(ctx, ticket.asHandle(store.CookieOptions.CookieName))
220+ err := store.Client.Del(ctx, ticket.asHandle(store.CookieOptions.Name))
221221 if err != nil {
222222 return fmt.Errorf("error clearing cookie from redis: %s", err)
223223 }
@@ -228,11 +228,11 @@ func (store *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) erro
228228// makeCookie makes a cookie, signing the value if present
229229func (store *SessionStore) makeCookie(req *http.Request, value string, expires time.Duration, now time.Time) *http.Cookie {
230230 if value != "" {
231− value = encryption.SignedValue(store.CookieOptions.CookieSecret, store.CookieOptions.CookieName, value, now)
231+ value = encryption.SignedValue(store.CookieOptions.Secret, store.CookieOptions.Name, value, now)
232232 }
233233 return cookies.MakeCookieFromOptions(
234234 req,
235− store.CookieOptions.CookieName,
235+ store.CookieOptions.Name,
236236 value,
237237 store.CookieOptions,
238238 expires,
@@ -256,12 +256,12 @@ func (store *SessionStore) storeValue(ctx context.Context, value string, expirat
256256 stream := cipher.NewCFBEncrypter(block, ticket.Secret)
257257 stream.XORKeyStream(ciphertext, []byte(value))
258258
259− handle := ticket.asHandle(store.CookieOptions.CookieName)
259+ handle := ticket.asHandle(store.CookieOptions.Name)
260260 err = store.Client.Set(ctx, handle, ciphertext, expiration)
261261 if err != nil {
262262 return "", err
263263 }
264− return ticket.encodeTicket(store.CookieOptions.CookieName), nil
264+ return ticket.encodeTicket(store.CookieOptions.Name), nil
265265}
266266
267267// getTicket retrieves an existing ticket from the cookie if present,
@@ -272,14 +272,14 @@ func (store *SessionStore) getTicket(requestCookie *http.Cookie) (*TicketData, e
272272 }
273273
274274 // An existing cookie exists, try to retrieve the ticket
275− val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.CookieSecret, store.CookieOptions.CookieExpire)
275+ val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.Secret, store.CookieOptions.Expire)
276276 if !ok {
277277 // Cookie is invalid, create a new ticket
278278 return newTicket()
279279 }
280280
281281 // Valid cookie, decode the ticket
282− ticket, err := decodeTicket(store.CookieOptions.CookieName, val)
282+ ticket, err := decodeTicket(store.CookieOptions.Name, val)
283283 if err != nil {
284284 // If we can't decode the ticket we have to create a new one
285285 return newTicket()
pkg/sessions/session_store_test.go+31−31
@@ -47,25 +47,25 @@ var _ = Describe("NewSessionStore", func() {
4747
4848 It("have the correct name set", func() {
4949 if len(cookies) == 1 {
50− Expect(cookies[0].Name).To(Equal(cookieOpts.CookieName))
50+ Expect(cookies[0].Name).To(Equal(cookieOpts.Name))
5151 } else {
5252 for _, cookie := range cookies {
53− Expect(cookie.Name).To(ContainSubstring(cookieOpts.CookieName))
53+ Expect(cookie.Name).To(ContainSubstring(cookieOpts.Name))
5454 }
5555 }
5656 })
5757
5858 It("have the correct path set", func() {
5959 for _, cookie := range cookies {
60− Expect(cookie.Path).To(Equal(cookieOpts.CookiePath))
60+ Expect(cookie.Path).To(Equal(cookieOpts.Path))
6161 }
6262 })
6363
6464 It("have the correct domain set", func() {
6565 for _, cookie := range cookies {
6666 specifiedDomain := ""
67− if len(cookieOpts.CookieDomains) > 0 {
68− specifiedDomain = cookieOpts.CookieDomains[0]
67+ if len(cookieOpts.Domains) > 0 {
68+ specifiedDomain = cookieOpts.Domains[0]
6969 }
7070 Expect(cookie.Domain).To(Equal(specifiedDomain))
7171 }
@@ -73,19 +73,19 @@ var _ = Describe("NewSessionStore", func() {
7373
7474 It("have the correct HTTPOnly set", func() {
7575 for _, cookie := range cookies {
76− Expect(cookie.HttpOnly).To(Equal(cookieOpts.CookieHTTPOnly))
76+ Expect(cookie.HttpOnly).To(Equal(cookieOpts.HTTPOnly))
7777 }
7878 })
7979
8080 It("have the correct secure set", func() {
8181 for _, cookie := range cookies {
82− Expect(cookie.Secure).To(Equal(cookieOpts.CookieSecure))
82+ Expect(cookie.Secure).To(Equal(cookieOpts.Secure))
8383 }
8484 })
8585
8686 It("have the correct SameSite set", func() {
8787 for _, cookie := range cookies {
88− Expect(cookie.SameSite).To(Equal(cookiesapi.ParseSameSite(cookieOpts.CookieSameSite)))
88+ Expect(cookie.SameSite).To(Equal(cookiesapi.ParseSameSite(cookieOpts.SameSite)))
8989 }
9090 })
9191
@@ -168,8 +168,8 @@ var _ = Describe("NewSessionStore", func() {
168168 BeforeEach(func() {
169169 By("Using a valid cookie with a different providers session encoding")
170170 broken := "BrokenSessionFromADifferentSessionImplementation"
171− value := encryption.SignedValue(cookieOpts.CookieSecret, cookieOpts.CookieName, broken, time.Now())
172− cookie := cookiesapi.MakeCookieFromOptions(request, cookieOpts.CookieName, value, cookieOpts, cookieOpts.CookieExpire, time.Now())
171+ value := encryption.SignedValue(cookieOpts.Secret, cookieOpts.Name, broken, time.Now())
172+ cookie := cookiesapi.MakeCookieFromOptions(request, cookieOpts.Name, value, cookieOpts, cookieOpts.Expire, time.Now())
173173 request.AddCookie(cookie)
174174
175175 err := ss.Save(response, request, session)
@@ -245,7 +245,7 @@ var _ = Describe("NewSessionStore", func() {
245245 })
246246
247247 It("loads a session equal to the original session", func() {
248− if cookieOpts.CookieSecret == "" {
248+ if cookieOpts.Secret == "" {
249249 // Only Email and User stored in session when encrypted
250250 Expect(loadedSession.Email).To(Equal(session.Email))
251251 Expect(loadedSession.User).To(Equal(session.User))
@@ -290,7 +290,7 @@ var _ = Describe("NewSessionStore", func() {
290290 BeforeEach(func() {
291291 switch ss.(type) {
292292 case *redis.SessionStore:
293− mr.FastForward(cookieOpts.CookieRefresh + time.Minute)
293+ mr.FastForward(cookieOpts.Refresh + time.Minute)
294294 }
295295 })
296296
@@ -304,7 +304,7 @@ var _ = Describe("NewSessionStore", func() {
304304 BeforeEach(func() {
305305 switch ss.(type) {
306306 case *redis.SessionStore:
307− mr.FastForward(cookieOpts.CookieExpire + time.Minute)
307+ mr.FastForward(cookieOpts.Expire + time.Minute)
308308 }
309309
310310 loadedSession, err = ss.Load(request)
@@ -341,14 +341,14 @@ var _ = Describe("NewSessionStore", func() {
341341 Context("with non-default options", func() {
342342 BeforeEach(func() {
343343 cookieOpts = &options.CookieOptions{
344− CookieName: "_cookie_name",
345− CookiePath: "/path",
346− CookieExpire: time.Duration(72) * time.Hour,
347− CookieRefresh: time.Duration(2) * time.Hour,
348− CookieSecure: false,
349− CookieHTTPOnly: false,
350− CookieDomains: []string{"example.com"},
351− CookieSameSite: "strict",
344+ Name: "_cookie_name",
345+ Path: "/path",
346+ Expire: time.Duration(72) * time.Hour,
347+ Refresh: time.Duration(2) * time.Hour,
348+ Secure: false,
349+ HTTPOnly: false,
350+ Domains: []string{"example.com"},
351+ SameSite: "strict",
352352 }
353353
354354 var err error
@@ -364,8 +364,8 @@ var _ = Describe("NewSessionStore", func() {
364364 secret := make([]byte, 32)
365365 _, err := rand.Read(secret)
366366 Expect(err).ToNot(HaveOccurred())
367− cookieOpts.CookieSecret = base64.URLEncoding.EncodeToString(secret)
368− cipher, err := encryption.NewCipher(utils.SecretBytes(cookieOpts.CookieSecret))
367+ cookieOpts.Secret = base64.URLEncoding.EncodeToString(secret)
368+ cipher, err := encryption.NewCipher(utils.SecretBytes(cookieOpts.Secret))
369369 Expect(err).ToNot(HaveOccurred())
370370 Expect(cipher).ToNot(BeNil())
371371 opts.Cipher = cipher
@@ -384,13 +384,13 @@ var _ = Describe("NewSessionStore", func() {
384384
385385 // Set default options in CookieOptions
386386 cookieOpts = &options.CookieOptions{
387− CookieName: "_oauth2_proxy",
388− CookiePath: "/",
389− CookieExpire: time.Duration(168) * time.Hour,
390− CookieRefresh: time.Duration(1) * time.Hour,
391− CookieSecure: true,
392− CookieHTTPOnly: true,
393− CookieSameSite: "",
387+ Name: "_oauth2_proxy",
388+ Path: "/",
389+ Expire: time.Duration(168) * time.Hour,
390+ Refresh: time.Duration(1) * time.Hour,
391+ Secure: true,
392+ HTTPOnly: true,
393+ SameSite: "",
394394 }
395395
396396 session = &sessionsapi.SessionState{
@@ -428,7 +428,7 @@ var _ = Describe("NewSessionStore", func() {
428428 mr, err = miniredis.Run()
429429 Expect(err).ToNot(HaveOccurred())
430430 opts.Type = options.RedisSessionStoreType
431− opts.RedisConnectionURL = "redis://" + mr.Addr()
431+ opts.Redis.ConnectionURL = "redis://" + mr.Addr()
432432 })
433433
434434 AfterEach(func() {