mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-02-14 18:10:17 +00:00
First draft of implementation of multiple IDPs support
This commit is contained in:
@@ -33,7 +33,7 @@ import (
|
||||
"go.pinniped.dev/internal/httputil/httperr"
|
||||
"go.pinniped.dev/internal/httputil/securityheader"
|
||||
"go.pinniped.dev/internal/net/phttp"
|
||||
"go.pinniped.dev/internal/oidc/provider"
|
||||
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/upstreamoidc"
|
||||
"go.pinniped.dev/pkg/oidcclient/nonce"
|
||||
@@ -107,7 +107,7 @@ type handlerState struct {
|
||||
getEnv func(key string) string
|
||||
listen func(string, string) (net.Listener, error)
|
||||
isTTY func(int) bool
|
||||
getProvider func(*oauth2.Config, *coreosoidc.Provider, *http.Client) provider.UpstreamOIDCIdentityProviderI
|
||||
getProvider func(*oauth2.Config, *coreosoidc.Provider, *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI
|
||||
validateIDToken func(ctx context.Context, provider *coreosoidc.Provider, audience string, token string) (*coreosoidc.IDToken, error)
|
||||
promptForValue func(ctx context.Context, promptLabel string) (string, error)
|
||||
promptForSecret func(promptLabel string) (string, error)
|
||||
@@ -196,10 +196,11 @@ func WithSkipListen() Option {
|
||||
|
||||
// SessionCacheKey contains the data used to select a valid session cache entry.
|
||||
type SessionCacheKey struct {
|
||||
Issuer string `json:"issuer"`
|
||||
ClientID string `json:"clientID"`
|
||||
Scopes []string `json:"scopes"`
|
||||
RedirectURI string `json:"redirect_uri"`
|
||||
Issuer string `json:"issuer"`
|
||||
ClientID string `json:"clientID"`
|
||||
Scopes []string `json:"scopes"`
|
||||
RedirectURI string `json:"redirect_uri"`
|
||||
UpstreamProviderName string `json:"upstream_provider_name,omitempty"`
|
||||
}
|
||||
|
||||
type SessionCache interface {
|
||||
@@ -351,6 +352,10 @@ func (h *handlerState) baseLogin() (*oidctypes.Token, error) {
|
||||
ClientID: h.clientID,
|
||||
Scopes: h.scopes,
|
||||
RedirectURI: (&url.URL{Scheme: "http", Host: h.listenAddr, Path: h.callbackPath}).String(),
|
||||
// When using a Supervisor with multiple IDPs, the cache keys need to be different for each IDP
|
||||
// so a user can have multiple sessions going for each IDP at the same time.
|
||||
// When using a non-Supervisor OIDC provider, then this value will be blank, so it won't be part of the key.
|
||||
UpstreamProviderName: h.upstreamIdentityProviderName,
|
||||
}
|
||||
|
||||
// If the ID token is still valid for a bit, return it immediately and skip the rest of the flow.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package oidcclient
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
"go.pinniped.dev/internal/httputil/roundtripper"
|
||||
"go.pinniped.dev/internal/mocks/mockupstreamoidcidentityprovider"
|
||||
"go.pinniped.dev/internal/net/phttp"
|
||||
"go.pinniped.dev/internal/oidc/provider"
|
||||
"go.pinniped.dev/internal/oidc/provider/upstreamprovider"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
"go.pinniped.dev/internal/testutil/testlogger"
|
||||
@@ -504,7 +504,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo
|
||||
return func(h *handlerState) error {
|
||||
require.NoError(t, WithClient(newClientForServer(successServer))(h))
|
||||
|
||||
h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ValidateTokenAndMergeWithUserInfo(gomock.Any(), HasAccessToken(testToken.AccessToken.Token), nonce.Nonce(""), true, false).
|
||||
@@ -553,7 +553,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo
|
||||
return func(h *handlerState) error {
|
||||
require.NoError(t, WithClient(newClientForServer(successServer))(h))
|
||||
|
||||
h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ValidateTokenAndMergeWithUserInfo(gomock.Any(), HasAccessToken(testToken.AccessToken.Token), nonce.Nonce(""), true, false).
|
||||
@@ -1159,7 +1159,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo
|
||||
fmt.Sprintf("http://127.0.0.1:0/callback?code=%s&state=test-state", fakeAuthCode),
|
||||
}},
|
||||
}, nil)
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(
|
||||
@@ -1181,7 +1181,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo
|
||||
return func(h *handlerState) error {
|
||||
fakeAuthCode := "test-authcode-value"
|
||||
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(
|
||||
@@ -1281,7 +1281,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo
|
||||
return func(h *handlerState) error {
|
||||
fakeAuthCode := "test-authcode-value"
|
||||
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(
|
||||
@@ -1392,7 +1392,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo
|
||||
return func(h *handlerState) error {
|
||||
fakeAuthCode := "test-authcode-value"
|
||||
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(
|
||||
@@ -1855,7 +1855,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo
|
||||
})
|
||||
h.cache = cache
|
||||
|
||||
h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ValidateTokenAndMergeWithUserInfo(gomock.Any(), HasAccessToken(testToken.AccessToken.Token), nonce.Nonce(""), true, false).
|
||||
@@ -1993,7 +1993,7 @@ func TestHandlePasteCallback(t *testing.T) {
|
||||
return "invalid", nil
|
||||
}
|
||||
h.oauth2Config = &oauth2.Config{RedirectURL: testRedirectURI}
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(gomock.Any(), "invalid", pkce.Code("test-pkce"), nonce.Nonce("test-nonce"), testRedirectURI).
|
||||
@@ -2017,7 +2017,7 @@ func TestHandlePasteCallback(t *testing.T) {
|
||||
return "valid", nil
|
||||
}
|
||||
h.oauth2Config = &oauth2.Config{RedirectURL: testRedirectURI}
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(gomock.Any(), "valid", pkce.Code("test-pkce"), nonce.Nonce("test-nonce"), testRedirectURI).
|
||||
@@ -2237,7 +2237,7 @@ func TestHandleAuthCodeCallback(t *testing.T) {
|
||||
opt: func(t *testing.T) Option {
|
||||
return func(h *handlerState) error {
|
||||
h.oauth2Config = &oauth2.Config{RedirectURL: testRedirectURI}
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(gomock.Any(), "invalid", pkce.Code("test-pkce"), nonce.Nonce("test-nonce"), testRedirectURI).
|
||||
@@ -2256,7 +2256,7 @@ func TestHandleAuthCodeCallback(t *testing.T) {
|
||||
opt: func(t *testing.T) Option {
|
||||
return func(h *handlerState) error {
|
||||
h.oauth2Config = &oauth2.Config{RedirectURL: testRedirectURI}
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(gomock.Any(), "valid", pkce.Code("test-pkce"), nonce.Nonce("test-nonce"), testRedirectURI).
|
||||
@@ -2282,7 +2282,7 @@ func TestHandleAuthCodeCallback(t *testing.T) {
|
||||
return func(h *handlerState) error {
|
||||
h.useFormPost = true
|
||||
h.oauth2Config = &oauth2.Config{RedirectURL: testRedirectURI}
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(gomock.Any(), "valid", pkce.Code("test-pkce"), nonce.Nonce("test-nonce"), testRedirectURI).
|
||||
@@ -2311,7 +2311,7 @@ func TestHandleAuthCodeCallback(t *testing.T) {
|
||||
return func(h *handlerState) error {
|
||||
h.useFormPost = true
|
||||
h.oauth2Config = &oauth2.Config{RedirectURL: testRedirectURI}
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) provider.UpstreamOIDCIdentityProviderI {
|
||||
h.getProvider = func(_ *oauth2.Config, _ *oidc.Provider, _ *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI {
|
||||
mock := mockUpstream(t)
|
||||
mock.EXPECT().
|
||||
ExchangeAuthcodeAndValidateTokens(gomock.Any(), "valid", pkce.Code("test-pkce"), nonce.Nonce("test-nonce"), testRedirectURI).
|
||||
|
||||
Reference in New Issue
Block a user