commit
d4745fda9d
20
CHANGELOG.md
20
CHANGELOG.md
|
|
@ -4,11 +4,31 @@
|
||||||
|
|
||||||
## Important Notes
|
## Important Notes
|
||||||
|
|
||||||
|
- [#575](https://github.com/oauth2-proxy/oauth2-proxy/pull/575) Sessions from v5.1.1 or earlier will no longer validate since they were not signed with SHA1.
|
||||||
|
- Sessions from v6.0.0 or later had a graceful conversion to SHA256 that resulted in no reauthentication
|
||||||
|
- Upgrading from v5.1.1 or earlier will result in a reauthentication
|
||||||
|
- [#616](https://github.com/oauth2-proxy/oauth2-proxy/pull/616) Ensure you have configured oauth2-proxy to use the `groups` scope. The user may be logged out initially as they may not currently have the `groups` claim however after going back through login process wil be authenticated.
|
||||||
|
|
||||||
## Breaking Changes
|
## Breaking Changes
|
||||||
|
|
||||||
|
- [#722](https://github.com/oauth2-proxy/oauth2-proxy/pull/722) When a Redis session store is configured, OAuth2-Proxy will fail to start up unless connection and health checks to Redis pass
|
||||||
|
- [#800](https://github.com/oauth2-proxy/oauth2-proxy/pull/800) Fix import path for v7. The import path has changed to support the go get installation.
|
||||||
|
- You can now `go get github.com/oauth2-proxy/oauth2-proxy/v7` to get the latest `v7` version of OAuth2 Proxy
|
||||||
|
- Import paths for package are now under `v7`, eg `github.com/oauth2-proxy/oauth2-proxy/v7/pkg/<module>`
|
||||||
|
- [#753](https://github.com/oauth2-proxy/oauth2-proxy/pull/753) A bug in the Azure provider prevented it from properly passing the configured protected `--resource`
|
||||||
|
via the login url. If this option was used in the past, behavior will change with this release as it will
|
||||||
|
affect the tokens returned by Azure. In the past, the tokens were always for `https://graph.microsoft.com` (the default)
|
||||||
|
and will now be for the configured resource (if it exists, otherwise it will run into errors)
|
||||||
|
|
||||||
## Changes since v6.1.1
|
## Changes since v6.1.1
|
||||||
|
|
||||||
|
- [#753](https://github.com/oauth2-proxy/oauth2-proxy/pull/753) Pass resource parameter in login url (@codablock)
|
||||||
|
- [#575](https://github.com/oauth2-proxy/oauth2-proxy/pull/575) Stop accepting legacy SHA1 signed cookies (@NickMeves)
|
||||||
|
- [#722](https://github.com/oauth2-proxy/oauth2-proxy/pull/722) Validate Redis configuration options at startup (@NickMeves)
|
||||||
|
- [#791](https://github.com/oauth2-proxy/oauth2-proxy/pull/791) Remove GetPreferredUsername method from provider interface (@NickMeves)
|
||||||
- [#764](https://github.com/oauth2-proxy/oauth2-proxy/pull/764) Document bcrypt encryption for htpasswd (and hide SHA) (@lentzi90)
|
- [#764](https://github.com/oauth2-proxy/oauth2-proxy/pull/764) Document bcrypt encryption for htpasswd (and hide SHA) (@lentzi90)
|
||||||
|
- [#616](https://github.com/oauth2-proxy/oauth2-proxy/pull/616) Add support to ensure user belongs in required groups when using the OIDC provider (@stefansedich)
|
||||||
|
- [#800](https://github.com/oauth2-proxy/oauth2-proxy/pull/800) Fix import path for v7 (@johejo)
|
||||||
|
|
||||||
# v6.1.1
|
# v6.1.1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ nav_order: 1
|
||||||
|
|
||||||
a. Download [Prebuilt Binary](https://github.com/oauth2-proxy/oauth2-proxy/releases) (current release is `v6.1.1`)
|
a. Download [Prebuilt Binary](https://github.com/oauth2-proxy/oauth2-proxy/releases) (current release is `v6.1.1`)
|
||||||
|
|
||||||
b. Build with `$ go get github.com/oauth2-proxy/oauth2-proxy` which will put the binary in `$GOROOT/bin`
|
b. Build with `$ go get github.com/oauth2-proxy/oauth2-proxy/v7` which will put the binary in `$GOPATH/bin`
|
||||||
|
|
||||||
c. Using the prebuilt docker image [quay.io/oauth2-proxy/oauth2-proxy](https://quay.io/oauth2-proxy/oauth2-proxy) (AMD64, ARMv6 and ARM64 tags available)
|
c. Using the prebuilt docker image [quay.io/oauth2-proxy/oauth2-proxy](https://quay.io/oauth2-proxy/oauth2-proxy) (AMD64, ARMv6 and ARM64 tags available)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,9 +142,9 @@ Make sure you set the following to the appropriate url:
|
||||||
-provider=keycloak
|
-provider=keycloak
|
||||||
-client-id=<client you have created>
|
-client-id=<client you have created>
|
||||||
-client-secret=<your client's secret>
|
-client-secret=<your client's secret>
|
||||||
-login-url="http(s)://<keycloak host>/realms/<your realm>/protocol/openid-connect/auth"
|
-login-url="http(s)://<keycloak host>/auth/realms/<your realm>/protocol/openid-connect/auth"
|
||||||
-redeem-url="http(s)://<keycloak host>/realms/<your realm>/protocol/openid-connect/token"
|
-redeem-url="http(s)://<keycloak host>/auth/realms/<your realm>/protocol/openid-connect/token"
|
||||||
-validate-url="http(s)://<keycloak host>/realms/<your realm>/protocol/openid-connect/userinfo"
|
-validate-url="http(s)://<keycloak host>/auth/realms/<your realm>/protocol/openid-connect/userinfo"
|
||||||
-keycloak-group=<user_group>
|
-keycloak-group=<user_group>
|
||||||
|
|
||||||
The group management in keycloak is using a tree. If you create a group named admin in keycloak you should define the 'keycloak-group' value to /admin.
|
The group management in keycloak is using a tree. If you create a group named admin in keycloak you should define the 'keycloak-group' value to /admin.
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,13 @@ An example [oauth2-proxy.cfg]({{ site.gitweb }}/contrib/oauth2-proxy.cfg.example
|
||||||
| `--insecure-oidc-skip-issuer-verification` | bool | allow the OIDC issuer URL to differ from the expected (currently required for Azure multi-tenant compatibility) | false |
|
| `--insecure-oidc-skip-issuer-verification` | bool | allow the OIDC issuer URL to differ from the expected (currently required for Azure multi-tenant compatibility) | false |
|
||||||
| `--oidc-issuer-url` | string | the OpenID Connect issuer URL, e.g. `"https://accounts.google.com"` | |
|
| `--oidc-issuer-url` | string | the OpenID Connect issuer URL, e.g. `"https://accounts.google.com"` | |
|
||||||
| `--oidc-jwks-url` | string | OIDC JWKS URI for token verification; required if OIDC discovery is disabled | |
|
| `--oidc-jwks-url` | string | OIDC JWKS URI for token verification; required if OIDC discovery is disabled | |
|
||||||
|
| `--oidc-groups-claim` | string | which claim contains the user groups | `"groups"` |
|
||||||
| `--pass-access-token` | bool | pass OAuth access_token to upstream via X-Forwarded-Access-Token header | false |
|
| `--pass-access-token` | bool | pass OAuth access_token to upstream via X-Forwarded-Access-Token header | false |
|
||||||
| `--pass-authorization-header` | bool | pass OIDC IDToken to upstream via Authorization Bearer header | false |
|
| `--pass-authorization-header` | bool | pass OIDC IDToken to upstream via Authorization Bearer header | false |
|
||||||
| `--pass-basic-auth` | bool | pass HTTP Basic Auth, X-Forwarded-User, X-Forwarded-Email and X-Forwarded-Preferred-Username information to upstream | true |
|
| `--pass-basic-auth` | bool | pass HTTP Basic Auth, X-Forwarded-User, X-Forwarded-Email and X-Forwarded-Preferred-Username information to upstream | true |
|
||||||
| `--prefer-email-to-user` | bool | Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, e.g. htaccess authentication. Used in conjunction with `--pass-basic-auth` and `--pass-user-headers` | false |
|
| `--prefer-email-to-user` | bool | Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, e.g. htaccess authentication. Used in conjunction with `--pass-basic-auth` and `--pass-user-headers` | false |
|
||||||
| `--pass-host-header` | bool | pass the request Host Header to upstream | true |
|
| `--pass-host-header` | bool | pass the request Host Header to upstream | true |
|
||||||
| `--pass-user-headers` | bool | pass X-Forwarded-User, X-Forwarded-Email and X-Forwarded-Preferred-Username information to upstream | true |
|
| `--pass-user-headers` | bool | pass X-Forwarded-User, X-Forwarded-Groups, X-Forwarded-Email and X-Forwarded-Preferred-Username information to upstream | true |
|
||||||
| `--profile-url` | string | Profile access endpoint | |
|
| `--profile-url` | string | Profile access endpoint | |
|
||||||
| `--prompt` | string | [OIDC prompt](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest); if present, `approval-prompt` is ignored | `""` |
|
| `--prompt` | string | [OIDC prompt](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest); if present, `approval-prompt` is ignored | `""` |
|
||||||
| `--provider` | string | OAuth provider | google |
|
| `--provider` | string | OAuth provider | google |
|
||||||
|
|
@ -112,7 +113,7 @@ An example [oauth2-proxy.cfg]({{ site.gitweb }}/contrib/oauth2-proxy.cfg.example
|
||||||
| `--scope` | string | OAuth scope specification | |
|
| `--scope` | string | OAuth scope specification | |
|
||||||
| `--session-cookie-minimal` | bool | strip OAuth tokens from cookie session stores if they aren't needed (cookie session store only) | false |
|
| `--session-cookie-minimal` | bool | strip OAuth tokens from cookie session stores if they aren't needed (cookie session store only) | false |
|
||||||
| `--session-store-type` | string | [Session data storage backend](configuration/sessions); redis or cookie | cookie |
|
| `--session-store-type` | string | [Session data storage backend](configuration/sessions); redis or cookie | cookie |
|
||||||
| `--set-xauthrequest` | bool | set X-Auth-Request-User, X-Auth-Request-Email and X-Auth-Request-Preferred-Username response headers (useful in Nginx auth_request mode) | false |
|
| `--set-xauthrequest` | bool | set X-Auth-Request-User, X-Auth-Request-Groups, X-Auth-Request-Email and X-Auth-Request-Preferred-Username response headers (useful in Nginx auth_request mode) | false |
|
||||||
| `--set-authorization-header` | bool | set Authorization Bearer response header (useful in Nginx auth_request mode) | false |
|
| `--set-authorization-header` | bool | set Authorization Bearer response header (useful in Nginx auth_request mode) | false |
|
||||||
| `--set-basic-auth` | bool | set HTTP Basic Auth information in response (useful in Nginx auth_request mode) | false |
|
| `--set-basic-auth` | bool | set HTTP Basic Auth information in response (useful in Nginx auth_request mode) | false |
|
||||||
| `--signature-key` | string | GAP-Signature request signature key (algorithm:secretkey) | |
|
| `--signature-key` | string | GAP-Signature request signature key (algorithm:secretkey) | |
|
||||||
|
|
@ -131,6 +132,7 @@ An example [oauth2-proxy.cfg]({{ site.gitweb }}/contrib/oauth2-proxy.cfg.example
|
||||||
| `--tls-key-file` | string | path to private key file | |
|
| `--tls-key-file` | string | path to private key file | |
|
||||||
| `--upstream` | string \| list | the http url(s) of the upstream endpoint, file:// paths for static files or `static://<status_code>` for static response. Routing is based on the path | |
|
| `--upstream` | string \| list | the http url(s) of the upstream endpoint, file:// paths for static files or `static://<status_code>` for static response. Routing is based on the path | |
|
||||||
| `--user-id-claim` | string | which claim contains the user ID | \["email"\] |
|
| `--user-id-claim` | string | which claim contains the user ID | \["email"\] |
|
||||||
|
| `--allowed-group` | string \| list | restrict logins to members of this group (may be given multiple times) | |
|
||||||
| `--validate-url` | string | Access token validation endpoint | |
|
| `--validate-url` | string | Access token validation endpoint | |
|
||||||
| `--version` | n/a | print version string | |
|
| `--version` | n/a | print version string | |
|
||||||
| `--whitelist-domain` | string \| list | allowed domains for redirection after authentication. Prefix domain with a `.` to allow subdomains (e.g. `.example.com`) \[[2](#footnote2)\] | |
|
| `--whitelist-domain` | string \| list | allowed domains for redirection after authentication. Prefix domain with a `.` to allow subdomains (e.g. `.example.com`) \[[2](#footnote2)\] | |
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -1,4 +1,4 @@
|
||||||
module github.com/oauth2-proxy/oauth2-proxy
|
module github.com/oauth2-proxy/oauth2-proxy/v7
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
|
|
|
||||||
6
go.sum
6
go.sum
|
|
@ -150,15 +150,11 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
|
|
||||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
|
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
|
||||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
|
|
||||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
|
||||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
|
|
@ -295,8 +291,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
|
|
||||||
4
http.go
4
http.go
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server represents an HTTP server
|
// Server represents an HTTP server
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
|
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
8
main.go
8
main.go
|
|
@ -11,10 +11,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/justinas/alice"
|
"github.com/justinas/alice"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/middleware"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/middleware"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
|
|
@ -16,20 +16,20 @@ import (
|
||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/justinas/alice"
|
"github.com/justinas/alice"
|
||||||
ipapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/ip"
|
ipapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/ip"
|
||||||
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/middleware"
|
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/authentication/basic"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/authentication/basic"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/cookies"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/ip"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/middleware"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/middleware"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/upstream"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/upstream"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/util"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/providers"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -102,6 +102,7 @@ type OAuthProxy struct {
|
||||||
trustedIPs *ip.NetSet
|
trustedIPs *ip.NetSet
|
||||||
Banner string
|
Banner string
|
||||||
Footer string
|
Footer string
|
||||||
|
AllowedGroups []string
|
||||||
|
|
||||||
sessionChain alice.Chain
|
sessionChain alice.Chain
|
||||||
}
|
}
|
||||||
|
|
@ -215,6 +216,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
|
||||||
Banner: opts.Banner,
|
Banner: opts.Banner,
|
||||||
Footer: opts.Footer,
|
Footer: opts.Footer,
|
||||||
SignInMessage: buildSignInMessage(opts),
|
SignInMessage: buildSignInMessage(opts),
|
||||||
|
AllowedGroups: opts.AllowedGroups,
|
||||||
|
|
||||||
basicAuthValidator: basicAuthValidator,
|
basicAuthValidator: basicAuthValidator,
|
||||||
displayHtpasswdForm: basicAuthValidator != nil,
|
displayHtpasswdForm: basicAuthValidator != nil,
|
||||||
|
|
@ -294,34 +296,31 @@ func (p *OAuthProxy) GetRedirectURI(host string) string {
|
||||||
return u.String()
|
return u.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *OAuthProxy) redeemCode(ctx context.Context, host, code string) (s *sessionsapi.SessionState, err error) {
|
func (p *OAuthProxy) redeemCode(ctx context.Context, host, code string) (*sessionsapi.SessionState, error) {
|
||||||
if code == "" {
|
if code == "" {
|
||||||
return nil, errors.New("missing code")
|
return nil, errors.New("missing code")
|
||||||
}
|
}
|
||||||
redirectURI := p.GetRedirectURI(host)
|
redirectURI := p.GetRedirectURI(host)
|
||||||
s, err = p.provider.Redeem(ctx, redirectURI, code)
|
s, err := p.provider.Redeem(ctx, redirectURI, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Email == "" {
|
if s.Email == "" {
|
||||||
s.Email, err = p.provider.GetEmailAddress(ctx, s)
|
s.Email, err = p.provider.GetEmailAddress(ctx, s)
|
||||||
}
|
if err != nil && err.Error() != "not implemented" {
|
||||||
|
return nil, err
|
||||||
if s.PreferredUsername == "" {
|
|
||||||
s.PreferredUsername, err = p.provider.GetPreferredUsername(ctx, s)
|
|
||||||
if err != nil && err.Error() == "not implemented" {
|
|
||||||
err = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.User == "" {
|
if s.User == "" {
|
||||||
s.User, err = p.provider.GetUserName(ctx, s)
|
s.User, err = p.provider.GetUserName(ctx, s)
|
||||||
if err != nil && err.Error() == "not implemented" {
|
if err != nil && err.Error() != "not implemented" {
|
||||||
err = nil
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeCSRFCookie creates a cookie for CSRF
|
// MakeCSRFCookie creates a cookie for CSRF
|
||||||
|
|
@ -888,7 +887,10 @@ func (p *OAuthProxy) getAuthenticatedSession(rw http.ResponseWriter, req *http.R
|
||||||
return nil, ErrNeedsLogin
|
return nil, ErrNeedsLogin
|
||||||
}
|
}
|
||||||
|
|
||||||
if session != nil && session.Email != "" && !p.Validator(session.Email) {
|
invalidEmail := session != nil && session.Email != "" && !p.Validator(session.Email)
|
||||||
|
invalidGroups := session != nil && !p.validateGroups(session.Groups)
|
||||||
|
|
||||||
|
if invalidEmail || invalidGroups {
|
||||||
logger.Printf(session.Email, req, logger.AuthFailure, "Invalid authentication via session: removing session %s", session)
|
logger.Printf(session.Email, req, logger.AuthFailure, "Invalid authentication via session: removing session %s", session)
|
||||||
// Invalid session, clear it
|
// Invalid session, clear it
|
||||||
err := p.ClearSessionCookie(rw, req)
|
err := p.ClearSessionCookie(rw, req)
|
||||||
|
|
@ -942,6 +944,14 @@ func (p *OAuthProxy) addHeadersForProxying(rw http.ResponseWriter, req *http.Req
|
||||||
} else {
|
} else {
|
||||||
req.Header.Del("X-Forwarded-Preferred-Username")
|
req.Header.Del("X-Forwarded-Preferred-Username")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(session.Groups) > 0 {
|
||||||
|
for _, group := range session.Groups {
|
||||||
|
req.Header.Add("X-Forwarded-Groups", group)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req.Header.Del("X-Forwarded-Groups")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.SetXAuthRequest {
|
if p.SetXAuthRequest {
|
||||||
|
|
@ -964,6 +974,14 @@ func (p *OAuthProxy) addHeadersForProxying(rw http.ResponseWriter, req *http.Req
|
||||||
rw.Header().Del("X-Auth-Request-Access-Token")
|
rw.Header().Del("X-Auth-Request-Access-Token")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(session.Groups) > 0 {
|
||||||
|
for _, group := range session.Groups {
|
||||||
|
rw.Header().Add("X-Auth-Request-Groups", group)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rw.Header().Del("X-Auth-Request-Groups")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.PassAccessToken {
|
if p.PassAccessToken {
|
||||||
|
|
@ -1012,6 +1030,7 @@ func (p *OAuthProxy) addHeadersForProxying(rw http.ResponseWriter, req *http.Req
|
||||||
func (p *OAuthProxy) stripAuthHeaders(req *http.Request) {
|
func (p *OAuthProxy) stripAuthHeaders(req *http.Request) {
|
||||||
if p.PassBasicAuth {
|
if p.PassBasicAuth {
|
||||||
req.Header.Del("X-Forwarded-User")
|
req.Header.Del("X-Forwarded-User")
|
||||||
|
req.Header.Del("X-Forwarded-Groups")
|
||||||
req.Header.Del("X-Forwarded-Email")
|
req.Header.Del("X-Forwarded-Email")
|
||||||
req.Header.Del("X-Forwarded-Preferred-Username")
|
req.Header.Del("X-Forwarded-Preferred-Username")
|
||||||
req.Header.Del("Authorization")
|
req.Header.Del("Authorization")
|
||||||
|
|
@ -1019,6 +1038,7 @@ func (p *OAuthProxy) stripAuthHeaders(req *http.Request) {
|
||||||
|
|
||||||
if p.PassUserHeaders {
|
if p.PassUserHeaders {
|
||||||
req.Header.Del("X-Forwarded-User")
|
req.Header.Del("X-Forwarded-User")
|
||||||
|
req.Header.Del("X-Forwarded-Groups")
|
||||||
req.Header.Del("X-Forwarded-Email")
|
req.Header.Del("X-Forwarded-Email")
|
||||||
req.Header.Del("X-Forwarded-Preferred-Username")
|
req.Header.Del("X-Forwarded-Preferred-Username")
|
||||||
}
|
}
|
||||||
|
|
@ -1049,3 +1069,23 @@ func (p *OAuthProxy) ErrorJSON(rw http.ResponseWriter, code int) {
|
||||||
rw.Header().Set("Content-Type", applicationJSON)
|
rw.Header().Set("Content-Type", applicationJSON)
|
||||||
rw.WriteHeader(code)
|
rw.WriteHeader(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *OAuthProxy) validateGroups(groups []string) bool {
|
||||||
|
if len(p.AllowedGroups) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
allowedGroups := map[string]struct{}{}
|
||||||
|
|
||||||
|
for _, group := range p.AllowedGroups {
|
||||||
|
allowedGroups[group] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, group := range groups {
|
||||||
|
if _, ok := allowedGroups[group]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ import (
|
||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/mbland/hmacauth"
|
"github.com/mbland/hmacauth"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
sessionscookie "github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/cookie"
|
sessionscookie "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/cookie"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/upstream"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/upstream"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/providers"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
@ -592,6 +592,37 @@ func TestPassUserHeadersWithEmail(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPassGroupsHeadersWithGroups(t *testing.T) {
|
||||||
|
opts := baseTestOptions()
|
||||||
|
err := validation.Validate(opts)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
const emailAddress = "john.doe@example.com"
|
||||||
|
const userName = "9fcab5c9b889a557"
|
||||||
|
|
||||||
|
groups := []string{"a", "b"}
|
||||||
|
created := time.Now()
|
||||||
|
session := &sessions.SessionState{
|
||||||
|
User: userName,
|
||||||
|
Groups: groups,
|
||||||
|
Email: emailAddress,
|
||||||
|
AccessToken: "oauth_token",
|
||||||
|
CreatedAt: &created,
|
||||||
|
}
|
||||||
|
{
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase0", nil)
|
||||||
|
proxy, err := NewOAuthProxy(opts, func(email string) bool {
|
||||||
|
return email == emailAddress
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
proxy.addHeadersForProxying(rw, req, session)
|
||||||
|
assert.Equal(t, groups, req.Header["X-Forwarded-Groups"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestStripAuthHeaders(t *testing.T) {
|
func TestStripAuthHeaders(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
SkipAuthStripHeaders bool
|
SkipAuthStripHeaders bool
|
||||||
|
|
@ -609,6 +640,7 @@ func TestStripAuthHeaders(t *testing.T) {
|
||||||
PassAuthorization: false,
|
PassAuthorization: false,
|
||||||
StrippedHeaders: map[string]bool{
|
StrippedHeaders: map[string]bool{
|
||||||
"X-Forwarded-User": true,
|
"X-Forwarded-User": true,
|
||||||
|
"X-Forwared-Groups": true,
|
||||||
"X-Forwarded-Email": true,
|
"X-Forwarded-Email": true,
|
||||||
"X-Forwarded-Preferred-Username": true,
|
"X-Forwarded-Preferred-Username": true,
|
||||||
"X-Forwarded-Access-Token": false,
|
"X-Forwarded-Access-Token": false,
|
||||||
|
|
@ -623,6 +655,7 @@ func TestStripAuthHeaders(t *testing.T) {
|
||||||
PassAuthorization: false,
|
PassAuthorization: false,
|
||||||
StrippedHeaders: map[string]bool{
|
StrippedHeaders: map[string]bool{
|
||||||
"X-Forwarded-User": true,
|
"X-Forwarded-User": true,
|
||||||
|
"X-Forwared-Groups": true,
|
||||||
"X-Forwarded-Email": true,
|
"X-Forwarded-Email": true,
|
||||||
"X-Forwarded-Preferred-Username": true,
|
"X-Forwarded-Preferred-Username": true,
|
||||||
"X-Forwarded-Access-Token": true,
|
"X-Forwarded-Access-Token": true,
|
||||||
|
|
@ -637,6 +670,7 @@ func TestStripAuthHeaders(t *testing.T) {
|
||||||
PassAuthorization: false,
|
PassAuthorization: false,
|
||||||
StrippedHeaders: map[string]bool{
|
StrippedHeaders: map[string]bool{
|
||||||
"X-Forwarded-User": true,
|
"X-Forwarded-User": true,
|
||||||
|
"X-Forwared-Groups": true,
|
||||||
"X-Forwarded-Email": true,
|
"X-Forwarded-Email": true,
|
||||||
"X-Forwarded-Preferred-Username": true,
|
"X-Forwarded-Preferred-Username": true,
|
||||||
"X-Forwarded-Access-Token": true,
|
"X-Forwarded-Access-Token": true,
|
||||||
|
|
@ -651,6 +685,7 @@ func TestStripAuthHeaders(t *testing.T) {
|
||||||
PassAuthorization: true,
|
PassAuthorization: true,
|
||||||
StrippedHeaders: map[string]bool{
|
StrippedHeaders: map[string]bool{
|
||||||
"X-Forwarded-User": false,
|
"X-Forwarded-User": false,
|
||||||
|
"X-Forwared-Groups": false,
|
||||||
"X-Forwarded-Email": false,
|
"X-Forwarded-Email": false,
|
||||||
"X-Forwarded-Preferred-Username": false,
|
"X-Forwarded-Preferred-Username": false,
|
||||||
"X-Forwarded-Access-Token": false,
|
"X-Forwarded-Access-Token": false,
|
||||||
|
|
@ -665,6 +700,7 @@ func TestStripAuthHeaders(t *testing.T) {
|
||||||
PassAuthorization: false,
|
PassAuthorization: false,
|
||||||
StrippedHeaders: map[string]bool{
|
StrippedHeaders: map[string]bool{
|
||||||
"X-Forwarded-User": false,
|
"X-Forwarded-User": false,
|
||||||
|
"X-Forwared-Groups": false,
|
||||||
"X-Forwarded-Email": false,
|
"X-Forwarded-Email": false,
|
||||||
"X-Forwarded-Preferred-Username": false,
|
"X-Forwarded-Preferred-Username": false,
|
||||||
"X-Forwarded-Access-Token": false,
|
"X-Forwarded-Access-Token": false,
|
||||||
|
|
@ -679,6 +715,7 @@ func TestStripAuthHeaders(t *testing.T) {
|
||||||
PassAuthorization: false,
|
PassAuthorization: false,
|
||||||
StrippedHeaders: map[string]bool{
|
StrippedHeaders: map[string]bool{
|
||||||
"X-Forwarded-User": false,
|
"X-Forwarded-User": false,
|
||||||
|
"X-Forwared-Groups": false,
|
||||||
"X-Forwarded-Email": false,
|
"X-Forwarded-Email": false,
|
||||||
"X-Forwarded-Preferred-Username": false,
|
"X-Forwarded-Preferred-Username": false,
|
||||||
"X-Forwarded-Access-Token": false,
|
"X-Forwarded-Access-Token": false,
|
||||||
|
|
@ -690,6 +727,7 @@ func TestStripAuthHeaders(t *testing.T) {
|
||||||
initialHeaders := map[string]string{
|
initialHeaders := map[string]string{
|
||||||
"X-Forwarded-User": "9fcab5c9b889a557",
|
"X-Forwarded-User": "9fcab5c9b889a557",
|
||||||
"X-Forwarded-Email": "john.doe@example.com",
|
"X-Forwarded-Email": "john.doe@example.com",
|
||||||
|
"X-Forwarded-Groups": "a,b,c",
|
||||||
"X-Forwarded-Preferred-Username": "john.doe",
|
"X-Forwarded-Preferred-Username": "john.doe",
|
||||||
"X-Forwarded-Access-Token": "AccessToken",
|
"X-Forwarded-Access-Token": "AccessToken",
|
||||||
"Authorization": "bearer IDToken",
|
"Authorization": "bearer IDToken",
|
||||||
|
|
@ -1333,6 +1371,7 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
|
||||||
|
|
||||||
pcTest.opts = baseTestOptions()
|
pcTest.opts = baseTestOptions()
|
||||||
pcTest.opts.SetXAuthRequest = true
|
pcTest.opts.SetXAuthRequest = true
|
||||||
|
pcTest.opts.AllowedGroups = []string{"oauth_groups"}
|
||||||
err := validation.Validate(pcTest.opts)
|
err := validation.Validate(pcTest.opts)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
|
@ -1354,13 +1393,14 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
|
||||||
|
|
||||||
created := time.Now()
|
created := time.Now()
|
||||||
startSession := &sessions.SessionState{
|
startSession := &sessions.SessionState{
|
||||||
User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token", CreatedAt: &created}
|
User: "oauth_user", Groups: []string{"oauth_groups"}, Email: "oauth_user@example.com", AccessToken: "oauth_token", CreatedAt: &created}
|
||||||
err = pcTest.SaveSession(startSession)
|
err = pcTest.SaveSession(startSession)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
pcTest.proxy.ServeHTTP(pcTest.rw, pcTest.req)
|
pcTest.proxy.ServeHTTP(pcTest.rw, pcTest.req)
|
||||||
assert.Equal(t, http.StatusAccepted, pcTest.rw.Code)
|
assert.Equal(t, http.StatusAccepted, pcTest.rw.Code)
|
||||||
assert.Equal(t, "oauth_user", pcTest.rw.Header().Get("X-Auth-Request-User"))
|
assert.Equal(t, "oauth_user", pcTest.rw.Header().Get("X-Auth-Request-User"))
|
||||||
|
assert.Equal(t, startSession.Groups, pcTest.rw.Header().Values("X-Auth-Request-Groups"))
|
||||||
assert.Equal(t, "oauth_user@example.com", pcTest.rw.Header().Get("X-Auth-Request-Email"))
|
assert.Equal(t, "oauth_user@example.com", pcTest.rw.Header().Get("X-Auth-Request-Email"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2199,3 +2239,108 @@ func TestTrustedIPs(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProxyAllowedGroups(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
allowedGroups []string
|
||||||
|
groups []string
|
||||||
|
expectUnauthorized bool
|
||||||
|
}{
|
||||||
|
{"NoAllowedGroups", []string{}, []string{}, false},
|
||||||
|
{"NoAllowedGroupsUserHasGroups", []string{}, []string{"a", "b"}, false},
|
||||||
|
{"UserInAllowedGroup", []string{"a"}, []string{"a", "b"}, false},
|
||||||
|
{"UserNotInAllowedGroup", []string{"a"}, []string{"c"}, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
emailAddress := "test"
|
||||||
|
created := time.Now()
|
||||||
|
|
||||||
|
session := &sessions.SessionState{
|
||||||
|
Groups: tt.groups,
|
||||||
|
Email: emailAddress,
|
||||||
|
AccessToken: "oauth_token",
|
||||||
|
CreatedAt: &created,
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(200)
|
||||||
|
}))
|
||||||
|
t.Cleanup(upstream.Close)
|
||||||
|
|
||||||
|
test, err := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
|
||||||
|
opts.AllowedGroups = tt.allowedGroups
|
||||||
|
opts.UpstreamServers = options.Upstreams{
|
||||||
|
{
|
||||||
|
ID: upstream.URL,
|
||||||
|
Path: "/",
|
||||||
|
URI: upstream.URL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
test.req, _ = http.NewRequest("GET", "/", nil)
|
||||||
|
|
||||||
|
test.req.Header.Add("accept", applicationJSON)
|
||||||
|
test.SaveSession(session)
|
||||||
|
test.proxy.ServeHTTP(test.rw, test.req)
|
||||||
|
|
||||||
|
if tt.expectUnauthorized {
|
||||||
|
assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, http.StatusOK, test.rw.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuthOnlyAllowedGroups(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
allowedGroups []string
|
||||||
|
groups []string
|
||||||
|
expectUnauthorized bool
|
||||||
|
}{
|
||||||
|
{"NoAllowedGroups", []string{}, []string{}, false},
|
||||||
|
{"NoAllowedGroupsUserHasGroups", []string{}, []string{"a", "b"}, false},
|
||||||
|
{"UserInAllowedGroup", []string{"a"}, []string{"a", "b"}, false},
|
||||||
|
{"UserNotInAllowedGroup", []string{"a"}, []string{"c"}, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
emailAddress := "test"
|
||||||
|
created := time.Now()
|
||||||
|
|
||||||
|
session := &sessions.SessionState{
|
||||||
|
Groups: tt.groups,
|
||||||
|
Email: emailAddress,
|
||||||
|
AccessToken: "oauth_token",
|
||||||
|
CreatedAt: &created,
|
||||||
|
}
|
||||||
|
|
||||||
|
test, err := NewAuthOnlyEndpointTest(func(opts *options.Options) {
|
||||||
|
opts.AllowedGroups = tt.allowedGroups
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = test.SaveSession(session)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
test.proxy.ServeHTTP(test.rw, test.req)
|
||||||
|
|
||||||
|
if tt.expectUnauthorized {
|
||||||
|
assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, http.StatusAccepted, test.rw.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequestScope contains information regarding the request that is being made.
|
// RequestScope contains information regarding the request that is being made.
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TokenToSessionFunc takes a rawIDToken and an idToken and converts it into a
|
// TokenToSessionFunc takes a rawIDToken and an idToken and converts it into a
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package options
|
package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
oidc "github.com/coreos/go-oidc"
|
oidc "github.com/coreos/go-oidc"
|
||||||
ipapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/ip"
|
ipapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/ip"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/providers"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -93,6 +93,7 @@ type Options struct {
|
||||||
InsecureOIDCSkipIssuerVerification bool `flag:"insecure-oidc-skip-issuer-verification" cfg:"insecure_oidc_skip_issuer_verification"`
|
InsecureOIDCSkipIssuerVerification bool `flag:"insecure-oidc-skip-issuer-verification" cfg:"insecure_oidc_skip_issuer_verification"`
|
||||||
SkipOIDCDiscovery bool `flag:"skip-oidc-discovery" cfg:"skip_oidc_discovery"`
|
SkipOIDCDiscovery bool `flag:"skip-oidc-discovery" cfg:"skip_oidc_discovery"`
|
||||||
OIDCJwksURL string `flag:"oidc-jwks-url" cfg:"oidc_jwks_url"`
|
OIDCJwksURL string `flag:"oidc-jwks-url" cfg:"oidc_jwks_url"`
|
||||||
|
OIDCGroupsClaim string `flag:"oidc-groups-claim" cfg:"oidc_groups_claim"`
|
||||||
LoginURL string `flag:"login-url" cfg:"login_url"`
|
LoginURL string `flag:"login-url" cfg:"login_url"`
|
||||||
RedeemURL string `flag:"redeem-url" cfg:"redeem_url"`
|
RedeemURL string `flag:"redeem-url" cfg:"redeem_url"`
|
||||||
ProfileURL string `flag:"profile-url" cfg:"profile_url"`
|
ProfileURL string `flag:"profile-url" cfg:"profile_url"`
|
||||||
|
|
@ -102,6 +103,7 @@ type Options struct {
|
||||||
Prompt string `flag:"prompt" cfg:"prompt"`
|
Prompt string `flag:"prompt" cfg:"prompt"`
|
||||||
ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt"` // Deprecated by OIDC 1.0
|
ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt"` // Deprecated by OIDC 1.0
|
||||||
UserIDClaim string `flag:"user-id-claim" cfg:"user_id_claim"`
|
UserIDClaim string `flag:"user-id-claim" cfg:"user_id_claim"`
|
||||||
|
AllowedGroups []string `flag:"allowed-group" cfg:"allowed_groups"`
|
||||||
|
|
||||||
SignatureKey string `flag:"signature-key" cfg:"signature_key"`
|
SignatureKey string `flag:"signature-key" cfg:"signature_key"`
|
||||||
AcrValues string `flag:"acr-values" cfg:"acr_values"`
|
AcrValues string `flag:"acr-values" cfg:"acr_values"`
|
||||||
|
|
@ -167,6 +169,7 @@ func NewOptions() *Options {
|
||||||
InsecureOIDCAllowUnverifiedEmail: false,
|
InsecureOIDCAllowUnverifiedEmail: false,
|
||||||
SkipOIDCDiscovery: false,
|
SkipOIDCDiscovery: false,
|
||||||
Logging: loggingDefaults(),
|
Logging: loggingDefaults(),
|
||||||
|
OIDCGroupsClaim: "groups",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,6 +251,7 @@ func NewFlagSet() *pflag.FlagSet {
|
||||||
flagSet.Bool("insecure-oidc-skip-issuer-verification", false, "Do not verify if issuer matches OIDC discovery URL")
|
flagSet.Bool("insecure-oidc-skip-issuer-verification", false, "Do not verify if issuer matches OIDC discovery URL")
|
||||||
flagSet.Bool("skip-oidc-discovery", false, "Skip OIDC discovery and use manually supplied Endpoints")
|
flagSet.Bool("skip-oidc-discovery", false, "Skip OIDC discovery and use manually supplied Endpoints")
|
||||||
flagSet.String("oidc-jwks-url", "", "OpenID Connect JWKS URL (ie: https://www.googleapis.com/oauth2/v3/certs)")
|
flagSet.String("oidc-jwks-url", "", "OpenID Connect JWKS URL (ie: https://www.googleapis.com/oauth2/v3/certs)")
|
||||||
|
flagSet.String("oidc-groups-claim", "groups", "which claim contains the user groups")
|
||||||
flagSet.String("login-url", "", "Authentication endpoint")
|
flagSet.String("login-url", "", "Authentication endpoint")
|
||||||
flagSet.String("redeem-url", "", "Token redemption endpoint")
|
flagSet.String("redeem-url", "", "Token redemption endpoint")
|
||||||
flagSet.String("profile-url", "", "Profile access endpoint")
|
flagSet.String("profile-url", "", "Profile access endpoint")
|
||||||
|
|
@ -265,6 +269,7 @@ func NewFlagSet() *pflag.FlagSet {
|
||||||
flagSet.Bool("gcp-healthchecks", false, "Enable GCP/GKE healthcheck endpoints")
|
flagSet.Bool("gcp-healthchecks", false, "Enable GCP/GKE healthcheck endpoints")
|
||||||
|
|
||||||
flagSet.String("user-id-claim", "email", "which claim contains the user ID")
|
flagSet.String("user-id-claim", "email", "which claim contains the user ID")
|
||||||
|
flagSet.StringSlice("allowed-group", []string{}, "restrict logins to members of this group (may be given multiple times)")
|
||||||
|
|
||||||
flagSet.AddFlagSet(cookieFlagSet())
|
flagSet.AddFlagSet(cookieFlagSet())
|
||||||
flagSet.AddFlagSet(loggingFlagSet())
|
flagSet.AddFlagSet(loggingFlagSet())
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package options
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
"github.com/pierrec/lz4"
|
"github.com/pierrec/lz4"
|
||||||
"github.com/vmihailenco/msgpack/v4"
|
"github.com/vmihailenco/msgpack/v4"
|
||||||
)
|
)
|
||||||
|
|
@ -24,6 +25,7 @@ type SessionState struct {
|
||||||
RefreshToken string `json:",omitempty" msgpack:"rt,omitempty"`
|
RefreshToken string `json:",omitempty" msgpack:"rt,omitempty"`
|
||||||
Email string `json:",omitempty" msgpack:"e,omitempty"`
|
Email string `json:",omitempty" msgpack:"e,omitempty"`
|
||||||
User string `json:",omitempty" msgpack:"u,omitempty"`
|
User string `json:",omitempty" msgpack:"u,omitempty"`
|
||||||
|
Groups []string `json:",omitempty" msgpack:"g,omitempty"`
|
||||||
PreferredUsername string `json:",omitempty" msgpack:"pu,omitempty"`
|
PreferredUsername string `json:",omitempty" msgpack:"pu,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,6 +63,9 @@ func (s *SessionState) String() string {
|
||||||
if s.RefreshToken != "" {
|
if s.RefreshToken != "" {
|
||||||
o += " refresh_token:true"
|
o += " refresh_token:true"
|
||||||
}
|
}
|
||||||
|
if len(s.Groups) > 0 {
|
||||||
|
o += fmt.Sprintf(" groups:%v", s.Groups)
|
||||||
|
}
|
||||||
return o + "}"
|
return o + "}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +238,7 @@ func (s *SessionState) validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
empty := new(SessionState)
|
empty := new(SessionState)
|
||||||
if *s == *empty {
|
if reflect.DeepEqual(*s, *empty) {
|
||||||
return errors.New("invalid empty session unmarshalled")
|
return errors.New("invalid empty session unmarshalled")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
@ -186,6 +186,17 @@ func TestEncodeAndDecodeSessionState(t *testing.T) {
|
||||||
IDToken: "IDToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
|
IDToken: "IDToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
|
||||||
ExpiresOn: &expires,
|
ExpiresOn: &expires,
|
||||||
},
|
},
|
||||||
|
"With groups": {
|
||||||
|
Email: "username@example.com",
|
||||||
|
User: "username",
|
||||||
|
PreferredUsername: "preferred.username",
|
||||||
|
AccessToken: "AccessToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
|
||||||
|
IDToken: "IDToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
|
||||||
|
CreatedAt: &created,
|
||||||
|
ExpiresOn: &expires,
|
||||||
|
RefreshToken: "RefreshToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
|
||||||
|
Groups: []string{"group-a", "group-b"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, secretSize := range []int{16, 24, 32} {
|
for _, secretSize := range []int{16, 24, 32} {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package basic
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/util"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeCookie constructs a cookie from the given parameters,
|
// MakeCookie constructs a cookie from the given parameters,
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ package encryption
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
// TODO (@NickMeves): Remove SHA1 signed cookie support in V7
|
|
||||||
"crypto/sha1" // #nosec G505
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -95,16 +93,7 @@ func checkSignature(signature string, args ...string) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if checkHmac(signature, checkSig) {
|
return checkHmac(signature, checkSig)
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (@NickMeves): Remove SHA1 signed cookie support in V7
|
|
||||||
legacySig, err := cookieSignature(sha1.New, args...)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return checkHmac(signature, legacySig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkHmac(input, expected string) bool {
|
func checkHmac(input, expected string) bool {
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,8 @@ func TestSignAndValidate(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.True(t, checkSignature(sha256sig, seed, key, value, epoch))
|
assert.True(t, checkSignature(sha256sig, seed, key, value, epoch))
|
||||||
// This should be switched to False after fully deprecating SHA1
|
// We don't validate legacy SHA1 signatures anymore
|
||||||
assert.True(t, checkSignature(sha1sig, seed, key, value, epoch))
|
assert.False(t, checkSignature(sha1sig, seed, key, value, epoch))
|
||||||
|
|
||||||
assert.False(t, checkSignature(sha256sig, seed, key, "tampered", epoch))
|
assert.False(t, checkSignature(sha256sig, seed, key, "tampered", epoch))
|
||||||
assert.False(t, checkSignature(sha1sig, seed, key, "tampered", epoch))
|
assert.False(t, checkSignature(sha1sig, seed, key, "tampered", epoch))
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
ipapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/ip"
|
ipapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/ip"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetRealClientIPParser(headerKey string) (ipapi.RealClientIPParser, error) {
|
func GetRealClientIPParser(headerKey string) (ipapi.RealClientIPParser, error) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
ipapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/ip"
|
ipapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/ip"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/util"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthStatus defines the different types of auth logging that occur
|
// AuthStatus defines the different types of auth logging that occur
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/justinas/alice"
|
"github.com/justinas/alice"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/authentication/basic"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/authentication/basic"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewBasicAuthSessionLoader(validator basic.Validator) alice.Constructor {
|
func NewBasicAuthSessionLoader(validator basic.Validator) alice.Constructor {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
|
||||||
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/middleware"
|
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/ginkgo/extensions/table"
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ import (
|
||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/justinas/alice"
|
"github.com/justinas/alice"
|
||||||
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/middleware"
|
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
const jwtRegexFormat = `^eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]+$`
|
const jwtRegexFormat = `^eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]+$`
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ import (
|
||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/middleware"
|
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/ginkgo/extensions/table"
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/justinas/alice"
|
"github.com/justinas/alice"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/util"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const httpsScheme = "https"
|
const httpsScheme = "https"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/justinas/alice"
|
"github.com/justinas/alice"
|
||||||
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/middleware"
|
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
type scopeKey string
|
type scopeKey string
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
|
||||||
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/middleware"
|
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/justinas/alice"
|
"github.com/justinas/alice"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StoredSessionLoaderOptions cotnains all of the requirements to construct
|
// StoredSessionLoaderOptions cotnains all of the requirements to construct
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/middleware"
|
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/ginkgo/extensions/table"
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
pkgcookies "github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
|
pkgcookies "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/cookies"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/tests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/tests"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Manager wraps a Store and handles the implementation details of the
|
// Manager wraps a Store and handles the implementation details of the
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ package persistence
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/tests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/tests"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package persistence
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/cookies"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
)
|
)
|
||||||
|
|
||||||
// saveFunc performs a persistent store's save functionality using
|
// saveFunc performs a persistent store's save functionality using
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/ginkgo/extensions/table"
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v7"
|
"github.com/go-redis/redis/v7"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/persistence"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/persistence"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SessionStore is an implementation of the persistence.Store
|
// SessionStore is an implementation of the persistence.Store
|
||||||
|
|
@ -23,7 +23,7 @@ type SessionStore struct {
|
||||||
// NewRedisSessionStore initialises a new instance of the SessionStore and wraps
|
// NewRedisSessionStore initialises a new instance of the SessionStore and wraps
|
||||||
// it in a persistence.Manager
|
// it in a persistence.Manager
|
||||||
func NewRedisSessionStore(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessions.SessionStore, error) {
|
func NewRedisSessionStore(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessions.SessionStore, error) {
|
||||||
client, err := newRedisClient(opts.Redis)
|
client, err := NewRedisClient(opts.Redis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error constructing redis client: %v", err)
|
return nil, fmt.Errorf("error constructing redis client: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -64,9 +64,9 @@ func (store *SessionStore) Clear(ctx context.Context, key string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newRedisClient makes a redis.Client (either standalone, sentinel aware, or
|
// NewRedisClient makes a redis.Client (either standalone, sentinel aware, or
|
||||||
// redis cluster)
|
// redis cluster)
|
||||||
func newRedisClient(opts options.RedisStoreOptions) (Client, error) {
|
func NewRedisClient(opts options.RedisStoreOptions) (Client, error) {
|
||||||
if opts.UseSentinel && opts.UseCluster {
|
if opts.UseSentinel && opts.UseCluster {
|
||||||
return nil, fmt.Errorf("options redis-use-sentinel and redis-use-cluster are mutually exclusive")
|
return nil, fmt.Errorf("options redis-use-sentinel and redis-use-cluster are mutually exclusive")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ import (
|
||||||
"github.com/Bose/minisentinel"
|
"github.com/Bose/minisentinel"
|
||||||
"github.com/alicebob/miniredis/v2"
|
"github.com/alicebob/miniredis/v2"
|
||||||
"github.com/go-redis/redis/v7"
|
"github.com/go-redis/redis/v7"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/persistence"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/persistence"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/tests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/tests"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ package sessions
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/cookie"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/cookie"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/redis"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewSessionStore creates a SessionStore from the provided configuration
|
// NewSessionStore creates a SessionStore from the provided configuration
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions"
|
||||||
sessionscookie "github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/cookie"
|
sessionscookie "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/cookie"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/persistence"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/persistence"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/redis"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/redis"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
cookiesapi "github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
|
cookiesapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/cookies"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mbland/hmacauth"
|
"github.com/mbland/hmacauth"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/yhat/wsutil"
|
"github.com/yhat/wsutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/ginkgo/extensions/table"
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProxyErrorHandler is a function that will be used to render error pages when
|
// ProxyErrorHandler is a function that will be used to render error pages when
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/ginkgo/extensions/table"
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
)
|
)
|
||||||
|
|
||||||
func validateCookie(o options.Cookie) []string {
|
func validateCookie(o options.Cookie) []string {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package validation
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"gopkg.in/natefinch/lumberjack.v2"
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,12 @@ import (
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/mbland/hmacauth"
|
"github.com/mbland/hmacauth"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/ip"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/util"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/providers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validate checks that required options are set and validates those that they
|
// Validate checks that required options are set and validates those that they
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
func Validate(o *options.Options) error {
|
func Validate(o *options.Options) error {
|
||||||
msgs := validateCookie(o.Cookie)
|
msgs := validateCookie(o.Cookie)
|
||||||
msgs = append(msgs, validateSessionCookieMinimal(o)...)
|
msgs = append(msgs, validateSessionCookieMinimal(o)...)
|
||||||
|
msgs = append(msgs, validateRedisSessionStore(o)...)
|
||||||
|
|
||||||
if o.SSLInsecureSkipVerify {
|
if o.SSLInsecureSkipVerify {
|
||||||
// InsecureSkipVerify is a configurable option we allow
|
// InsecureSkipVerify is a configurable option we allow
|
||||||
|
|
@ -152,6 +153,10 @@ func Validate(o *options.Options) error {
|
||||||
}
|
}
|
||||||
if o.Scope == "" {
|
if o.Scope == "" {
|
||||||
o.Scope = "openid email profile"
|
o.Scope = "openid email profile"
|
||||||
|
|
||||||
|
if len(o.AllowedGroups) > 0 {
|
||||||
|
o.Scope += " groups"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,6 +284,7 @@ func parseProviderInfo(o *options.Options, msgs []string) []string {
|
||||||
case *providers.OIDCProvider:
|
case *providers.OIDCProvider:
|
||||||
p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
|
p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
|
||||||
p.UserIDClaim = o.UserIDClaim
|
p.UserIDClaim = o.UserIDClaim
|
||||||
|
p.GroupsClaim = o.OIDCGroupsClaim
|
||||||
if o.GetOIDCVerifier() == nil {
|
if o.GetOIDCVerifier() == nil {
|
||||||
msgs = append(msgs, "oidc provider requires an oidc issuer URL")
|
msgs = append(msgs, "oidc provider requires an oidc issuer URL")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
func validateSessionCookieMinimal(o *options.Options) []string {
|
func validateSessionCookieMinimal(o *options.Options) []string {
|
||||||
|
|
@ -30,3 +34,50 @@ func validateSessionCookieMinimal(o *options.Options) []string {
|
||||||
}
|
}
|
||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateRedisSessionStore builds a Redis Client from the options and
|
||||||
|
// attempts to connect, Set, Get and Del a random health check key
|
||||||
|
func validateRedisSessionStore(o *options.Options) []string {
|
||||||
|
if o.Session.Type != options.RedisSessionStoreType {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := redis.NewRedisClient(o.Session.Redis)
|
||||||
|
if err != nil {
|
||||||
|
return []string{fmt.Sprintf("unable to initialize a redis client: %v", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce, err := encryption.Nonce()
|
||||||
|
if err != nil {
|
||||||
|
return []string{fmt.Sprintf("unable to generate a redis initialization test key: %v", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
key := fmt.Sprintf("%s-healthcheck-%s", o.Cookie.Name, nonce)
|
||||||
|
return sendRedisConnectionTest(client, key, nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendRedisConnectionTest(client redis.Client, key string, val string) []string {
|
||||||
|
msgs := []string{}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
err := client.Set(ctx, key, []byte(val), time.Duration(60)*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
msgs = append(msgs, fmt.Sprintf("unable to set a redis initialization key: %v", err))
|
||||||
|
} else {
|
||||||
|
gval, err := client.Get(ctx, key)
|
||||||
|
if err != nil {
|
||||||
|
msgs = append(msgs,
|
||||||
|
fmt.Sprintf("unable to retrieve redis initialization key: %v", err))
|
||||||
|
}
|
||||||
|
if string(gval) != val {
|
||||||
|
msgs = append(msgs,
|
||||||
|
"the retrieved redis initialization key did not match the value we set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.Del(ctx, key)
|
||||||
|
if err != nil {
|
||||||
|
msgs = append(msgs, fmt.Sprintf("unable to delete the redis initialization key: %v", err))
|
||||||
|
}
|
||||||
|
return msgs
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/Bose/minisentinel"
|
||||||
|
"github.com/alicebob/miniredis/v2"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_validateSessionCookieMinimal(t *testing.T) {
|
var _ = Describe("Sessions", func() {
|
||||||
const (
|
const (
|
||||||
passAuthorizationMsg = "pass_authorization_header requires oauth tokens in sessions. session_cookie_minimal cannot be set"
|
passAuthorizationMsg = "pass_authorization_header requires oauth tokens in sessions. session_cookie_minimal cannot be set"
|
||||||
setAuthorizationMsg = "set_authorization_header requires oauth tokens in sessions. session_cookie_minimal cannot be set"
|
setAuthorizationMsg = "set_authorization_header requires oauth tokens in sessions. session_cookie_minimal cannot be set"
|
||||||
|
|
@ -16,11 +19,16 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
cookieRefreshMsg = "cookie_refresh > 0 requires oauth tokens in sessions. session_cookie_minimal cannot be set"
|
cookieRefreshMsg = "cookie_refresh > 0 requires oauth tokens in sessions. session_cookie_minimal cannot be set"
|
||||||
)
|
)
|
||||||
|
|
||||||
testCases := map[string]struct {
|
type cookieMinimalTableInput struct {
|
||||||
opts *options.Options
|
opts *options.Options
|
||||||
errStrings []string
|
errStrings []string
|
||||||
}{
|
}
|
||||||
"No minimal cookie session": {
|
|
||||||
|
DescribeTable("validateSessionCookieMinimal",
|
||||||
|
func(o *cookieMinimalTableInput) {
|
||||||
|
Expect(validateSessionCookieMinimal(o.opts)).To(ConsistOf(o.errStrings))
|
||||||
|
},
|
||||||
|
Entry("No minimal cookie session", &cookieMinimalTableInput{
|
||||||
opts: &options.Options{
|
opts: &options.Options{
|
||||||
Session: options.SessionOptions{
|
Session: options.SessionOptions{
|
||||||
Cookie: options.CookieStoreOptions{
|
Cookie: options.CookieStoreOptions{
|
||||||
|
|
@ -29,8 +37,8 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errStrings: []string{},
|
errStrings: []string{},
|
||||||
},
|
}),
|
||||||
"No minimal cookie session & passAuthorization": {
|
Entry("No minimal cookie session & passAuthorization", &cookieMinimalTableInput{
|
||||||
opts: &options.Options{
|
opts: &options.Options{
|
||||||
Session: options.SessionOptions{
|
Session: options.SessionOptions{
|
||||||
Cookie: options.CookieStoreOptions{
|
Cookie: options.CookieStoreOptions{
|
||||||
|
|
@ -40,8 +48,8 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
PassAuthorization: true,
|
PassAuthorization: true,
|
||||||
},
|
},
|
||||||
errStrings: []string{},
|
errStrings: []string{},
|
||||||
},
|
}),
|
||||||
"Minimal cookie session no conflicts": {
|
Entry("Minimal cookie session no conflicts", &cookieMinimalTableInput{
|
||||||
opts: &options.Options{
|
opts: &options.Options{
|
||||||
Session: options.SessionOptions{
|
Session: options.SessionOptions{
|
||||||
Cookie: options.CookieStoreOptions{
|
Cookie: options.CookieStoreOptions{
|
||||||
|
|
@ -50,8 +58,8 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errStrings: []string{},
|
errStrings: []string{},
|
||||||
},
|
}),
|
||||||
"PassAuthorization conflict": {
|
Entry("PassAuthorization conflict", &cookieMinimalTableInput{
|
||||||
opts: &options.Options{
|
opts: &options.Options{
|
||||||
Session: options.SessionOptions{
|
Session: options.SessionOptions{
|
||||||
Cookie: options.CookieStoreOptions{
|
Cookie: options.CookieStoreOptions{
|
||||||
|
|
@ -61,8 +69,8 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
PassAuthorization: true,
|
PassAuthorization: true,
|
||||||
},
|
},
|
||||||
errStrings: []string{passAuthorizationMsg},
|
errStrings: []string{passAuthorizationMsg},
|
||||||
},
|
}),
|
||||||
"SetAuthorization conflict": {
|
Entry("SetAuthorization conflict", &cookieMinimalTableInput{
|
||||||
opts: &options.Options{
|
opts: &options.Options{
|
||||||
Session: options.SessionOptions{
|
Session: options.SessionOptions{
|
||||||
Cookie: options.CookieStoreOptions{
|
Cookie: options.CookieStoreOptions{
|
||||||
|
|
@ -72,8 +80,8 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
SetAuthorization: true,
|
SetAuthorization: true,
|
||||||
},
|
},
|
||||||
errStrings: []string{setAuthorizationMsg},
|
errStrings: []string{setAuthorizationMsg},
|
||||||
},
|
}),
|
||||||
"PassAccessToken conflict": {
|
Entry("PassAccessToken conflict", &cookieMinimalTableInput{
|
||||||
opts: &options.Options{
|
opts: &options.Options{
|
||||||
Session: options.SessionOptions{
|
Session: options.SessionOptions{
|
||||||
Cookie: options.CookieStoreOptions{
|
Cookie: options.CookieStoreOptions{
|
||||||
|
|
@ -83,8 +91,8 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
PassAccessToken: true,
|
PassAccessToken: true,
|
||||||
},
|
},
|
||||||
errStrings: []string{passAccessTokenMsg},
|
errStrings: []string{passAccessTokenMsg},
|
||||||
},
|
}),
|
||||||
"CookieRefresh conflict": {
|
Entry("CookieRefresh conflict", &cookieMinimalTableInput{
|
||||||
opts: &options.Options{
|
opts: &options.Options{
|
||||||
Cookie: options.Cookie{
|
Cookie: options.Cookie{
|
||||||
Refresh: time.Hour,
|
Refresh: time.Hour,
|
||||||
|
|
@ -96,8 +104,8 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errStrings: []string{cookieRefreshMsg},
|
errStrings: []string{cookieRefreshMsg},
|
||||||
},
|
}),
|
||||||
"Multiple conflicts": {
|
Entry("Multiple conflicts", &cookieMinimalTableInput{
|
||||||
opts: &options.Options{
|
opts: &options.Options{
|
||||||
Session: options.SessionOptions{
|
Session: options.SessionOptions{
|
||||||
Cookie: options.CookieStoreOptions{
|
Cookie: options.CookieStoreOptions{
|
||||||
|
|
@ -108,14 +116,228 @@ func Test_validateSessionCookieMinimal(t *testing.T) {
|
||||||
PassAccessToken: true,
|
PassAccessToken: true,
|
||||||
},
|
},
|
||||||
errStrings: []string{passAuthorizationMsg, passAccessTokenMsg},
|
errStrings: []string{passAuthorizationMsg, passAccessTokenMsg},
|
||||||
},
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
clusterAndSentinelMsg = "unable to initialize a redis client: options redis-use-sentinel and redis-use-cluster are mutually exclusive"
|
||||||
|
parseWrongSchemeMsg = "unable to initialize a redis client: unable to parse redis url: invalid redis URL scheme: https"
|
||||||
|
parseWrongFormatMsg = "unable to initialize a redis client: unable to parse redis url: invalid redis database number: \"wrong\""
|
||||||
|
invalidPasswordSetMsg = "unable to set a redis initialization key: WRONGPASS invalid username-password pair"
|
||||||
|
invalidPasswordDelMsg = "unable to delete the redis initialization key: WRONGPASS invalid username-password pair"
|
||||||
|
unreachableRedisSetMsg = "unable to set a redis initialization key: dial tcp 127.0.0.1:65535: connect: connection refused"
|
||||||
|
unreachableRedisDelMsg = "unable to delete the redis initialization key: dial tcp 127.0.0.1:65535: connect: connection refused"
|
||||||
|
unreachableSentinelSetMsg = "unable to set a redis initialization key: redis: all sentinels are unreachable"
|
||||||
|
unrechableSentinelDelMsg = "unable to delete the redis initialization key: redis: all sentinels are unreachable"
|
||||||
|
)
|
||||||
|
|
||||||
|
type redisStoreTableInput struct {
|
||||||
|
// miniredis setup details
|
||||||
|
password string
|
||||||
|
useSentinel bool
|
||||||
|
setAddr bool
|
||||||
|
setSentinelAddr bool
|
||||||
|
setMasterName bool
|
||||||
|
|
||||||
|
opts *options.Options
|
||||||
|
errStrings []string
|
||||||
}
|
}
|
||||||
|
|
||||||
for testName, tc := range testCases {
|
DescribeTable("validateRedisSessionStore",
|
||||||
t.Run(testName, func(t *testing.T) {
|
func(o *redisStoreTableInput) {
|
||||||
errStrings := validateSessionCookieMinimal(tc.opts)
|
mr, err := miniredis.Run()
|
||||||
g := NewWithT(t)
|
Expect(err).ToNot(HaveOccurred())
|
||||||
g.Expect(errStrings).To(ConsistOf(tc.errStrings))
|
mr.RequireAuth(o.password)
|
||||||
})
|
defer mr.Close()
|
||||||
}
|
|
||||||
}
|
if o.setAddr && !o.useSentinel {
|
||||||
|
o.opts.Session.Redis.ConnectionURL = "redis://" + mr.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.useSentinel {
|
||||||
|
ms := minisentinel.NewSentinel(mr)
|
||||||
|
Expect(ms.Start()).To(Succeed())
|
||||||
|
defer ms.Close()
|
||||||
|
|
||||||
|
if o.setSentinelAddr {
|
||||||
|
o.opts.Session.Redis.SentinelConnectionURLs = []string{"redis://" + ms.Addr()}
|
||||||
|
}
|
||||||
|
if o.setMasterName {
|
||||||
|
o.opts.Session.Redis.SentinelMasterName = ms.MasterInfo().Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Expect(validateRedisSessionStore(o.opts)).To(ConsistOf(o.errStrings))
|
||||||
|
},
|
||||||
|
Entry("cookie sessions are skipped", &redisStoreTableInput{
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.CookieSessionStoreType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{},
|
||||||
|
}),
|
||||||
|
Entry("connect successfully to pure redis", &redisStoreTableInput{
|
||||||
|
setAddr: true,
|
||||||
|
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{},
|
||||||
|
}),
|
||||||
|
Entry("failed redis connection with wrong address", &redisStoreTableInput{
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
ConnectionURL: "redis://127.0.0.1:65535",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{unreachableRedisSetMsg, unreachableRedisDelMsg},
|
||||||
|
}),
|
||||||
|
Entry("fail to parse an invalid connection URL with wrong scheme", &redisStoreTableInput{
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
ConnectionURL: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{parseWrongSchemeMsg},
|
||||||
|
}),
|
||||||
|
Entry("fail to parse an invalid connection URL with invalid format", &redisStoreTableInput{
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
ConnectionURL: "redis://127.0.0.1:6379/wrong",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{parseWrongFormatMsg},
|
||||||
|
}),
|
||||||
|
Entry("connect successfully to pure redis with password", &redisStoreTableInput{
|
||||||
|
password: "abcdef123",
|
||||||
|
setAddr: true,
|
||||||
|
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
Password: "abcdef123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{},
|
||||||
|
}),
|
||||||
|
Entry("failed connection with wrong password", &redisStoreTableInput{
|
||||||
|
password: "abcdef123",
|
||||||
|
setAddr: true,
|
||||||
|
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
Password: "zyxwtuv987",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{invalidPasswordSetMsg, invalidPasswordDelMsg},
|
||||||
|
}),
|
||||||
|
Entry("connect successfully to sentinel redis", &redisStoreTableInput{
|
||||||
|
useSentinel: true,
|
||||||
|
setSentinelAddr: true,
|
||||||
|
setMasterName: true,
|
||||||
|
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
UseSentinel: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{},
|
||||||
|
}),
|
||||||
|
Entry("connect successfully to sentinel redis with password", &redisStoreTableInput{
|
||||||
|
password: "abcdef123",
|
||||||
|
useSentinel: true,
|
||||||
|
setSentinelAddr: true,
|
||||||
|
setMasterName: true,
|
||||||
|
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
Password: "abcdef123",
|
||||||
|
UseSentinel: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{},
|
||||||
|
}),
|
||||||
|
Entry("failed connection to sentinel redis with wrong password", &redisStoreTableInput{
|
||||||
|
password: "abcdef123",
|
||||||
|
useSentinel: true,
|
||||||
|
setSentinelAddr: true,
|
||||||
|
setMasterName: true,
|
||||||
|
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
Password: "zyxwtuv987",
|
||||||
|
UseSentinel: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{invalidPasswordSetMsg, invalidPasswordDelMsg},
|
||||||
|
}),
|
||||||
|
Entry("failed connection to sentinel redis with wrong master name", &redisStoreTableInput{
|
||||||
|
useSentinel: true,
|
||||||
|
setSentinelAddr: true,
|
||||||
|
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
UseSentinel: true,
|
||||||
|
SentinelMasterName: "WRONG",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{unreachableSentinelSetMsg, unrechableSentinelDelMsg},
|
||||||
|
}),
|
||||||
|
Entry("failed connection to sentinel redis with wrong address", &redisStoreTableInput{
|
||||||
|
useSentinel: true,
|
||||||
|
setMasterName: true,
|
||||||
|
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
UseSentinel: true,
|
||||||
|
SentinelConnectionURLs: []string{"redis://127.0.0.1:65535"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{unreachableSentinelSetMsg, unrechableSentinelDelMsg},
|
||||||
|
}),
|
||||||
|
Entry("sentinel and cluster both enabled fails", &redisStoreTableInput{
|
||||||
|
opts: &options.Options{
|
||||||
|
Session: options.SessionOptions{
|
||||||
|
Type: options.RedisSessionStoreType,
|
||||||
|
Redis: options.RedisStoreOptions{
|
||||||
|
UseSentinel: true,
|
||||||
|
UseCluster: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errStrings: []string{clusterAndSentinelMsg},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
func validateUpstreams(upstreams options.Upstreams) []string {
|
func validateUpstreams(upstreams options.Upstreams) []string {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package validation
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/ginkgo/extensions/table"
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package validation
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
var authorizedAccessToken = "imaginary_access_token"
|
var authorizedAccessToken = "imaginary_access_token"
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bitly/go-simplejson"
|
"github.com/bitly/go-simplejson"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AzureProvider represents an Azure based Identity Provider
|
// AzureProvider represents an Azure based Identity Provider
|
||||||
|
|
@ -210,3 +210,12 @@ func (p *AzureProvider) GetEmailAddress(ctx context.Context, s *sessions.Session
|
||||||
|
|
||||||
return email, err
|
return email, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *AzureProvider) GetLoginURL(redirectURI, state string) string {
|
||||||
|
extraParams := url.Values{}
|
||||||
|
if p.ProtectedResource != nil && p.ProtectedResource.String() != "" {
|
||||||
|
extraParams.Add("resource", p.ProtectedResource.String())
|
||||||
|
}
|
||||||
|
a := makeLoginURL(p.ProviderData, redirectURI, state, extraParams)
|
||||||
|
return a.String()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -213,3 +213,10 @@ func TestAzureProviderRedeemReturnsIdToken(t *testing.T) {
|
||||||
assert.Equal(t, timestamp, s.ExpiresOn.UTC())
|
assert.Equal(t, timestamp, s.ExpiresOn.UTC())
|
||||||
assert.Equal(t, "refresh1234", s.RefreshToken)
|
assert.Equal(t, "refresh1234", s.RefreshToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAzureProviderProtectedResourceConfigured(t *testing.T) {
|
||||||
|
p := testAzureProvider("")
|
||||||
|
p.ProtectedResource, _ = url.Parse("http://my.resource.test")
|
||||||
|
result := p.GetLoginURL("https://my.test.app/oauth", "")
|
||||||
|
assert.Contains(t, result, "resource="+url.QueryEscape("http://my.resource.test"))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BitbucketProvider represents an Bitbucket based Identity Provider
|
// BitbucketProvider represents an Bitbucket based Identity Provider
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DigitalOceanProvider represents a DigitalOcean based Identity Provider
|
// DigitalOceanProvider represents a DigitalOcean based Identity Provider
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FacebookProvider represents an Facebook based Identity Provider
|
// FacebookProvider represents an Facebook based Identity Provider
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitHubProvider represents an GitHub based Identity Provider
|
// GitHubProvider represents an GitHub based Identity Provider
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
oidc "github.com/coreos/go-oidc"
|
oidc "github.com/coreos/go-oidc"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
"golang.org/x/oauth2/google"
|
"golang.org/x/oauth2/google"
|
||||||
admin "google.golang.org/api/admin/directory/v1"
|
admin "google.golang.org/api/admin/directory/v1"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
// stripToken is a helper function to obfuscate "access_token"
|
// stripToken is a helper function to obfuscate "access_token"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
type KeycloakProvider struct {
|
type KeycloakProvider struct {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LinkedInProvider represents an LinkedIn based Identity Provider
|
// LinkedInProvider represents an LinkedIn based Identity Provider
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
"gopkg.in/square/go-jose.v2"
|
"gopkg.in/square/go-jose.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -225,20 +225,12 @@ func (p *LoginGovProvider) Redeem(ctx context.Context, redirectURL, code string)
|
||||||
|
|
||||||
// GetLoginURL overrides GetLoginURL to add login.gov parameters
|
// GetLoginURL overrides GetLoginURL to add login.gov parameters
|
||||||
func (p *LoginGovProvider) GetLoginURL(redirectURI, state string) string {
|
func (p *LoginGovProvider) GetLoginURL(redirectURI, state string) string {
|
||||||
a := *p.LoginURL
|
extraParams := url.Values{}
|
||||||
params, _ := url.ParseQuery(a.RawQuery)
|
if p.AcrValues == "" {
|
||||||
params.Set("redirect_uri", redirectURI)
|
acr := "http://idmanagement.gov/ns/assurance/loa/1"
|
||||||
params.Set("approval_prompt", p.ApprovalPrompt)
|
extraParams.Add("acr_values", acr)
|
||||||
params.Add("scope", p.Scope)
|
|
||||||
params.Set("client_id", p.ClientID)
|
|
||||||
params.Set("response_type", "code")
|
|
||||||
params.Add("state", state)
|
|
||||||
acr := p.AcrValues
|
|
||||||
if acr == "" {
|
|
||||||
acr = "http://idmanagement.gov/ns/assurance/loa/1"
|
|
||||||
}
|
}
|
||||||
params.Add("acr_values", acr)
|
extraParams.Add("nonce", p.Nonce)
|
||||||
params.Add("nonce", p.Nonce)
|
a := makeLoginURL(p.ProviderData, redirectURI, state, extraParams)
|
||||||
a.RawQuery = params.Encode()
|
|
||||||
return a.String()
|
return a.String()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -289,3 +289,10 @@ func TestLoginGovProviderBadNonce(t *testing.T) {
|
||||||
// The "badfakenonce" in the idtoken above should cause this to error out
|
// The "badfakenonce" in the idtoken above should cause this to error out
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoginGovProviderGetLoginURL(t *testing.T) {
|
||||||
|
p, _, _ := newLoginGovProvider()
|
||||||
|
result := p.GetLoginURL("http://redirect/", "")
|
||||||
|
assert.Contains(t, result, "acr_values="+url.QueryEscape("http://idmanagement.gov/ns/assurance/loa/1"))
|
||||||
|
assert.Contains(t, result, "nonce=fakenonce")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NextcloudProvider represents an Nextcloud based Identity Provider
|
// NextcloudProvider represents an Nextcloud based Identity Provider
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import (
|
||||||
oidc "github.com/coreos/go-oidc"
|
oidc "github.com/coreos/go-oidc"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
const emailClaim = "email"
|
const emailClaim = "email"
|
||||||
|
|
@ -22,6 +22,7 @@ type OIDCProvider struct {
|
||||||
Verifier *oidc.IDTokenVerifier
|
Verifier *oidc.IDTokenVerifier
|
||||||
AllowUnverifiedEmail bool
|
AllowUnverifiedEmail bool
|
||||||
UserIDClaim string
|
UserIDClaim string
|
||||||
|
GroupsClaim string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOIDCProvider initiates a new OIDCProvider
|
// NewOIDCProvider initiates a new OIDCProvider
|
||||||
|
|
@ -123,6 +124,7 @@ func (p *OIDCProvider) redeemRefreshToken(ctx context.Context, s *sessions.Sessi
|
||||||
s.IDToken = newSession.IDToken
|
s.IDToken = newSession.IDToken
|
||||||
s.Email = newSession.Email
|
s.Email = newSession.Email
|
||||||
s.User = newSession.User
|
s.User = newSession.User
|
||||||
|
s.Groups = newSession.Groups
|
||||||
s.PreferredUsername = newSession.PreferredUsername
|
s.PreferredUsername = newSession.PreferredUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,6 +206,7 @@ func (p *OIDCProvider) createSessionStateInternal(ctx context.Context, idToken *
|
||||||
newSession.Email = claims.UserID // TODO Rename SessionState.Email to .UserID in the near future
|
newSession.Email = claims.UserID // TODO Rename SessionState.Email to .UserID in the near future
|
||||||
|
|
||||||
newSession.User = claims.Subject
|
newSession.User = claims.Subject
|
||||||
|
newSession.Groups = claims.Groups
|
||||||
newSession.PreferredUsername = claims.PreferredUsername
|
newSession.PreferredUsername = claims.PreferredUsername
|
||||||
|
|
||||||
verifyEmail := (p.UserIDClaim == emailClaim) && !p.AllowUnverifiedEmail
|
verifyEmail := (p.UserIDClaim == emailClaim) && !p.AllowUnverifiedEmail
|
||||||
|
|
@ -222,6 +225,7 @@ func (p *OIDCProvider) ValidateSessionState(ctx context.Context, s *sessions.Ses
|
||||||
|
|
||||||
func (p *OIDCProvider) findClaimsFromIDToken(ctx context.Context, idToken *oidc.IDToken, token *oauth2.Token) (*OIDCClaims, error) {
|
func (p *OIDCProvider) findClaimsFromIDToken(ctx context.Context, idToken *oidc.IDToken, token *oauth2.Token) (*OIDCClaims, error) {
|
||||||
claims := &OIDCClaims{}
|
claims := &OIDCClaims{}
|
||||||
|
|
||||||
// Extract default claims.
|
// Extract default claims.
|
||||||
if err := idToken.Claims(&claims); err != nil {
|
if err := idToken.Claims(&claims); err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse default id_token claims: %v", err)
|
return nil, fmt.Errorf("failed to parse default id_token claims: %v", err)
|
||||||
|
|
@ -236,6 +240,8 @@ func (p *OIDCProvider) findClaimsFromIDToken(ctx context.Context, idToken *oidc.
|
||||||
claims.UserID = fmt.Sprint(userID)
|
claims.UserID = fmt.Sprint(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
claims.Groups = p.extractGroupsFromRawClaims(claims.rawClaims)
|
||||||
|
|
||||||
// userID claim was not present or was empty in the ID Token
|
// userID claim was not present or was empty in the ID Token
|
||||||
if claims.UserID == "" {
|
if claims.UserID == "" {
|
||||||
// BearerToken case, allow empty UserID
|
// BearerToken case, allow empty UserID
|
||||||
|
|
@ -273,10 +279,27 @@ func (p *OIDCProvider) findClaimsFromIDToken(ctx context.Context, idToken *oidc.
|
||||||
return claims, nil
|
return claims, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *OIDCProvider) extractGroupsFromRawClaims(rawClaims map[string]interface{}) []string {
|
||||||
|
groups := []string{}
|
||||||
|
|
||||||
|
rawGroups, ok := rawClaims[p.GroupsClaim].([]interface{})
|
||||||
|
if rawGroups != nil && ok {
|
||||||
|
for _, rawGroup := range rawGroups {
|
||||||
|
group, ok := rawGroup.(string)
|
||||||
|
if ok {
|
||||||
|
groups = append(groups, group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
type OIDCClaims struct {
|
type OIDCClaims struct {
|
||||||
rawClaims map[string]interface{}
|
rawClaims map[string]interface{}
|
||||||
UserID string
|
UserID string
|
||||||
Subject string `json:"sub"`
|
Subject string `json:"sub"`
|
||||||
Verified *bool `json:"email_verified"`
|
Verified *bool `json:"email_verified"`
|
||||||
PreferredUsername string `json:"preferred_username"`
|
PreferredUsername string `json:"preferred_username"`
|
||||||
|
Groups []string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
const accessToken = "access_token"
|
const accessToken = "access_token"
|
||||||
|
|
@ -29,10 +29,12 @@ const clientID = "https://test.myapp.com"
|
||||||
const secret = "secret"
|
const secret = "secret"
|
||||||
|
|
||||||
type idTokenClaims struct {
|
type idTokenClaims struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
Phone string `json:"phone_number,omitempty"`
|
Phone string `json:"phone_number,omitempty"`
|
||||||
Picture string `json:"picture,omitempty"`
|
Picture string `json:"picture,omitempty"`
|
||||||
|
Groups []string `json:"groups,omitempty"`
|
||||||
|
OtherGroups []string `json:"other_groups,omitempty"`
|
||||||
jwt.StandardClaims
|
jwt.StandardClaims
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,6 +51,8 @@ var defaultIDToken idTokenClaims = idTokenClaims{
|
||||||
"janed@me.com",
|
"janed@me.com",
|
||||||
"+4798765432",
|
"+4798765432",
|
||||||
"http://mugbook.com/janed/me.jpg",
|
"http://mugbook.com/janed/me.jpg",
|
||||||
|
[]string{"test:a", "test:b"},
|
||||||
|
[]string{"test:c", "test:d"},
|
||||||
jwt.StandardClaims{
|
jwt.StandardClaims{
|
||||||
Audience: "https://test.myapp.com",
|
Audience: "https://test.myapp.com",
|
||||||
ExpiresAt: time.Now().Add(time.Duration(5) * time.Minute).Unix(),
|
ExpiresAt: time.Now().Add(time.Duration(5) * time.Minute).Unix(),
|
||||||
|
|
@ -65,6 +69,8 @@ var minimalIDToken idTokenClaims = idTokenClaims{
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
[]string{},
|
||||||
|
[]string{},
|
||||||
jwt.StandardClaims{
|
jwt.StandardClaims{
|
||||||
Audience: "https://test.myapp.com",
|
Audience: "https://test.myapp.com",
|
||||||
ExpiresAt: time.Now().Add(time.Duration(5) * time.Minute).Unix(),
|
ExpiresAt: time.Now().Add(time.Duration(5) * time.Minute).Unix(),
|
||||||
|
|
@ -273,25 +279,39 @@ func TestCreateSessionStateFromBearerToken(t *testing.T) {
|
||||||
const profileURLEmail = "janed@me.com"
|
const profileURLEmail = "janed@me.com"
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
IDToken idTokenClaims
|
IDToken idTokenClaims
|
||||||
ExpectedUser string
|
GroupsClaim string
|
||||||
ExpectedEmail string
|
ExpectedUser string
|
||||||
|
ExpectedEmail string
|
||||||
|
ExpectedGroups []string
|
||||||
}{
|
}{
|
||||||
"Default IDToken": {
|
"Default IDToken": {
|
||||||
IDToken: defaultIDToken,
|
IDToken: defaultIDToken,
|
||||||
ExpectedUser: defaultIDToken.Subject,
|
GroupsClaim: "groups",
|
||||||
ExpectedEmail: defaultIDToken.Email,
|
ExpectedUser: defaultIDToken.Subject,
|
||||||
|
ExpectedEmail: defaultIDToken.Email,
|
||||||
|
ExpectedGroups: []string{"test:a", "test:b"},
|
||||||
},
|
},
|
||||||
"Minimal IDToken with no email claim": {
|
"Minimal IDToken with no email claim": {
|
||||||
IDToken: minimalIDToken,
|
IDToken: minimalIDToken,
|
||||||
ExpectedUser: minimalIDToken.Subject,
|
GroupsClaim: "groups",
|
||||||
ExpectedEmail: minimalIDToken.Subject,
|
ExpectedUser: minimalIDToken.Subject,
|
||||||
|
ExpectedEmail: minimalIDToken.Subject,
|
||||||
|
ExpectedGroups: []string{},
|
||||||
|
},
|
||||||
|
"Custom Groups Claim": {
|
||||||
|
IDToken: defaultIDToken,
|
||||||
|
GroupsClaim: "other_groups",
|
||||||
|
ExpectedUser: defaultIDToken.Subject,
|
||||||
|
ExpectedEmail: defaultIDToken.Email,
|
||||||
|
ExpectedGroups: []string{"test:c", "test:d"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for testName, tc := range testCases {
|
for testName, tc := range testCases {
|
||||||
t.Run(testName, func(t *testing.T) {
|
t.Run(testName, func(t *testing.T) {
|
||||||
jsonResp := []byte(fmt.Sprintf(`{"email":"%s"}`, profileURLEmail))
|
jsonResp := []byte(fmt.Sprintf(`{"email":"%s"}`, profileURLEmail))
|
||||||
server, provider := newTestSetup(jsonResp)
|
server, provider := newTestSetup(jsonResp)
|
||||||
|
provider.GroupsClaim = tc.GroupsClaim
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
rawIDToken, err := newSignedTestIDToken(tc.IDToken)
|
rawIDToken, err := newSignedTestIDToken(tc.IDToken)
|
||||||
|
|
@ -311,6 +331,7 @@ func TestCreateSessionStateFromBearerToken(t *testing.T) {
|
||||||
assert.Equal(t, tc.ExpectedEmail, ss.Email)
|
assert.Equal(t, tc.ExpectedEmail, ss.Email)
|
||||||
assert.Equal(t, rawIDToken, ss.IDToken)
|
assert.Equal(t, rawIDToken, ss.IDToken)
|
||||||
assert.Equal(t, rawIDToken, ss.AccessToken)
|
assert.Equal(t, rawIDToken, ss.AccessToken)
|
||||||
|
assert.Equal(t, tc.ExpectedGroups, ss.Groups)
|
||||||
assert.Equal(t, "", ss.RefreshToken)
|
assert.Equal(t, "", ss.RefreshToken)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProviderData contains information required to configure all implementations
|
// ProviderData contains information required to configure all implementations
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import (
|
||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Provider = (*ProviderData)(nil)
|
var _ Provider = (*ProviderData)(nil)
|
||||||
|
|
@ -75,22 +75,8 @@ func (p *ProviderData) Redeem(ctx context.Context, redirectURL, code string) (s
|
||||||
|
|
||||||
// GetLoginURL with typical oauth parameters
|
// GetLoginURL with typical oauth parameters
|
||||||
func (p *ProviderData) GetLoginURL(redirectURI, state string) string {
|
func (p *ProviderData) GetLoginURL(redirectURI, state string) string {
|
||||||
a := *p.LoginURL
|
extraParams := url.Values{}
|
||||||
params, _ := url.ParseQuery(a.RawQuery)
|
a := makeLoginURL(p, redirectURI, state, extraParams)
|
||||||
params.Set("redirect_uri", redirectURI)
|
|
||||||
if p.AcrValues != "" {
|
|
||||||
params.Add("acr_values", p.AcrValues)
|
|
||||||
}
|
|
||||||
if p.Prompt != "" {
|
|
||||||
params.Set("prompt", p.Prompt)
|
|
||||||
} else { // Legacy variant of the prompt param:
|
|
||||||
params.Set("approval_prompt", p.ApprovalPrompt)
|
|
||||||
}
|
|
||||||
params.Add("scope", p.Scope)
|
|
||||||
params.Set("client_id", p.ClientID)
|
|
||||||
params.Set("response_type", "code")
|
|
||||||
params.Add("state", state)
|
|
||||||
a.RawQuery = params.Encode()
|
|
||||||
return a.String()
|
return a.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,11 +90,6 @@ func (p *ProviderData) GetUserName(ctx context.Context, s *sessions.SessionState
|
||||||
return "", errors.New("not implemented")
|
return "", errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPreferredUsername returns the Account preferred username
|
|
||||||
func (p *ProviderData) GetPreferredUsername(ctx context.Context, s *sessions.SessionState) (string, error) {
|
|
||||||
return "", errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateGroup validates that the provided email exists in the configured provider
|
// ValidateGroup validates that the provided email exists in the configured provider
|
||||||
// email group(s).
|
// email group(s).
|
||||||
func (p *ProviderData) ValidateGroup(email string) bool {
|
func (p *ProviderData) ValidateGroup(email string) bool {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider represents an upstream identity provider implementation
|
// Provider represents an upstream identity provider implementation
|
||||||
|
|
@ -12,7 +12,6 @@ type Provider interface {
|
||||||
Data() *ProviderData
|
Data() *ProviderData
|
||||||
GetEmailAddress(ctx context.Context, s *sessions.SessionState) (string, error)
|
GetEmailAddress(ctx context.Context, s *sessions.SessionState) (string, error)
|
||||||
GetUserName(ctx context.Context, s *sessions.SessionState) (string, error)
|
GetUserName(ctx context.Context, s *sessions.SessionState) (string, error)
|
||||||
GetPreferredUsername(ctx context.Context, s *sessions.SessionState) (string, error)
|
|
||||||
Redeem(ctx context.Context, redirectURI, code string) (*sessions.SessionState, error)
|
Redeem(ctx context.Context, redirectURI, code string) (*sessions.SessionState, error)
|
||||||
ValidateGroup(string) bool
|
ValidateGroup(string) bool
|
||||||
ValidateSessionState(ctx context.Context, s *sessions.SessionState) bool
|
ValidateSessionState(ctx context.Context, s *sessions.SessionState) bool
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package providers
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -29,3 +30,28 @@ func makeOIDCHeader(accessToken string) http.Header {
|
||||||
}
|
}
|
||||||
return makeAuthorizationHeader(tokenTypeBearer, accessToken, extraHeaders)
|
return makeAuthorizationHeader(tokenTypeBearer, accessToken, extraHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeLoginURL(p *ProviderData, redirectURI, state string, extraParams url.Values) url.URL {
|
||||||
|
a := *p.LoginURL
|
||||||
|
params, _ := url.ParseQuery(a.RawQuery)
|
||||||
|
params.Set("redirect_uri", redirectURI)
|
||||||
|
if p.AcrValues != "" {
|
||||||
|
params.Add("acr_values", p.AcrValues)
|
||||||
|
}
|
||||||
|
if p.Prompt != "" {
|
||||||
|
params.Set("prompt", p.Prompt)
|
||||||
|
} else { // Legacy variant of the prompt param:
|
||||||
|
params.Set("approval_prompt", p.ApprovalPrompt)
|
||||||
|
}
|
||||||
|
params.Add("scope", p.Scope)
|
||||||
|
params.Set("client_id", p.ClientID)
|
||||||
|
params.Set("response_type", "code")
|
||||||
|
params.Add("state", state)
|
||||||
|
for n, p := range extraParams {
|
||||||
|
for _, v := range p {
|
||||||
|
params.Add(n, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.RawQuery = params.Encode()
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func loadTemplates(dir string) *template.Template {
|
func loadTemplates(dir string) *template.Template {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserMap holds information from the authenticated emails file
|
// UserMap holds information from the authenticated emails file
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue