Merge remote-tracking branch 'origin2/master'

This commit is contained in:
Kevin Kreitner 2020-12-21 09:38:45 +01:00
commit 3b90bf3f2a
10 changed files with 530 additions and 161 deletions

View File

@ -4,13 +4,14 @@
## Important Notes ## Important Notes
- [#630](https://github.com/oauth2-proxy/oauth2-proxy/pull/630) Gitlab projects needs a Gitlab application with the extra `read_api` enabled
- [#905](https://github.com/oauth2-proxy/oauth2-proxy/pull/905) Existing sessions from v6.0.0 or earlier are no longer valid. They will trigger a reauthentication. - [#905](https://github.com/oauth2-proxy/oauth2-proxy/pull/905) Existing sessions from v6.0.0 or earlier are no longer valid. They will trigger a reauthentication.
- [#826](https://github.com/oauth2-proxy/oauth2-proxy/pull/826) `skip-auth-strip-headers` now applies to all requests, not just those where authentication would be skipped. - [#826](https://github.com/oauth2-proxy/oauth2-proxy/pull/826) `skip-auth-strip-headers` now applies to all requests, not just those where authentication would be skipped.
- [#797](https://github.com/oauth2-proxy/oauth2-proxy/pull/797) The behavior of the Google provider Groups restriction changes with this - [#797](https://github.com/oauth2-proxy/oauth2-proxy/pull/797) The behavior of the Google provider Groups restriction changes with this
- Either `--google-group` or the new `--allowed-group` will work for Google now (`--google-group` will be used if both are set) - Either `--google-group` or the new `--allowed-group` will work for Google now (`--google-group` will be used if both are set)
- Group membership lists will be passed to the backend with the `X-Forwarded-Groups` header - Group membership lists will be passed to the backend with the `X-Forwarded-Groups` header
- If you change the list of allowed groups, existing sessions that now don't have a valid group will be logged out immediately. - If you change the list of allowed groups, existing sessions that now don't have a valid group will be logged out immediately.
- Previously, group membership was only checked on session creation and refresh. - Previously, group membership was only checked on session creation and refresh.
- [#789](https://github.com/oauth2-proxy/oauth2-proxy/pull/789) `--skip-auth-route` is (almost) backwards compatible with `--skip-auth-regex` - [#789](https://github.com/oauth2-proxy/oauth2-proxy/pull/789) `--skip-auth-route` is (almost) backwards compatible with `--skip-auth-regex`
- We are marking `--skip-auth-regex` as DEPRECATED and will remove it in the next major version. - We are marking `--skip-auth-regex` as DEPRECATED and will remove it in the next major version.
- If your regex contains an `=` and you want it for all methods, you will need to add a leading `=` (this is the area where `--skip-auth-regex` doesn't port perfectly) - If your regex contains an `=` and you want it for all methods, you will need to add a leading `=` (this is the area where `--skip-auth-regex` doesn't port perfectly)
@ -38,11 +39,12 @@
be any redirects in the browser anymore when tokens expire, but instead a token refresh is initiated be any redirects in the browser anymore when tokens expire, but instead a token refresh is initiated
in the background, which leads to new tokens being returned in the cookies. in the background, which leads to new tokens being returned in the cookies.
- Please note that `--cookie-refresh` must be 0 (the default) or equal to the token lifespan configured in Azure AD to make - Please note that `--cookie-refresh` must be 0 (the default) or equal to the token lifespan configured in Azure AD to make
Azure token refresh reliable. Setting this value to 0 means that it relies on the provider implementation Azure token refresh reliable. Setting this value to 0 means that it relies on the provider implementation
to decide if a refresh is required. to decide if a refresh is required.
## Changes since v6.1.1 ## Changes since v6.1.1
- [#630](https://github.com/oauth2-proxy/oauth2-proxy/pull/630) Add support for Gitlab project based authentication (@factorysh)
- [#907](https://github.com/oauth2-proxy/oauth2-proxy/pull/907) Introduce alpha configuration option to enable testing of structured configuration (@JoelSpeed) - [#907](https://github.com/oauth2-proxy/oauth2-proxy/pull/907) Introduce alpha configuration option to enable testing of structured configuration (@JoelSpeed)
- [#938](https://github.com/oauth2-proxy/oauth2-proxy/pull/938) Cleanup missed provider renaming refactor methods (@NickMeves) - [#938](https://github.com/oauth2-proxy/oauth2-proxy/pull/938) Cleanup missed provider renaming refactor methods (@NickMeves)
- [#925](https://github.com/oauth2-proxy/oauth2-proxy/pull/925) Fix basic auth legacy header conversion (@JoelSpeed) - [#925](https://github.com/oauth2-proxy/oauth2-proxy/pull/925) Fix basic auth legacy header conversion (@JoelSpeed)
@ -78,7 +80,6 @@
- [#829](https://github.com/oauth2-proxy/oauth2-proxy/pull/820) Rename test directory to testdata (@johejo) - [#829](https://github.com/oauth2-proxy/oauth2-proxy/pull/820) Rename test directory to testdata (@johejo)
- [#819](https://github.com/oauth2-proxy/oauth2-proxy/pull/819) Improve CI (@johejo) - [#819](https://github.com/oauth2-proxy/oauth2-proxy/pull/819) Improve CI (@johejo)
# v6.1.1 # v6.1.1
## Release Highlights ## Release Highlights
@ -180,7 +181,7 @@ N/A
- [#440](https://github.com/oauth2-proxy/oauth2-proxy/pull/440) Switch Azure AD Graph API to Microsoft Graph API - [#440](https://github.com/oauth2-proxy/oauth2-proxy/pull/440) Switch Azure AD Graph API to Microsoft Graph API
- The Azure AD Graph API has been [deprecated](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api) and is being replaced by the Microsoft Graph API. - The Azure AD Graph API has been [deprecated](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api) and is being replaced by the Microsoft Graph API.
If your application relies on the access token being passed to it to access the Azure AD Graph API, you should migrate your application to use the Microsoft Graph API. If your application relies on the access token being passed to it to access the Azure AD Graph API, you should migrate your application to use the Microsoft Graph API.
Existing behaviour can be retained by setting `-resource=https://graph.windows.net`. Existing behaviour can be retained by setting `-resource=https://graph.windows.net`.
- [#484](https://github.com/oauth2-proxy/oauth2-proxy/pull/484) Configuration loading has been replaced with Viper and PFlag - [#484](https://github.com/oauth2-proxy/oauth2-proxy/pull/484) Configuration loading has been replaced with Viper and PFlag
- Flags now require a `--` prefix before the option - Flags now require a `--` prefix before the option
- Previously flags allowed either `-` or `--` to prefix the option name - Previously flags allowed either `-` or `--` to prefix the option name
@ -201,7 +202,7 @@ N/A
- [#556](https://github.com/oauth2-proxy/oauth2-proxy/pull/556) Remove unintentional auto-padding of secrets that were too short - [#556](https://github.com/oauth2-proxy/oauth2-proxy/pull/556) Remove unintentional auto-padding of secrets that were too short
- Previously, after cookie-secrets were opportunistically base64 decoded to raw bytes, - Previously, after cookie-secrets were opportunistically base64 decoded to raw bytes,
they were padded to have a length divisible by 4. they were padded to have a length divisible by 4.
- This led to wrong sized secrets being valid AES lengths of 16, 24, or 32 bytes. Or it led to confusing errors - This led to wrong sized secrets being valid AES lengths of 16, 24, or 32 bytes. Or it led to confusing errors
reporting an invalid length of 20 or 28 when the user input cookie-secret was not that length. reporting an invalid length of 20 or 28 when the user input cookie-secret was not that length.
- Now we will only base64 decode a cookie-secret to raw bytes if it is 16, 24, or 32 bytes long. Otherwise, we will convert - Now we will only base64 decode a cookie-secret to raw bytes if it is 16, 24, or 32 bytes long. Otherwise, we will convert
the direct cookie-secret to bytes without silent padding added. the direct cookie-secret to bytes without silent padding added.
@ -306,15 +307,18 @@ N/A
# v5.1.0 # v5.1.0
## Release Highlights ## Release Highlights
- Bump to Go 1.14 - Bump to Go 1.14
- Reduced number of Google API requests for group validation - Reduced number of Google API requests for group validation
- Support for Redis Cluster - Support for Redis Cluster
- Support for overriding hosts in hosts file - Support for overriding hosts in hosts file
## Important Notes ## Important Notes
- [#335] The session expiry for the OIDC provider is now taken from the Token Response (expires_in) rather than from the id_token (exp) - [#335] The session expiry for the OIDC provider is now taken from the Token Response (expires_in) rather than from the id_token (exp)
## Breaking Changes ## Breaking Changes
N/A N/A
## Changes since v5.0.0 ## Changes since v5.0.0
@ -338,13 +342,15 @@ N/A
# v5.0.0 # v5.0.0
## Release Highlights ## Release Highlights
- Disabled CGO (binaries will work regardless og glibc/musl) - Disabled CGO (binaries will work regardless og glibc/musl)
- Allow whitelisted redirect ports - Allow whitelisted redirect ports
- Nextcloud provider support added - Nextcloud provider support added
- DigitalOcean provider support added - DigitalOcean provider support added
## Important Notes ## Important Notes
- (Security) Fix for [open redirect vulnerability](https://github.com/oauth2-proxy/oauth2-proxy/security/advisories/GHSA-qqxw-m5fj-f7gv).. a bad actor using `/\` in redirect URIs can redirect a session to another domain
- (Security) Fix for [open redirect vulnerability](https://github.com/oauth2-proxy/oauth2-proxy/security/advisories/GHSA-qqxw-m5fj-f7gv).. a bad actor using `/\` in redirect URIs can redirect a session to another domain
## Breaking Changes ## Breaking Changes
@ -365,6 +371,7 @@ N/A
# v4.1.0 # v4.1.0
## Release Highlights ## Release Highlights
- Added Keycloak provider - Added Keycloak provider
- Build on Go 1.13 - Build on Go 1.13
- Upgrade Docker image to use Debian Buster - Upgrade Docker image to use Debian Buster
@ -373,12 +380,15 @@ N/A
- Added support for GitHub teams - Added support for GitHub teams
## Important Notes ## Important Notes
N/A N/A
## Breaking Changes ## Breaking Changes
N/A N/A
## Changes since v4.0.0 ## Changes since v4.0.0
- [#292](https://github.com/oauth2-proxy/oauth2-proxy/pull/292) Added bash >= 4.0 dependency to configure script (@jmfrank63) - [#292](https://github.com/oauth2-proxy/oauth2-proxy/pull/292) Added bash >= 4.0 dependency to configure script (@jmfrank63)
- [#227](https://github.com/oauth2-proxy/oauth2-proxy/pull/227) Add Keycloak provider (@Ofinka) - [#227](https://github.com/oauth2-proxy/oauth2-proxy/pull/227) Add Keycloak provider (@Ofinka)
- [#259](https://github.com/oauth2-proxy/oauth2-proxy/pull/259) Redirect to HTTPS (@jmickey) - [#259](https://github.com/oauth2-proxy/oauth2-proxy/pull/259) Redirect to HTTPS (@jmickey)
@ -401,6 +411,7 @@ N/A
# v4.0.0 # v4.0.0
## Release Highlights ## Release Highlights
- Documentation is now on a [microsite](https://oauth2-proxy.github.io/oauth2-proxy/) - Documentation is now on a [microsite](https://oauth2-proxy.github.io/oauth2-proxy/)
- Health check logging can now be disabled for quieter logs - Health check logging can now be disabled for quieter logs
- Authorization Header JWTs can now be verified by the proxy to skip authentication for machine users - Authorization Header JWTs can now be verified by the proxy to skip authentication for machine users
@ -408,29 +419,30 @@ N/A
- Logging overhaul allows customisable logging formats - Logging overhaul allows customisable logging formats
## Important Notes ## Important Notes
- This release includes a number of breaking changes that will require users to - This release includes a number of breaking changes that will require users to
reconfigure their proxies. Please read the Breaking Changes below thoroughly. reconfigure their proxies. Please read the Breaking Changes below thoroughly.
## Breaking Changes ## Breaking Changes
- [#231](https://github.com/oauth2-proxy/oauth2-proxy/pull/231) Rework GitLab provider - [#231](https://github.com/oauth2-proxy/oauth2-proxy/pull/231) Rework GitLab provider
- This PR changes the configuration options for the GitLab provider to use - This PR changes the configuration options for the GitLab provider to use
a self-hosted instance. You now need to specify a `-oidc-issuer-url` rather than a self-hosted instance. You now need to specify a `-oidc-issuer-url` rather than
explicit `-login-url`, `-redeem-url` and `-validate-url` parameters. explicit `-login-url`, `-redeem-url` and `-validate-url` parameters.
- [#186](https://github.com/oauth2-proxy/oauth2-proxy/pull/186) Make config consistent - [#186](https://github.com/oauth2-proxy/oauth2-proxy/pull/186) Make config consistent
- This PR changes configuration options so that all flags have a config counterpart - This PR changes configuration options so that all flags have a config counterpart
of the same name but with underscores (`_`) in place of hyphens (`-`). of the same name but with underscores (`_`) in place of hyphens (`-`).
This change affects the following flags: This change affects the following flags:
- The `--tls-key` flag is now `--tls-key-file` to be consistent with existing - The `--tls-key` flag is now `--tls-key-file` to be consistent with existing
file flags and the existing config and environment settings file flags and the existing config and environment settings
- The `--tls-cert` flag is now `--tls-cert-file` to be consistent with existing - The `--tls-cert` flag is now `--tls-cert-file` to be consistent with existing
file flags and the existing config and environment settings file flags and the existing config and environment settings
This change affects the following existing configuration options: This change affects the following existing configuration options:
- The `proxy-prefix` option is now `proxy_prefix`. - The `proxy-prefix` option is now `proxy_prefix`.
This PR changes environment variables so that all flags have an environment This PR changes environment variables so that all flags have an environment
counterpart of the same name but capitalised, with underscores (`_`) in place counterpart of the same name but capitalised, with underscores (`_`) in place
of hyphens (`-`) and with the prefix `OAUTH2_PROXY_`. of hyphens (`-`) and with the prefix `OAUTH2_PROXY_`.
This change affects the following existing environment variables: This change affects the following existing environment variables:
- The `OAUTH2_SKIP_OIDC_DISCOVERY` environment variable is now `OAUTH2_PROXY_SKIP_OIDC_DISCOVERY`. - The `OAUTH2_SKIP_OIDC_DISCOVERY` environment variable is now `OAUTH2_PROXY_SKIP_OIDC_DISCOVERY`.
- The `OAUTH2_OIDC_JWKS_URL` environment variable is now `OAUTH2_PROXY_OIDC_JWKS_URL`. - The `OAUTH2_OIDC_JWKS_URL` environment variable is now `OAUTH2_PROXY_OIDC_JWKS_URL`.
- [#146](https://github.com/oauth2-proxy/oauth2-proxy/pull/146) Use full email address as `User` if the auth response did not contain a `User` field - [#146](https://github.com/oauth2-proxy/oauth2-proxy/pull/146) Use full email address as `User` if the auth response did not contain a `User` field
@ -456,7 +468,7 @@ reconfigure their proxies. Please read the Breaking Changes below thoroughly.
- [#65](https://github.com/oauth2-proxy/oauth2-proxy/pull/65) Improvements to authenticate requests with a JWT bearer token in the `Authorization` header via - [#65](https://github.com/oauth2-proxy/oauth2-proxy/pull/65) Improvements to authenticate requests with a JWT bearer token in the `Authorization` header via
the `-skip-jwt-bearer-token` options. (@brianv0) the `-skip-jwt-bearer-token` options. (@brianv0)
- Additional verifiers can be configured via the `-extra-jwt-issuers` flag if the JWT issuers is either an OpenID provider or has a JWKS URL - Additional verifiers can be configured via the `-extra-jwt-issuers` flag if the JWT issuers is either an OpenID provider or has a JWKS URL
(e.g. `https://example.com/.well-known/jwks.json`). (e.g. `https://example.com/.well-known/jwks.json`).
- [#180](https://github.com/oauth2-proxy/oauth2-proxy/pull/180) Minor refactor of core proxying path (@aeijdenberg). - [#180](https://github.com/oauth2-proxy/oauth2-proxy/pull/180) Minor refactor of core proxying path (@aeijdenberg).
- [#175](https://github.com/oauth2-proxy/oauth2-proxy/pull/175) Bump go-oidc to v2.0.0 (@aeijdenberg). - [#175](https://github.com/oauth2-proxy/oauth2-proxy/pull/175) Bump go-oidc to v2.0.0 (@aeijdenberg).
- Includes fix for potential signature checking issue when OIDC discovery is skipped. - Includes fix for potential signature checking issue when OIDC discovery is skipped.
@ -514,6 +526,7 @@ reconfigure their proxies. Please read the Breaking Changes below thoroughly.
# v3.2.0 # v3.2.0
## Release highlights ## Release highlights
- Internal restructure of session state storage to use JSON rather than proprietary scheme - Internal restructure of session state storage to use JSON rather than proprietary scheme
- Added health check options for running on GCP behind a load balancer - Added health check options for running on GCP behind a load balancer
- Improved support for protecting websockets - Improved support for protecting websockets
@ -521,9 +534,10 @@ reconfigure their proxies. Please read the Breaking Changes below thoroughly.
- Allow manual configuration of OIDC providers - Allow manual configuration of OIDC providers
## Important notes ## Important notes
- Dockerfile user is now non-root, this may break your existing deployment - Dockerfile user is now non-root, this may break your existing deployment
- In the OIDC provider, when no email is returned, the ID Token subject will be used - In the OIDC provider, when no email is returned, the ID Token subject will be used
instead of returning an error instead of returning an error
- GitHub user emails must now be primary and verified before authenticating - GitHub user emails must now be primary and verified before authenticating
## Changes since v3.1.0 ## Changes since v3.1.0

View File

@ -54,7 +54,7 @@ Read the docs on our [Docs site](https://oauth2-proxy.github.io/oauth2-proxy/doc
## Getting Involved ## Getting Involved
If you would like to reach out to the maintainers, come talk to us in the `#oauth2_proxy` channel in the [Gophers slack](http://gophers.slack.com/). If you would like to reach out to the maintainers, come talk to us in the `#oauth2-proxy` channel in the [Gophers slack](http://gophers.slack.com/).
## Contributing ## Contributing

View File

@ -0,0 +1,3 @@
# oauth2-proxy: local-environment
Run `make up` to deploy local dex, etcd and oauth2-proxy instances in Docker containers. Review the [`Makefile`](Makefile) for additional deployment options.

View File

@ -149,6 +149,8 @@ The group management in keycloak is using a tree. If you create a group named ad
Whether you are using GitLab.com or self-hosting GitLab, follow [these steps to add an application](https://docs.gitlab.com/ce/integration/oauth_provider.html). Make sure to enable at least the `openid`, `profile` and `email` scopes, and set the redirect url to your application url e.g. https://myapp.com/oauth2/callback. Whether you are using GitLab.com or self-hosting GitLab, follow [these steps to add an application](https://docs.gitlab.com/ce/integration/oauth_provider.html). Make sure to enable at least the `openid`, `profile` and `email` scopes, and set the redirect url to your application url e.g. https://myapp.com/oauth2/callback.
If you need projects filtering, add the extra `read_api` scope to your application.
The following config should be set to ensure that the oauth will work properly. To get a cookie secret follow [these steps](https://github.com/oauth2-proxy/oauth2-proxy/blob/master/docs/configuration/configuration.md#configuration) The following config should be set to ensure that the oauth will work properly. To get a cookie secret follow [these steps](https://github.com/oauth2-proxy/oauth2-proxy/blob/master/docs/configuration/configuration.md#configuration)
``` ```
@ -186,27 +188,66 @@ Take note of your `TenantId` if applicable for your situation. The `TenantId` ca
### OpenID Connect Provider ### OpenID Connect Provider
OpenID Connect is a spec for OAUTH 2.0 + identity that is implemented by many major providers and several open source projects. This provider was originally built against CoreOS Dex and we will use it as an example. OpenID Connect is a spec for OAUTH 2.0 + identity that is implemented by many major providers and several open source projects.
1. Launch a Dex instance using the [getting started guide](https://github.com/coreos/dex/blob/master/Documentation/getting-started.md). This provider was originally built against CoreOS Dex and we will use it as an example.
2. Setup oauth2-proxy with the correct provider and using the default ports and callbacks. The OpenID Connect Provider (OIDC) can also be used to connect to other Identity Providers such as Okta, an example can be found below.
3. Login with the fixture use in the dex guide and run the oauth2-proxy with the following args:
``` #### Dex
To configure the OIDC provider for Dex, perform the following steps:
1. Download Dex:
```
go get github.com/dexidp/dex
```
See the [getting started guide](https://github.com/coreos/dex/blob/master/Documentation/getting-started.md) for more details.
2. Setup oauth2-proxy with the correct provider and using the default ports and callbacks. Add a configuration block to the `staticClients` section of `examples/config-dev.yaml`:
```
- id: oauth2-proxy
redirectURIs:
- 'http://127.0.0.1:4180/oauth2/callback'
name: 'oauth2-proxy'
secret: proxy
```
3. Launch Dex: from `$GOPATH/github.com/dexidp/dex`, run:
```
bin/dex serve examples/config-dev.yaml
```
4. In a second terminal, run the oauth2-proxy with the following args:
```
-provider oidc -provider oidc
-provider-display-name "My OIDC Provider" -provider-display-name "My OIDC Provider"
-client-id oauth2-proxy -client-id oauth2-proxy
-client-secret proxy -client-secret proxy
-redirect-url http://127.0.0.1:4180/oauth2/callback -redirect-url http://127.0.0.1:4180/oauth2/callback
-oidc-issuer-url http://127.0.0.1:5556 -oidc-issuer-url http://127.0.0.1:5556/dex
-cookie-secure=false -cookie-secure=false
-email-domain example.com -cookie-secret=secret
``` -email-domain kilgore.trout
```
The OpenID Connect Provider (OIDC) can also be used to connect to other Identity Providers such as Okta. To configure the OIDC provider for Okta, perform To serve the current working directory as a web site under the `/static` endpoint, add:
the following steps:
#### Configuring the OIDC Provider with Okta ```
-upstream file://$PWD/#/static/
```
5. Test the setup by visiting http://127.0.0.1:4180 or http://127.0.0.1:4180/static .
See also [our local testing environment](https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/local-environment) for a self-contained example using Docker and etcd as storage for Dex.
#### Okta
To configure the OIDC provider for Okta, perform the following steps:
1. Log in to Okta using an administrative account. It is suggested you try this in preview first, `example.oktapreview.com` 1. Log in to Okta using an administrative account. It is suggested you try this in preview first, `example.oktapreview.com`
2. (OPTIONAL) If you want to configure authorization scopes and claims to be passed on to multiple applications, 2. (OPTIONAL) If you want to configure authorization scopes and claims to be passed on to multiple applications,
@ -229,30 +270,31 @@ you may wish to configure an authorization server for each application. Otherwis
* Under **Assignments** select the users or groups you wish to access your application. * Under **Assignments** select the users or groups you wish to access your application.
4. Create a configuration file like the following: 4. Create a configuration file like the following:
``` ```
provider = "oidc" provider = "oidc"
redirect_url = "https://example.corp.com/oauth2/callback" redirect_url = "https://example.corp.com/oauth2/callback"
oidc_issuer_url = "https://corp.okta.com/oauth2/abCd1234" oidc_issuer_url = "https://corp.okta.com/oauth2/abCd1234"
upstreams = [ upstreams = [
"https://example.corp.com" "https://example.corp.com"
] ]
email_domains = [ email_domains = [
"corp.com" "corp.com"
] ]
client_id = "XXXXX" client_id = "XXXXX"
client_secret = "YYYYY" client_secret = "YYYYY"
pass_access_token = true pass_access_token = true
cookie_secret = "ZZZZZ" cookie_secret = "ZZZZZ"
skip_provider_button = true skip_provider_button = true
``` ```
The `oidc_issuer_url` is based on URL from your **Authorization Server**'s **Issuer** field in step 2, or simply https://corp.okta.com The `oidc_issuer_url` is based on URL from your **Authorization Server**'s **Issuer** field in step 2, or simply https://corp.okta.com .
The `client_id` and `client_secret` are configured in the application settings. The `client_id` and `client_secret` are configured in the application settings.
Generate a unique `client_secret` to encrypt the cookie. Generate a unique `client_secret` to encrypt the cookie.
Then you can start the oauth2-proxy with `./oauth2-proxy --config /etc/example.cfg` Then you can start the oauth2-proxy with `./oauth2-proxy --config /etc/example.cfg`
#### Configuring the OIDC Provider with Okta - localhost #### Okta - localhost
1. Signup for developer account: https://developer.okta.com/signup/ 1. Signup for developer account: https://developer.okta.com/signup/
2. Create New `Web` Application: https://${your-okta-domain}/dev/console/apps/new 2. Create New `Web` Application: https://${your-okta-domain}/dev/console/apps/new
3. Example Application Settings for localhost: 3. Example Application Settings for localhost:
@ -265,25 +307,25 @@ Then you can start the oauth2-proxy with `./oauth2-proxy --config /etc/example.c
4. Make note of the `Client ID` and `Client secret`, they are needed in a future step 4. Make note of the `Client ID` and `Client secret`, they are needed in a future step
5. Make note of the **default** Authorization Server Issuer URI from: https://${your-okta-domain}/admin/oauth2/as 5. Make note of the **default** Authorization Server Issuer URI from: https://${your-okta-domain}/admin/oauth2/as
6. Example config file `/etc/localhost.cfg` 6. Example config file `/etc/localhost.cfg`
``` ```
provider = "oidc" provider = "oidc"
redirect_url = "http://localhost:4180/oauth2/callback" redirect_url = "http://localhost:4180/oauth2/callback"
oidc_issuer_url = "https://${your-okta-domain}/oauth2/default" oidc_issuer_url = "https://${your-okta-domain}/oauth2/default"
upstreams = [ upstreams = [
"http://0.0.0.0:8080" "http://0.0.0.0:8080"
] ]
email_domains = [ email_domains = [
"*" "*"
] ]
client_id = "XXX" client_id = "XXX"
client_secret = "YYY" client_secret = "YYY"
pass_access_token = true pass_access_token = true
cookie_secret = "ZZZ" cookie_secret = "ZZZ"
cookie_secure = false cookie_secure = false
skip_provider_button = true skip_provider_button = true
# Note: use the following for testing within a container # Note: use the following for testing within a container
# http_address = "0.0.0.0:4180" # http_address = "0.0.0.0:4180"
``` ```
7. Then you can start the oauth2-proxy with `./oauth2-proxy --config /etc/localhost.cfg` 7. Then you can start the oauth2-proxy with `./oauth2-proxy --config /etc/localhost.cfg`
### login.gov Provider ### login.gov Provider

View File

@ -54,6 +54,7 @@ An example [oauth2-proxy.cfg](https://github.com/oauth2-proxy/oauth2-proxy/blob/
| `--github-token` | string | the token to use when verifying repository collaborators (must have push access to the repository) | | | `--github-token` | string | the token to use when verifying repository collaborators (must have push access to the repository) | |
| `--github-user` | string \| list | To allow users to login by username even if they do not belong to the specified org and team or collaborators | | | `--github-user` | string \| list | To allow users to login by username even if they do not belong to the specified org and team or collaborators | |
| `--gitlab-group` | string \| list | restrict logins to members of any of these groups (slug), separated by a comma | | | `--gitlab-group` | string \| list | restrict logins to members of any of these groups (slug), separated by a comma | |
| `--gitlab-projects` | string \| list | restrict logins to members of any of these projects (may be given multiple times) formatted as `orgname/repo=accesslevel`. Access level should be a value matching [Gitlab access levels](https://docs.gitlab.com/ee/api/members.html#valid-access-levels), defaulted to 20 if absent | |
| `--google-admin-email` | string | the google admin to impersonate for api calls | | | `--google-admin-email` | string | the google admin to impersonate for api calls | |
| `--google-group` | string | restrict logins to members of this google group (may be given multiple times). | | | `--google-group` | string | restrict logins to members of this google group (may be given multiple times). | |
| `--google-service-account-json` | string | the path to the service account json credentials | | | `--google-service-account-json` | string | the path to the service account json credentials | |

View File

@ -48,6 +48,7 @@ type Options struct {
GitHubToken string `flag:"github-token" cfg:"github_token"` GitHubToken string `flag:"github-token" cfg:"github_token"`
GitHubUsers []string `flag:"github-user" cfg:"github_users"` GitHubUsers []string `flag:"github-user" cfg:"github_users"`
GitLabGroup []string `flag:"gitlab-group" cfg:"gitlab_groups"` GitLabGroup []string `flag:"gitlab-group" cfg:"gitlab_groups"`
GitlabProjects []string `flag:"gitlab-project" cfg:"gitlab_projects"`
GoogleGroups []string `flag:"google-group" cfg:"google_group"` GoogleGroups []string `flag:"google-group" cfg:"google_group"`
GoogleAdminEmail string `flag:"google-admin-email" cfg:"google_admin_email"` GoogleAdminEmail string `flag:"google-admin-email" cfg:"google_admin_email"`
GoogleServiceAccountJSON string `flag:"google-service-account-json" cfg:"google_service_account_json"` GoogleServiceAccountJSON string `flag:"google-service-account-json" cfg:"google_service_account_json"`
@ -188,6 +189,7 @@ func NewFlagSet() *pflag.FlagSet {
flagSet.String("github-token", "", "the token to use when verifying repository collaborators (must have push access to the repository)") flagSet.String("github-token", "", "the token to use when verifying repository collaborators (must have push access to the repository)")
flagSet.StringSlice("github-user", []string{}, "allow users with these usernames to login even if they do not belong to the specified org and team or collaborators (may be given multiple times)") flagSet.StringSlice("github-user", []string{}, "allow users with these usernames to login even if they do not belong to the specified org and team or collaborators (may be given multiple times)")
flagSet.StringSlice("gitlab-group", []string{}, "restrict logins to members of this group (may be given multiple times)") flagSet.StringSlice("gitlab-group", []string{}, "restrict logins to members of this group (may be given multiple times)")
flagSet.StringSlice("gitlab-project", []string{}, "restrict logins to members of this project (may be given multiple times) (eg `group/project=accesslevel`). Access level should be a value matching Gitlab access levels (see https://docs.gitlab.com/ee/api/members.html#valid-access-levels), defaulted to 20 if absent")
flagSet.StringSlice("google-group", []string{}, "restrict logins to members of this google group (may be given multiple times).") flagSet.StringSlice("google-group", []string{}, "restrict logins to members of this google group (may be given multiple times).")
flagSet.String("google-admin-email", "", "the google admin to impersonate for api calls") flagSet.String("google-admin-email", "", "the google admin to impersonate for api calls")
flagSet.String("google-service-account-json", "", "the path to the service account json credentials") flagSet.String("google-service-account-json", "", "the path to the service account json credentials")

View File

@ -29,7 +29,7 @@ func Validate(o *options.Options) error {
msgs = append(msgs, validateSessionCookieMinimal(o)...) msgs = append(msgs, validateSessionCookieMinimal(o)...)
msgs = append(msgs, validateRedisSessionStore(o)...) msgs = append(msgs, validateRedisSessionStore(o)...)
msgs = append(msgs, prefixValues("injectRequestHeaders: ", validateHeaders(o.InjectRequestHeaders)...)...) msgs = append(msgs, prefixValues("injectRequestHeaders: ", validateHeaders(o.InjectRequestHeaders)...)...)
msgs = append(msgs, prefixValues("injectRespeonseHeaders: ", validateHeaders(o.InjectRequestHeaders)...)...) msgs = append(msgs, prefixValues("injectResponseHeaders: ", validateHeaders(o.InjectResponseHeaders)...)...)
if o.SSLInsecureSkipVerify { if o.SSLInsecureSkipVerify {
// InsecureSkipVerify is a configurable option we allow // InsecureSkipVerify is a configurable option we allow
@ -282,6 +282,12 @@ func parseProviderInfo(o *options.Options, msgs []string) []string {
case *providers.GitLabProvider: case *providers.GitLabProvider:
p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
p.Groups = o.GitLabGroup p.Groups = o.GitLabGroup
err := p.AddProjects(o.GitlabProjects)
if err != nil {
msgs = append(msgs, "failed to setup gitlab project access level")
}
p.SetAllowedGroups(p.PrefixAllowedGroups())
p.SetProjectScope()
if p.Verifier == nil { if p.Verifier == nil {
// Initialize with default verifier for gitlab.com // Initialize with default verifier for gitlab.com

View File

@ -3,10 +3,13 @@ package providers
import ( import (
"context" "context"
"fmt" "fmt"
"net/url"
"strconv"
"strings"
"time" "time"
oidc "github.com/coreos/go-oidc"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions" "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests" "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@ -15,11 +18,54 @@ import (
type GitLabProvider struct { type GitLabProvider struct {
*ProviderData *ProviderData
Groups []string Groups []string
Verifier *oidc.IDTokenVerifier Projects []*GitlabProject
AllowUnverifiedEmail bool AllowUnverifiedEmail bool
} }
// GitlabProject represents a Gitlab project constraint entity
type GitlabProject struct {
Name string
AccessLevel int
}
// newGitlabProject Creates a new GitlabProject struct from project string formatted as namespace/project=accesslevel
// if no accesslevel provided, use the default one
func newGitlabproject(project string) (*GitlabProject, error) {
// default access level is 20
defaultAccessLevel := 20
// see https://docs.gitlab.com/ee/api/members.html#valid-access-levels
validAccessLevel := [4]int{10, 20, 30, 40}
parts := strings.SplitN(project, "=", 2)
if len(parts) == 2 {
lvl, err := strconv.Atoi(parts[1])
if err != nil {
return nil, err
}
for _, valid := range validAccessLevel {
if lvl == valid {
return &GitlabProject{
Name: parts[0],
AccessLevel: lvl},
err
}
}
return nil, fmt.Errorf("invalid gitlab project access level specified (%s)", parts[0])
}
return &GitlabProject{
Name: project,
AccessLevel: defaultAccessLevel},
nil
}
var _ Provider = (*GitLabProvider)(nil) var _ Provider = (*GitLabProvider)(nil)
const ( const (
@ -64,6 +110,19 @@ func (p *GitLabProvider) Redeem(ctx context.Context, redirectURL, code string) (
return return
} }
// SetProjectScope ensure read_api is added to scope when filtering on projects
func (p *GitLabProvider) SetProjectScope() {
if len(p.Projects) > 0 {
for _, val := range strings.Split(p.Scope, " ") {
if val == "read_api" {
return
}
}
p.Scope += " read_api"
}
}
// RefreshSessionIfNeeded checks if the session has expired and uses the // RefreshSessionIfNeeded checks if the session has expired and uses the
// RefreshToken to fetch a new ID token if required // RefreshToken to fetch a new ID token if required
func (p *GitLabProvider) RefreshSessionIfNeeded(ctx context.Context, s *sessions.SessionState) (bool, error) { func (p *GitLabProvider) RefreshSessionIfNeeded(ctx context.Context, s *sessions.SessionState) (bool, error) {
@ -144,25 +203,56 @@ func (p *GitLabProvider) getUserInfo(ctx context.Context, s *sessions.SessionSta
return &userInfo, nil return &userInfo, nil
} }
func (p *GitLabProvider) verifyGroupMembership(userInfo *gitlabUserInfo) error { type gitlabPermissionAccess struct {
if len(p.Groups) == 0 { AccessLevel int `json:"access_level"`
return nil }
type gitlabProjectPermission struct {
ProjectAccess *gitlabPermissionAccess `json:"project_access"`
GroupAccess *gitlabPermissionAccess `json:"group_access"`
}
type gitlabProjectInfo struct {
Name string `json:"name"`
Archived bool `json:"archived"`
PathWithNamespace string `json:"path_with_namespace"`
Permissions gitlabProjectPermission `json:"permissions"`
}
func (p *GitLabProvider) getProjectInfo(ctx context.Context, s *sessions.SessionState, project string) (*gitlabProjectInfo, error) {
var projectInfo gitlabProjectInfo
endpointURL := &url.URL{
Scheme: p.LoginURL.Scheme,
Host: p.LoginURL.Host,
Path: "/api/v4/projects/",
} }
// Collect user group memberships err := requests.New(fmt.Sprintf("%s%s", endpointURL.String(), url.QueryEscape(project))).
membershipSet := make(map[string]bool) WithContext(ctx).
for _, group := range userInfo.Groups { SetHeader("Authorization", "Bearer "+s.AccessToken).
membershipSet[group] = true Do().
UnmarshalInto(&projectInfo)
if err != nil {
return nil, fmt.Errorf("failed to get project info: %v", err)
} }
// Find a valid group that they are a member of return &projectInfo, nil
for _, validGroup := range p.Groups { }
if _, ok := membershipSet[validGroup]; ok {
return nil // AddProjects adds Gitlab projects from options to GitlabProvider struct
func (p *GitLabProvider) AddProjects(projects []string) error {
for _, project := range projects {
gp, err := newGitlabproject(project)
if err != nil {
return err
} }
p.Projects = append(p.Projects, gp)
} }
return fmt.Errorf("user is not a member of '%s'", p.Groups) return nil
} }
func (p *GitLabProvider) createSessionState(ctx context.Context, token *oauth2.Token) (*sessions.SessionState, error) { func (p *GitLabProvider) createSessionState(ctx context.Context, token *oauth2.Token) (*sessions.SessionState, error) {
@ -193,7 +283,7 @@ func (p *GitLabProvider) ValidateSession(ctx context.Context, s *sessions.Sessio
return err == nil return err == nil
} }
// GetEmailAddress returns the Account email address // EnrichSession adds values and data from the Gitlab endpoint to current session
func (p *GitLabProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error { func (p *GitLabProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {
// Retrieve user info // Retrieve user info
userInfo, err := p.getUserInfo(ctx, s) userInfo, err := p.getUserInfo(ctx, s)
@ -206,15 +296,67 @@ func (p *GitLabProvider) EnrichSession(ctx context.Context, s *sessions.SessionS
return fmt.Errorf("user email is not verified") return fmt.Errorf("user email is not verified")
} }
// Check group membership
// TODO (@NickMeves) - Refactor to Authorize
err = p.verifyGroupMembership(userInfo)
if err != nil {
return fmt.Errorf("group membership check failed: %v", err)
}
s.User = userInfo.Username s.User = userInfo.Username
s.Email = userInfo.Email s.Email = userInfo.Email
p.addGroupsToSession(ctx, s)
p.addProjectsToSession(ctx, s)
return nil return nil
}
// addGroupsToSession projects into session.Groups
func (p *GitLabProvider) addGroupsToSession(ctx context.Context, s *sessions.SessionState) {
// Iterate over projects, check if oauth2-proxy can get project information on behalf of the user
for _, group := range p.Groups {
s.Groups = append(s.Groups, fmt.Sprintf("group:%s", group))
}
}
// addProjectsToSession adds projects matching user access requirements into the session state groups list
// This method prefix projects names with `project` to specify group kind
func (p *GitLabProvider) addProjectsToSession(ctx context.Context, s *sessions.SessionState) {
// Iterate over projects, check if oauth2-proxy can get project information on behalf of the user
for _, project := range p.Projects {
projectInfo, err := p.getProjectInfo(ctx, s, project.Name)
if err != nil {
logger.Errorf("Warning: project info request failed: %v", err)
continue
}
if !projectInfo.Archived {
perms := projectInfo.Permissions.ProjectAccess
if perms == nil {
// use group project access as fallback
perms = projectInfo.Permissions.GroupAccess
}
if perms.AccessLevel >= project.AccessLevel {
s.Groups = append(s.Groups, fmt.Sprintf("project:%s", project.Name))
} else {
logger.Errorf("Warning: user %q does not have the minimum required access level for project %q", s.Email, project.Name)
}
} else {
logger.Errorf("Warning: project %s is archived", project.Name)
}
}
}
// PrefixAllowedGroups returns a list of allowed groups, prefixed by their `kind` value
func (p *GitLabProvider) PrefixAllowedGroups() (groups []string) {
for _, val := range p.Groups {
groups = append(groups, fmt.Sprintf("group:%s", val))
}
for _, val := range p.Projects {
groups = append(groups, fmt.Sprintf("project:%s", val.Name))
}
return groups
} }

View File

@ -2,13 +2,15 @@ package providers
import ( import (
"context" "context"
"errors"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"testing"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions" "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
"github.com/stretchr/testify/assert" . "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
) )
func testGitLabProvider(hostname string) *GitLabProvider { func testGitLabProvider(hostname string) *GitLabProvider {
@ -39,100 +41,241 @@ func testGitLabBackend() *httptest.Server {
"groups": ["foo", "bar"] "groups": ["foo", "bar"]
} }
` `
projectInfo := `
{
"name": "MyProject",
"archived": false,
"path_with_namespace": "my_group/my_project",
"permissions": {
"project_access": null,
"group_access": {
"access_level": 30,
"notification_level": 3
}
}
}
`
personalProjectInfo := `
{
"name": "MyPersonalProject",
"archived": false,
"path_with_namespace": "my_profile/my_personal_project",
"permissions": {
"project_access": {
"access_level": 30,
"notification_level": 3
},
"group_access": null
}
}
`
archivedProjectInfo := `
{
"name": "MyArchivedProject",
"archived": true,
"path_with_namespace": "my_group/my_archived_project",
"permissions": {
"project_access": {
"access_level": 30,
"notification_level": 3
},
"group_access": null
}
}
`
authHeader := "Bearer gitlab_access_token" authHeader := "Bearer gitlab_access_token"
return httptest.NewServer(http.HandlerFunc( return httptest.NewServer(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) { func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/oauth/userinfo" { switch r.URL.Path {
case "/oauth/userinfo":
if r.Header["Authorization"][0] == authHeader { if r.Header["Authorization"][0] == authHeader {
w.WriteHeader(200) w.WriteHeader(200)
w.Write([]byte(userInfo)) w.Write([]byte(userInfo))
} else { } else {
w.WriteHeader(401) w.WriteHeader(401)
} }
} else { case "/api/v4/projects/my_group/my_project":
if r.Header["Authorization"][0] == authHeader {
w.WriteHeader(200)
w.Write([]byte(projectInfo))
} else {
w.WriteHeader(401)
}
case "/api/v4/projects/my_group/my_archived_project":
if r.Header["Authorization"][0] == authHeader {
w.WriteHeader(200)
w.Write([]byte(archivedProjectInfo))
} else {
w.WriteHeader(401)
}
case "/api/v4/projects/my_profile/my_personal_project":
if r.Header["Authorization"][0] == authHeader {
w.WriteHeader(200)
w.Write([]byte(personalProjectInfo))
} else {
w.WriteHeader(401)
}
case "/api/v4/projects/my_group/my_bad_project":
w.WriteHeader(403)
default:
w.WriteHeader(404) w.WriteHeader(404)
} }
})) }))
} }
func TestGitLabProviderBadToken(t *testing.T) { var _ = Describe("Gitlab Provider Tests", func() {
b := testGitLabBackend() var p *GitLabProvider
defer b.Close() var b *httptest.Server
bURL, _ := url.Parse(b.URL) BeforeEach(func() {
p := testGitLabProvider(bURL.Host) b = testGitLabBackend()
session := &sessions.SessionState{AccessToken: "unexpected_gitlab_access_token"} bURL, err := url.Parse(b.URL)
err := p.EnrichSession(context.Background(), session) Expect(err).To(BeNil())
assert.Error(t, err)
}
func TestGitLabProviderUnverifiedEmailDenied(t *testing.T) { p = testGitLabProvider(bURL.Host)
b := testGitLabBackend() })
defer b.Close()
bURL, _ := url.Parse(b.URL) AfterEach(func() {
p := testGitLabProvider(bURL.Host) b.Close()
})
session := &sessions.SessionState{AccessToken: "gitlab_access_token"} Context("with bad token", func() {
err := p.EnrichSession(context.Background(), session) It("should trigger an error", func() {
assert.Error(t, err) p.AllowUnverifiedEmail = false
} session := &sessions.SessionState{AccessToken: "unexpected_gitlab_access_token"}
err := p.EnrichSession(context.Background(), session)
Expect(err).To(MatchError(errors.New("failed to retrieve user info: error getting user info: unexpected status \"401\": ")))
})
})
func TestGitLabProviderUnverifiedEmailAllowed(t *testing.T) { Context("when filtering on email", func() {
b := testGitLabBackend() type emailsTableInput struct {
defer b.Close() expectedError error
expectedValue string
allowUnverifiedEmail bool
}
bURL, _ := url.Parse(b.URL) DescribeTable("should return expected results",
p := testGitLabProvider(bURL.Host) func(in emailsTableInput) {
p.AllowUnverifiedEmail = true p.AllowUnverifiedEmail = in.allowUnverifiedEmail
session := &sessions.SessionState{AccessToken: "gitlab_access_token"}
session := &sessions.SessionState{AccessToken: "gitlab_access_token"} err := p.EnrichSession(context.Background(), session)
err := p.EnrichSession(context.Background(), session)
assert.NoError(t, err)
assert.Equal(t, "foo@bar.com", session.Email)
}
func TestGitLabProviderUsername(t *testing.T) { if in.expectedError != nil {
b := testGitLabBackend() Expect(err).To(MatchError(err))
defer b.Close() } else {
Expect(err).To(BeNil())
Expect(session.Email).To(Equal(in.expectedValue))
}
},
Entry("unverified email denied", emailsTableInput{
expectedError: errors.New("user email is not verified"),
allowUnverifiedEmail: false,
}),
Entry("unverified email allowed", emailsTableInput{
expectedError: nil,
expectedValue: "foo@bar.com",
allowUnverifiedEmail: true,
}),
)
})
bURL, _ := url.Parse(b.URL) Context("when filtering on gitlab entities (groups and projects)", func() {
p := testGitLabProvider(bURL.Host) type entitiesTableInput struct {
p.AllowUnverifiedEmail = true expectedValue []string
projects []string
groups []string
}
session := &sessions.SessionState{AccessToken: "gitlab_access_token"} DescribeTable("should return expected results",
err := p.EnrichSession(context.Background(), session) func(in entitiesTableInput) {
assert.NoError(t, err) p.AllowUnverifiedEmail = true
assert.Equal(t, "FooBar", session.User) session := &sessions.SessionState{AccessToken: "gitlab_access_token"}
}
func TestGitLabProviderGroupMembershipValid(t *testing.T) { err := p.AddProjects(in.projects)
b := testGitLabBackend() Expect(err).To(BeNil())
defer b.Close() p.SetProjectScope()
bURL, _ := url.Parse(b.URL) if len(in.groups) > 0 {
p := testGitLabProvider(bURL.Host) p.Groups = in.groups
p.AllowUnverifiedEmail = true }
p.Groups = []string{"foo"}
session := &sessions.SessionState{AccessToken: "gitlab_access_token"} err = p.EnrichSession(context.Background(), session)
err := p.EnrichSession(context.Background(), session)
assert.NoError(t, err)
assert.Equal(t, "FooBar", session.User)
}
func TestGitLabProviderGroupMembershipMissing(t *testing.T) { Expect(err).To(BeNil())
b := testGitLabBackend() Expect(session.Groups).To(Equal(in.expectedValue))
defer b.Close() },
Entry("project membership valid on group project", entitiesTableInput{
expectedValue: []string{"project:my_group/my_project"},
projects: []string{"my_group/my_project"},
}),
Entry("project membership invalid on group project, insufficient access level level", entitiesTableInput{
expectedValue: nil,
projects: []string{"my_group/my_project=40"},
}),
Entry("project membership valid on personnal project", entitiesTableInput{
expectedValue: []string{"project:my_profile/my_personal_project"},
projects: []string{"my_profile/my_personal_project"},
}),
Entry("project membership invalid on personnal project, insufficient access level", entitiesTableInput{
expectedValue: nil,
projects: []string{"my_profile/my_personal_project=40"},
}),
Entry("project membership invalid", entitiesTableInput{
expectedValue: nil,
projects: []string{"my_group/my_bad_project"},
}),
Entry("group membership valid", entitiesTableInput{
expectedValue: []string{"group:foo"},
groups: []string{"foo"},
}),
Entry("groups and projects", entitiesTableInput{
expectedValue: []string{"group:foo", "group:baz", "project:my_group/my_project", "project:my_profile/my_personal_project"},
groups: []string{"foo", "baz"},
projects: []string{"my_group/my_project", "my_profile/my_personal_project"},
}),
Entry("archived projects", entitiesTableInput{
expectedValue: nil,
groups: []string{},
projects: []string{"my_group/my_archived_project"},
}),
)
bURL, _ := url.Parse(b.URL) })
p := testGitLabProvider(bURL.Host)
p.AllowUnverifiedEmail = true
p.Groups = []string{"baz"}
session := &sessions.SessionState{AccessToken: "gitlab_access_token"} Context("when generating group list from multiple kind", func() {
err := p.EnrichSession(context.Background(), session) type entitiesTableInput struct {
assert.Error(t, err) projects []string
} groups []string
}
DescribeTable("should prefix entities with group kind", func(in entitiesTableInput) {
p.Groups = in.groups
err := p.AddProjects(in.projects)
Expect(err).To(BeNil())
all := p.PrefixAllowedGroups()
Expect(len(all)).To(Equal(len(in.projects) + len(in.groups)))
},
Entry("simple test case", entitiesTableInput{
projects: []string{"my_group/my_project", "my_group/my_other_project"},
groups: []string{"mygroup", "myothergroup"},
}),
Entry("projects only", entitiesTableInput{
projects: []string{"my_group/my_project", "my_group/my_other_project"},
groups: []string{},
}),
Entry("groups only", entitiesTableInput{
projects: []string{},
groups: []string{"mygroup", "myothergroup"},
}),
)
})
})

View File

@ -0,0 +1,16 @@
package providers_test
import (
"testing"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestProviderSuite(t *testing.T) {
logger.SetOutput(GinkgoWriter)
RegisterFailHandler(Fail)
RunSpecs(t, "Providers")
}