mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-09-06 16:17:08 +00:00
Update authorization endpoint to redirect to new login page
Also fix some test failures on the callback handler, register the new login handler in manager.go and add a (half baked) integration test Signed-off-by: Margo Crawford <margaretc@vmware.com>
This commit is contained in:
@@ -964,6 +964,122 @@ func TestE2EFullIntegration_Browser(t *testing.T) { // nolint:gocyclo
|
||||
expectedGroups,
|
||||
)
|
||||
})
|
||||
|
||||
// Add an OIDC upstream IDP and try using it to authenticate during kubectl commands.
|
||||
t.Run("with Supervisor LDAP upstream IDP and browser flow", func(t *testing.T) {
|
||||
testCtx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
// Start a fresh browser driver because we don't want to share cookies between the various tests in this file.
|
||||
page := browsertest.Open(t)
|
||||
|
||||
expectedUsername := env.SupervisorUpstreamLDAP.TestUserMailAttributeValue
|
||||
|
||||
setupClusterForEndToEndLDAPTest(t, expectedUsername, env)
|
||||
|
||||
// Use a specific session cache for this test.
|
||||
sessionCachePath := tempDir + "/ldap-test-sessions.yaml"
|
||||
|
||||
kubeconfigPath := runPinnipedGetKubeconfig(t, env, pinnipedExe, tempDir, []string{
|
||||
"get", "kubeconfig",
|
||||
"--concierge-api-group-suffix", env.APIGroupSuffix,
|
||||
"--concierge-authenticator-type", "jwt",
|
||||
"--concierge-authenticator-name", authenticator.Name,
|
||||
"--oidc-skip-browser",
|
||||
"--oidc-ca-bundle", testCABundlePath,
|
||||
"--upstream-identity-provider-flow", "browser_authcode",
|
||||
"--oidc-session-cache", sessionCachePath,
|
||||
})
|
||||
|
||||
// Run "kubectl get namespaces" which should trigger a browser login via the plugin.
|
||||
kubectlCmd := exec.CommandContext(testCtx, "kubectl", "get", "namespace", "--kubeconfig", kubeconfigPath, "-v", "6")
|
||||
kubectlCmd.Env = append(os.Environ(), env.ProxyEnv()...)
|
||||
|
||||
// Wrap the stdout and stderr pipes with TeeReaders which will copy each incremental read to an
|
||||
// in-memory buffer, so we can have the full output available to us at the end.
|
||||
originalStderrPipe, err := kubectlCmd.StderrPipe()
|
||||
require.NoError(t, err)
|
||||
originalStdoutPipe, err := kubectlCmd.StdoutPipe()
|
||||
require.NoError(t, err)
|
||||
var stderrPipeBuf, stdoutPipeBuf bytes.Buffer
|
||||
stderrPipe := io.TeeReader(originalStderrPipe, &stderrPipeBuf)
|
||||
stdoutPipe := io.TeeReader(originalStdoutPipe, &stdoutPipeBuf)
|
||||
|
||||
t.Logf("starting kubectl subprocess")
|
||||
require.NoError(t, kubectlCmd.Start())
|
||||
t.Cleanup(func() {
|
||||
// Consume readers so that the tee buffers will contain all the output so far.
|
||||
_, stdoutReadAllErr := readAllCtx(testCtx, stdoutPipe)
|
||||
_, stderrReadAllErr := readAllCtx(testCtx, stderrPipe)
|
||||
|
||||
// Note that Wait closes the stdout/stderr pipes, so we don't need to close them ourselves.
|
||||
waitErr := kubectlCmd.Wait()
|
||||
t.Logf("kubectl subprocess exited with code %d", kubectlCmd.ProcessState.ExitCode())
|
||||
|
||||
// Upon failure, print the full output so far of the kubectl command.
|
||||
var testAlreadyFailedErr error
|
||||
if t.Failed() {
|
||||
testAlreadyFailedErr = errors.New("test failed prior to clean up function")
|
||||
}
|
||||
cleanupErrs := utilerrors.NewAggregate([]error{waitErr, stdoutReadAllErr, stderrReadAllErr, testAlreadyFailedErr})
|
||||
|
||||
if cleanupErrs != nil {
|
||||
t.Logf("kubectl stdout was:\n----start of stdout\n%s\n----end of stdout", stdoutPipeBuf.String())
|
||||
t.Logf("kubectl stderr was:\n----start of stderr\n%s\n----end of stderr", stderrPipeBuf.String())
|
||||
}
|
||||
require.NoErrorf(t, cleanupErrs, "kubectl process did not exit cleanly and/or the test failed. "+
|
||||
"Note: if kubectl's first call to the Pinniped CLI results in the Pinniped CLI returning an error, "+
|
||||
"then kubectl may call the Pinniped CLI again, which may hang because it will wait for the user "+
|
||||
"to finish the login. This test will kill the kubectl process after a timeout. In this case, the "+
|
||||
" kubectl output printed above will include multiple prompts for the user to enter their authcode.",
|
||||
)
|
||||
})
|
||||
|
||||
// Start a background goroutine to read stderr from the CLI and parse out the login URL.
|
||||
loginURLChan := make(chan string, 1)
|
||||
spawnTestGoroutine(testCtx, t, func() error {
|
||||
reader := bufio.NewReader(testlib.NewLoggerReader(t, "stderr", stderrPipe))
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
loginURL, err := url.Parse(strings.TrimSpace(scanner.Text()))
|
||||
if err == nil && loginURL.Scheme == "https" {
|
||||
loginURLChan <- loginURL.String() // this channel is buffered so this will not block
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("expected stderr to contain login URL")
|
||||
})
|
||||
|
||||
// Start a background goroutine to read stdout from kubectl and return the result as a string.
|
||||
kubectlOutputChan := make(chan string, 1)
|
||||
spawnTestGoroutine(testCtx, t, func() error {
|
||||
output, err := readAllCtx(testCtx, stdoutPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Logf("kubectl output:\n%s\n", output)
|
||||
kubectlOutputChan <- string(output) // this channel is buffered so this will not block
|
||||
return nil
|
||||
})
|
||||
|
||||
// Wait for the CLI to print out the login URL and open the browser to it.
|
||||
t.Logf("waiting for CLI to output login URL")
|
||||
var loginURL string
|
||||
select {
|
||||
case <-time.After(1 * time.Minute):
|
||||
require.Fail(t, "timed out waiting for login URL")
|
||||
case loginURL = <-loginURLChan:
|
||||
}
|
||||
t.Logf("navigating to login page: %q", loginURL)
|
||||
require.NoError(t, page.Navigate(loginURL))
|
||||
|
||||
// Expect to be redirected to the supervisor's ldap login page.
|
||||
t.Logf("waiting for redirect to supervisor ldap login page")
|
||||
regex := regexp.MustCompile(`\A` + downstream.Spec.Issuer + `/login.+`)
|
||||
browsertest.WaitForURL(t, page, regex)
|
||||
|
||||
// TODO actually log in :P
|
||||
})
|
||||
}
|
||||
|
||||
func setupClusterForEndToEndLDAPTest(t *testing.T, username string, env *testlib.TestEnv) {
|
||||
|
||||
Reference in New Issue
Block a user