mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-12 07:42:49 +02:00
identity: support custom code flow request params (#998)
Signed-off-by: Bobby DeSimone <bobbydesimone@gmail.com>
This commit is contained in:
parent
666420f4c9
commit
dbd1eac97f
7 changed files with 73 additions and 48 deletions
|
@ -182,6 +182,7 @@ func New(opts config.Options) (*Authenticate, error) {
|
||||||
ClientSecret: opts.ClientSecret,
|
ClientSecret: opts.ClientSecret,
|
||||||
Scopes: opts.Scopes,
|
Scopes: opts.Scopes,
|
||||||
ServiceAccount: opts.ServiceAccount,
|
ServiceAccount: opts.ServiceAccount,
|
||||||
|
AuthCodeOptions: opts.RequestParams,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -125,6 +125,13 @@ type Options struct {
|
||||||
Scopes []string `mapstructure:"idp_scopes" yaml:"idp_scopes,omitempty"`
|
Scopes []string `mapstructure:"idp_scopes" yaml:"idp_scopes,omitempty"`
|
||||||
ServiceAccount string `mapstructure:"idp_service_account" yaml:"idp_service_account,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
|
// Administrators contains a set of emails with users who have super user
|
||||||
// (sudo) access including the ability to impersonate other users' access
|
// (sudo) access including the ability to impersonate other users' access
|
||||||
Administrators []string `mapstructure:"administrators" yaml:"administrators,omitempty"`
|
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 limits the rate a user can refresh her session
|
||||||
RefreshCooldown time.Duration `mapstructure:"refresh_cooldown" yaml:"refresh_cooldown,omitempty"`
|
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"`
|
DefaultUpstreamTimeout time.Duration `mapstructure:"default_upstream_timeout" yaml:"default_upstream_timeout,omitempty"`
|
||||||
|
|
||||||
// Address/Port to bind to for prometheus metrics
|
// Address/Port to bind to for prometheus metrics
|
||||||
|
|
|
@ -74,16 +74,11 @@ Autocert requires that ports `80`/`443` be accessible from the internet in order
|
||||||
- Type: `bool`
|
- Type: `bool`
|
||||||
- Optional
|
- Optional
|
||||||
|
|
||||||
If true, cause autocert to request a certificate with `status_request`
|
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.
|
||||||
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
|
NOTE: this only takes effect the next time Pomerium renews your certificates.
|
||||||
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
|
### Autocert Directory
|
||||||
|
|
||||||
|
@ -294,8 +289,7 @@ spec:
|
||||||
|
|
||||||
#### Traefik docker-compose
|
#### Traefik docker-compose
|
||||||
|
|
||||||
If the `forward_auth_url` is also handled by Traefik, you will need to configure Traefik to trust the `X-Forwarded-*`
|
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).
|
||||||
headers as described in [the documentation](https://docs.traefik.io/v2.2/routing/entrypoints/#forwarded-headers).
|
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
version: "3"
|
version: "3"
|
||||||
|
@ -487,9 +481,7 @@ pomerium_config_last_reload_success_timestamp | Gauge | The timestamp of the
|
||||||
|
|
||||||
#### Envoy Proxy Metrics
|
#### 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
|
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.
|
||||||
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.
|
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).
|
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
|
## Proxy Service
|
||||||
|
|
||||||
### Authenticate Service URL
|
### Authenticate Service URL
|
||||||
|
|
|
@ -29,4 +29,8 @@ type Options struct {
|
||||||
// ServiceAccount can be set for those providers that require additional
|
// ServiceAccount can be set for those providers that require additional
|
||||||
// credentials or tokens to do follow up API calls (e.g. Google)
|
// credentials or tokens to do follow up API calls (e.g. Google)
|
||||||
ServiceAccount string
|
ServiceAccount string
|
||||||
|
|
||||||
|
// AuthCodeOptions specifies additional key value pairs query params to add
|
||||||
|
// to the request flow signin url.
|
||||||
|
AuthCodeOptions map[string]string
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/internal/identity/oauth"
|
"github.com/pomerium/pomerium/internal/identity/oauth"
|
||||||
pom_oidc "github.com/pomerium/pomerium/internal/identity/oidc"
|
pom_oidc "github.com/pomerium/pomerium/internal/identity/oidc"
|
||||||
)
|
)
|
||||||
|
@ -21,6 +19,9 @@ const Name = "azure"
|
||||||
// an sign in to the application.
|
// an sign in to the application.
|
||||||
const defaultProviderURL = "https://login.microsoftonline.com/common"
|
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.
|
// Provider is an Azure implementation of the Authenticator interface.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
*pom_oidc.Provider
|
*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)
|
return nil, fmt.Errorf("%s: failed creating oidc provider: %w", Name, err)
|
||||||
}
|
}
|
||||||
p.Provider = genericOidc
|
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
|
return &p, nil
|
||||||
// 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"))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
oidc "github.com/coreos/go-oidc"
|
oidc "github.com/coreos/go-oidc"
|
||||||
"golang.org/x/oauth2"
|
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/internal/identity/oauth"
|
"github.com/pomerium/pomerium/internal/identity/oauth"
|
||||||
pom_oidc "github.com/pomerium/pomerium/internal/identity/oidc"
|
pom_oidc "github.com/pomerium/pomerium/internal/identity/oidc"
|
||||||
|
@ -24,6 +23,9 @@ const (
|
||||||
|
|
||||||
var defaultScopes = []string{oidc.ScopeOpenID, "profile", "email"}
|
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.
|
// Provider is a Google implementation of the Authenticator interface.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
*pom_oidc.Provider
|
*pom_oidc.Provider
|
||||||
|
@ -45,20 +47,9 @@ func New(ctx context.Context, o *oauth.Options) (*Provider, error) {
|
||||||
}
|
}
|
||||||
p.Provider = genericOidc
|
p.Provider = genericOidc
|
||||||
|
|
||||||
|
p.AuthCodeOptions = defaultAuthCodeOptions
|
||||||
|
if len(o.AuthCodeOptions) != 0 {
|
||||||
|
p.AuthCodeOptions = o.AuthCodeOptions
|
||||||
|
}
|
||||||
return &p, nil
|
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"))
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ const Name = "oidc"
|
||||||
|
|
||||||
var defaultScopes = []string{go_oidc.ScopeOpenID, "profile", "email", "offline_access"}
|
var defaultScopes = []string{go_oidc.ScopeOpenID, "profile", "email", "offline_access"}
|
||||||
|
|
||||||
|
var defaultAuthCodeOptions = []oauth2.AuthCodeOption{oauth2.AccessTypeOffline}
|
||||||
|
|
||||||
// Provider provides a standard, OpenID Connect implementation
|
// Provider provides a standard, OpenID Connect implementation
|
||||||
// of an authorization identity provider.
|
// of an authorization identity provider.
|
||||||
// https://openid.net/specs/openid-connect-core-1_0.html
|
// 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.
|
// providers that doesn't implement the revocation endpoint but a logout session.
|
||||||
// https://openid.net/specs/openid-connect-frontchannel-1_0.html#RPInitiated
|
// https://openid.net/specs/openid-connect-frontchannel-1_0.html#RPInitiated
|
||||||
EndSessionURL string `json:"end_session_endpoint,omitempty"`
|
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.
|
// 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(),
|
RedirectURL: o.RedirectURL.String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(o.AuthCodeOptions) != 0 {
|
||||||
|
p.AuthCodeOptions = o.AuthCodeOptions
|
||||||
|
}
|
||||||
|
|
||||||
// add non-standard claims like end-session, revoke, and user info
|
// add non-standard claims like end-session, revoke, and user info
|
||||||
if err := p.Provider.Claims(&p); err != nil {
|
if err := p.Provider.Claims(&p); err != nil {
|
||||||
return nil, fmt.Errorf("identity/oidc: could not retrieve additional claims: %w", err)
|
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.
|
// the state query parameter on your redirect callback.
|
||||||
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
||||||
func (p *Provider) GetSignInURL(state string) string {
|
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
|
// Authenticate converts an authorization code returned from the identity
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue