Passing integration test for LDAP login! 🚀
This commit is contained in:
parent
6bba529b10
commit
47b66ceaa7
@ -2,7 +2,6 @@
|
|||||||
#! SPDX-License-Identifier: Apache-2.0
|
#! SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
#@ load("@ytt:data", "data")
|
#@ load("@ytt:data", "data")
|
||||||
#@ load("@ytt:base64", "base64")
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
@ -48,7 +47,7 @@ stringData:
|
|||||||
sn: Seal
|
sn: Seal
|
||||||
givenName: Pinny
|
givenName: Pinny
|
||||||
mail: pinny.ldap@example.com
|
mail: pinny.ldap@example.com
|
||||||
userPassword:: (@= base64.encode(data.values.pinny_ldap_password) @)
|
userPassword: (@= data.values.pinny_ldap_password @)
|
||||||
uid: pinny
|
uid: pinny
|
||||||
uidNumber: 1000
|
uidNumber: 1000
|
||||||
gidNumber: 1000
|
gidNumber: 1000
|
||||||
|
@ -80,7 +80,7 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
library.CreateTestLDAPIdentityProvider(t, idpv1alpha1.LDAPIdentityProviderSpec{
|
library.CreateTestLDAPIdentityProvider(t, idpv1alpha1.LDAPIdentityProviderSpec{
|
||||||
Host: env.SupervisorUpstreamLDAP.Host,
|
Host: env.SupervisorUpstreamLDAP.Host,
|
||||||
TLS: &idpv1alpha1.LDAPIdentityProviderTLSSpec{
|
TLS: &idpv1alpha1.LDAPIdentityProviderTLSSpec{
|
||||||
CertificateAuthorityData: env.SupervisorUpstreamLDAP.CABundle,
|
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamLDAP.CABundle)),
|
||||||
},
|
},
|
||||||
Bind: idpv1alpha1.LDAPIdentityProviderBindSpec{
|
Bind: idpv1alpha1.LDAPIdentityProviderBindSpec{
|
||||||
SecretName: secret.Name,
|
SecretName: secret.Name,
|
||||||
@ -93,7 +93,7 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
UniqueID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
|
UniqueID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, "") // TODO: this should be idpv1alpha1.LDAPPhaseReady once we have a controller
|
}, idpv1alpha1.LDAPPhaseReady)
|
||||||
},
|
},
|
||||||
requestAuthorization: func(t *testing.T, downstreamAuthorizeURL, _ string, httpClient *http.Client) {
|
requestAuthorization: func(t *testing.T, downstreamAuthorizeURL, _ string, httpClient *http.Client) {
|
||||||
requestAuthorizationUsingLDAPIdentityProvider(t,
|
requestAuthorizationUsingLDAPIdentityProvider(t,
|
||||||
@ -152,6 +152,10 @@ func testSupervisorLogin(
|
|||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{RootCAs: ca.Pool()},
|
TLSClientConfig: &tls.Config{RootCAs: ca.Pool()},
|
||||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||||
|
if strings.HasPrefix(req.URL.Host, "127.0.0.1") {
|
||||||
|
// don't proxy requests to localhost to avoid proxying calls to our local callback listener
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
if env.Proxy == "" {
|
if env.Proxy == "" {
|
||||||
t.Logf("passing request for %s with no proxy", req.URL)
|
t.Logf("passing request for %s with no proxy", req.URL)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -249,14 +253,6 @@ func testSupervisorLogin(
|
|||||||
pkceParam.Method(),
|
pkceParam.Method(),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Make the authorize request once "manually" so we can check its response security headers.
|
|
||||||
authorizeRequest, err := http.NewRequestWithContext(ctx, http.MethodGet, downstreamAuthorizeURL, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
authorizeResp, err := httpClient.Do(authorizeRequest)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, authorizeResp.Body.Close())
|
|
||||||
expectSecurityHeaders(t, authorizeResp)
|
|
||||||
|
|
||||||
// Perform parameterized auth code acquisition.
|
// Perform parameterized auth code acquisition.
|
||||||
requestAuthorization(t, downstreamAuthorizeURL, localCallbackServer.URL, httpClient)
|
requestAuthorization(t, downstreamAuthorizeURL, localCallbackServer.URL, httpClient)
|
||||||
|
|
||||||
@ -350,10 +346,21 @@ func verifyTokenResponse(
|
|||||||
require.NotEmpty(t, tokenResponse.RefreshToken)
|
require.NotEmpty(t, tokenResponse.RefreshToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestAuthorizationUsingOIDCIdentityProvider(t *testing.T, downstreamAuthorizeURL, downstreamCallbackURL string, _ *http.Client) {
|
func requestAuthorizationUsingOIDCIdentityProvider(t *testing.T, downstreamAuthorizeURL, downstreamCallbackURL string, httpClient *http.Client) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
env := library.IntegrationEnv(t)
|
env := library.IntegrationEnv(t)
|
||||||
|
|
||||||
|
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancelFunc()
|
||||||
|
|
||||||
|
// Make the authorize request once "manually" so we can check its response security headers.
|
||||||
|
authorizeRequest, err := http.NewRequestWithContext(ctx, http.MethodGet, downstreamAuthorizeURL, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
authorizeResp, err := httpClient.Do(authorizeRequest)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, authorizeResp.Body.Close())
|
||||||
|
expectSecurityHeaders(t, authorizeResp, false)
|
||||||
|
|
||||||
// Open the web browser and navigate to the downstream authorize URL.
|
// Open the web browser and navigate to the downstream authorize URL.
|
||||||
page := browsertest.Open(t)
|
page := browsertest.Open(t)
|
||||||
t.Logf("opening browser to downstream authorize URL %s", library.MaskTokens(downstreamAuthorizeURL))
|
t.Logf("opening browser to downstream authorize URL %s", library.MaskTokens(downstreamAuthorizeURL))
|
||||||
@ -381,18 +388,29 @@ func requestAuthorizationUsingLDAPIdentityProvider(t *testing.T, downstreamAutho
|
|||||||
authRequest.Header.Set("X-Pinniped-Upstream-Username", upstreamUsername)
|
authRequest.Header.Set("X-Pinniped-Upstream-Username", upstreamUsername)
|
||||||
authRequest.Header.Set("X-Pinniped-Upstream-Password", upstreamPassword)
|
authRequest.Header.Set("X-Pinniped-Upstream-Password", upstreamPassword)
|
||||||
|
|
||||||
// The authorize request is supposed to redirect to this test's callback handler, which in turn is supposed to return 200 OK.
|
|
||||||
authResponse, err := httpClient.Do(authRequest)
|
authResponse, err := httpClient.Do(authRequest)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
responseBody, err := ioutil.ReadAll(authResponse.Body)
|
responseBody, err := ioutil.ReadAll(authResponse.Body)
|
||||||
defer authResponse.Body.Close()
|
defer authResponse.Body.Close()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
expectSecurityHeaders(t, authResponse, true)
|
||||||
|
|
||||||
// TODO remove this skip
|
// A successful authorize request results in a redirect to our localhost callback listener with an authcode param.
|
||||||
_ = responseBody // suppress linter until we remove the below skip
|
require.Equalf(t, http.StatusFound, authResponse.StatusCode, "response body was: %s", string(responseBody))
|
||||||
t.Skip("The rest of this test will not work until we implement the corresponding production code.")
|
redirectLocation := authResponse.Header.Get("Location")
|
||||||
|
require.Contains(t, redirectLocation, "127.0.0.1")
|
||||||
|
require.Contains(t, redirectLocation, "/callback")
|
||||||
|
require.Contains(t, redirectLocation, "code=")
|
||||||
|
|
||||||
require.Equalf(t, http.StatusOK, authResponse.StatusCode, "response body was: %s", string(responseBody))
|
// Follow the redirect.
|
||||||
|
callbackRequest, err := http.NewRequestWithContext(ctx, http.MethodGet, redirectLocation, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Our localhost callback listener should have returned 200 OK.
|
||||||
|
callbackResponse, err := httpClient.Do(callbackRequest)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer callbackResponse.Body.Close()
|
||||||
|
require.Equal(t, http.StatusOK, callbackResponse.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func startLocalCallbackServer(t *testing.T) *localCallbackServer {
|
func startLocalCallbackServer(t *testing.T) *localCallbackServer {
|
||||||
@ -462,7 +480,7 @@ func doTokenExchange(t *testing.T, config *oauth2.Config, tokenResponse *oauth2.
|
|||||||
t.Logf("exchanged token claims:\n%s", string(indentedClaims))
|
t.Logf("exchanged token claims:\n%s", string(indentedClaims))
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectSecurityHeaders(t *testing.T, response *http.Response) {
|
func expectSecurityHeaders(t *testing.T, response *http.Response, expectFositeToOverrideSome bool) {
|
||||||
h := response.Header
|
h := response.Header
|
||||||
assert.Equal(t, "default-src 'none'; frame-ancestors 'none'", h.Get("Content-Security-Policy"))
|
assert.Equal(t, "default-src 'none'; frame-ancestors 'none'", h.Get("Content-Security-Policy"))
|
||||||
assert.Equal(t, "DENY", h.Get("X-Frame-Options"))
|
assert.Equal(t, "DENY", h.Get("X-Frame-Options"))
|
||||||
@ -470,7 +488,11 @@ func expectSecurityHeaders(t *testing.T, response *http.Response) {
|
|||||||
assert.Equal(t, "nosniff", h.Get("X-Content-Type-Options"))
|
assert.Equal(t, "nosniff", h.Get("X-Content-Type-Options"))
|
||||||
assert.Equal(t, "no-referrer", h.Get("Referrer-Policy"))
|
assert.Equal(t, "no-referrer", h.Get("Referrer-Policy"))
|
||||||
assert.Equal(t, "off", h.Get("X-DNS-Prefetch-Control"))
|
assert.Equal(t, "off", h.Get("X-DNS-Prefetch-Control"))
|
||||||
|
if expectFositeToOverrideSome {
|
||||||
|
assert.Equal(t, "no-store", h.Get("Cache-Control"))
|
||||||
|
} else {
|
||||||
assert.Equal(t, "no-cache,no-store,max-age=0,must-revalidate", h.Get("Cache-Control"))
|
assert.Equal(t, "no-cache,no-store,max-age=0,must-revalidate", h.Get("Cache-Control"))
|
||||||
|
}
|
||||||
assert.Equal(t, "no-cache", h.Get("Pragma"))
|
assert.Equal(t, "no-cache", h.Get("Pragma"))
|
||||||
assert.Equal(t, "0", h.Get("Expires"))
|
assert.Equal(t, "0", h.Get("Expires"))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user