Skip to content

Commit

Permalink
Update the googleapps IDP provider to work with changes to Google log…
Browse files Browse the repository at this point in the history
…in page while maintaining gaialogin compatibility
  • Loading branch information
aaronthebaron committed Jun 5, 2024
1 parent 07a7eb0 commit 3196e06
Showing 1 changed file with 46 additions and 12 deletions.
58 changes: 46 additions & 12 deletions pkg/provider/googleapps/googleapps.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,14 @@ func (kc *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error)
// Post email address w/o password, then Get the password-input page
passwordURL, passwordForm, err := kc.loadLoginPage(authURL+"?hl=en&loc=US", loginDetails.URL+"&hl=en&loc=US", authForm)
if err != nil {
return "", errors.Wrap(err, "error loading login page")
//if failed, try with "identifier"
authForm.Set("Email", "") // Clear previous key
authForm.Set("identifier", loginDetails.Username)
passwordURL, passwordForm, err = kc.loadLoginPage(authURL+"?hl=en&loc=US", loginDetails.URL+"&hl=en&loc=US", authForm)

if err != nil {
return "", errors.Wrap(err, "error loading login page")
}
}

logger.Debugf("loginURL: %s", passwordURL)
Expand Down Expand Up @@ -269,7 +276,7 @@ func (kc *Client) loadLoginPage(submitURL string, referer string, authForm url.V
loginForm, loginURL, err := extractInputsByFormID(doc, "gaia_loginform", "challenge")
if err != nil {
return "", nil, errors.Wrap(err, "failed to build login form data")
}
}

return loginURL, loginForm, err
}
Expand All @@ -290,6 +297,7 @@ func (kc *Client) loadChallengePage(submitURL string, referer string, authForm u

res, err := kc.client.Do(req)
if err != nil {

return nil, errors.Wrap(err, "failed to make request to login form")
}

Expand All @@ -311,11 +319,13 @@ func (kc *Client) loadChallengePage(submitURL string, referer string, authForm u

secondFactorHeader := "This extra step shows it’s really you trying to sign in"
secondFactorHeader2 := "This extra step shows that it’s really you trying to sign in"
secondFactorHeader3 := "2-Step Verification"
secondFactorHeaderJp := "2 段階認証プロセス"

// have we been asked for 2-Step Verification
if extractNodeText(doc, "h2", secondFactorHeader) != "" ||
extractNodeText(doc, "h2", secondFactorHeader2) != "" ||
extractNodeText(doc, "h1", secondFactorHeader3) != "" ||
extractNodeText(doc, "h1", secondFactorHeaderJp) != "" {

responseForm, secondActionURL, err := extractInputsByFormID(doc, "challenge")
Expand All @@ -326,7 +336,7 @@ func (kc *Client) loadChallengePage(submitURL string, referer string, authForm u
logger.Debugf("secondActionURL: %s", secondActionURL)

switch {
case strings.Contains(secondActionURL, "challenge/totp/"): // handle TOTP challenge
case strings.Contains(secondActionURL, "challenge/totp"): // handle TOTP challenge

var token = loginDetails.MFAToken
if token == "" {
Expand All @@ -337,7 +347,7 @@ func (kc *Client) loadChallengePage(submitURL string, referer string, authForm u
responseForm.Set("TrustDevice", "on") // Don't ask again on this computer

return kc.loadResponsePage(secondActionURL, submitURL, responseForm)
case strings.Contains(secondActionURL, "challenge/ipp/"): // handle SMS challenge
case strings.Contains(secondActionURL, "challenge/ipp"): // handle SMS challenge

if extractNodeText(doc, "button", "Send text message") != "" {
responseForm.Set("SendMethod", "SMS") // extractInputsByFormID does not extract the name and value from <button> tag that is the form submit
Expand Down Expand Up @@ -366,7 +376,7 @@ func (kc *Client) loadChallengePage(submitURL string, referer string, authForm u

return kc.loadResponsePage(secondActionURL, submitURL, responseForm)

case strings.Contains(secondActionURL, "challenge/sk/"): // handle u2f challenge
case strings.Contains(secondActionURL, "challenge/sk"): // handle u2f challenge
facetComponents, err := url.Parse(secondActionURL)
if err != nil {
return nil, errors.Wrap(err, "unable to parse action URL for U2F challenge")
Expand All @@ -389,7 +399,7 @@ func (kc *Client) loadChallengePage(submitURL string, referer string, authForm u
responseForm.Set("TrustDevice", "on")

return kc.loadResponsePage(secondActionURL, submitURL, responseForm)
case strings.Contains(secondActionURL, "challenge/az/"): // handle phone challenge
case strings.Contains(secondActionURL, "challenge/az"): // handle phone challenge

dataAttrs := extractDataAttributes(doc, "div[data-context]", []string{"data-context", "data-gapi-url", "data-tx-id", "data-api-key", "data-tx-lifetime"})

Expand All @@ -411,7 +421,7 @@ func (kc *Client) loadChallengePage(submitURL string, referer string, authForm u

return kc.loadResponsePage(secondActionURL, submitURL, responseForm)

case strings.Contains(secondActionURL, "challenge/dp/"): // handle device push challenge
case strings.Contains(secondActionURL, "challenge/dp"): // handle device push challenge
if extraNumber := extractDevicePushExtraNumber(doc); extraNumber != "" {
log.Println("Check your phone and tap 'Yes' on the prompt, then tap the number:")
log.Printf("\t%v\n", extraNumber)
Expand All @@ -427,7 +437,7 @@ func (kc *Client) loadChallengePage(submitURL string, referer string, authForm u
responseForm.Set("TrustDevice", "on") // Don't ask again on this computer
return kc.loadResponsePage(secondActionURL, submitURL, responseForm)

case strings.Contains(secondActionURL, "challenge/skotp/"): // handle one-time HOTP challenge
case strings.Contains(secondActionURL, "challenge/skotp"): // handle one-time HOTP challenge
log.Println("Get a one-time code by visiting https://g.co/sc on another device where you can use your security key")
var token = prompter.RequestSecurityCode("000 000")

Expand Down Expand Up @@ -598,15 +608,39 @@ func mustFindErrorMsg(doc *goquery.Document) string {
return fieldValue
}

//func extractInputsByFormID(doc *goquery.Document, formID ...string) (url.Values, string, error) {
// for _, id := range formID {
// formData, actionURL, err := extractInputsByFormQuery(doc, fmt.Sprintf("#%s", id))
// if err != nil && strings.HasPrefix(err.Error(), "could not find form with query ") {
// continue
// }
// return formData, actionURL, err
// }
// return url.Values{}, "", errors.New("could not find any forms matching the provided IDs")
//}

func extractInputsByFormID(doc *goquery.Document, formID ...string) (url.Values, string, error) {
// First try to find form by specific id
for _, id := range formID {
formData, actionURL, err := extractInputsByFormQuery(doc, fmt.Sprintf("#%s", id))
if err != nil && strings.HasPrefix(err.Error(), "could not find form with query ") {
continue
if err == nil && actionURL != "" {
return formData, actionURL, nil
}
return formData, actionURL, err
}
return url.Values{}, "", errors.New("could not find any forms matching the provided IDs")

// If no form found by id or actionURL in the previous forms, search for any form
formData, actionURL, err := extractInputsByFormQuery(doc, "")
if err != nil && actionURL != "" {
fmt.Print("Right there")
return formData, actionURL, errors.New("could not find any forms with actions")
}

if len(formData) == 0 {
return nil, "", errors.New("could not find any forms")
}

// Fallback in case no forms with actionURL were found
return formData, actionURL, err
}

func extractInputsByFormQuery(doc *goquery.Document, formQuery string) (url.Values, string, error) {
Expand Down

0 comments on commit 3196e06

Please sign in to comment.