Skip to content

Commit

Permalink
Multiple providers in alpha config (oauth2-proxy#947)
Browse files Browse the repository at this point in the history
* Initial commit of multiple provider logic:
1. Created new provider options.
2. Created legacy provider options and conversion options.
3. Added Providers to alpha Options.
4. Started Validation migration of multiple providers
5. Tests.

* fixed lint issues

* additional lint fixes

* Nits and alterations based on CR: manliy splitting large providers validation function and adding comments to provider options

* fixed typo

* removed weird : file

* small CR changes

* Removed GoogleGroups validation due to new allowed-groups (including tests). Added line in CHANGELOG

* Update pkg/apis/options/providers.go

Co-authored-by: Joel Speed <[email protected]>

* Update pkg/apis/options/providers.go

Co-authored-by: Joel Speed <[email protected]>

* Update pkg/apis/options/providers.go

Co-authored-by: Nick Meves <[email protected]>

* Initial commit of multiple provider logic:
1. Created new provider options.
2. Created legacy provider options and conversion options.
3. Added Providers to alpha Options.
4. Started Validation migration of multiple providers
5. Tests.

* fixed lint issues

* additional lint fixes

* Nits and alterations based on CR: manliy splitting large providers validation function and adding comments to provider options

* small CR changes

* auto generates alpha_config.md

* rebase (mainly service alpha options related conflicts)

* removed :

* Nits and alterations based on CR: manliy splitting large providers validation function and adding comments to provider options

* small CR changes

* Removed GoogleGroups validation due to new allowed-groups (including tests). Added line in CHANGELOG

* "cntd. rebase"

* ran make generate again

* last conflicts

* removed duplicate client id validation

* 1. Removed provider prefixes
2. altered optionsWithNilProvider logic
3. altered default provider logic
4. moved change in CHANELOG to 7.0.0

* fixed TestGoogleGroupOptions test

* ran make generate

* moved CHANGLOG line to 7.1.1

* moved changelog comment to 7.1.2 (additional rebase)

Co-authored-by: Yana Segal <[email protected]>
Co-authored-by: Joel Speed <[email protected]>
Co-authored-by: Nick Meves <[email protected]>
  • Loading branch information
4 people authored Apr 3, 2021
1 parent 9d20b4e commit 42475c2
Show file tree
Hide file tree
Showing 18 changed files with 1,014 additions and 265 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

## Changes since v7.1.2

- [#947](https://github.com/oauth2-proxy/oauth2-proxy/pull/947) Multiple provider ingestion and validation in alpha options (first stage: [#926](https://github.com/oauth2-proxy/oauth2-proxy/issues/926)) (@yanasega)

# V7.1.2

## Release Highlights
Expand Down
5 changes: 0 additions & 5 deletions contrib/local-environment/oauth2-proxy-alpha-config.cfg
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
http_address="0.0.0.0:4180"
cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
provider="oidc"
email_domains="example.com"
oidc_issuer_url="http://dex.localhost:4190/dex"
client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK"
client_id="oauth2-proxy"
cookie_secure="false"

redirect_url="http://localhost:4180/oauth2/callback"
6 changes: 6 additions & 0 deletions contrib/local-environment/oauth2-proxy-alpha-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ injectRequestHeaders:
- name: X-Forwarded-Preferred-Username
values:
- claim: preferred_username
providers:
- provider: oidc
clientSecret: b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK
clientID: oauth2-proxy
oidcConfig:
oidcIssuerURL: http://dex.localhost:4190/dex
141 changes: 141 additions & 0 deletions docs/docs/configuration/alpha_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,28 @@ They may change between releases without notice.
| `injectResponseHeaders` | _[[]Header](#header)_ | InjectResponseHeaders is used to configure headers that should be added<br/>to responses from the proxy.<br/>This is typically used when using the proxy as an external authentication<br/>provider in conjunction with another proxy such as NGINX and its<br/>auth_request module.<br/>Headers may source values from either the authenticated user's session<br/>or from a static secret value. |
| `server` | _[Server](#server)_ | Server is used to configure the HTTP(S) server for the proxy application.<br/>You may choose to run both HTTP and HTTPS servers simultaneously.<br/>This can be done by setting the BindAddress and the SecureBindAddress simultaneously.<br/>To use the secure server you must configure a TLS certificate and key. |
| `metricsServer` | _[Server](#server)_ | MetricsServer is used to configure the HTTP(S) server for metrics.<br/>You may choose to run both HTTP and HTTPS servers simultaneously.<br/>This can be done by setting the BindAddress and the SecureBindAddress simultaneously.<br/>To use the secure server you must configure a TLS certificate and key. |
| `providers` | _[Providers](#providers)_ | Providers is used to configure multiple providers. |

### AzureOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `tenant` | _string_ | Tenant directs to a tenant-specific or common (tenant-independent) endpoint<br/>Default value is 'commmon' |

### BitbucketOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `team` | _string_ | Team sets restrict logins to members of this team |
| `repository` | _string_ | Repository sets restrict logins to user with access to this repository |

### ClaimSource

Expand All @@ -143,6 +165,43 @@ each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".


### GitHubOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `org` | _string_ | Org sets restrict logins to members of this organisation |
| `team` | _string_ | Team sets restrict logins to members of this team |
| `repo` | _string_ | Repo sets restrict logins to collaborators of this repository |
| `token` | _string_ | Token is the token to use when verifying repository collaborators<br/>it must have push access to the repository |
| `users` | _[]string_ | Users allows users with these usernames to login<br/>even if they do not belong to the specified org and team or collaborators |

### GitLabOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `group` | _[]string_ | Group sets restrict logins to members of this group |
| `projects` | _[]string_ | Projects restricts logins to members of any of these projects |

### GoogleOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `group` | _[]string_ | Groups sets restrict logins to members of this google group |
| `adminEmail` | _string_ | AdminEmail is the google admin to impersonate for api calls |
| `serviceAccountJson` | _string_ | ServiceAccountJSON is the path to the service account json credentials |

### Header

(**Appears on:** [AlphaOptions](#alphaoptions))
Expand Down Expand Up @@ -172,6 +231,88 @@ make up the header value
| `prefix` | _string_ | Prefix is an optional prefix that will be prepended to the value of the<br/>claim if it is non-empty. |
| `basicAuthPassword` | _[SecretSource](#secretsource)_ | BasicAuthPassword converts this claim into a basic auth header.<br/>Note the value of claim will become the basic auth username and the<br/>basicAuthPassword will be used as the password value. |

### KeycloakOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `groups` | _[]string_ | Group enables to restrict login to members of indicated group |

### LoginGovOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `jwtKey` | _string_ | JWTKey is a private key in PEM format used to sign JWT, |
| `jwtKeyFile` | _string_ | JWTKeyFile is a path to the private key file in PEM format used to sign the JWT |
| `pubjwkURL` | _string_ | PubJWKURL is the JWK pubkey access endpoint |

### OIDCOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `issuerURL` | _string_ | IssuerURL is the OpenID Connect issuer URL<br/>eg: https://accounts.google.com |
| `insecureAllowUnverifiedEmail` | _bool_ | InsecureAllowUnverifiedEmail prevents failures if an email address in an id_token is not verified<br/>default set to 'false' |
| `insecureSkipIssuerVerification` | _bool_ | InsecureSkipIssuerVerification skips verification of ID token issuers. When false, ID Token Issuers must match the OIDC discovery URL<br/>default set to 'false' |
| `skipDiscovery` | _bool_ | SkipDiscovery allows to skip OIDC discovery and use manually supplied Endpoints<br/>default set to 'false' |
| `jwksURL` | _string_ | JwksURL is the OpenID Connect JWKS URL<br/>eg: https://www.googleapis.com/oauth2/v3/certs |
| `emailClaim` | _string_ | EmailClaim indicates which claim contains the user email,<br/>default set to 'email' |
| `groupsClaim` | _string_ | GroupsClaim indicates which claim contains the user groups<br/>default set to 'groups' |
| `userIDClaim` | _string_ | UserIDClaim indicates which claim contains the user ID<br/>default set to 'email' |

### Provider

(**Appears on:** [Providers](#providers))

Provider holds all configuration for a single provider

| Field | Type | Description |
| ----- | ---- | ----------- |
| `clientID` | _string_ | ClientID is the OAuth Client ID that is defined in the provider<br/>This value is required for all providers. |
| `clientSecret` | _string_ | ClientSecret is the OAuth Client Secret that is defined in the provider<br/>This value is required for all providers. |
| `clientSecretFile` | _string_ | ClientSecretFile is the name of the file<br/>containing the OAuth Client Secret, it will be used if ClientSecret is not set. |
| `keycloakConfig` | _[KeycloakOptions](#keycloakoptions)_ | KeycloakConfig holds all configurations for Keycloak provider. |
| `azureConfig` | _[AzureOptions](#azureoptions)_ | AzureConfig holds all configurations for Azure provider. |
| `bitbucketConfig` | _[BitbucketOptions](#bitbucketoptions)_ | BitbucketConfig holds all configurations for Bitbucket provider. |
| `githubConfig` | _[GitHubOptions](#githuboptions)_ | GitHubConfig holds all configurations for GitHubC provider. |
| `gitlabConfig` | _[GitLabOptions](#gitlaboptions)_ | GitLabConfig holds all configurations for GitLab provider. |
| `googleConfig` | _[GoogleOptions](#googleoptions)_ | GoogleConfig holds all configurations for Google provider. |
| `oidcConfig` | _[OIDCOptions](#oidcoptions)_ | OIDCConfig holds all configurations for OIDC provider<br/>or providers utilize OIDC configurations. |
| `loginGovConfig` | _[LoginGovOptions](#logingovoptions)_ | LoginGovConfig holds all configurations for LoginGov provider. |
| `id` | _string_ | ID should be a unique identifier for the provider.<br/>This value is required for all providers. |
| `provider` | _string_ | Type is the OAuth provider<br/>must be set from the supported providers group,<br/>otherwise 'Google' is set as default |
| `name` | _string_ | Name is the providers display name<br/>if set, it will be shown to the users in the login page. |
| `caFiles` | _[]string_ | CAFiles is a list of paths to CA certificates that should be used when connecting to the provider.<br/>If not specified, the default Go trust sources are used instead |
| `loginURL` | _string_ | LoginURL is the authentication endpoint |
| `redeemURL` | _string_ | RedeemURL is the token redemption endpoint |
| `profileURL` | _string_ | ProfileURL is the profile access endpoint |
| `resource` | _string_ | ProtectedResource is the resource that is protected (Azure AD only) |
| `validateURL` | _string_ | ValidateURL is the access token validation endpoint |
| `scope` | _string_ | Scope is the OAuth scope specification |
| `prompt` | _string_ | Prompt is OIDC prompt |
| `approvalPrompt` | _string_ | ApprovalPrompt is the OAuth approval_prompt<br/>default is set to 'force' |
| `allowedGroups` | _[]string_ | AllowedGroups is a list of restrict logins to members of this group |
| `acrValues` | _string_ | AcrValues is a string of acr values |

### Providers

#### ([[]Provider](#provider) alias)

(**Appears on:** [AlphaOptions](#alphaoptions))

Providers is a collection of definitions for providers.


### SecretSource

(**Appears on:** [ClaimSource](#claimsource), [HeaderValue](#headervalue), [TLS](#tls))
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
Expand Down
42 changes: 33 additions & 9 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ http_address="127.0.0.1:4180"
upstreams="http://httpbin"
set_basic_auth="true"
basic_auth_password="super-secret-password"
client_id="oauth2-proxy"
client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK"
`

const testAlphaConfig = `
Expand Down Expand Up @@ -57,15 +59,23 @@ injectResponseHeaders:
value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk
server:
bindAddress: "127.0.0.1:4180"
providers:
- provider: google
ID: google=oauth2-proxy
clientSecret: b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK
clientID: oauth2-proxy
approvalPrompt: force
azureConfig:
tenant: common
oidcConfig:
groupsClaim: groups
emailClaim: email
userIDClaim: email
`

const testCoreConfig = `
cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
provider="oidc"
email_domains="example.com"
oidc_issuer_url="http://dex.localhost:4190/dex"
client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK"
client_id="oauth2-proxy"
cookie_secure="false"
redirect_url="http://localhost:4180/oauth2/callback"
Expand All @@ -85,11 +95,7 @@ redirect_url="http://localhost:4180/oauth2/callback"
Expect(err).ToNot(HaveOccurred())

opts.Cookie.Secret = "OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
opts.ProviderType = "oidc"
opts.EmailDomains = []string{"example.com"}
opts.OIDCIssuerURL = "http://dex.localhost:4190/dex"
opts.ClientSecret = "b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK"
opts.ClientID = "oauth2-proxy"
opts.Cookie.Secure = false
opts.RawRedirectURL = "http://localhost:4180/oauth2/callback"

Expand Down Expand Up @@ -121,6 +127,24 @@ redirect_url="http://localhost:4180/oauth2/callback"

opts.InjectRequestHeaders = append([]options.Header{authHeader}, opts.InjectRequestHeaders...)
opts.InjectResponseHeaders = append(opts.InjectResponseHeaders, authHeader)

opts.Providers = options.Providers{
{
ID: "google=oauth2-proxy",
Type: "google",
ClientSecret: "b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK",
ClientID: "oauth2-proxy",
AzureConfig: options.AzureOptions{
Tenant: "common",
},
OIDCConfig: options.OIDCOptions{
GroupsClaim: "groups",
EmailClaim: "email",
UserIDClaim: "email",
},
ApprovalPrompt: "force",
},
}
return opts
}

Expand Down Expand Up @@ -204,7 +228,7 @@ redirect_url="http://localhost:4180/oauth2/callback"
configContent: testCoreConfig,
alphaConfigContent: testAlphaConfig + ":",
expectedOptions: func() *options.Options { return nil },
expectedErr: errors.New("failed to load alpha options: error unmarshalling config: error converting YAML to JSON: yaml: line 36: did not find expected key"),
expectedErr: errors.New("failed to load alpha options: error unmarshalling config: error converting YAML to JSON: yaml: line 48: did not find expected key"),
}),
Entry("with alpha configuration and bad core configuration", loadConfigurationTableInput{
configContent: testCoreConfig + "unknown_field=\"something\"",
Expand Down
6 changes: 3 additions & 3 deletions oauthproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
Footer: opts.Templates.Footer,
Version: VERSION,
Debug: opts.Templates.Debug,
ProviderName: buildProviderName(opts.GetProvider(), opts.ProviderName),
ProviderName: buildProviderName(opts.GetProvider(), opts.Providers[0].Name),
SignInMessage: buildSignInMessage(opts),
DisplayLoginForm: basicAuthValidator != nil && opts.Templates.DisplayLoginForm,
})
Expand All @@ -136,7 +136,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
}

if opts.SkipJwtBearerTokens {
logger.Printf("Skipping JWT tokens from configured OIDC issuer: %q", opts.OIDCIssuerURL)
logger.Printf("Skipping JWT tokens from configured OIDC issuer: %q", opts.Providers[0].OIDCConfig.IssuerURL)
for _, issuer := range opts.ExtraJwtIssuers {
logger.Printf("Skipping JWT tokens from extra JWT issuer: %q", issuer)
}
Expand All @@ -146,7 +146,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
redirectURL.Path = fmt.Sprintf("%s/callback", opts.ProxyPrefix)
}

logger.Printf("OAuthProxy configured for %s Client ID: %s", opts.GetProvider().Data().ProviderName, opts.ClientID)
logger.Printf("OAuthProxy configured for %s Client ID: %s", opts.GetProvider().Data().ProviderName, opts.Providers[0].ClientID)
refresh := "disabled"
if opts.Cookie.Refresh != time.Duration(0) {
refresh = fmt.Sprintf("after %s", opts.Cookie.Refresh)
Expand Down
13 changes: 7 additions & 6 deletions oauthproxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifi
ProviderData: &providers.ProviderData{},
ValidToken: opts.providerValidateCookieResponse,
}
pcTest.proxy.provider.(*TestProvider).SetAllowedGroups(pcTest.opts.AllowedGroups)
pcTest.proxy.provider.(*TestProvider).SetAllowedGroups(pcTest.opts.Providers[0].AllowedGroups)

pcTest.rw = httptest.NewRecorder()
pcTest.req, _ = http.NewRequest("GET", "/", strings.NewReader(""))
Expand Down Expand Up @@ -1322,7 +1322,7 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
},
},
}
pcTest.opts.AllowedGroups = []string{"oauth_groups"}
pcTest.opts.Providers[0].AllowedGroups = []string{"oauth_groups"}
err := validation.Validate(pcTest.opts)
assert.NoError(t, err)

Expand Down Expand Up @@ -2292,8 +2292,9 @@ func Test_noCacheHeaders(t *testing.T) {
func baseTestOptions() *options.Options {
opts := options.NewOptions()
opts.Cookie.Secret = rawCookieSecret
opts.ClientID = clientID
opts.ClientSecret = clientSecret
opts.Providers[0].ID = "providerID"
opts.Providers[0].ClientID = clientID
opts.Providers[0].ClientSecret = clientSecret
opts.EmailDomains = []string{"*"}

// Default injected headers for legacy configuration
Expand Down Expand Up @@ -2786,7 +2787,7 @@ func TestProxyAllowedGroups(t *testing.T) {
t.Cleanup(upstreamServer.Close)

test, err := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
opts.AllowedGroups = tt.allowedGroups
opts.Providers[0].AllowedGroups = tt.allowedGroups
opts.UpstreamServers = options.Upstreams{
{
ID: upstreamServer.URL,
Expand Down Expand Up @@ -2915,7 +2916,7 @@ func TestAuthOnlyAllowedGroups(t *testing.T) {
}

test, err := NewAuthOnlyEndpointTest(tc.querystring, func(opts *options.Options) {
opts.AllowedGroups = tc.allowedGroups
opts.Providers[0].AllowedGroups = tc.allowedGroups
})
if err != nil {
t.Fatal(err)
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/options/alpha_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type AlphaOptions struct {
// This can be done by setting the BindAddress and the SecureBindAddress simultaneously.
// To use the secure server you must configure a TLS certificate and key.
MetricsServer Server `json:"metricsServer,omitempty"`

// Providers is used to configure multiple providers.
Providers Providers `json:"providers,omitempty"`
}

// MergeInto replaces alpha options in the Options struct with the values
Expand All @@ -50,6 +53,8 @@ func (a *AlphaOptions) MergeInto(opts *Options) {
opts.InjectResponseHeaders = a.InjectResponseHeaders
opts.Server = a.Server
opts.MetricsServer = a.MetricsServer
opts.Providers = a.Providers

}

// ExtractFrom populates the fields in the AlphaOptions with the values from
Expand All @@ -60,4 +65,5 @@ func (a *AlphaOptions) ExtractFrom(opts *Options) {
a.InjectResponseHeaders = opts.InjectResponseHeaders
a.Server = opts.Server
a.MetricsServer = opts.MetricsServer
a.Providers = opts.Providers
}
Loading

0 comments on commit 42475c2

Please sign in to comment.