mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-01-06 13:36:54 +00:00
Finish initial github login flow
Also: - fix github teams query: fix bug and sort/unique the results - add IDP display name to github downstream subject - fix error types returned by LoginFromCallback - add trace logs to github API results - update e2e test - implement placeholder version of refresh for github
This commit is contained in:
committed by
Joshua Casey
parent
ba2d122308
commit
8923704f3c
@@ -398,14 +398,27 @@ func LoginToUpstreamGitHub(t *testing.T, b *Browser, upstream testlib.TestGithub
|
||||
t.Logf("entering GitHub OTP code")
|
||||
b.SendKeysToFirstMatch(t, otpSelector, code)
|
||||
|
||||
// Keep looping until we get to a page that we do not know how to handle. Then return to allow the test to move on.
|
||||
for handleOccasionalGithubLoginPage(t, b) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// handleOccasionalGithubLoginPage handles the interstitial pages which GitHub might show during a login flow.
|
||||
// None of these will always happen.
|
||||
func handleOccasionalGithubLoginPage(t *testing.T, b *Browser) bool {
|
||||
t.Helper()
|
||||
|
||||
t.Log("sleeping for 2 seconds before looking at page title")
|
||||
time.Sleep(2 * time.Second)
|
||||
pageTitle := b.Title(t)
|
||||
t.Logf("saw page title %q", pageTitle)
|
||||
lowercaseTitle := strings.ToLower(pageTitle)
|
||||
|
||||
// Next Github might go to another page asking if you authorize the GitHub App to act on your behalf,
|
||||
// if this user has never authorized this app.
|
||||
if strings.HasPrefix(pageTitle, "Authorize ") { // the title is "Authorize <App Name>"
|
||||
switch {
|
||||
case strings.HasPrefix(lowercaseTitle, "authorize "): // the title is "Authorize <App Name>"
|
||||
// Next Github might go to another page asking if you authorize the GitHub App to act on your behalf,
|
||||
// if this user has never authorized this app.
|
||||
// Wait for the authorize app page to be rendered.
|
||||
t.Logf("waiting for GitHub authorize button")
|
||||
// There are unfortunately two very similar buttons on this page:
|
||||
@@ -415,16 +428,23 @@ func LoginToUpstreamGitHub(t *testing.T, b *Browser, upstream testlib.TestGithub
|
||||
b.WaitForVisibleElements(t, submitAuthorizeAppButtonSelector)
|
||||
t.Logf("clicking authorize button")
|
||||
b.ClickFirstMatch(t, submitAuthorizeAppButtonSelector)
|
||||
return true
|
||||
|
||||
t.Log("sleeping for 2 seconds before looking at page title again")
|
||||
time.Sleep(2 * time.Second)
|
||||
pageTitle = b.Title(t)
|
||||
t.Logf("saw page title %q", pageTitle)
|
||||
}
|
||||
case strings.HasPrefix(lowercaseTitle, "confirm your account recovery settings"):
|
||||
// Next Github might occasionally as you to confirm your recovery settings.
|
||||
// Wait for the page to be rendered.
|
||||
t.Logf("waiting for GitHub confirm button")
|
||||
// There are several buttons and links. We want to click this confirm button to confirm our settings:
|
||||
// <button type="submit" name="type" value="confirmed" class="btn btn-block btn-primary ml-3">Confirm</button>
|
||||
submitConfirmButtonSelector := "button.btn-primary"
|
||||
b.WaitForVisibleElements(t, submitConfirmButtonSelector)
|
||||
t.Logf("clicking confirm button")
|
||||
b.ClickFirstMatch(t, submitConfirmButtonSelector)
|
||||
return true
|
||||
|
||||
// TODO I only saw this happen once, so I did not get a chance to finish this code. Not sure if it will happen again?
|
||||
// Next GitHub might ask if we want to configure a passkey for auth.
|
||||
if strings.HasPrefix(pageTitle, "Passkey TODO GET THIS PAGE TITLE") {
|
||||
case strings.HasPrefix(lowercaseTitle, "configure passwordless authentication"):
|
||||
// Next GitHub might occasionally ask if we want to configure a passkey for auth.
|
||||
// The URL bar shows https://github.com/sessions/trusted-device for this page.
|
||||
// The link that we want to click looks like this:
|
||||
// <input class="btn-link" type="submit" value="Don't ask again for this browser">
|
||||
dontAskAgainLinkSelector := `input[value="Don't ask again for this browser"]`
|
||||
@@ -434,6 +454,19 @@ func LoginToUpstreamGitHub(t *testing.T, b *Browser, upstream testlib.TestGithub
|
||||
// Tell it that we do not want to use a passkey.
|
||||
t.Logf("clicking don't ask again button")
|
||||
b.ClickFirstMatch(t, dontAskAgainLinkSelector)
|
||||
return true
|
||||
|
||||
case strings.HasPrefix(lowercaseTitle, "server error"):
|
||||
// Sometimes this happens after the OTP page. Not sure why. The page has a cute cartoon, but no helpful information.
|
||||
// The URL bar shows https://github.com/sessions/trusted-device for this error page, which is the URL that usually
|
||||
// asks if you want to configure passwordless authentication (aka passkey).
|
||||
t.Fatal("Got GitHub server error page during login flow. This is not expected, but is unfortunately unrecoverable.")
|
||||
return false // we recognized the title, but we don't know how to handle this page because it has no buttons or other way forward
|
||||
|
||||
default:
|
||||
// We did not know how to handle the page given its title.
|
||||
// Maybe we successfully got through all the interstitial pages and finished the login.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,11 +112,15 @@ type TestLDAPUpstream struct {
|
||||
}
|
||||
|
||||
type TestGithubUpstream struct {
|
||||
GithubAppClientID string `json:"githubAppClientId"`
|
||||
GithubAppClientSecret string `json:"githubAppClientSecret"`
|
||||
TestUserUsername string `json:"testUserUsername"`
|
||||
TestUserPassword string `json:"testUserPassword"`
|
||||
TestUserOTPSecret string `json:"testUserOTPSecret"`
|
||||
GithubAppClientID string `json:"githubAppClientId"`
|
||||
GithubAppClientSecret string `json:"githubAppClientSecret"`
|
||||
TestUserUsername string `json:"testUserUsername"` // the "login" attribute value for the user
|
||||
TestUserPassword string `json:"testUserPassword"`
|
||||
TestUserOTPSecret string `json:"testUserOTPSecret"`
|
||||
TestUserID string `json:"testUserID"` // the "id" attribute value for the user
|
||||
TestUserOrganization string `json:"testUserOrganization"` // an org to which the user belongs
|
||||
TestUserExpectedTeamNames []string `json:"testUserExpectedTeamNames"`
|
||||
TestUserExpectedTeamSlugs []string `json:"testUserExpectedTeamSlugs"`
|
||||
}
|
||||
|
||||
// ProxyEnv returns a set of environment variable strings (e.g., to combine with os.Environ()) which set up the configured test HTTP proxy.
|
||||
@@ -329,11 +333,15 @@ func loadEnvVars(t *testing.T, result *TestEnv) {
|
||||
}
|
||||
|
||||
result.SupervisorUpstreamGithub = TestGithubUpstream{
|
||||
GithubAppClientID: wantEnv("PINNIPED_TEST_GITHUB_APP_CLIENT_ID", ""),
|
||||
GithubAppClientSecret: wantEnv("PINNIPED_TEST_GITHUB_APP_CLIENT_SECRET", ""),
|
||||
TestUserUsername: wantEnv("PINNIPED_TEST_GITHUB_USER_USERNAME", ""),
|
||||
TestUserPassword: wantEnv("PINNIPED_TEST_GITHUB_USER_PASSWORD", ""),
|
||||
TestUserOTPSecret: wantEnv("PINNIPED_TEST_GITHUB_USER_OTP_SECRET", ""),
|
||||
GithubAppClientID: wantEnv("PINNIPED_TEST_GITHUB_APP_CLIENT_ID", ""),
|
||||
GithubAppClientSecret: wantEnv("PINNIPED_TEST_GITHUB_APP_CLIENT_SECRET", ""),
|
||||
TestUserUsername: wantEnv("PINNIPED_TEST_GITHUB_USER_USERNAME", ""),
|
||||
TestUserPassword: wantEnv("PINNIPED_TEST_GITHUB_USER_PASSWORD", ""),
|
||||
TestUserOTPSecret: wantEnv("PINNIPED_TEST_GITHUB_USER_OTP_SECRET", ""),
|
||||
TestUserID: wantEnv("PINNIPED_TEST_GITHUB_USERID", ""),
|
||||
TestUserOrganization: wantEnv("PINNIPED_TEST_GITHUB_ORG", ""),
|
||||
TestUserExpectedTeamNames: filterEmpty(strings.Split(wantEnv("PINNIPED_TEST_GITHUB_EXPECTED_TEAM_NAMES", ""), ",")),
|
||||
TestUserExpectedTeamSlugs: filterEmpty(strings.Split(wantEnv("PINNIPED_TEST_GITHUB_EXPECTED_TEAM_SLUGS", ""), ",")),
|
||||
}
|
||||
|
||||
sort.Strings(result.SupervisorUpstreamLDAP.TestUserDirectGroupsCNs)
|
||||
@@ -341,6 +349,8 @@ func loadEnvVars(t *testing.T, result *TestEnv) {
|
||||
sort.Strings(result.SupervisorUpstreamActiveDirectory.TestUserDirectGroupsCNs)
|
||||
sort.Strings(result.SupervisorUpstreamActiveDirectory.TestUserDirectGroupsDNs)
|
||||
sort.Strings(result.SupervisorUpstreamActiveDirectory.TestUserIndirectGroupsSAMAccountNames)
|
||||
sort.Strings(result.SupervisorUpstreamGithub.TestUserExpectedTeamNames)
|
||||
sort.Strings(result.SupervisorUpstreamGithub.TestUserExpectedTeamSlugs)
|
||||
}
|
||||
|
||||
func (e *TestEnv) HasCapability(cap Capability) bool {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package testlib
|
||||
@@ -33,3 +33,11 @@ func SkipTestWhenActiveDirectoryIsUnavailable(t *testing.T, env *TestEnv) {
|
||||
t.Skip("Active Directory hostname not specified")
|
||||
}
|
||||
}
|
||||
|
||||
func SkipTestWhenGitHubIsUnavailable(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if IntegrationEnv(t).SupervisorUpstreamGithub.GithubAppClientID == "" {
|
||||
t.Skip("GitHub test env vars not specified")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user