identity: support custom code flow request params (#998)

Signed-off-by: Bobby DeSimone <bobbydesimone@gmail.com>
This commit is contained in:
bobby 2020-06-25 08:28:46 -07:00 committed by GitHub
parent 666420f4c9
commit dbd1eac97f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 48 deletions

View file

@ -182,6 +182,7 @@ func New(opts config.Options) (*Authenticate, error) {
ClientSecret: opts.ClientSecret,
Scopes: opts.Scopes,
ServiceAccount: opts.ServiceAccount,
AuthCodeOptions: opts.RequestParams,
})
if err != nil {

View file

@ -125,6 +125,13 @@ type Options struct {
Scopes []string `mapstructure:"idp_scopes" yaml:"idp_scopes,omitempty"`
ServiceAccount string `mapstructure:"idp_service_account" yaml:"idp_service_account,omitempty"`
// RequestParams are custom request params added to the signin request as
// part of an Oauth2 code flow.
//
// https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml
// https://openid.net/specs/openid-connect-basic-1_0.html#RequestParameters
RequestParams map[string]string `mapstructure:"idp_request_params" yaml:"idp_request_params,omitempty"`
// Administrators contains a set of emails with users who have super user
// (sudo) access including the ability to impersonate other users' access
Administrators []string `mapstructure:"administrators" yaml:"administrators,omitempty"`
@ -154,7 +161,6 @@ type Options struct {
// RefreshCooldown limits the rate a user can refresh her session
RefreshCooldown time.Duration `mapstructure:"refresh_cooldown" yaml:"refresh_cooldown,omitempty"`
//Routes map[string]string `mapstructure:"routes" yaml:"routes,omitempty"`
DefaultUpstreamTimeout time.Duration `mapstructure:"default_upstream_timeout" yaml:"default_upstream_timeout,omitempty"`
// Address/Port to bind to for prometheus metrics

View file

@ -74,16 +74,11 @@ Autocert requires that ports `80`/`443` be accessible from the internet in order
- Type: `bool`
- Optional
If true, cause autocert to request a certificate with `status_request`
extension (commonly called `Must-Staple`). This allows the TLS client
(the browser) to fail immediately if the TLS handshake doesn't include
OCSP stapling information. Only used when [Autocert](./#autocert) is
true.
If true, cause autocert to request a certificate with `status_request` extension (commonly called `Must-Staple`). This allows the TLS client (the browser) to fail immediately if the TLS handshake doesn't include OCSP stapling information. Only used when [Autocert](./#autocert) is true.
NOTE: this only takes effect the next time Pomerium renews your
certificates.
NOTE: this only takes effect the next time Pomerium renews your certificates.
See also https://tools.ietf.org/html/rfc7633 for more context.
See also <https://tools.ietf.org/html/rfc7633> for more context.
### Autocert Directory
@ -294,8 +289,7 @@ spec:
#### Traefik docker-compose
If the `forward_auth_url` is also handled by Traefik, you will need to configure Traefik to trust the `X-Forwarded-*`
headers as described in [the documentation](https://docs.traefik.io/v2.2/routing/entrypoints/#forwarded-headers).
If the `forward_auth_url` is also handled by Traefik, you will need to configure Traefik to trust the `X-Forwarded-*` headers as described in [the documentation](https://docs.traefik.io/v2.2/routing/entrypoints/#forwarded-headers).
```yml
version: "3"
@ -487,9 +481,7 @@ pomerium_config_last_reload_success_timestamp | Gauge | The timestamp of the
#### Envoy Proxy Metrics
As of `v0.9`, Pomerium uses [envoy Proxy]([https://](https://www.envoyproxy.io/) for the data plane. As such, proxy related metrics are sourced
from envoy, and use envoy's internal [stats data model](https://www.envoyproxy.io/docs/envoy/latest/operations/stats_overview). Please see Envoy's documentation for information
about specific metrics.
As of `v0.9`, Pomerium uses [envoy Proxy]([https://](https://www.envoyproxy.io/) for the data plane. As such, proxy related metrics are sourced from envoy, and use envoy's internal [stats data model](https://www.envoyproxy.io/docs/envoy/latest/operations/stats_overview). Please see Envoy's documentation for information about specific metrics.
All metrics coming from envoy will be labeled with `service="pomerium"` or `service="pomerium-proxy"`, depending if you're running all-in-one or distributed service mode.
@ -658,6 +650,22 @@ Identity Provider Service Account is field used to configure any additional user
Provider URL is the base path to an identity provider's [OpenID connect discovery document](https://openid.net/specs/openid-connect-discovery-1_0.html). For example, google's URL would be `https://accounts.google.com` for [their discover document](https://accounts.google.com/.well-known/openid-configuration).
### Identity Provider Request Params
- Environmental Variable: `IDP_REQUEST_PARAMS`
- Config File Key: `idp_request_params`
- Type: map of `strings` key value pairs
- Optional
Request parameters to be added as part of a signin request using OAuth2 code flow.
For more information see:
- [OIDC Request Parameters](https://openid.net/specs/openid-connect-basic-1_0.html#RequestParameters)
- [IANA OAuth Parameters](https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml)
- [Microsoft Azure Request params](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code)
- [Google Authentication URI parameters](https://developers.google.com/identity/protocols/oauth2/openid-connect)
## Proxy Service
### Authenticate Service URL

View file

@ -29,4 +29,8 @@ type Options struct {
// ServiceAccount can be set for those providers that require additional
// credentials or tokens to do follow up API calls (e.g. Google)
ServiceAccount string
// AuthCodeOptions specifies additional key value pairs query params to add
// to the request flow signin url.
AuthCodeOptions map[string]string
}

View file

@ -7,8 +7,6 @@ import (
"context"
"fmt"
"golang.org/x/oauth2"
"github.com/pomerium/pomerium/internal/identity/oauth"
pom_oidc "github.com/pomerium/pomerium/internal/identity/oidc"
)
@ -21,6 +19,9 @@ const Name = "azure"
// an sign in to the application.
const defaultProviderURL = "https://login.microsoftonline.com/common"
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code
var defaultAuthCodeOptions = map[string]string{"prompt": "select_account"}
// Provider is an Azure implementation of the Authenticator interface.
type Provider struct {
*pom_oidc.Provider
@ -38,11 +39,11 @@ func New(ctx context.Context, o *oauth.Options) (*Provider, error) {
return nil, fmt.Errorf("%s: failed creating oidc provider: %w", Name, err)
}
p.Provider = genericOidc
return &p, nil
p.AuthCodeOptions = defaultAuthCodeOptions
if len(o.AuthCodeOptions) != 0 {
p.AuthCodeOptions = o.AuthCodeOptions
}
// GetSignInURL returns the sign in url with typical oauth parameters
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-implicit-grant-flow
func (p *Provider) GetSignInURL(state string) string {
return p.Oauth.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("prompt", "select_account"))
return &p, nil
}

View file

@ -9,7 +9,6 @@ import (
"fmt"
oidc "github.com/coreos/go-oidc"
"golang.org/x/oauth2"
"github.com/pomerium/pomerium/internal/identity/oauth"
pom_oidc "github.com/pomerium/pomerium/internal/identity/oidc"
@ -24,6 +23,9 @@ const (
var defaultScopes = []string{oidc.ScopeOpenID, "profile", "email"}
// https://developers.google.com/identity/protocols/oauth2/openid-connect#authenticationuriparameters
var defaultAuthCodeOptions = map[string]string{"prompt": "select_account consent"}
// Provider is a Google implementation of the Authenticator interface.
type Provider struct {
*pom_oidc.Provider
@ -45,20 +47,9 @@ func New(ctx context.Context, o *oauth.Options) (*Provider, error) {
}
p.Provider = genericOidc
p.AuthCodeOptions = defaultAuthCodeOptions
if len(o.AuthCodeOptions) != 0 {
p.AuthCodeOptions = o.AuthCodeOptions
}
return &p, nil
}
// GetSignInURL returns a URL to OAuth 2.0 provider's consent page that asks for permissions for
// the required scopes explicitly.
// Google requires an additional access scope for offline access which is a requirement for any
// application that needs to access a Google API when the user is not present.
// Support for this scope differs between OpenID Connect providers. For instance
// Google rejects it, favoring appending "access_type=offline" as part of the
// authorization request instead.
// Google only provide refresh_token on the first authorization from the user. If user clears
// cookies, re-authorization will not bring back refresh_token. A work around to this is to add
// prompt=consent to the OAuth redirect URL and will always return a refresh_token.
// https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
func (p *Provider) GetSignInURL(state string) string {
return p.Oauth.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("prompt", "select_account consent"))
}

View file

@ -25,6 +25,8 @@ const Name = "oidc"
var defaultScopes = []string{go_oidc.ScopeOpenID, "profile", "email", "offline_access"}
var defaultAuthCodeOptions = []oauth2.AuthCodeOption{oauth2.AccessTypeOffline}
// Provider provides a standard, OpenID Connect implementation
// of an authorization identity provider.
// https://openid.net/specs/openid-connect-core-1_0.html
@ -45,6 +47,10 @@ type Provider struct {
// providers that doesn't implement the revocation endpoint but a logout session.
// https://openid.net/specs/openid-connect-frontchannel-1_0.html#RPInitiated
EndSessionURL string `json:"end_session_endpoint,omitempty"`
// AuthCodeOptions specifies additional key value pairs query params to add
// to the request flow signin url.
AuthCodeOptions map[string]string
}
// New creates a new instance of a generic OpenID Connect provider.
@ -71,6 +77,10 @@ func New(ctx context.Context, o *oauth.Options) (*Provider, error) {
RedirectURL: o.RedirectURL.String(),
}
if len(o.AuthCodeOptions) != 0 {
p.AuthCodeOptions = o.AuthCodeOptions
}
// add non-standard claims like end-session, revoke, and user info
if err := p.Provider.Claims(&p); err != nil {
return nil, fmt.Errorf("identity/oidc: could not retrieve additional claims: %w", err)
@ -86,7 +96,11 @@ func New(ctx context.Context, o *oauth.Options) (*Provider, error) {
// the state query parameter on your redirect callback.
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
func (p *Provider) GetSignInURL(state string) string {
return p.Oauth.AuthCodeURL(state, oauth2.AccessTypeOffline)
opts := defaultAuthCodeOptions
for k, v := range p.AuthCodeOptions {
opts = append(opts, oauth2.SetAuthURLParam(k, v))
}
return p.Oauth.AuthCodeURL(state, opts...)
}
// Authenticate converts an authorization code returned from the identity