git.iko.soy/typeable/oauth2-proxy
on master help sign in
Move SessionStore tests to independent package
commit34137f73054ba77831002a4e53d65dd9538a475d authorJoel Speed <joel.speed@hotmail.co.uk> dateSun 10 May 2020, 16:59 (6 years ago) parentd9a45a3
9 files changed+576−490
.golangci.yml+6 CHANGELOG.md+1 go.mod+2−4 go.sum+8−19 pkg/sessions/cookie/session_store_test.go+21 pkg/sessions/redis/redis_store_test.go−69 pkg/sessions/redis/session_store_test.go+101 pkg/sessions/session_store_test.go+2−398 pkg/sessions/tests/session_store_tests.go+435
.golangci.yml+6
@@ -33,3 +33,9 @@ issues:
3333 - bodyclose
3434 - unconvert
3535 - gocritic
36+ # If we have tests in shared test folders, these can be less strictly linted
37+ - path: tests/.*_tests\.go
38+ linters:
39+ - golint
40+ - bodyclose
41+ - stylecheck
CHANGELOG.md+1
@@ -8,6 +8,7 @@
88
99## Changes since v6.0.0
1010
11+- [#542](https://github.com/oauth2-proxy/oauth2-proxy/pull/542) Move SessionStore tests to independent package (@JoelSpeed)
1112- [#577](https://github.com/oauth2-proxy/oauth2-proxy/pull/577) Move Cipher and Session Store initialisation out of Validation (@JoelSpeed)
1213
1314# v6.0.0
go.mod+2−4
@@ -4,8 +4,7 @@ go 1.14
44
55require (
66 github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb
7− github.com/alicebob/miniredis v2.5.0+incompatible // indirect
8− github.com/alicebob/miniredis/v2 v2.11.2
7+ github.com/alicebob/miniredis/v2 v2.13.0
98 github.com/bitly/go-simplejson v0.5.0
109 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
1110 github.com/coreos/go-oidc v2.2.1+incompatible
@@ -15,7 +14,6 @@ require (
1514 github.com/justinas/alice v1.2.0
1615 github.com/kr/pretty v0.2.0 // indirect
1716 github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa
18− github.com/mdempsky/maligned v0.0.0-20180708014732-6e39bd26a8c8 // indirect
1917 github.com/mitchellh/mapstructure v1.1.2
2018 github.com/onsi/ginkgo v1.12.0
2119 github.com/onsi/gomega v1.9.0
@@ -27,8 +25,8 @@ require (
2725 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
2826 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
2927 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
28+ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
3029 google.golang.org/api v0.20.0
3130 gopkg.in/natefinch/lumberjack.v2 v2.0.0
3231 gopkg.in/square/go-jose.v2 v2.4.1
33− mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 // indirect
3432)
go.sum+8−19
@@ -6,17 +6,18 @@ github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWO
66github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss=
77github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
88github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
9+github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYIc=
910github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI=
1011github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
1112github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
1213github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
1314github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U=
1415github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
15−github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
16−github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
16+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
17+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
1718github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE=
18−github.com/alicebob/miniredis/v2 v2.11.2 h1:OtWO7akm5otuhssnE/sNfsWxG4gZ8DbGhShDtRrByJs=
19−github.com/alicebob/miniredis/v2 v2.11.2/go.mod h1:VL3UDEfAH59bSa7MuHMuFToxkqyHh69s/WUbYlOAuyg=
19+github.com/alicebob/miniredis/v2 v2.13.0 h1:QPosMaxm+r6Qs+YcCtL2Z2a2RSdC9VfXJLpd80l8ICU=
20+github.com/alicebob/miniredis/v2 v2.13.0/go.mod h1:0UIBNuf97uxrWhdVBpJvPtafKyGpL2NS2pYe0tYM97k=
2021github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
2122github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
2223github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -70,6 +71,8 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs
7071github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
7172github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3 h1:6amM4HsNPOvMLVc2ZnyqrjeQ92YAVWn7T4WBKK87inY=
7273github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
74+github.com/gomodule/redigo v1.8.1 h1:Abmo0bI7Xf0IhdIPc7HZQzZcShdnmxeoVuDDtIQp8N8=
75+github.com/gomodule/redigo v1.8.1/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
7376github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
7477github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
7578github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -117,12 +120,11 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
117120github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
118121github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
119122github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
123+github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
120124github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
121125github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
122126github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa h1:hI1uC2A3vJFjwvBn0G0a7QBRdBUp6Y048BtLAHRTKPo=
123127github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa/go.mod h1:8vxFeeg++MqgCHwehSuwTlYCF0ALyDJbYJ1JsKi7v6s=
124−github.com/mdempsky/maligned v0.0.0-20180708014732-6e39bd26a8c8 h1:zvpKif6gkrh82wAd2JIffdLyCL52N8r+ABwHxdIOvWM=
125−github.com/mdempsky/maligned v0.0.0-20180708014732-6e39bd26a8c8/go.mod h1:oGVD62YTpMEWw0JqJ2Vl48dzHywJBMlapkfsmhtokOU=
126128github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
127129github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
128130github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -134,7 +136,6 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
134136github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
135137github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
136138github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
137−github.com/onsi/ginkgo v1.12.3 h1:+RYp9QczoWz9zfUyLP/5SLXQVhfr6gZOoKGfQqHuLZQ=
138139github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
139140github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
140141github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
@@ -157,7 +158,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
157158github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
158159github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
159160github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
160−github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
161161github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
162162github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
163163github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -188,7 +188,6 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
188188github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
189189github.com/yhat/wsutil v0.0.0-20170731153501-1d66fa95c997 h1:1+FQ4Ns+UZtUiQ4lP0sTCyKSQ0EXoiwAdHZB0Pd5t9Q=
190190github.com/yhat/wsutil v0.0.0-20170731153501-1d66fa95c997/go.mod h1:DIGbh/f5XMAessMV/uaIik81gkDVjUeQ9ApdaU7wRKE=
191−github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
192191github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
193192github.com/yuin/gopher-lua v0.0.0-20191213034115-f46add6fdb5c/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
194193github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
@@ -210,7 +209,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
210209golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
211210golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
212211golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
213−golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
214212golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
215213golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
216214golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -223,7 +221,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
223221golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
224222golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
225223golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
226−golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
227224golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
228225golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
229226golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
@@ -239,7 +236,6 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
239236golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
240237golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
241238golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
242−golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
243239golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
244240golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
245241golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -269,12 +265,8 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
269265golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
270266golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
271267golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
272−golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
273−golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b h1:zSzQJAznWxAh9fZxiPy2FZo+ZZEYoYFYYDYdOrU7AaM=
274−golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
275268golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
276269golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
277−golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
278270golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
279271golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
280272google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@@ -300,7 +292,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
300292gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
301293gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
302294gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
303−gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
304295gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
305296gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
306297gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
@@ -321,5 +312,3 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
321312honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
322313honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
323314honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
324−mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 h1:kAREL6MPwpsk1/PQPFD3Eg7WAQR5mPTWZJaBiG5LDbY=
325−mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc=
pkg/sessions/cookie/session_store_test.go+21
@@ -5,9 +5,30 @@ import (
55 "testing"
66 "time"
77
8+ "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
9+ sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
10+ "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
11+ "github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/tests"
12+ . "github.com/onsi/ginkgo"
13+ . "github.com/onsi/gomega"
814 "github.com/stretchr/testify/assert"
915)
1016
17+func TestSessionStore(t *testing.T) {
18+ logger.SetOutput(GinkgoWriter)
19+ RegisterFailHandler(Fail)
20+ RunSpecs(t, "Cookie SessionStore")
21+}
22+
23+var _ = Describe("Cookie SessionStore Tests", func() {
24+ tests.RunSessionStoreTests(
25+ func(opts *options.SessionOptions, cookieOpts *options.CookieOptions) (sessionsapi.SessionStore, error) {
26+ // Set the connection URL
27+ opts.Type = options.CookieSessionStoreType
28+ return NewCookieSessionStore(opts, cookieOpts)
29+ }, nil)
30+})
31+
1132func Test_copyCookie(t *testing.T) {
1233 expire, _ := time.Parse(time.RFC3339, "2020-03-17T00:00:00Z")
1334 c := &http.Cookie{
pkg/sessions/redis/redis_store_test.godeleted−69
@@ -1,69 +0,0 @@
1−package redis
2−
3−import (
4− "crypto/rand"
5− "net/http"
6− "net/http/httptest"
7− "net/url"
8− "testing"
9−
10− "github.com/Bose/minisentinel"
11− "github.com/alicebob/miniredis/v2"
12− "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
13− "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
14− "github.com/stretchr/testify/assert"
15− "github.com/stretchr/testify/require"
16−)
17−
18−func TestRedisStore(t *testing.T) {
19− secret := make([]byte, 32)
20− _, err := rand.Read(secret)
21− assert.NoError(t, err)
22−
23− t.Run("save session on redis standalone", func(t *testing.T) {
24− redisServer, err := miniredis.Run()
25− require.NoError(t, err)
26− defer redisServer.Close()
27− opts := options.NewOptions()
28− redisURL := url.URL{
29− Scheme: "redis",
30− Host: redisServer.Addr(),
31− }
32− opts.Session.Redis.ConnectionURL = redisURL.String()
33−
34− opts.Cookie.Secret = string(secret)
35− redisStore, err := NewRedisSessionStore(&opts.Session, &opts.Cookie)
36− require.NoError(t, err)
37− err = redisStore.Save(
38− httptest.NewRecorder(),
39− httptest.NewRequest(http.MethodGet, "/", nil),
40− &sessions.SessionState{})
41− assert.NoError(t, err)
42− })
43− t.Run("save session on redis sentinel", func(t *testing.T) {
44− redisServer, err := miniredis.Run()
45− require.NoError(t, err)
46− defer redisServer.Close()
47− sentinel := minisentinel.NewSentinel(redisServer)
48− err = sentinel.Start()
49− require.NoError(t, err)
50− defer sentinel.Close()
51− opts := options.NewOptions()
52− sentinelURL := url.URL{
53− Scheme: "redis",
54− Host: sentinel.Addr(),
55− }
56− opts.Session.Redis.SentinelConnectionURLs = []string{sentinelURL.String()}
57− opts.Session.Redis.UseSentinel = true
58− opts.Session.Redis.SentinelMasterName = sentinel.MasterInfo().Name
59−
60− opts.Cookie.Secret = string(secret)
61− redisStore, err := NewRedisSessionStore(&opts.Session, &opts.Cookie)
62− require.NoError(t, err)
63− err = redisStore.Save(
64− httptest.NewRecorder(),
65− httptest.NewRequest(http.MethodGet, "/", nil),
66− &sessions.SessionState{})
67− assert.NoError(t, err)
68− })
69−}
pkg/sessions/redis/session_store_test.gonew file+101
@@ -0,0 +1,101 @@
1+package redis
2+
3+import (
4+ "log"
5+ "os"
6+ "testing"
7+ "time"
8+
9+ "github.com/Bose/minisentinel"
10+ "github.com/alicebob/miniredis/v2"
11+ "github.com/go-redis/redis/v7"
12+ "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
13+ sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
14+ "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
15+ "github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/tests"
16+ . "github.com/onsi/ginkgo"
17+ . "github.com/onsi/gomega"
18+)
19+
20+func TestSessionStore(t *testing.T) {
21+ logger.SetOutput(GinkgoWriter)
22+
23+ redisLogger := log.New(os.Stderr, "redis: ", log.LstdFlags|log.Lshortfile)
24+ redisLogger.SetOutput(GinkgoWriter)
25+ redis.SetLogger(redisLogger)
26+
27+ RegisterFailHandler(Fail)
28+ RunSpecs(t, "Redis SessionStore")
29+}
30+
31+var _ = Describe("Redis SessionStore Tests", func() {
32+ var mr *miniredis.Miniredis
33+
34+ BeforeEach(func() {
35+ var err error
36+ mr, err = miniredis.Run()
37+ Expect(err).ToNot(HaveOccurred())
38+ })
39+
40+ AfterEach(func() {
41+ mr.Close()
42+ })
43+
44+ tests.RunSessionStoreTests(
45+ func(opts *options.SessionOptions, cookieOpts *options.CookieOptions) (sessionsapi.SessionStore, error) {
46+ // Set the connection URL
47+ opts.Type = options.RedisSessionStoreType
48+ opts.Redis.ConnectionURL = "redis://" + mr.Addr()
49+ return NewRedisSessionStore(opts, cookieOpts)
50+ },
51+ func(d time.Duration) error {
52+ mr.FastForward(d)
53+ return nil
54+ },
55+ )
56+
57+ Context("with sentinel", func() {
58+ var ms *minisentinel.Sentinel
59+
60+ BeforeEach(func() {
61+ ms = minisentinel.NewSentinel(mr)
62+ Expect(ms.Start()).To(Succeed())
63+ })
64+
65+ AfterEach(func() {
66+ go ms.Close()
67+ })
68+
69+ tests.RunSessionStoreTests(
70+ func(opts *options.SessionOptions, cookieOpts *options.CookieOptions) (sessionsapi.SessionStore, error) {
71+ // Set the sentinel connection URL
72+ sentinelAddr := "redis://" + ms.Addr()
73+ opts.Type = options.RedisSessionStoreType
74+ opts.Redis.SentinelConnectionURLs = []string{sentinelAddr}
75+ opts.Redis.UseSentinel = true
76+ opts.Redis.SentinelMasterName = ms.MasterInfo().Name
77+ return NewRedisSessionStore(opts, cookieOpts)
78+ },
79+ func(d time.Duration) error {
80+ mr.FastForward(d)
81+ return nil
82+ },
83+ )
84+ })
85+
86+ Context("with cluster", func() {
87+ tests.RunSessionStoreTests(
88+ func(opts *options.SessionOptions, cookieOpts *options.CookieOptions) (sessionsapi.SessionStore, error) {
89+ clusterAddr := "redis://" + mr.Addr()
90+ opts.Type = options.RedisSessionStoreType
91+ opts.Redis.ClusterConnectionURLs = []string{clusterAddr}
92+ opts.Redis.UseCluster = true
93+ return NewRedisSessionStore(opts, cookieOpts)
94+ },
95+ func(d time.Duration) error {
96+ mr.FastForward(d)
97+ return nil
98+ },
99+ )
100+ })
101+})
pkg/sessions/session_store_test.go+2−398
@@ -1,20 +1,12 @@
11package sessions_test
22
33import (
4− "crypto/rand"
54 "encoding/base64"
6− "net/http"
7− "net/http/httptest"
8− "strconv"
9− "strings"
5+ "math/rand"
106 "testing"
117 "time"
128
13− miniredis "github.com/alicebob/miniredis/v2"
149 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
15− sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
16− cookiesapi "github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
17− "github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
1810 "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
1911 "github.com/oauth2-proxy/oauth2-proxy/pkg/sessions"
2012 sessionscookie "github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/cookie"
@@ -34,341 +26,7 @@ var _ = Describe("NewSessionStore", func() {
3426 var opts *options.SessionOptions
3527 var cookieOpts *options.CookieOptions
3628
37− var request *http.Request
38− var response *httptest.ResponseRecorder
39− var session *sessionsapi.SessionState
40− var ss sessionsapi.SessionStore
41− var mr *miniredis.Miniredis
42−
43− CheckCookieOptions := func() {
44− Context("the cookies returned", func() {
45− var cookies []*http.Cookie
46− BeforeEach(func() {
47− cookies = response.Result().Cookies()
48− })
49−
50− It("have the correct name set", func() {
51− if len(cookies) == 1 {
52− Expect(cookies[0].Name).To(Equal(cookieOpts.Name))
53− } else {
54− for _, cookie := range cookies {
55− Expect(cookie.Name).To(ContainSubstring(cookieOpts.Name))
56− }
57− }
58− })
59−
60− It("have the correct path set", func() {
61− for _, cookie := range cookies {
62− Expect(cookie.Path).To(Equal(cookieOpts.Path))
63− }
64− })
65−
66− It("have the correct domain set", func() {
67− for _, cookie := range cookies {
68− specifiedDomain := ""
69− if len(cookieOpts.Domains) > 0 {
70− specifiedDomain = cookieOpts.Domains[0]
71− }
72− Expect(cookie.Domain).To(Equal(specifiedDomain))
73− }
74− })
75−
76− It("have the correct HTTPOnly set", func() {
77− for _, cookie := range cookies {
78− Expect(cookie.HttpOnly).To(Equal(cookieOpts.HTTPOnly))
79− }
80− })
81−
82− It("have the correct secure set", func() {
83− for _, cookie := range cookies {
84− Expect(cookie.Secure).To(Equal(cookieOpts.Secure))
85− }
86− })
87−
88− It("have the correct SameSite set", func() {
89− for _, cookie := range cookies {
90− Expect(cookie.SameSite).To(Equal(cookiesapi.ParseSameSite(cookieOpts.SameSite)))
91− }
92− })
93−
94− It("have a signature timestamp matching session.CreatedAt", func() {
95− for _, cookie := range cookies {
96− if cookie.Value != "" {
97− parts := strings.Split(cookie.Value, "|")
98− Expect(parts).To(HaveLen(3))
99− Expect(parts[1]).To(Equal(strconv.Itoa(int(session.CreatedAt.Unix()))))
100− }
101− }
102− })
103−
104− })
105− }
106−
107− // The following should only be for server stores
108− PersistentSessionStoreTests := func() {
109− Context("when Clear is called on a persistent store", func() {
110− var resultCookies []*http.Cookie
111−
112− BeforeEach(func() {
113− req := httptest.NewRequest("GET", "http://example.com/", nil)
114− saveResp := httptest.NewRecorder()
115− err := ss.Save(saveResp, req, session)
116− Expect(err).ToNot(HaveOccurred())
117−
118− resultCookies = saveResp.Result().Cookies()
119− for _, c := range resultCookies {
120− request.AddCookie(c)
121− }
122− err = ss.Clear(response, request)
123− Expect(err).ToNot(HaveOccurred())
124− })
125−
126− Context("attempting to Load", func() {
127− var loadedAfterClear *sessionsapi.SessionState
128− var loadErr error
129−
130− BeforeEach(func() {
131− loadReq := httptest.NewRequest("GET", "http://example.com/", nil)
132− for _, c := range resultCookies {
133− loadReq.AddCookie(c)
134− }
135−
136− loadedAfterClear, loadErr = ss.Load(loadReq)
137− })
138−
139− It("returns an empty session", func() {
140− Expect(loadedAfterClear).To(BeNil())
141− })
142−
143− It("returns an error", func() {
144− Expect(loadErr).To(HaveOccurred())
145− })
146− })
147−
148− CheckCookieOptions()
149− })
150− }
151−
152− SessionStoreInterfaceTests := func(persistent bool) {
153− Context("when Save is called", func() {
154− Context("with no existing session", func() {
155− BeforeEach(func() {
156− err := ss.Save(response, request, session)
157− Expect(err).ToNot(HaveOccurred())
158− })
159−
160− It("sets a `set-cookie` header in the response", func() {
161− Expect(response.Header().Get("set-cookie")).ToNot(BeEmpty())
162− })
163−
164− It("Ensures the session CreatedAt is not zero", func() {
165− Expect(session.CreatedAt.IsZero()).To(BeFalse())
166− })
167− })
168−
169− Context("with a broken session", func() {
170− BeforeEach(func() {
171− By("Using a valid cookie with a different providers session encoding")
172− broken := "BrokenSessionFromADifferentSessionImplementation"
173− value := encryption.SignedValue(cookieOpts.Secret, cookieOpts.Name, []byte(broken), time.Now())
174− cookie := cookiesapi.MakeCookieFromOptions(request, cookieOpts.Name, value, cookieOpts, cookieOpts.Expire, time.Now())
175− request.AddCookie(cookie)
176−
177− err := ss.Save(response, request, session)
178− Expect(err).ToNot(HaveOccurred())
179− })
180−
181− It("sets a `set-cookie` header in the response", func() {
182− Expect(response.Header().Get("set-cookie")).ToNot(BeEmpty())
183− })
184−
185− It("Ensures the session CreatedAt is not zero", func() {
186− Expect(session.CreatedAt.IsZero()).To(BeFalse())
187− })
188− })
189−
190− Context("with an expired saved session", func() {
191− var err error
192− BeforeEach(func() {
193− By("saving a session")
194− req := httptest.NewRequest("GET", "http://example.com/", nil)
195− saveResp := httptest.NewRecorder()
196− err = ss.Save(saveResp, req, session)
197− Expect(err).ToNot(HaveOccurred())
198−
199− By("and clearing the session")
200− for _, c := range saveResp.Result().Cookies() {
201− request.AddCookie(c)
202− }
203− clearResp := httptest.NewRecorder()
204− err = ss.Clear(clearResp, request)
205− Expect(err).ToNot(HaveOccurred())
206−
207− By("then saving a request with the cleared session")
208− err = ss.Save(response, request, session)
209− })
210−
211− It("no error should occur", func() {
212− Expect(err).ToNot(HaveOccurred())
213− })
214− })
215−
216− CheckCookieOptions()
217− })
218−
219− Context("when Clear is called", func() {
220− BeforeEach(func() {
221− req := httptest.NewRequest("GET", "http://example.com/", nil)
222− saveResp := httptest.NewRecorder()
223− err := ss.Save(saveResp, req, session)
224− Expect(err).ToNot(HaveOccurred())
225−
226− for _, c := range saveResp.Result().Cookies() {
227− request.AddCookie(c)
228− }
229− err = ss.Clear(response, request)
230− Expect(err).ToNot(HaveOccurred())
231− })
232−
233− It("sets a `set-cookie` header in the response", func() {
234− Expect(response.Header().Get("Set-Cookie")).ToNot(BeEmpty())
235− })
236−
237− CheckCookieOptions()
238− })
239−
240− Context("when Load is called", func() {
241− LoadSessionTests := func() {
242− var loadedSession *sessionsapi.SessionState
243− BeforeEach(func() {
244− var err error
245− loadedSession, err = ss.Load(request)
246− Expect(err).ToNot(HaveOccurred())
247− })
248−
249− It("loads a session equal to the original session", func() {
250− if cookieOpts.Secret == "" {
251− // Only Email and User stored in session when encrypted
252− Expect(loadedSession.Email).To(Equal(session.Email))
253− Expect(loadedSession.User).To(Equal(session.User))
254− } else {
255− // All fields stored in session if encrypted
256−
257− // Can't compare time.Time using Equal() so remove ExpiresOn from sessions
258− l := *loadedSession
259− l.CreatedAt = nil
260− l.ExpiresOn = nil
261− s := *session
262− s.CreatedAt = nil
263− s.ExpiresOn = nil
264− Expect(l).To(Equal(s))
265−
266− // Compare time.Time separately
267− Expect(loadedSession.CreatedAt.Equal(*session.CreatedAt)).To(BeTrue())
268− Expect(loadedSession.ExpiresOn.Equal(*session.ExpiresOn)).To(BeTrue())
269− }
270− })
271− }
272−
273− BeforeEach(func() {
274− req := httptest.NewRequest("GET", "http://example.com/", nil)
275− resp := httptest.NewRecorder()
276− err := ss.Save(resp, req, session)
277− Expect(err).ToNot(HaveOccurred())
278−
279− for _, cookie := range resp.Result().Cookies() {
280− request.AddCookie(cookie)
281− }
282− })
283−
284− Context("before the refresh period", func() {
285− LoadSessionTests()
286− })
287−
288− // Test TTLs and cleanup of persistent session storage
289− // For non-persistent we rely on the browser cookie lifecycle
290− if persistent {
291− Context("after the refresh period, but before the cookie expire period", func() {
292− BeforeEach(func() {
293− switch ss.(type) {
294− case *redis.SessionStore:
295− mr.FastForward(cookieOpts.Refresh + time.Minute)
296− }
297− })
298−
299− LoadSessionTests()
300− })
301−
302− Context("after the cookie expire period", func() {
303− var loadedSession *sessionsapi.SessionState
304− var err error
305−
306− BeforeEach(func() {
307− switch ss.(type) {
308− case *redis.SessionStore:
309− mr.FastForward(cookieOpts.Expire + time.Minute)
310− }
311−
312− loadedSession, err = ss.Load(request)
313− Expect(err).To(HaveOccurred())
314− })
315−
316− It("returns an error loading the session", func() {
317− Expect(err).To(HaveOccurred())
318− })
319−
320− It("returns an empty session", func() {
321− Expect(loadedSession).To(BeNil())
322− })
323− })
324− }
325− })
326−
327− if persistent {
328− PersistentSessionStoreTests()
329− }
330− }
331−
332− RunSessionTests := func(persistent bool) {
333− Context("with default options", func() {
334− BeforeEach(func() {
335− var err error
336− ss, err = sessions.NewSessionStore(opts, cookieOpts)
337− Expect(err).ToNot(HaveOccurred())
338− })
339−
340− SessionStoreInterfaceTests(persistent)
341− })
342−
343− Context("with non-default options", func() {
344− BeforeEach(func() {
345− cookieOpts = &options.CookieOptions{
346− Name: "_cookie_name",
347− Path: "/path",
348− Expire: time.Duration(72) * time.Hour,
349− Refresh: time.Duration(2) * time.Hour,
350− Secure: false,
351− HTTPOnly: false,
352− Domains: []string{"example.com"},
353− SameSite: "strict",
354− }
355−
356− // A secret is required but not defaulted
357− secret := make([]byte, 32)
358− _, err := rand.Read(secret)
359− Expect(err).ToNot(HaveOccurred())
360− cookieOpts.Secret = base64.URLEncoding.EncodeToString(secret)
361−
362− ss, err = sessions.NewSessionStore(opts, cookieOpts)
363− Expect(err).ToNot(HaveOccurred())
364− })
365−
366− SessionStoreInterfaceTests(persistent)
367− })
368− }
369−
37029 BeforeEach(func() {
371− ss = nil
37230 opts = &options.SessionOptions{}
37331
37432 // A secret is required to create a Cipher, validation ensures it is the correct
@@ -388,19 +46,6 @@ var _ = Describe("NewSessionStore", func() {
38846 HTTPOnly: true,
38947 SameSite: "",
39048 }
391−
392− expires := time.Now().Add(1 * time.Hour)
393− session = &sessionsapi.SessionState{
394− AccessToken: "AccessToken",
395− IDToken: "IDToken",
396− ExpiresOn: &expires,
397− RefreshToken: "RefreshToken",
398− Email: "john.doe@example.com",
399− User: "john.doe",
400− }
401−
402− request = httptest.NewRequest("GET", "http://example.com/", nil)
403− response = httptest.NewRecorder()
40449 })
40550
40651 Context("with type 'cookie'", func() {
@@ -413,36 +58,12 @@ var _ = Describe("NewSessionStore", func() {
41358 Expect(err).NotTo(HaveOccurred())
41459 Expect(ss).To(BeAssignableToTypeOf(&sessionscookie.SessionStore{}))
41560 })
416−
417− Context("the cookie.SessionStore", func() {
418− RunSessionTests(false)
419− })
420−
421− Context("with an invalid cookie secret", func() {
422− BeforeEach(func() {
423− cookieOpts.Secret = "invalid"
424− })
425−
426− It("returns an error", func() {
427− ss, err := sessions.NewSessionStore(opts, cookieOpts)
428− Expect(err).To(HaveOccurred())
429− Expect(err.Error()).To(Equal("error initialising cipher: crypto/aes: invalid key size 7"))
430− Expect(ss).To(BeNil())
431− })
432− })
43361 })
43462
43563 Context("with type 'redis'", func() {
43664 BeforeEach(func() {
437− var err error
438− mr, err = miniredis.Run()
439− Expect(err).ToNot(HaveOccurred())
44065 opts.Type = options.RedisSessionStoreType
441− opts.Redis.ConnectionURL = "redis://" + mr.Addr()
442− })
443−
444− AfterEach(func() {
445− mr.Close()
66+ opts.Redis.ConnectionURL = "redis://"
44667 })
44768
44869 It("creates a redis.SessionStore", func() {
@@ -450,23 +71,6 @@ var _ = Describe("NewSessionStore", func() {
45071 Expect(err).NotTo(HaveOccurred())
45172 Expect(ss).To(BeAssignableToTypeOf(&redis.SessionStore{}))
45273 })
453−
454− Context("the redis.SessionStore", func() {
455− RunSessionTests(true)
456− })
457−
458− Context("with an invalid cookie secret", func() {
459− BeforeEach(func() {
460− cookieOpts.Secret = "invalid"
461− })
462−
463− It("returns an error", func() {
464− ss, err := sessions.NewSessionStore(opts, cookieOpts)
465− Expect(err).To(HaveOccurred())
466− Expect(err.Error()).To(Equal("error initialising cipher: crypto/aes: invalid key size 7"))
467− Expect(ss).To(BeNil())
468− })
469− })
47074 })
47175
47276 Context("with an invalid type", func() {
pkg/sessions/tests/session_store_tests.gonew file+435
@@ -0,0 +1,435 @@
1+package tests
2+
3+import (
4+ "crypto/rand"
5+ "net/http"
6+ "net/http/httptest"
7+ "strconv"
8+ "strings"
9+ "time"
10+
11+ "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
12+ sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
13+ cookiesapi "github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
14+ "github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
15+ . "github.com/onsi/ginkgo"
16+ . "github.com/onsi/gomega"
17+)
18+
19+// testInput is passed to test function as a pointer.
20+// This allows BeforeEach blocks to initialise and use these values after
21+// Ginkgo has unpacked the tests.
22+// Interfaces have to be wrapped in closures otherwise nil pointers are thrown.
23+type testInput struct {
24+ cookieOpts *options.CookieOptions
25+ ss sessionStoreFunc
26+ session *sessionsapi.SessionState
27+ request *http.Request
28+ response *httptest.ResponseRecorder
29+ persistentFastForward PersistentStoreFastForwardFunc
30+}
31+
32+// sessionStoreFunc is used in testInput to wrap the SessionStore interface.
33+type sessionStoreFunc func() sessionsapi.SessionStore
34+
35+// PersistentStoreFastForwardFunc is used to adjust the time of the persistent
36+// store to fast forward expiry of sessions.
37+type PersistentStoreFastForwardFunc func(time.Duration) error
38+
39+// NewSessionStoreFunc allows any session store implementation to configure their
40+// own session store before each test.
41+type NewSessionStoreFunc func(sessionOpts *options.SessionOptions, cookieOpts *options.CookieOptions) (sessionsapi.SessionStore, error)
42+
43+func RunSessionStoreTests(newSS NewSessionStoreFunc, persistentFastForward PersistentStoreFastForwardFunc) {
44+ Describe("Session Store Suite", func() {
45+ var opts *options.SessionOptions
46+ var ss sessionsapi.SessionStore
47+ var input testInput
48+ var cookieSecret []byte
49+
50+ getSessionStore := func() sessionsapi.SessionStore {
51+ return ss
52+ }
53+
54+ BeforeEach(func() {
55+ ss = nil
56+ opts = &options.SessionOptions{}
57+
58+ // A secret is required to create a Cipher, validation ensures it is the correct
59+ // length before a session store is initialised.
60+ cookieSecret = make([]byte, 32)
61+ _, err := rand.Read(cookieSecret)
62+ Expect(err).ToNot(HaveOccurred())
63+
64+ // Set default options in CookieOptions
65+ cookieOpts := &options.CookieOptions{
66+ Name: "_oauth2_proxy",
67+ Path: "/",
68+ Expire: time.Duration(168) * time.Hour,
69+ Refresh: time.Duration(1) * time.Hour,
70+ Secure: true,
71+ HTTPOnly: true,
72+ SameSite: "",
73+ Secret: string(cookieSecret),
74+ }
75+
76+ expires := time.Now().Add(1 * time.Hour)
77+ session := &sessionsapi.SessionState{
78+ AccessToken: "AccessToken",
79+ IDToken: "IDToken",
80+ ExpiresOn: &expires,
81+ RefreshToken: "RefreshToken",
82+ Email: "john.doe@example.com",
83+ User: "john.doe",
84+ }
85+
86+ request := httptest.NewRequest("GET", "http://example.com/", nil)
87+ response := httptest.NewRecorder()
88+
89+ input = testInput{
90+ cookieOpts: cookieOpts,
91+ ss: getSessionStore,
92+ session: session,
93+ request: request,
94+ response: response,
95+ persistentFastForward: persistentFastForward,
96+ }
97+ })
98+
99+ Context("with default options", func() {
100+ BeforeEach(func() {
101+ var err error
102+ ss, err = newSS(opts, input.cookieOpts)
103+ Expect(err).ToNot(HaveOccurred())
104+ })
105+
106+ SessionStoreInterfaceTests(&input)
107+ if persistentFastForward != nil {
108+ PersistentSessionStoreInterfaceTests(&input)
109+ }
110+ })
111+
112+ Context("with non-default options", func() {
113+ BeforeEach(func() {
114+ input.cookieOpts = &options.CookieOptions{
115+ Name: "_cookie_name",
116+ Path: "/path",
117+ Expire: time.Duration(72) * time.Hour,
118+ Refresh: time.Duration(2) * time.Hour,
119+ Secure: false,
120+ HTTPOnly: false,
121+ Domains: []string{"example.com"},
122+ SameSite: "strict",
123+ Secret: string(cookieSecret),
124+ }
125+
126+ var err error
127+ ss, err = newSS(opts, input.cookieOpts)
128+ Expect(err).ToNot(HaveOccurred())
129+ })
130+
131+ SessionStoreInterfaceTests(&input)
132+ if persistentFastForward != nil {
133+ PersistentSessionStoreInterfaceTests(&input)
134+ }
135+ })
136+
137+ Context("with an invalid cookie secret", func() {
138+ BeforeEach(func() {
139+ input.cookieOpts.Secret = "invalid"
140+ })
141+
142+ It("returns an error when initialising the session store", func() {
143+ ss, err := newSS(opts, input.cookieOpts)
144+ Expect(err).To(MatchError("error initialising cipher: crypto/aes: invalid key size 7"))
145+ Expect(ss).To(BeNil())
146+ })
147+ })
148+ })
149+}
150+
151+func CheckCookieOptions(in *testInput) {
152+ Context("the cookies returned", func() {
153+ var cookies []*http.Cookie
154+ BeforeEach(func() {
155+ cookies = in.response.Result().Cookies()
156+ })
157+
158+ It("have the correct name set", func() {
159+ if len(cookies) == 1 {
160+ Expect(cookies[0].Name).To(Equal(in.cookieOpts.Name))
161+ } else {
162+ for _, cookie := range cookies {
163+ Expect(cookie.Name).To(ContainSubstring(in.cookieOpts.Name))
164+ }
165+ }
166+ })
167+
168+ It("have the correct path set", func() {
169+ for _, cookie := range cookies {
170+ Expect(cookie.Path).To(Equal(in.cookieOpts.Path))
171+ }
172+ })
173+
174+ It("have the correct domain set", func() {
175+ for _, cookie := range cookies {
176+ specifiedDomain := ""
177+ if len(in.cookieOpts.Domains) > 0 {
178+ specifiedDomain = in.cookieOpts.Domains[0]
179+ }
180+ Expect(cookie.Domain).To(Equal(specifiedDomain))
181+ }
182+ })
183+
184+ It("have the correct HTTPOnly set", func() {
185+ for _, cookie := range cookies {
186+ Expect(cookie.HttpOnly).To(Equal(in.cookieOpts.HTTPOnly))
187+ }
188+ })
189+
190+ It("have the correct secure set", func() {
191+ for _, cookie := range cookies {
192+ Expect(cookie.Secure).To(Equal(in.cookieOpts.Secure))
193+ }
194+ })
195+
196+ It("have the correct SameSite set", func() {
197+ for _, cookie := range cookies {
198+ Expect(cookie.SameSite).To(Equal(cookiesapi.ParseSameSite(in.cookieOpts.SameSite)))
199+ }
200+ })
201+
202+ It("have a signature timestamp matching session.CreatedAt", func() {
203+ for _, cookie := range cookies {
204+ if cookie.Value != "" {
205+ parts := strings.Split(cookie.Value, "|")
206+ Expect(parts).To(HaveLen(3))
207+ Expect(parts[1]).To(Equal(strconv.Itoa(int(in.session.CreatedAt.Unix()))))
208+ }
209+ }
210+ })
211+
212+ })
213+}
214+
215+func PersistentSessionStoreInterfaceTests(in *testInput) {
216+ // Check that a stale cookie can't load an already cleared session
217+ Context("when Clear is called on a persistent store", func() {
218+ var resultCookies []*http.Cookie
219+
220+ BeforeEach(func() {
221+ req := httptest.NewRequest("GET", "http://example.com/", nil)
222+ saveResp := httptest.NewRecorder()
223+ err := in.ss().Save(saveResp, req, in.session)
224+ Expect(err).ToNot(HaveOccurred())
225+
226+ resultCookies = saveResp.Result().Cookies()
227+ for _, c := range resultCookies {
228+ in.request.AddCookie(c)
229+ }
230+ err = in.ss().Clear(in.response, in.request)
231+ Expect(err).ToNot(HaveOccurred())
232+ })
233+
234+ Context("attempting to Load", func() {
235+ var loadedAfterClear *sessionsapi.SessionState
236+ var loadErr error
237+
238+ BeforeEach(func() {
239+ loadReq := httptest.NewRequest("GET", "http://example.com/", nil)
240+ for _, c := range resultCookies {
241+ loadReq.AddCookie(c)
242+ }
243+
244+ loadedAfterClear, loadErr = in.ss().Load(loadReq)
245+ })
246+
247+ It("returns an empty session", func() {
248+ Expect(loadedAfterClear).To(BeNil())
249+ })
250+
251+ It("returns an error", func() {
252+ Expect(loadErr).To(HaveOccurred())
253+ })
254+ })
255+
256+ CheckCookieOptions(in)
257+ })
258+
259+ // Test TTLs and cleanup of persistent session storage
260+ // For non-persistent we rely on the browser cookie lifecycle
261+ Context("when Load is called on a persistent store", func() {
262+ BeforeEach(func() {
263+ req := httptest.NewRequest("GET", "http://example.com/", nil)
264+ resp := httptest.NewRecorder()
265+ err := in.ss().Save(resp, req, in.session)
266+ Expect(err).ToNot(HaveOccurred())
267+
268+ for _, cookie := range resp.Result().Cookies() {
269+ in.request.AddCookie(cookie)
270+ }
271+ })
272+
273+ Context("after the refresh period, but before the cookie expire period", func() {
274+ BeforeEach(func() {
275+ Expect(in.persistentFastForward(in.cookieOpts.Refresh + time.Minute)).To(Succeed())
276+ })
277+
278+ LoadSessionTests(in)
279+ })
280+
281+ Context("after the cookie expire period", func() {
282+ var loadedSession *sessionsapi.SessionState
283+ var err error
284+
285+ BeforeEach(func() {
286+ Expect(in.persistentFastForward(in.cookieOpts.Expire + time.Minute)).To(Succeed())
287+
288+ loadedSession, err = in.ss().Load(in.request)
289+ Expect(err).To(HaveOccurred())
290+ })
291+
292+ It("returns an error loading the session", func() {
293+ Expect(err).To(HaveOccurred())
294+ })
295+
296+ It("returns an empty session", func() {
297+ Expect(loadedSession).To(BeNil())
298+ })
299+ })
300+ })
301+}
302+
303+func SessionStoreInterfaceTests(in *testInput) {
304+ Context("when Save is called", func() {
305+ Context("with no existing session", func() {
306+ BeforeEach(func() {
307+ err := in.ss().Save(in.response, in.request, in.session)
308+ Expect(err).ToNot(HaveOccurred())
309+ })
310+
311+ It("sets a `set-cookie` header in the response", func() {
312+ Expect(in.response.Header().Get("set-cookie")).ToNot(BeEmpty())
313+ })
314+
315+ It("Ensures the session CreatedAt is not zero", func() {
316+ Expect(in.session.CreatedAt.IsZero()).To(BeFalse())
317+ })
318+
319+ CheckCookieOptions(in)
320+ })
321+
322+ Context("with a broken session", func() {
323+ BeforeEach(func() {
324+ By("Using a valid cookie with a different providers session encoding")
325+ broken := "BrokenSessionFromADifferentSessionImplementation"
326+ value := encryption.SignedValue(in.cookieOpts.Secret, in.cookieOpts.Name, []byte(broken), time.Now())
327+ cookie := cookiesapi.MakeCookieFromOptions(in.request, in.cookieOpts.Name, value, in.cookieOpts, in.cookieOpts.Expire, time.Now())
328+ in.request.AddCookie(cookie)
329+
330+ err := in.ss().Save(in.response, in.request, in.session)
331+ Expect(err).ToNot(HaveOccurred())
332+ })
333+
334+ It("sets a `set-cookie` header in the response", func() {
335+ Expect(in.response.Header().Get("set-cookie")).ToNot(BeEmpty())
336+ })
337+
338+ It("Ensures the session CreatedAt is not zero", func() {
339+ Expect(in.session.CreatedAt.IsZero()).To(BeFalse())
340+ })
341+
342+ CheckCookieOptions(in)
343+ })
344+
345+ Context("with an expired saved session", func() {
346+ var err error
347+ BeforeEach(func() {
348+ By("saving a session")
349+ req := httptest.NewRequest("GET", "http://example.com/", nil)
350+ saveResp := httptest.NewRecorder()
351+ err = in.ss().Save(saveResp, req, in.session)
352+ Expect(err).ToNot(HaveOccurred())
353+
354+ By("and clearing the session")
355+ for _, c := range saveResp.Result().Cookies() {
356+ in.request.AddCookie(c)
357+ }
358+ clearResp := httptest.NewRecorder()
359+ err = in.ss().Clear(clearResp, in.request)
360+ Expect(err).ToNot(HaveOccurred())
361+
362+ By("then saving a request with the cleared session")
363+ err = in.ss().Save(in.response, in.request, in.session)
364+ })
365+
366+ It("no error should occur", func() {
367+ Expect(err).ToNot(HaveOccurred())
368+ })
369+ })
370+ })
371+
372+ Context("when Clear is called", func() {
373+ BeforeEach(func() {
374+ req := httptest.NewRequest("GET", "http://example.com/", nil)
375+ saveResp := httptest.NewRecorder()
376+ err := in.ss().Save(saveResp, req, in.session)
377+ Expect(err).ToNot(HaveOccurred())
378+
379+ for _, c := range saveResp.Result().Cookies() {
380+ in.request.AddCookie(c)
381+ }
382+ err = in.ss().Clear(in.response, in.request)
383+ Expect(err).ToNot(HaveOccurred())
384+ })
385+
386+ It("sets a `set-cookie` header in the response", func() {
387+ Expect(in.response.Header().Get("Set-Cookie")).ToNot(BeEmpty())
388+ })
389+
390+ CheckCookieOptions(in)
391+ })
392+
393+ Context("when Load is called", func() {
394+ BeforeEach(func() {
395+ req := httptest.NewRequest("GET", "http://example.com/", nil)
396+ resp := httptest.NewRecorder()
397+ err := in.ss().Save(resp, req, in.session)
398+ Expect(err).ToNot(HaveOccurred())
399+
400+ for _, cookie := range resp.Result().Cookies() {
401+ in.request.AddCookie(cookie)
402+ }
403+ })
404+
405+ Context("before the refresh period", func() {
406+ LoadSessionTests(in)
407+ })
408+
409+ })
410+}
411+
412+func LoadSessionTests(in *testInput) {
413+ var loadedSession *sessionsapi.SessionState
414+ BeforeEach(func() {
415+ var err error
416+ loadedSession, err = in.ss().Load(in.request)
417+ Expect(err).ToNot(HaveOccurred())
418+ })
419+
420+ It("loads a session equal to the original session", func() {
421+ // Can't compare time.Time using Equal() so remove ExpiresOn from sessions
422+ l := *loadedSession
423+ l.CreatedAt = nil
424+ l.ExpiresOn = nil
425+ s := *in.session
426+ s.CreatedAt = nil
427+ s.ExpiresOn = nil
428+ Expect(l).To(Equal(s))
429+
430+ // Compare time.Time separately
431+ Expect(loadedSession.CreatedAt.Equal(*in.session.CreatedAt)).To(BeTrue())
432+ Expect(loadedSession.ExpiresOn.Equal(*in.session.ExpiresOn)).To(BeTrue())
433+
434+ })
435+}