2021-04-07 23:12:13 +00:00
|
|
|
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
2020-11-03 20:06:07 +00:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
package provider
|
|
|
|
|
|
|
|
import (
|
2020-11-18 21:38:13 +00:00
|
|
|
"context"
|
2020-11-03 20:06:07 +00:00
|
|
|
"net/url"
|
|
|
|
"sync"
|
2020-11-18 21:38:13 +00:00
|
|
|
|
2020-11-30 23:08:27 +00:00
|
|
|
"golang.org/x/oauth2"
|
2021-10-08 22:48:21 +00:00
|
|
|
"k8s.io/apimachinery/pkg/types"
|
2020-11-30 23:08:27 +00:00
|
|
|
|
2021-04-10 01:49:43 +00:00
|
|
|
"go.pinniped.dev/internal/authenticators"
|
2020-11-20 23:13:25 +00:00
|
|
|
"go.pinniped.dev/pkg/oidcclient/nonce"
|
2020-11-30 23:02:03 +00:00
|
|
|
"go.pinniped.dev/pkg/oidcclient/oidctypes"
|
2020-11-20 23:13:25 +00:00
|
|
|
"go.pinniped.dev/pkg/oidcclient/pkce"
|
2020-11-03 20:06:07 +00:00
|
|
|
)
|
|
|
|
|
2020-11-18 21:38:13 +00:00
|
|
|
type UpstreamOIDCIdentityProviderI interface {
|
2021-08-12 17:00:18 +00:00
|
|
|
// GetName returns a name for this upstream provider, which will be used as a component of the path for the
|
|
|
|
// callback endpoint hosted by the Supervisor.
|
2020-11-18 21:38:13 +00:00
|
|
|
GetName() string
|
2020-11-03 20:06:07 +00:00
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// GetClientID returns the OAuth client ID registered with the upstream provider to be used in the authorization code flow.
|
2020-11-18 21:38:13 +00:00
|
|
|
GetClientID() string
|
2020-11-03 20:06:07 +00:00
|
|
|
|
2021-10-08 22:48:21 +00:00
|
|
|
// GetResourceUID returns the Kubernetes resource ID
|
|
|
|
GetResourceUID() types.UID
|
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// GetAuthorizationURL returns the Authorization Endpoint fetched from discovery.
|
2020-11-18 21:38:13 +00:00
|
|
|
GetAuthorizationURL() *url.URL
|
2020-11-03 20:06:07 +00:00
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// GetScopes returns the scopes to request in authorization (authcode or password grant) flow.
|
2020-11-18 21:38:13 +00:00
|
|
|
GetScopes() []string
|
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// GetUsernameClaim returns the ID Token username claim name. May return empty string, in which case we
|
|
|
|
// will use some reasonable defaults.
|
2020-11-18 21:38:13 +00:00
|
|
|
GetUsernameClaim() string
|
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// GetGroupsClaim returns the ID Token groups claim name. May return empty string, in which case we won't
|
|
|
|
// try to read groups from the upstream provider.
|
2020-11-18 21:38:13 +00:00
|
|
|
GetGroupsClaim() string
|
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// AllowsPasswordGrant returns true if a client should be allowed to use the resource owner password credentials grant
|
|
|
|
// flow with this upstream provider. When false, it should not be allowed.
|
|
|
|
AllowsPasswordGrant() bool
|
|
|
|
|
2021-10-08 22:48:21 +00:00
|
|
|
// GetAdditionalAuthcodeParams returns additional params to be sent on authcode requests.
|
|
|
|
GetAdditionalAuthcodeParams() map[string]string
|
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// PasswordCredentialsGrantAndValidateTokens performs upstream OIDC resource owner password credentials grant and
|
|
|
|
// token validation. Returns the validated raw tokens as well as the parsed claims of the ID token.
|
|
|
|
PasswordCredentialsGrantAndValidateTokens(ctx context.Context, username, password string) (*oidctypes.Token, error)
|
|
|
|
|
|
|
|
// ExchangeAuthcodeAndValidateTokens performs upstream OIDC authorization code exchange and token validation.
|
2020-11-30 20:54:11 +00:00
|
|
|
// Returns the validated raw tokens as well as the parsed claims of the ID token.
|
2020-11-18 21:38:13 +00:00
|
|
|
ExchangeAuthcodeAndValidateTokens(
|
|
|
|
ctx context.Context,
|
|
|
|
authcode string,
|
|
|
|
pkceCodeVerifier pkce.Code,
|
|
|
|
expectedIDTokenNonce nonce.Nonce,
|
2020-12-02 16:36:07 +00:00
|
|
|
redirectURI string,
|
2020-12-04 21:33:36 +00:00
|
|
|
) (*oidctypes.Token, error)
|
2020-11-30 23:08:27 +00:00
|
|
|
|
2020-12-04 21:33:36 +00:00
|
|
|
ValidateToken(ctx context.Context, tok *oauth2.Token, expectedIDTokenNonce nonce.Nonce) (*oidctypes.Token, error)
|
2020-11-18 21:38:13 +00:00
|
|
|
}
|
|
|
|
|
2021-04-07 23:12:13 +00:00
|
|
|
type UpstreamLDAPIdentityProviderI interface {
|
2021-08-12 17:00:18 +00:00
|
|
|
// GetName returns a name for this upstream provider.
|
2021-04-07 23:12:13 +00:00
|
|
|
GetName() string
|
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// GetURL returns a URL which uniquely identifies this LDAP provider, e.g. "ldaps://host.example.com:1234".
|
2021-04-09 00:28:01 +00:00
|
|
|
// This URL is not used for connecting to the provider, but rather is used for creating a globally unique user
|
|
|
|
// identifier by being combined with the user's UID, since user UIDs are only unique within one provider.
|
2021-05-27 00:04:20 +00:00
|
|
|
GetURL() *url.URL
|
2021-04-09 00:28:01 +00:00
|
|
|
|
2021-10-08 22:48:21 +00:00
|
|
|
// GetResourceUID returns the Kubernetes resource ID
|
|
|
|
GetResourceUID() types.UID
|
|
|
|
|
2021-08-12 17:00:18 +00:00
|
|
|
// UserAuthenticator adds an interface method for performing user authentication against the upstream LDAP provider.
|
2021-04-10 01:49:43 +00:00
|
|
|
authenticators.UserAuthenticator
|
2021-04-07 23:12:13 +00:00
|
|
|
}
|
|
|
|
|
2020-11-03 20:06:07 +00:00
|
|
|
type DynamicUpstreamIDPProvider interface {
|
2021-04-07 23:12:13 +00:00
|
|
|
SetOIDCIdentityProviders(oidcIDPs []UpstreamOIDCIdentityProviderI)
|
|
|
|
GetOIDCIdentityProviders() []UpstreamOIDCIdentityProviderI
|
|
|
|
SetLDAPIdentityProviders(ldapIDPs []UpstreamLDAPIdentityProviderI)
|
|
|
|
GetLDAPIdentityProviders() []UpstreamLDAPIdentityProviderI
|
2021-07-02 22:30:27 +00:00
|
|
|
SetActiveDirectoryIdentityProviders(adIDPs []UpstreamLDAPIdentityProviderI)
|
|
|
|
GetActiveDirectoryIdentityProviders() []UpstreamLDAPIdentityProviderI
|
2020-11-03 20:06:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type dynamicUpstreamIDPProvider struct {
|
2021-07-02 22:30:27 +00:00
|
|
|
oidcUpstreams []UpstreamOIDCIdentityProviderI
|
|
|
|
ldapUpstreams []UpstreamLDAPIdentityProviderI
|
|
|
|
activeDirectoryUpstreams []UpstreamLDAPIdentityProviderI
|
|
|
|
mutex sync.RWMutex
|
2020-11-03 20:06:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewDynamicUpstreamIDPProvider() DynamicUpstreamIDPProvider {
|
|
|
|
return &dynamicUpstreamIDPProvider{
|
2021-07-02 22:30:27 +00:00
|
|
|
oidcUpstreams: []UpstreamOIDCIdentityProviderI{},
|
|
|
|
ldapUpstreams: []UpstreamLDAPIdentityProviderI{},
|
|
|
|
activeDirectoryUpstreams: []UpstreamLDAPIdentityProviderI{},
|
2020-11-03 20:06:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-07 23:12:13 +00:00
|
|
|
func (p *dynamicUpstreamIDPProvider) SetOIDCIdentityProviders(oidcIDPs []UpstreamOIDCIdentityProviderI) {
|
|
|
|
p.mutex.Lock() // acquire a write lock
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
p.oidcUpstreams = oidcIDPs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *dynamicUpstreamIDPProvider) GetOIDCIdentityProviders() []UpstreamOIDCIdentityProviderI {
|
|
|
|
p.mutex.RLock() // acquire a read lock
|
|
|
|
defer p.mutex.RUnlock()
|
|
|
|
return p.oidcUpstreams
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *dynamicUpstreamIDPProvider) SetLDAPIdentityProviders(ldapIDPs []UpstreamLDAPIdentityProviderI) {
|
2020-11-03 20:06:07 +00:00
|
|
|
p.mutex.Lock() // acquire a write lock
|
|
|
|
defer p.mutex.Unlock()
|
2021-04-07 23:12:13 +00:00
|
|
|
p.ldapUpstreams = ldapIDPs
|
2020-11-03 20:06:07 +00:00
|
|
|
}
|
|
|
|
|
2021-04-07 23:12:13 +00:00
|
|
|
func (p *dynamicUpstreamIDPProvider) GetLDAPIdentityProviders() []UpstreamLDAPIdentityProviderI {
|
2020-11-03 20:06:07 +00:00
|
|
|
p.mutex.RLock() // acquire a read lock
|
|
|
|
defer p.mutex.RUnlock()
|
2021-04-07 23:12:13 +00:00
|
|
|
return p.ldapUpstreams
|
2020-11-03 20:06:07 +00:00
|
|
|
}
|
2021-07-02 22:30:27 +00:00
|
|
|
|
|
|
|
func (p *dynamicUpstreamIDPProvider) SetActiveDirectoryIdentityProviders(adIDPs []UpstreamLDAPIdentityProviderI) {
|
|
|
|
p.mutex.Lock() // acquire a write lock
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
p.activeDirectoryUpstreams = adIDPs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *dynamicUpstreamIDPProvider) GetActiveDirectoryIdentityProviders() []UpstreamLDAPIdentityProviderI {
|
|
|
|
p.mutex.RLock() // acquire a read lock
|
|
|
|
defer p.mutex.RUnlock()
|
|
|
|
return p.activeDirectoryUpstreams
|
|
|
|
}
|