More unit tests for dynamic clients
- Add dynamic client unit tests for the upstream OIDC callback and POST login endpoints. - Enhance a few log statements to print the full fosite error messages into the logs where they were previously only printing the name of the error type.
This commit is contained in:
parent
34509e7430
commit
e42f5488fa
@ -25,7 +25,6 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
kubetesting "k8s.io/client-go/testing"
|
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
|
|
||||||
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
|
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
|
||||||
@ -3088,7 +3087,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
// OIDC validations are checked in fosite after the OAuth authcode (and sometimes the OIDC session)
|
// OIDC validations are checked in fosite after the OAuth authcode (and sometimes the OIDC session)
|
||||||
// is stored, so it is possible with an LDAP upstream to store objects and then return an error to
|
// is stored, so it is possible with an LDAP upstream to store objects and then return an error to
|
||||||
// the client anyway (which makes the stored objects useless, but oh well).
|
// the client anyway (which makes the stored objects useless, but oh well).
|
||||||
require.Len(t, filterActions(kubeClient.Actions()), test.wantUnnecessaryStoredRecords)
|
require.Len(t, oidctestutil.FilterClientSecretCreateActions(kubeClient.Actions()), test.wantUnnecessaryStoredRecords)
|
||||||
case test.wantRedirectLocationRegexp != "":
|
case test.wantRedirectLocationRegexp != "":
|
||||||
if test.wantDownstreamClientID == "" {
|
if test.wantDownstreamClientID == "" {
|
||||||
test.wantDownstreamClientID = pinnipedCLIClientID // default assertion value when not provided by test case
|
test.wantDownstreamClientID = pinnipedCLIClientID // default assertion value when not provided by test case
|
||||||
@ -3301,20 +3300,3 @@ func requireEqualURLs(t *testing.T, actualURL string, expectedURL string, ignore
|
|||||||
}
|
}
|
||||||
require.Equal(t, expectedLocationQuery, actualLocationQuery)
|
require.Equal(t, expectedLocationQuery, actualLocationQuery)
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterActions ignores any reads made to get a storage secret corresponding to an OIDCClient, since these
|
|
||||||
// are normal actions when the request is using a dynamic client's client_id, and we don't need to make assertions
|
|
||||||
// about these Secrets since they are not related to session storage.
|
|
||||||
func filterActions(actions []kubetesting.Action) []kubetesting.Action {
|
|
||||||
filtered := make([]kubetesting.Action, 0, len(actions))
|
|
||||||
for _, action := range actions {
|
|
||||||
if action.Matches("get", "secrets") {
|
|
||||||
getAction := action.(kubetesting.GetAction)
|
|
||||||
if strings.HasPrefix(getAction.GetName(), "pinniped-storage-oidc-client-secret-") {
|
|
||||||
continue // filter out OIDCClient's storage secret reads
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filtered = append(filtered, action) // otherwise include the action
|
|
||||||
}
|
|
||||||
return filtered
|
|
||||||
}
|
|
||||||
|
@ -48,7 +48,8 @@ func NewHandler(
|
|||||||
reconstitutedAuthRequest := &http.Request{Form: downstreamAuthParams}
|
reconstitutedAuthRequest := &http.Request{Form: downstreamAuthParams}
|
||||||
authorizeRequester, err := oauthHelper.NewAuthorizeRequest(r.Context(), reconstitutedAuthRequest)
|
authorizeRequester, err := oauthHelper.NewAuthorizeRequest(r.Context(), reconstitutedAuthRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plog.Error("error using state downstream auth params", err)
|
plog.Error("error using state downstream auth params", err,
|
||||||
|
"fositeErr", oidc.FositeErrorForLog(err))
|
||||||
return httperr.New(http.StatusBadRequest, "error using state downstream auth params")
|
return httperr.New(http.StatusBadRequest, "error using state downstream auth params")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +84,8 @@ func NewHandler(
|
|||||||
|
|
||||||
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plog.WarningErr("error while generating and saving authcode", err, "upstreamName", upstreamIDPConfig.GetName())
|
plog.WarningErr("error while generating and saving authcode", err,
|
||||||
|
"upstreamName", upstreamIDPConfig.GetName(), "fositeErr", oidc.FositeErrorForLog(err))
|
||||||
return httperr.Wrap(http.StatusInternalServerError, "error while generating and saving authcode", err)
|
return httperr.Wrap(http.StatusInternalServerError, "error while generating and saving authcode", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,9 @@ const (
|
|||||||
|
|
||||||
downstreamIssuer = "https://my-downstream-issuer.com/path"
|
downstreamIssuer = "https://my-downstream-issuer.com/path"
|
||||||
downstreamRedirectURI = "http://127.0.0.1/callback"
|
downstreamRedirectURI = "http://127.0.0.1/callback"
|
||||||
downstreamClientID = "pinniped-cli"
|
downstreamPinnipedClientID = "pinniped-cli"
|
||||||
|
downstreamDynamicClientID = "client.oauth.pinniped.dev-test-name"
|
||||||
|
downstreamDynamicClientUID = "fake-client-uid"
|
||||||
downstreamNonce = "some-nonce-value"
|
downstreamNonce = "some-nonce-value"
|
||||||
downstreamPKCEChallenge = "some-challenge"
|
downstreamPKCEChallenge = "some-challenge"
|
||||||
downstreamPKCEChallengeMethod = "S256"
|
downstreamPKCEChallengeMethod = "S256"
|
||||||
@ -70,14 +72,19 @@ var (
|
|||||||
happyDownstreamRequestParamsQuery = url.Values{
|
happyDownstreamRequestParamsQuery = url.Values{
|
||||||
"response_type": []string{"code"},
|
"response_type": []string{"code"},
|
||||||
"scope": []string{strings.Join(happyDownstreamScopesRequested, " ")},
|
"scope": []string{strings.Join(happyDownstreamScopesRequested, " ")},
|
||||||
"client_id": []string{downstreamClientID},
|
"client_id": []string{downstreamPinnipedClientID},
|
||||||
"state": []string{happyDownstreamState},
|
"state": []string{happyDownstreamState},
|
||||||
"nonce": []string{downstreamNonce},
|
"nonce": []string{downstreamNonce},
|
||||||
"code_challenge": []string{downstreamPKCEChallenge},
|
"code_challenge": []string{downstreamPKCEChallenge},
|
||||||
"code_challenge_method": []string{downstreamPKCEChallengeMethod},
|
"code_challenge_method": []string{downstreamPKCEChallengeMethod},
|
||||||
"redirect_uri": []string{downstreamRedirectURI},
|
"redirect_uri": []string{downstreamRedirectURI},
|
||||||
}
|
}
|
||||||
happyDownstreamRequestParams = happyDownstreamRequestParamsQuery.Encode()
|
happyDownstreamRequestParams = happyDownstreamRequestParamsQuery.Encode()
|
||||||
|
|
||||||
|
happyDownstreamRequestParamsForDynamicClient = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
|
map[string]string{"client_id": downstreamDynamicClientID},
|
||||||
|
).Encode()
|
||||||
|
|
||||||
happyDownstreamCustomSessionData = &psession.CustomSessionData{
|
happyDownstreamCustomSessionData = &psession.CustomSessionData{
|
||||||
ProviderUID: happyUpstreamIDPResourceUID,
|
ProviderUID: happyUpstreamIDPResourceUID,
|
||||||
ProviderName: happyUpstreamIDPName,
|
ProviderName: happyUpstreamIDPName,
|
||||||
@ -122,6 +129,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
happyCookieCodec.SetSerializer(securecookie.JSONEncoder{})
|
happyCookieCodec.SetSerializer(securecookie.JSONEncoder{})
|
||||||
|
|
||||||
happyState := happyUpstreamStateParam().Build(t, happyStateCodec)
|
happyState := happyUpstreamStateParam().Build(t, happyStateCodec)
|
||||||
|
happyStateForDynamicClient := happyUpstreamStateParamForDynamicClient().Build(t, happyStateCodec)
|
||||||
|
|
||||||
encodedIncomingCookieCSRFValue, err := happyCookieCodec.Encode("csrf", happyDownstreamCSRF)
|
encodedIncomingCookieCSRFValue, err := happyCookieCodec.Encode("csrf", happyDownstreamCSRF)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -137,6 +145,13 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
// Note that fosite puts the granted scopes as a param in the redirect URI even though the spec doesn't seem to require it
|
// Note that fosite puts the granted scopes as a param in the redirect URI even though the spec doesn't seem to require it
|
||||||
happyDownstreamRedirectLocationRegexp := downstreamRedirectURI + `\?code=([^&]+)&scope=openid\+groups&state=` + happyDownstreamState
|
happyDownstreamRedirectLocationRegexp := downstreamRedirectURI + `\?code=([^&]+)&scope=openid\+groups&state=` + happyDownstreamState
|
||||||
|
|
||||||
|
addFullyCapableDynamicClientAndSecretToKubeResources := func(t *testing.T, supervisorClient *supervisorfake.Clientset, kubeClient *fake.Clientset) {
|
||||||
|
oidcClient, secret := testutil.FullyCapableOIDCClientAndStorageSecret(t,
|
||||||
|
"some-namespace", downstreamDynamicClientID, downstreamDynamicClientUID, downstreamRedirectURI, []string{testutil.HashedPassword1AtGoMinCost})
|
||||||
|
require.NoError(t, supervisorClient.Tracker().Add(oidcClient))
|
||||||
|
require.NoError(t, kubeClient.Tracker().Add(secret))
|
||||||
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
||||||
@ -157,6 +172,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamIDTokenGroups []string
|
wantDownstreamIDTokenGroups []string
|
||||||
wantDownstreamRequestedScopes []string
|
wantDownstreamRequestedScopes []string
|
||||||
wantDownstreamNonce string
|
wantDownstreamNonce string
|
||||||
|
wantDownstreamClientID string
|
||||||
wantDownstreamPKCEChallenge string
|
wantDownstreamPKCEChallenge string
|
||||||
wantDownstreamPKCEChallengeMethod string
|
wantDownstreamPKCEChallengeMethod string
|
||||||
wantDownstreamCustomSessionData *psession.CustomSessionData
|
wantDownstreamCustomSessionData *psession.CustomSessionData
|
||||||
@ -185,6 +201,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -208,6 +225,32 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GET with good state and cookie and successful upstream token exchange returns 303 to downstream client callback with its state and code when using dynamic client",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(happyUpstream().Build()),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: newRequestPath().WithState(happyStateForDynamicClient).String(),
|
||||||
|
csrfCookie: happyCSRFCookie,
|
||||||
|
wantStatus: http.StatusSeeOther,
|
||||||
|
wantRedirectLocationRegexp: happyDownstreamRedirectLocationRegexp,
|
||||||
|
wantBody: "",
|
||||||
|
wantDownstreamIDTokenSubject: oidcUpstreamIssuer + "?sub=" + oidcUpstreamSubjectQueryEscaped,
|
||||||
|
wantDownstreamIDTokenUsername: oidcUpstreamUsername,
|
||||||
|
wantDownstreamIDTokenGroups: oidcUpstreamGroupMembership,
|
||||||
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamDynamicClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -231,6 +274,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamAccessTokenCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamAccessTokenCustomSessionData,
|
||||||
@ -263,6 +307,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: []string{"openid"},
|
wantDownstreamRequestedScopes: []string{"openid"},
|
||||||
wantDownstreamGrantedScopes: []string{"openid"},
|
wantDownstreamGrantedScopes: []string{"openid"},
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -286,6 +331,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: &psession.CustomSessionData{
|
wantDownstreamCustomSessionData: &psession.CustomSessionData{
|
||||||
@ -321,6 +367,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -346,6 +393,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -373,6 +421,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -401,6 +450,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -531,6 +581,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -556,6 +607,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -581,6 +633,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -714,6 +767,42 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantContentType: htmlContentType,
|
wantContentType: htmlContentType,
|
||||||
wantBody: "Bad Request: error using state downstream auth params\n",
|
wantBody: "Bad Request: error using state downstream auth params\n",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "state's downstream auth params have invalid client_id",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(happyUpstream().Build()),
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: newRequestPath().WithState(
|
||||||
|
happyUpstreamStateParam().
|
||||||
|
WithAuthorizeRequestParams(shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery, map[string]string{"client_id": "bogus"}).Encode()).
|
||||||
|
Build(t, happyStateCodec),
|
||||||
|
).String(),
|
||||||
|
csrfCookie: happyCSRFCookie,
|
||||||
|
wantStatus: http.StatusBadRequest,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBody: "Bad Request: error using state downstream auth params\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dynamic clients do not allow response_mode=form_post",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(happyUpstream().Build()),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: newRequestPath().WithState(
|
||||||
|
happyUpstreamStateParam().WithAuthorizeRequestParams(
|
||||||
|
shallowCopyAndModifyQuery(
|
||||||
|
happyDownstreamRequestParamsQuery,
|
||||||
|
map[string]string{
|
||||||
|
"client_id": downstreamDynamicClientID,
|
||||||
|
"response_mode": "form_post",
|
||||||
|
"scope": "openid",
|
||||||
|
},
|
||||||
|
).Encode(),
|
||||||
|
).Build(t, happyStateCodec),
|
||||||
|
).String(),
|
||||||
|
csrfCookie: happyCSRFCookie,
|
||||||
|
wantStatus: http.StatusBadRequest,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBody: "Bad Request: error using state downstream auth params\n",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "state's downstream auth params does not contain openid scope",
|
name: "state's downstream auth params does not contain openid scope",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(happyUpstream().Build()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(happyUpstream().Build()),
|
||||||
@ -733,6 +822,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamGrantedScopes: []string{"groups"},
|
wantDownstreamGrantedScopes: []string{"groups"},
|
||||||
wantDownstreamIDTokenGroups: oidcUpstreamGroupMembership,
|
wantDownstreamIDTokenGroups: oidcUpstreamGroupMembership,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -759,6 +849,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRequestedScopes: []string{"profile", "email"},
|
wantDownstreamRequestedScopes: []string{"profile", "email"},
|
||||||
wantDownstreamGrantedScopes: []string{},
|
wantDownstreamGrantedScopes: []string{},
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -786,6 +877,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamGrantedScopes: []string{"openid", "offline_access", "groups"},
|
wantDownstreamGrantedScopes: []string{"openid", "offline_access", "groups"},
|
||||||
wantDownstreamIDTokenGroups: oidcUpstreamGroupMembership,
|
wantDownstreamIDTokenGroups: oidcUpstreamGroupMembership,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -884,6 +976,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamIDTokenGroups: []string{},
|
wantDownstreamIDTokenGroups: []string{},
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClientID: downstreamPinnipedClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
@ -1139,7 +1232,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
test.wantDownstreamPKCEChallenge,
|
test.wantDownstreamPKCEChallenge,
|
||||||
test.wantDownstreamPKCEChallengeMethod,
|
test.wantDownstreamPKCEChallengeMethod,
|
||||||
test.wantDownstreamNonce,
|
test.wantDownstreamNonce,
|
||||||
downstreamClientID,
|
test.wantDownstreamClientID,
|
||||||
downstreamRedirectURI,
|
downstreamRedirectURI,
|
||||||
test.wantDownstreamCustomSessionData,
|
test.wantDownstreamCustomSessionData,
|
||||||
)
|
)
|
||||||
@ -1166,7 +1259,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
test.wantDownstreamPKCEChallenge,
|
test.wantDownstreamPKCEChallenge,
|
||||||
test.wantDownstreamPKCEChallengeMethod,
|
test.wantDownstreamPKCEChallengeMethod,
|
||||||
test.wantDownstreamNonce,
|
test.wantDownstreamNonce,
|
||||||
downstreamClientID,
|
test.wantDownstreamClientID,
|
||||||
downstreamRedirectURI,
|
downstreamRedirectURI,
|
||||||
test.wantDownstreamCustomSessionData,
|
test.wantDownstreamCustomSessionData,
|
||||||
)
|
)
|
||||||
@ -1237,6 +1330,12 @@ func happyUpstreamStateParam() *oidctestutil.UpstreamStateParamBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func happyUpstreamStateParamForDynamicClient() *oidctestutil.UpstreamStateParamBuilder {
|
||||||
|
p := happyUpstreamStateParam()
|
||||||
|
p.P = happyDownstreamRequestParamsForDynamicClient
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
func happyUpstream() *oidctestutil.TestUpstreamOIDCIdentityProviderBuilder {
|
func happyUpstream() *oidctestutil.TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
return oidctestutil.NewTestUpstreamOIDCIdentityProviderBuilder().
|
return oidctestutil.NewTestUpstreamOIDCIdentityProviderBuilder().
|
||||||
WithName(happyUpstreamIDPName).
|
WithName(happyUpstreamIDPName).
|
||||||
|
@ -41,7 +41,8 @@ func NewPostHandler(issuerURL string, upstreamIDPs oidc.UpstreamIdentityProvider
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// This shouldn't really happen because the authorization endpoint has already validated these params
|
// This shouldn't really happen because the authorization endpoint has already validated these params
|
||||||
// by calling NewAuthorizeRequest() itself.
|
// by calling NewAuthorizeRequest() itself.
|
||||||
plog.Error("error using state downstream auth params", err)
|
plog.Error("error using state downstream auth params", err,
|
||||||
|
"fositeErr", oidc.FositeErrorForLog(err))
|
||||||
return httperr.New(http.StatusBadRequest, "error using state downstream auth params")
|
return httperr.New(http.StatusBadRequest, "error using state downstream auth params")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
|
|
||||||
downstreamIssuer = "https://my-downstream-issuer.com/path"
|
downstreamIssuer = "https://my-downstream-issuer.com/path"
|
||||||
downstreamRedirectURI = "http://127.0.0.1/callback"
|
downstreamRedirectURI = "http://127.0.0.1/callback"
|
||||||
downstreamClientID = "pinniped-cli"
|
downstreamPinnipedCLIClientID = "pinniped-cli"
|
||||||
|
downstreamDynamicClientID = "client.oauth.pinniped.dev-test-name"
|
||||||
|
downstreamDynamicClientUID = "fake-client-uid"
|
||||||
happyDownstreamState = "8b-state"
|
happyDownstreamState = "8b-state"
|
||||||
downstreamNonce = "some-nonce-value"
|
downstreamNonce = "some-nonce-value"
|
||||||
downstreamPKCEChallenge = "some-challenge"
|
downstreamPKCEChallenge = "some-challenge"
|
||||||
@ -90,7 +92,7 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
happyDownstreamRequestParamsQuery := url.Values{
|
happyDownstreamRequestParamsQuery := url.Values{
|
||||||
"response_type": []string{"code"},
|
"response_type": []string{"code"},
|
||||||
"scope": []string{strings.Join(happyDownstreamScopesRequested, " ")},
|
"scope": []string{strings.Join(happyDownstreamScopesRequested, " ")},
|
||||||
"client_id": []string{downstreamClientID},
|
"client_id": []string{downstreamPinnipedCLIClientID},
|
||||||
"state": []string{happyDownstreamState},
|
"state": []string{happyDownstreamState},
|
||||||
"nonce": []string{downstreamNonce},
|
"nonce": []string{downstreamNonce},
|
||||||
"code_challenge": []string{downstreamPKCEChallenge},
|
"code_challenge": []string{downstreamPKCEChallenge},
|
||||||
@ -99,14 +101,10 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
}
|
}
|
||||||
happyDownstreamRequestParams := happyDownstreamRequestParamsQuery.Encode()
|
happyDownstreamRequestParams := happyDownstreamRequestParamsQuery.Encode()
|
||||||
|
|
||||||
copyOfHappyDownstreamRequestParamsQuery := func() url.Values {
|
happyDownstreamRequestParamsQueryForDynamicClient := shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
params := url.Values{}
|
map[string]string{"client_id": downstreamDynamicClientID},
|
||||||
for k, v := range happyDownstreamRequestParamsQuery {
|
)
|
||||||
params[k] = make([]string, len(v))
|
happyDownstreamRequestParamsForDynamicClient := happyDownstreamRequestParamsQueryForDynamicClient.Encode()
|
||||||
copy(params[k], v)
|
|
||||||
}
|
|
||||||
return params
|
|
||||||
}
|
|
||||||
|
|
||||||
happyLDAPDecodedState := &oidc.UpstreamStateParamData{
|
happyLDAPDecodedState := &oidc.UpstreamStateParamData{
|
||||||
AuthParams: happyDownstreamRequestParams,
|
AuthParams: happyDownstreamRequestParams,
|
||||||
@ -124,15 +122,20 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
return ©OfHappyLDAPDecodedState
|
return ©OfHappyLDAPDecodedState
|
||||||
}
|
}
|
||||||
|
|
||||||
happyActiveDirectoryDecodedState := &oidc.UpstreamStateParamData{
|
happyLDAPDecodedStateForDynamicClient := modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
AuthParams: happyDownstreamRequestParams,
|
data.AuthParams = happyDownstreamRequestParamsForDynamicClient
|
||||||
UpstreamName: activeDirectoryUpstreamName,
|
})
|
||||||
UpstreamType: activeDirectoryUpstreamType,
|
|
||||||
Nonce: happyDownstreamNonce,
|
happyActiveDirectoryDecodedState := modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
CSRFToken: happyDownstreamCSRF,
|
data.UpstreamName = activeDirectoryUpstreamName
|
||||||
PKCECode: happyDownstreamPKCE,
|
data.UpstreamType = activeDirectoryUpstreamType
|
||||||
FormatVersion: happyDownstreamStateVersion,
|
})
|
||||||
}
|
|
||||||
|
happyActiveDirectoryDecodedStateForDynamicClient := modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
|
data.AuthParams = happyDownstreamRequestParamsForDynamicClient
|
||||||
|
data.UpstreamName = activeDirectoryUpstreamName
|
||||||
|
data.UpstreamType = activeDirectoryUpstreamType
|
||||||
|
})
|
||||||
|
|
||||||
happyLDAPUsername := "some-ldap-user"
|
happyLDAPUsername := "some-ldap-user"
|
||||||
happyLDAPUsernameFromAuthenticator := "some-mapped-ldap-username"
|
happyLDAPUsernameFromAuthenticator := "some-mapped-ldap-username"
|
||||||
@ -232,6 +235,13 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
return urlToReturn
|
return urlToReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addFullyCapableDynamicClientAndSecretToKubeResources := func(t *testing.T, supervisorClient *supervisorfake.Clientset, kubeClient *fake.Clientset) {
|
||||||
|
oidcClient, secret := testutil.FullyCapableOIDCClientAndStorageSecret(t,
|
||||||
|
"some-namespace", downstreamDynamicClientID, downstreamDynamicClientUID, downstreamRedirectURI, []string{testutil.HashedPassword1AtGoMinCost})
|
||||||
|
require.NoError(t, supervisorClient.Tracker().Add(oidcClient))
|
||||||
|
require.NoError(t, kubeClient.Tracker().Add(secret))
|
||||||
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
idps *oidctestutil.UpstreamIDPListerBuilder
|
idps *oidctestutil.UpstreamIDPListerBuilder
|
||||||
@ -262,6 +272,7 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
wantDownstreamPKCEChallenge string
|
wantDownstreamPKCEChallenge string
|
||||||
wantDownstreamPKCEChallengeMethod string
|
wantDownstreamPKCEChallengeMethod string
|
||||||
wantDownstreamNonce string
|
wantDownstreamNonce string
|
||||||
|
wantDownstreamClient string
|
||||||
wantDownstreamCustomSessionData *psession.CustomSessionData
|
wantDownstreamCustomSessionData *psession.CustomSessionData
|
||||||
|
|
||||||
// Authorization requests for either a successful OIDC upstream or for an error with any upstream
|
// Authorization requests for either a successful OIDC upstream or for an error with any upstream
|
||||||
@ -289,6 +300,31 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRedirectURI: downstreamRedirectURI,
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamPinnipedCLIClientID,
|
||||||
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy LDAP login with dynamic client",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().
|
||||||
|
WithLDAP(&upstreamLDAPIdentityProvider). // should pick this one
|
||||||
|
WithActiveDirectory(&erroringUpstreamLDAPIdentityProvider),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
decodedState: happyLDAPDecodedStateForDynamicClient,
|
||||||
|
formParams: happyUsernamePasswordFormParams,
|
||||||
|
wantStatus: http.StatusSeeOther,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBodyString: "",
|
||||||
|
wantRedirectLocationRegexp: happyAuthcodeDownstreamRedirectLocationRegexp,
|
||||||
|
wantDownstreamIDTokenSubject: upstreamLDAPURL + "&sub=" + happyLDAPUID,
|
||||||
|
wantDownstreamIDTokenUsername: happyLDAPUsernameFromAuthenticator,
|
||||||
|
wantDownstreamIDTokenGroups: happyLDAPGroups,
|
||||||
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamDynamicClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
@ -311,6 +347,31 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRedirectURI: downstreamRedirectURI,
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamPinnipedCLIClientID,
|
||||||
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyActiveDirectoryUpstreamCustomSession,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy AD login with dynamic client",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().
|
||||||
|
WithLDAP(&erroringUpstreamLDAPIdentityProvider).
|
||||||
|
WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider), // should pick this one
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
decodedState: happyActiveDirectoryDecodedStateForDynamicClient,
|
||||||
|
formParams: happyUsernamePasswordFormParams,
|
||||||
|
wantStatus: http.StatusSeeOther,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBodyString: "",
|
||||||
|
wantRedirectLocationRegexp: happyAuthcodeDownstreamRedirectLocationRegexp,
|
||||||
|
wantDownstreamIDTokenSubject: upstreamLDAPURL + "&sub=" + happyLDAPUID,
|
||||||
|
wantDownstreamIDTokenUsername: happyLDAPUsernameFromAuthenticator,
|
||||||
|
wantDownstreamIDTokenGroups: happyLDAPGroups,
|
||||||
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamDynamicClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: expectedHappyActiveDirectoryUpstreamCustomSession,
|
wantDownstreamCustomSessionData: expectedHappyActiveDirectoryUpstreamCustomSession,
|
||||||
@ -319,9 +380,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "happy LDAP login when downstream response_mode=form_post returns 200 with HTML+JS form",
|
name: "happy LDAP login when downstream response_mode=form_post returns 200 with HTML+JS form",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["response_mode"] = []string{"form_post"}
|
map[string]string{"response_mode": "form_post"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusOK,
|
wantStatus: http.StatusOK,
|
||||||
@ -335,6 +396,7 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRedirectURI: downstreamRedirectURI,
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamPinnipedCLIClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
@ -343,9 +405,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "happy LDAP login when downstream redirect uri matches what is configured for client except for the port number",
|
name: "happy LDAP login when downstream redirect uri matches what is configured for client except for the port number",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["redirect_uri"] = []string{"http://127.0.0.1:4242/callback"}
|
map[string]string{"redirect_uri": "http://127.0.0.1:4242/callback"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -359,6 +421,33 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRedirectURI: "http://127.0.0.1:4242/callback",
|
wantDownstreamRedirectURI: "http://127.0.0.1:4242/callback",
|
||||||
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamPinnipedCLIClientID,
|
||||||
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy LDAP login when downstream redirect uri matches what is configured for client except for the port number with dynamic client",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQueryForDynamicClient,
|
||||||
|
map[string]string{"redirect_uri": "http://127.0.0.1:4242/callback"},
|
||||||
|
).Encode()
|
||||||
|
}),
|
||||||
|
formParams: happyUsernamePasswordFormParams,
|
||||||
|
wantStatus: http.StatusSeeOther,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBodyString: "",
|
||||||
|
wantRedirectLocationRegexp: "http://127.0.0.1:4242/callback" + `\?code=([^&]+)&scope=openid\+groups&state=` + happyDownstreamState,
|
||||||
|
wantDownstreamIDTokenSubject: upstreamLDAPURL + "&sub=" + happyLDAPUID,
|
||||||
|
wantDownstreamIDTokenUsername: happyLDAPUsernameFromAuthenticator,
|
||||||
|
wantDownstreamIDTokenGroups: happyLDAPGroups,
|
||||||
|
wantDownstreamRequestedScopes: happyDownstreamScopesRequested,
|
||||||
|
wantDownstreamRedirectURI: "http://127.0.0.1:4242/callback",
|
||||||
|
wantDownstreamGrantedScopes: happyDownstreamScopesGranted,
|
||||||
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamDynamicClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
@ -367,9 +456,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "happy LDAP login when there are additional allowed downstream requested scopes",
|
name: "happy LDAP login when there are additional allowed downstream requested scopes",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["scope"] = []string{"openid offline_access pinniped:request-audience"}
|
map[string]string{"scope": "openid offline_access pinniped:request-audience"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -383,6 +472,33 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRedirectURI: downstreamRedirectURI,
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
wantDownstreamGrantedScopes: []string{"openid", "offline_access", "pinniped:request-audience"},
|
wantDownstreamGrantedScopes: []string{"openid", "offline_access", "pinniped:request-audience"},
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamPinnipedCLIClientID,
|
||||||
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "happy LDAP login when there are additional allowed downstream requested scopes with dynamic client",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQueryForDynamicClient,
|
||||||
|
map[string]string{"scope": "openid offline_access pinniped:request-audience"},
|
||||||
|
).Encode()
|
||||||
|
}),
|
||||||
|
formParams: happyUsernamePasswordFormParams,
|
||||||
|
wantStatus: http.StatusSeeOther,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBodyString: "",
|
||||||
|
wantRedirectLocationRegexp: downstreamRedirectURI + `\?code=([^&]+)&scope=openid\+offline_access\+pinniped%3Arequest-audience&state=` + happyDownstreamState,
|
||||||
|
wantDownstreamIDTokenSubject: upstreamLDAPURL + "&sub=" + happyLDAPUID,
|
||||||
|
wantDownstreamIDTokenUsername: happyLDAPUsernameFromAuthenticator,
|
||||||
|
wantDownstreamIDTokenGroups: happyLDAPGroups,
|
||||||
|
wantDownstreamRequestedScopes: []string{"openid", "offline_access", "pinniped:request-audience"},
|
||||||
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
|
wantDownstreamGrantedScopes: []string{"openid", "offline_access", "pinniped:request-audience"},
|
||||||
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamDynamicClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
@ -391,11 +507,13 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "happy LDAP when downstream OIDC validations are skipped because the openid scope was not requested",
|
name: "happy LDAP when downstream OIDC validations are skipped because the openid scope was not requested",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["scope"] = []string{"email"}
|
map[string]string{
|
||||||
// The following prompt value is illegal when openid is requested, but note that openid is not requested.
|
"scope": "email",
|
||||||
query["prompt"] = []string{"none login"}
|
// The following prompt value is illegal when openid is requested, but note that openid is not requested.
|
||||||
data.AuthParams = query.Encode()
|
"prompt": "none login",
|
||||||
|
},
|
||||||
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -409,6 +527,7 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRedirectURI: downstreamRedirectURI,
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
wantDownstreamGrantedScopes: []string{}, // no scopes granted
|
wantDownstreamGrantedScopes: []string{}, // no scopes granted
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamPinnipedCLIClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
@ -419,9 +538,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
WithLDAP(&upstreamLDAPIdentityProvider). // should pick this one
|
WithLDAP(&upstreamLDAPIdentityProvider). // should pick this one
|
||||||
WithActiveDirectory(&erroringUpstreamLDAPIdentityProvider),
|
WithActiveDirectory(&erroringUpstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["scope"] = []string{"openid"}
|
map[string]string{"scope": "openid"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -434,6 +553,7 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
wantDownstreamRedirectURI: downstreamRedirectURI,
|
wantDownstreamRedirectURI: downstreamRedirectURI,
|
||||||
wantDownstreamGrantedScopes: []string{"openid"},
|
wantDownstreamGrantedScopes: []string{"openid"},
|
||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
|
wantDownstreamClient: downstreamPinnipedCLIClientID,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
@ -502,9 +622,21 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "downstream redirect uri does not match what is configured for client",
|
name: "downstream redirect uri does not match what is configured for client",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["redirect_uri"] = []string{"http://127.0.0.1/wrong_callback"}
|
map[string]string{"redirect_uri": "http://127.0.0.1/wrong_callback"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
|
}),
|
||||||
|
formParams: happyUsernamePasswordFormParams,
|
||||||
|
wantErr: "error using state downstream auth params",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "downstream redirect uri does not match what is configured for client with dynamic client",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQueryForDynamicClient,
|
||||||
|
map[string]string{"redirect_uri": "http://127.0.0.1/wrong_callback"},
|
||||||
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantErr: "error using state downstream auth params",
|
wantErr: "error using state downstream auth params",
|
||||||
@ -513,9 +645,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "downstream client does not exist",
|
name: "downstream client does not exist",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["client_id"] = []string{"wrong_client_id"}
|
map[string]string{"client_id": "wrong_client_id"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantErr: "error using state downstream auth params",
|
wantErr: "error using state downstream auth params",
|
||||||
@ -524,9 +656,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "downstream client is missing",
|
name: "downstream client is missing",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
delete(query, "client_id")
|
map[string]string{"client_id": ""},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantErr: "error using state downstream auth params",
|
wantErr: "error using state downstream auth params",
|
||||||
@ -535,9 +667,21 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "response type is unsupported",
|
name: "response type is unsupported",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["response_type"] = []string{"unsupported"}
|
map[string]string{"response_type": "unsupported"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
|
}),
|
||||||
|
formParams: happyUsernamePasswordFormParams,
|
||||||
|
wantErr: "error using state downstream auth params",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "response type form_post is unsupported for dynamic clients",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQueryForDynamicClient,
|
||||||
|
map[string]string{"response_type": "form_post"},
|
||||||
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantErr: "error using state downstream auth params",
|
wantErr: "error using state downstream auth params",
|
||||||
@ -546,9 +690,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "response type is missing",
|
name: "response type is missing",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
delete(query, "response_type")
|
map[string]string{"response_type": ""},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantErr: "error using state downstream auth params",
|
wantErr: "error using state downstream auth params",
|
||||||
@ -557,9 +701,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "PKCE code_challenge is missing",
|
name: "PKCE code_challenge is missing",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
delete(query, "code_challenge")
|
map[string]string{"code_challenge": ""},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -572,9 +716,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "PKCE code_challenge_method is invalid",
|
name: "PKCE code_challenge_method is invalid",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["code_challenge_method"] = []string{"this-is-not-a-valid-pkce-alg"}
|
map[string]string{"code_challenge_method": "this-is-not-a-valid-pkce-alg"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -587,9 +731,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "PKCE code_challenge_method is `plain`",
|
name: "PKCE code_challenge_method is `plain`",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["code_challenge_method"] = []string{"plain"} // plain is not allowed
|
map[string]string{"code_challenge_method": "plain"}, // plain is not allowed
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -602,9 +746,25 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "PKCE code_challenge_method is missing",
|
name: "PKCE code_challenge_method is missing",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
delete(query, "code_challenge_method")
|
map[string]string{"code_challenge_method": ""},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
|
}),
|
||||||
|
formParams: happyUsernamePasswordFormParams,
|
||||||
|
wantStatus: http.StatusSeeOther,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBodyString: "",
|
||||||
|
wantRedirectLocationString: urlWithQuery(downstreamRedirectURI, fositeMissingCodeChallengeMethodErrorQuery),
|
||||||
|
wantUnnecessaryStoredRecords: 2, // fosite already stored the authcode and oidc session before it noticed the error
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PKCE code_challenge_method is missing with dynamic client",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQueryForDynamicClient,
|
||||||
|
map[string]string{"code_challenge_method": ""},
|
||||||
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -617,9 +777,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "prompt param is not allowed to have none and another legal value at the same time",
|
name: "prompt param is not allowed to have none and another legal value at the same time",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["prompt"] = []string{"none login"}
|
map[string]string{"prompt": "none login"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantStatus: http.StatusSeeOther,
|
wantStatus: http.StatusSeeOther,
|
||||||
@ -632,9 +792,9 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "downstream state does not have enough entropy",
|
name: "downstream state does not have enough entropy",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["state"] = []string{"short"}
|
map[string]string{"state": "short"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantErr: "error using state downstream auth params",
|
wantErr: "error using state downstream auth params",
|
||||||
@ -643,9 +803,21 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
name: "downstream scopes do not match what is configured for client",
|
name: "downstream scopes do not match what is configured for client",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
query := copyOfHappyDownstreamRequestParamsQuery()
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQuery,
|
||||||
query["scope"] = []string{"openid offline_access pinniped:request-audience scope_not_allowed"}
|
map[string]string{"scope": "openid offline_access pinniped:request-audience scope_not_allowed"},
|
||||||
data.AuthParams = query.Encode()
|
).Encode()
|
||||||
|
}),
|
||||||
|
formParams: happyUsernamePasswordFormParams,
|
||||||
|
wantErr: "error using state downstream auth params",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "downstream scopes do not match what is configured for client with dynamic client",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithLDAP(&upstreamLDAPIdentityProvider),
|
||||||
|
kubeResources: addFullyCapableDynamicClientAndSecretToKubeResources,
|
||||||
|
decodedState: modifyHappyLDAPDecodedState(func(data *oidc.UpstreamStateParamData) {
|
||||||
|
data.AuthParams = shallowCopyAndModifyQuery(happyDownstreamRequestParamsQueryForDynamicClient,
|
||||||
|
map[string]string{"scope": "openid offline_access pinniped:request-audience scope_not_allowed"},
|
||||||
|
).Encode()
|
||||||
}),
|
}),
|
||||||
formParams: happyUsernamePasswordFormParams,
|
formParams: happyUsernamePasswordFormParams,
|
||||||
wantErr: "error using state downstream auth params",
|
wantErr: "error using state downstream auth params",
|
||||||
@ -677,8 +849,8 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
secretsClient := kubeClient.CoreV1().Secrets("some-namespace")
|
secretsClient := kubeClient.CoreV1().Secrets("some-namespace")
|
||||||
oidcClientsClient := supervisorClient.ConfigV1alpha1().OIDCClients("some-namespace")
|
oidcClientsClient := supervisorClient.ConfigV1alpha1().OIDCClients("some-namespace")
|
||||||
|
|
||||||
if test.kubeResources != nil {
|
if tt.kubeResources != nil {
|
||||||
test.kubeResources(t, supervisorClient, kubeClient)
|
tt.kubeResources(t, supervisorClient, kubeClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure fosite the same way that the production code would.
|
// Configure fosite the same way that the production code would.
|
||||||
@ -704,7 +876,7 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
err := subject(rsp, req, happyEncodedUpstreamState, tt.decodedState)
|
err := subject(rsp, req, happyEncodedUpstreamState, tt.decodedState)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.EqualError(t, err, tt.wantErr)
|
require.EqualError(t, err, tt.wantErr)
|
||||||
require.Empty(t, kubeClient.Actions())
|
require.Empty(t, oidctestutil.FilterClientSecretCreateActions(kubeClient.Actions()))
|
||||||
return // the http response doesn't matter when the function returns an error, because the caller should handle the error
|
return // the http response doesn't matter when the function returns an error, because the caller should handle the error
|
||||||
}
|
}
|
||||||
// Otherwise, expect no error.
|
// Otherwise, expect no error.
|
||||||
@ -735,7 +907,7 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
tt.wantDownstreamPKCEChallenge,
|
tt.wantDownstreamPKCEChallenge,
|
||||||
tt.wantDownstreamPKCEChallengeMethod,
|
tt.wantDownstreamPKCEChallengeMethod,
|
||||||
tt.wantDownstreamNonce,
|
tt.wantDownstreamNonce,
|
||||||
downstreamClientID,
|
tt.wantDownstreamClient,
|
||||||
tt.wantDownstreamRedirectURI,
|
tt.wantDownstreamRedirectURI,
|
||||||
tt.wantDownstreamCustomSessionData,
|
tt.wantDownstreamCustomSessionData,
|
||||||
)
|
)
|
||||||
@ -745,12 +917,12 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
expectedLocation := downstreamIssuer + oidc.PinnipedLoginPath +
|
expectedLocation := downstreamIssuer + oidc.PinnipedLoginPath +
|
||||||
"?err=" + tt.wantRedirectToLoginPageError + "&state=" + happyEncodedUpstreamState
|
"?err=" + tt.wantRedirectToLoginPageError + "&state=" + happyEncodedUpstreamState
|
||||||
require.Equal(t, expectedLocation, actualLocation)
|
require.Equal(t, expectedLocation, actualLocation)
|
||||||
require.Len(t, kubeClient.Actions(), tt.wantUnnecessaryStoredRecords)
|
require.Len(t, oidctestutil.FilterClientSecretCreateActions(kubeClient.Actions()), tt.wantUnnecessaryStoredRecords)
|
||||||
case tt.wantRedirectLocationString != "":
|
case tt.wantRedirectLocationString != "":
|
||||||
// Expecting an error redirect to the client.
|
// Expecting an error redirect to the client.
|
||||||
require.Equal(t, tt.wantBodyString, rsp.Body.String())
|
require.Equal(t, tt.wantBodyString, rsp.Body.String())
|
||||||
require.Equal(t, tt.wantRedirectLocationString, actualLocation)
|
require.Equal(t, tt.wantRedirectLocationString, actualLocation)
|
||||||
require.Len(t, kubeClient.Actions(), tt.wantUnnecessaryStoredRecords)
|
require.Len(t, oidctestutil.FilterClientSecretCreateActions(kubeClient.Actions()), tt.wantUnnecessaryStoredRecords)
|
||||||
case tt.wantBodyFormResponseRegexp != "":
|
case tt.wantBodyFormResponseRegexp != "":
|
||||||
// Expecting the body of the response to be a html page with a form (for "response_mode=form_post").
|
// Expecting the body of the response to be a html page with a form (for "response_mode=form_post").
|
||||||
_, hasLocationHeader := rsp.Header()["Location"]
|
_, hasLocationHeader := rsp.Header()["Location"]
|
||||||
@ -770,7 +942,7 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
tt.wantDownstreamPKCEChallenge,
|
tt.wantDownstreamPKCEChallenge,
|
||||||
tt.wantDownstreamPKCEChallengeMethod,
|
tt.wantDownstreamPKCEChallengeMethod,
|
||||||
tt.wantDownstreamNonce,
|
tt.wantDownstreamNonce,
|
||||||
downstreamClientID,
|
tt.wantDownstreamClient,
|
||||||
tt.wantDownstreamRedirectURI,
|
tt.wantDownstreamRedirectURI,
|
||||||
tt.wantDownstreamCustomSessionData,
|
tt.wantDownstreamCustomSessionData,
|
||||||
)
|
)
|
||||||
@ -781,3 +953,18 @@ func TestPostLoginEndpoint(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shallowCopyAndModifyQuery(query url.Values, modifications map[string]string) url.Values {
|
||||||
|
copied := url.Values{}
|
||||||
|
for key, value := range query {
|
||||||
|
copied[key] = value
|
||||||
|
}
|
||||||
|
for key, value := range modifications {
|
||||||
|
if value == "" {
|
||||||
|
copied.Del(key)
|
||||||
|
} else {
|
||||||
|
copied[key] = []string{value}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copied
|
||||||
|
}
|
||||||
|
@ -457,7 +457,7 @@ func PerformAuthcodeRedirect(
|
|||||||
) {
|
) {
|
||||||
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plog.WarningErr("error while generating and saving authcode", err)
|
plog.WarningErr("error while generating and saving authcode", err, "fositeErr", FositeErrorForLog(err))
|
||||||
WriteAuthorizeError(w, oauthHelper, authorizeRequester, err, isBrowserless)
|
WriteAuthorizeError(w, oauthHelper, authorizeRequester, err, isBrowserless)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
|
kubetesting "k8s.io/client-go/testing"
|
||||||
"k8s.io/utils/strings/slices"
|
"k8s.io/utils/strings/slices"
|
||||||
|
|
||||||
"go.pinniped.dev/internal/authenticators"
|
"go.pinniped.dev/internal/authenticators"
|
||||||
@ -954,7 +955,7 @@ func RequireAuthCodeRegexpMatch(
|
|||||||
if includesOpenIDScope(wantDownstreamGrantedScopes) {
|
if includesOpenIDScope(wantDownstreamGrantedScopes) {
|
||||||
expectedNumberOfCreatedSecrets++
|
expectedNumberOfCreatedSecrets++
|
||||||
}
|
}
|
||||||
require.Len(t, kubeClient.Actions(), expectedNumberOfCreatedSecrets)
|
require.Len(t, FilterClientSecretCreateActions(kubeClient.Actions()), expectedNumberOfCreatedSecrets)
|
||||||
|
|
||||||
// One authcode should have been stored.
|
// One authcode should have been stored.
|
||||||
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secretsClient, labels.Set{crud.SecretLabelKey: authorizationcode.TypeLabelValue}, 1)
|
testutil.RequireNumberOfSecretsMatchingLabelSelector(t, secretsClient, labels.Set{crud.SecretLabelKey: authorizationcode.TypeLabelValue}, 1)
|
||||||
@ -1164,3 +1165,20 @@ func castStoredAuthorizeRequest(t *testing.T, storedAuthorizeRequest fosite.Requ
|
|||||||
|
|
||||||
return storedRequest, storedSession
|
return storedRequest, storedSession
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterClientSecretCreateActions ignores any reads made to get a storage secret corresponding to an OIDCClient, since these
|
||||||
|
// are normal actions when the request is using a dynamic client's client_id, and we don't need to make assertions
|
||||||
|
// about these Secrets since they are not related to session storage.
|
||||||
|
func FilterClientSecretCreateActions(actions []kubetesting.Action) []kubetesting.Action {
|
||||||
|
filtered := make([]kubetesting.Action, 0, len(actions))
|
||||||
|
for _, action := range actions {
|
||||||
|
if action.Matches("get", "secrets") {
|
||||||
|
getAction := action.(kubetesting.GetAction)
|
||||||
|
if strings.HasPrefix(getAction.GetName(), "pinniped-storage-oidc-client-secret-") {
|
||||||
|
continue // filter out OIDCClient's storage secret reads
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filtered = append(filtered, action) // otherwise include the action
|
||||||
|
}
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
@ -15,6 +15,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.pinniped.dev/internal/oidc/oidcclientvalidator"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
authorizationv1 "k8s.io/api/authorization/v1"
|
authorizationv1 "k8s.io/api/authorization/v1"
|
||||||
@ -435,7 +437,7 @@ func createOIDCClientSecret(t *testing.T, forOIDCClient *configv1alpha1.OIDCClie
|
|||||||
_, err := io.ReadFull(rand.Reader, buf[:])
|
_, err := io.ReadFull(rand.Reader, buf[:])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
randomSecret := hex.EncodeToString(buf[:])
|
randomSecret := hex.EncodeToString(buf[:])
|
||||||
hashedRandomSecret, err := bcrypt.GenerateFromPassword([]byte(randomSecret), 15)
|
hashedRandomSecret, err := bcrypt.GenerateFromPassword([]byte(randomSecret), oidcclientvalidator.DefaultMinBcryptCost)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
created, err := kubeClient.CoreV1().Secrets(env.SupervisorNamespace).Create(ctx, &corev1.Secret{
|
created, err := kubeClient.CoreV1().Secrets(env.SupervisorNamespace).Create(ctx, &corev1.Secret{
|
||||||
|
Loading…
Reference in New Issue
Block a user