ContainerImage.Pinniped/internal/oidc/idpdiscovery/idp_discovery_handler_test.go
Margo Crawford 694e4d6df6 Advertise browser_authcode flow in ldap idp discovery
To keep this backwards compatible, this PR changes how
the cli deals with ambiguous flows. Previously, if there
was more than one flow advertised, the cli would require users
to set the flag --upstream-identity-provider-flow. Now it
chooses the first one in the list.

Signed-off-by: Margo Crawford <margaretc@vmware.com>
2022-04-25 14:54:21 -07:00

134 lines
5.5 KiB
Go

// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package idpdiscovery
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/testutil/oidctestutil"
)
func TestIDPDiscovery(t *testing.T) {
tests := []struct {
name string
method string
path string
wantStatus int
wantContentType string
wantFirstResponseBodyJSON string
wantSecondResponseBodyJSON string
wantBodyString string
}{
{
name: "happy path",
method: http.MethodGet,
path: "/some/path" + oidc.WellKnownEndpointPath,
wantStatus: http.StatusOK,
wantContentType: "application/json",
wantFirstResponseBodyJSON: here.Doc(`{
"pinniped_identity_providers": [
{"name": "a-some-ldap-idp", "type": "ldap", "flows": ["cli_password", "browser_authcode"]},
{"name": "a-some-oidc-idp", "type": "oidc", "flows": ["browser_authcode"]},
{"name": "x-some-idp", "type": "ldap", "flows": ["cli_password", "browser_authcode"]},
{"name": "x-some-idp", "type": "oidc", "flows": ["browser_authcode"]},
{"name": "y-some-ad-idp", "type": "activedirectory", "flows": ["cli_password", "browser_authcode"]},
{"name": "z-some-ad-idp", "type": "activedirectory", "flows": ["cli_password", "browser_authcode"]},
{"name": "z-some-ldap-idp", "type": "ldap", "flows": ["cli_password", "browser_authcode"]},
{"name": "z-some-oidc-idp", "type": "oidc", "flows": ["browser_authcode", "cli_password"]}
]
}`),
wantSecondResponseBodyJSON: here.Doc(`{
"pinniped_identity_providers": [
{"name": "some-other-ad-idp-1", "type": "activedirectory", "flows": ["cli_password", "browser_authcode"]},
{"name": "some-other-ad-idp-2", "type": "activedirectory", "flows": ["cli_password", "browser_authcode"]},
{"name": "some-other-ldap-idp-1", "type": "ldap", "flows": ["cli_password", "browser_authcode"]},
{"name": "some-other-ldap-idp-2", "type": "ldap", "flows": ["cli_password", "browser_authcode"]},
{"name": "some-other-oidc-idp-1", "type": "oidc", "flows": ["browser_authcode", "cli_password"]},
{"name": "some-other-oidc-idp-2", "type": "oidc", "flows": ["browser_authcode"]}
]
}`),
},
{
name: "bad method",
method: http.MethodPost,
path: oidc.WellKnownEndpointPath,
wantStatus: http.StatusMethodNotAllowed,
wantContentType: "text/plain; charset=utf-8",
wantBodyString: "Method not allowed (try GET)\n",
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
idpLister := oidctestutil.NewUpstreamIDPListerBuilder().
WithOIDC(&oidctestutil.TestUpstreamOIDCIdentityProvider{Name: "z-some-oidc-idp", AllowPasswordGrant: true}).
WithOIDC(&oidctestutil.TestUpstreamOIDCIdentityProvider{Name: "x-some-idp"}).
WithLDAP(&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "a-some-ldap-idp"}).
WithOIDC(&oidctestutil.TestUpstreamOIDCIdentityProvider{Name: "a-some-oidc-idp"}).
WithLDAP(&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "z-some-ldap-idp"}).
WithLDAP(&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "x-some-idp"}).
WithActiveDirectory(&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "z-some-ad-idp"}).
WithActiveDirectory(&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "y-some-ad-idp"}).
Build()
handler := NewHandler(idpLister)
req := httptest.NewRequest(test.method, test.path, nil)
rsp := httptest.NewRecorder()
handler.ServeHTTP(rsp, req)
require.Equal(t, test.wantStatus, rsp.Code)
require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type"))
if test.wantFirstResponseBodyJSON != "" {
require.JSONEq(t, test.wantFirstResponseBodyJSON, rsp.Body.String())
}
if test.wantBodyString != "" {
require.Equal(t, test.wantBodyString, rsp.Body.String())
}
// Change the list of IDPs in the cache.
idpLister.SetLDAPIdentityProviders([]provider.UpstreamLDAPIdentityProviderI{
&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "some-other-ldap-idp-1"},
&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "some-other-ldap-idp-2"},
})
idpLister.SetOIDCIdentityProviders([]provider.UpstreamOIDCIdentityProviderI{
&oidctestutil.TestUpstreamOIDCIdentityProvider{Name: "some-other-oidc-idp-1", AllowPasswordGrant: true},
&oidctestutil.TestUpstreamOIDCIdentityProvider{Name: "some-other-oidc-idp-2"},
})
idpLister.SetActiveDirectoryIdentityProviders([]provider.UpstreamLDAPIdentityProviderI{
&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "some-other-ad-idp-2"},
&oidctestutil.TestUpstreamLDAPIdentityProvider{Name: "some-other-ad-idp-1"},
})
// Make the same request to the same handler instance again, and expect different results.
rsp = httptest.NewRecorder()
handler.ServeHTTP(rsp, req)
require.Equal(t, test.wantStatus, rsp.Code)
require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type"))
if test.wantFirstResponseBodyJSON != "" {
require.JSONEq(t, test.wantSecondResponseBodyJSON, rsp.Body.String())
}
if test.wantBodyString != "" {
require.Equal(t, test.wantBodyString, rsp.Body.String())
}
})
}
}