2020-11-13 23:59:51 +00:00
|
|
|
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
2020-11-20 01:57:07 +00:00
|
|
|
package oidctestutil
|
2020-11-13 23:59:51 +00:00
|
|
|
|
2020-11-18 21:38:13 +00:00
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net/url"
|
|
|
|
|
2020-11-30 23:08:27 +00:00
|
|
|
"golang.org/x/oauth2"
|
|
|
|
|
2020-11-18 21:38:13 +00:00
|
|
|
"go.pinniped.dev/internal/oidc/provider"
|
2020-11-20 23:13:25 +00:00
|
|
|
"go.pinniped.dev/pkg/oidcclient/nonce"
|
2020-11-30 23:02:03 +00:00
|
|
|
"go.pinniped.dev/pkg/oidcclient/oidctypes"
|
2020-11-20 23:13:25 +00:00
|
|
|
"go.pinniped.dev/pkg/oidcclient/pkce"
|
2020-11-18 21:38:13 +00:00
|
|
|
)
|
2020-11-13 23:59:51 +00:00
|
|
|
|
|
|
|
// Test helpers for the OIDC package.
|
|
|
|
|
2020-11-19 15:20:46 +00:00
|
|
|
// ExchangeAuthcodeAndValidateTokenArgs is a POGO (plain old go object?) used to spy on calls to
|
|
|
|
// TestUpstreamOIDCIdentityProvider.ExchangeAuthcodeAndValidateTokensFunc().
|
|
|
|
type ExchangeAuthcodeAndValidateTokenArgs struct {
|
|
|
|
Ctx context.Context
|
|
|
|
Authcode string
|
|
|
|
PKCECodeVerifier pkce.Code
|
|
|
|
ExpectedIDTokenNonce nonce.Nonce
|
2020-12-02 16:36:07 +00:00
|
|
|
RedirectURI string
|
2020-11-19 15:20:46 +00:00
|
|
|
}
|
|
|
|
|
2020-11-18 21:38:13 +00:00
|
|
|
type TestUpstreamOIDCIdentityProvider struct {
|
|
|
|
Name string
|
|
|
|
ClientID string
|
|
|
|
AuthorizationURL url.URL
|
|
|
|
UsernameClaim string
|
|
|
|
GroupsClaim string
|
|
|
|
Scopes []string
|
|
|
|
ExchangeAuthcodeAndValidateTokensFunc func(
|
|
|
|
ctx context.Context,
|
|
|
|
authcode string,
|
|
|
|
pkceCodeVerifier pkce.Code,
|
|
|
|
expectedIDTokenNonce nonce.Nonce,
|
2020-11-30 23:02:03 +00:00
|
|
|
) (oidctypes.Token, map[string]interface{}, error)
|
2020-11-19 15:20:46 +00:00
|
|
|
|
|
|
|
exchangeAuthcodeAndValidateTokensCallCount int
|
|
|
|
exchangeAuthcodeAndValidateTokensArgs []*ExchangeAuthcodeAndValidateTokenArgs
|
2020-11-18 21:38:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) GetName() string {
|
|
|
|
return u.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) GetClientID() string {
|
|
|
|
return u.ClientID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) GetAuthorizationURL() *url.URL {
|
|
|
|
return &u.AuthorizationURL
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) GetScopes() []string {
|
|
|
|
return u.Scopes
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) GetUsernameClaim() string {
|
|
|
|
return u.UsernameClaim
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) GetGroupsClaim() string {
|
|
|
|
return u.GroupsClaim
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) ExchangeAuthcodeAndValidateTokens(
|
|
|
|
ctx context.Context,
|
|
|
|
authcode string,
|
|
|
|
pkceCodeVerifier pkce.Code,
|
|
|
|
expectedIDTokenNonce nonce.Nonce,
|
2020-12-02 16:36:07 +00:00
|
|
|
redirectURI string,
|
2020-11-30 23:02:03 +00:00
|
|
|
) (oidctypes.Token, map[string]interface{}, error) {
|
2020-11-19 15:20:46 +00:00
|
|
|
if u.exchangeAuthcodeAndValidateTokensArgs == nil {
|
|
|
|
u.exchangeAuthcodeAndValidateTokensArgs = make([]*ExchangeAuthcodeAndValidateTokenArgs, 0)
|
|
|
|
}
|
|
|
|
u.exchangeAuthcodeAndValidateTokensCallCount++
|
|
|
|
u.exchangeAuthcodeAndValidateTokensArgs = append(u.exchangeAuthcodeAndValidateTokensArgs, &ExchangeAuthcodeAndValidateTokenArgs{
|
|
|
|
Ctx: ctx,
|
|
|
|
Authcode: authcode,
|
|
|
|
PKCECodeVerifier: pkceCodeVerifier,
|
|
|
|
ExpectedIDTokenNonce: expectedIDTokenNonce,
|
2020-12-02 16:36:07 +00:00
|
|
|
RedirectURI: redirectURI,
|
2020-11-19 15:20:46 +00:00
|
|
|
})
|
2020-11-18 21:38:13 +00:00
|
|
|
return u.ExchangeAuthcodeAndValidateTokensFunc(ctx, authcode, pkceCodeVerifier, expectedIDTokenNonce)
|
|
|
|
}
|
|
|
|
|
2020-11-19 15:20:46 +00:00
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) ExchangeAuthcodeAndValidateTokensCallCount() int {
|
|
|
|
return u.exchangeAuthcodeAndValidateTokensCallCount
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) ExchangeAuthcodeAndValidateTokensArgs(call int) *ExchangeAuthcodeAndValidateTokenArgs {
|
|
|
|
if u.exchangeAuthcodeAndValidateTokensArgs == nil {
|
|
|
|
u.exchangeAuthcodeAndValidateTokensArgs = make([]*ExchangeAuthcodeAndValidateTokenArgs, 0)
|
|
|
|
}
|
|
|
|
return u.exchangeAuthcodeAndValidateTokensArgs[call]
|
|
|
|
}
|
|
|
|
|
2020-11-30 23:08:27 +00:00
|
|
|
func (u *TestUpstreamOIDCIdentityProvider) ValidateToken(ctx context.Context, tok *oauth2.Token, expectedIDTokenNonce nonce.Nonce) (oidctypes.Token, map[string]interface{}, error) {
|
|
|
|
panic("implement me")
|
|
|
|
}
|
|
|
|
|
2020-11-19 15:20:46 +00:00
|
|
|
func NewIDPListGetter(upstreamOIDCIdentityProviders ...*TestUpstreamOIDCIdentityProvider) provider.DynamicUpstreamIDPProvider {
|
2020-11-13 23:59:51 +00:00
|
|
|
idpProvider := provider.NewDynamicUpstreamIDPProvider()
|
2020-11-18 21:38:13 +00:00
|
|
|
upstreams := make([]provider.UpstreamOIDCIdentityProviderI, len(upstreamOIDCIdentityProviders))
|
|
|
|
for i := range upstreamOIDCIdentityProviders {
|
2020-11-19 15:20:46 +00:00
|
|
|
upstreams[i] = provider.UpstreamOIDCIdentityProviderI(upstreamOIDCIdentityProviders[i])
|
2020-11-18 21:38:13 +00:00
|
|
|
}
|
|
|
|
idpProvider.SetIDPList(upstreams)
|
2020-11-13 23:59:51 +00:00
|
|
|
return idpProvider
|
|
|
|
}
|
|
|
|
|
|
|
|
// Declare a separate type from the production code to ensure that the state param's contents was serialized
|
|
|
|
// in the format that we expect, with the json keys that we expect, etc. This also ensure that the order of
|
|
|
|
// the serialized fields is the same, which doesn't really matter expect that we can make simpler equality
|
|
|
|
// assertions about the redirect URL in this test.
|
|
|
|
type ExpectedUpstreamStateParamFormat struct {
|
|
|
|
P string `json:"p"`
|
2020-11-20 21:14:45 +00:00
|
|
|
U string `json:"u"`
|
2020-11-13 23:59:51 +00:00
|
|
|
N string `json:"n"`
|
|
|
|
C string `json:"c"`
|
|
|
|
K string `json:"k"`
|
|
|
|
V string `json:"v"`
|
|
|
|
}
|