Skip to content

Commit

Permalink
Merge pull request #53 from GESkunkworks/fix/password-expired
Browse files Browse the repository at this point in the history
handle password expiration errors
  • Loading branch information
Squwid authored Oct 28, 2020
2 parents dfead57 + 665bd35 commit 8dec79f
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 0 deletions.
62 changes: 62 additions & 0 deletions pkg/provider/pingfed/example/password-expired.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">

<head><br>
<title>Change Password</title><br>
<base href="https://example.com/" /><br>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><br>
<meta name="viewport" content="initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /><br>
<meta http-equiv="x-ua-compatible" content="IE=edge" /><br><br>
</head><br>

<body><br> <br>
<div class="ping-container" id="company-container">
<br> <br>
<!--
if there is a logo present in the 'company-logo' container,
then 'has-logo' class should be added to 'ping-header' container.
-->
<br>
<div class="ping-header">
<br>
<!-- <span class="company-logo"> -->
<br>
<!-- client company logo here -->
<br>
<!-- </span> -->
<br>
<img id="company-logo" src="logo.png" aria-label="company logo" />
<br>
Change Password
<br>
</div>
<br> <br>
<div class="ping-body-container" id="company-body-container"><br>
<div><br>
<div class="ping-messages"><br>
<div tabindex="0"><br> To change your password, please access the password management system.<br>
</div><br><br>
<div tabindex="0" class="ping-error"><br> Your password is expired and must be changed.<br>
</div><br>
</div><br> <!-- <div class="ping-buttons" > --><br>
<div>
<br>
<button id="changePassLink">
<br>
<a href="https://password.example.com" title="Continue to password management system">
<br> Continue to password management system<br>
</a>
<br>
</button>
<br>
</div><br>
</div><!-- .ping-body --><br>
</div><!-- .ping-body-container --><br> <br>
</div><!-- .ping-container --><br>
<div class="company-footer-container"><br>
<p id="company-copyright"><br> ©<br>
<script>document.write(new Date().getFullYear())</script><br> Company Name<br> </p><br>
</div><br><br><br><br>
</body>

</html>
29 changes: 29 additions & 0 deletions pkg/provider/pingfed/pingfed.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ func (ac *Client) follow(ctx context.Context, req *http.Request) (string, error)
} else if docIsWebAuthn(doc) {
logger.WithField("type", "webauthn").Debug("doc detect")
handler = ac.handleWebAuthn
} else if docIsPingMessage(doc) {
logger.WithField("type", "ping-message").Debug("doc detect")
handler = ac.handlePingMessage
} else if docIsError(doc) {
logger.WithField("type", "error").Debug("doc detect")
pingError := strings.TrimSpace(doc.Find("div.ping-error").Text())
Expand Down Expand Up @@ -569,6 +572,28 @@ func (ac *Client) handleSwipe(ctx context.Context, doc *goquery.Document) (conte
return ctx, req, err
}

func (ac *Client) handlePingMessage(ctx context.Context, doc *goquery.Document) (context.Context, *http.Request, error) {
// Extract the error message
messages := doc.Find(".ping-messages>.ping-error")
pingError := strings.TrimSpace(messages.Text())

// Print out the link to change password if we can find it
if strings.Contains(pingError, "password is expired") {
changePassLink := doc.Find("#changePassLink>a")
if changePassLink.Size() == 1 {
if link, ok := changePassLink.Attr("href"); ok {
changePassText := strings.TrimSpace(changePassLink.Text())
if changePassText == "" {
changePassText = "Change your password"
}
log.Printf("%s: %s", changePassText, link)
}
}
}

return ctx, nil, errors.New(pingError)
}

func (ac *Client) handleFormRedirect(ctx context.Context, doc *goquery.Document) (context.Context, *http.Request, error) {
form, err := page.NewFormFromDocument(doc, "")
if err != nil {
Expand Down Expand Up @@ -601,6 +626,10 @@ func docIsLogin(doc *goquery.Document) bool {
doc.Has("input[name=\"pf.pass\"]").Size() == 1
}

func docIsPingMessage(doc *goquery.Document) bool {
return doc.Has(".ping-messages>.ping-error").Size() > 0
}

func docIsToken(doc *goquery.Document) bool {
return doc.Has("#login-password-field").Size() == 0 &&
doc.Has("input[name=\"pf.pass\"]").Size() == 1
Expand Down
13 changes: 13 additions & 0 deletions pkg/provider/pingfed/pingfed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ var docTests = []struct {
{docIsWebAuthn, "example/swipe.html", false},
{docIsWebAuthn, "example/form-redirect.html", false},
{docIsWebAuthn, "example/webauthn.html", true},
{docIsPingMessage, "example/password-expired.html", true},
}

func TestDocTypes(t *testing.T) {
Expand Down Expand Up @@ -182,3 +183,15 @@ func TestHandleWebAuthn(t *testing.T) {
s := string(b[:])
require.Contains(t, s, "isWebAuthnSupportedByBrowser=true")
}

func TestHandlePasswordExpired(t *testing.T) {
data, err := ioutil.ReadFile("example/password-expired.html")
require.Nil(t, err)

doc, err := goquery.NewDocumentFromReader(bytes.NewReader(data))
require.Nil(t, err)

ac := Client{}
_, _, err = ac.handlePingMessage(context.Background(), doc)
require.Error(t, err, "Your password is expired and must be changed.")
}

0 comments on commit 8dec79f

Please sign in to comment.