Skip to content

Commit

Permalink
Merge branch 'master' into feature/okta-number-challenge
Browse files Browse the repository at this point in the history
  • Loading branch information
mapkon authored Aug 25, 2023
2 parents 52c44b2 + b63aed1 commit afc2d52
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 0 deletions.
104 changes: 104 additions & 0 deletions pkg/provider/pingfed/example/swipe-number.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="format-detection" content="telephone=no">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<link rel="stylesheet" href="/pingid/assets/css/main-v21.144.css" media="screen" title="no title" charset="utf-8">
<link rel="stylesheet" media="screen" type="text/css" href="/pingid/assets/css/jsdisabled.css" />
<script type="text/javascript" src="/pingid/assets/js/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="/pingid/assets/js/spin.js"></script>
</head>
<body>
<noscript>
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name = "format-detection" content = "telephone=no">
<link rel="stylesheet" href="/pingid/assets/css/jsdisabled.css" media="screen" title="no title" charset="utf-8">
</head>
<body>
<div class="nojspage">
<div class="window error">
<div class="content">
<div class="status"></div>
<div class="title-text">
Important
</div>
<div class="error-text">
<div class="text">
PingID requires Javascript to be enabled. If the problem persists, please contact your administrator.
</div>
</div>
</div>
</div>
<div class="footer">
<div class="pingid_logo"></div>
<div class="copyright">
Copyright &copy; 2003-2018 Ping Identity Corporation. All rights reserved.
</div>
</div>
</div>
</body>
</html>
<style type="text/css">
.dialog { display:none; }
</style>
</noscript>
<div class="dialog">
<div class="window authenticating">
<div class="content">
<h1>
Authentication
</h1>
<p>
Select the number displayed in your PingID mobile app
</p>
<div class="status">
<div class="numbermatching">10</div>
</div>
<div class="text device">
Authenticating on
<div class="device-name">
iPhone X
</div>
</div>
<a class="button" href="/pingid/ppm/devices">Change Device</a>
</div>
</div>
<div class="admin-message">corporate motd</div>
<div class="footer">
<a class="button settings-btn" href="https://authenticator.pingone.com/pingid/ppm/settings">Settings</a>
<div class="logo"></div>
<div class="copyright">
Copyright &copy; 2003-2018 Ping Identity Corporation. All rights reserved.
</div>
</div>
<!-- This can be removed once Async FF is removed. -->
<form method="POST" action="https://authenticator.pingone.com/pingid/ppm/auth/status" id="form1">
<input type="hidden" name="csrfToken" id="csrfToken" value="abdb4264-6aab-4e1a-a830-63c9188e2395" encode="false" />
<noscript><input type="submit" value="Resume"/></noscript>
</form>
<form method="GET" action="https://authenticator.pingone.com/pingid/ppm/auth/response" id="reponseView">
<input type="hidden" name="csrfToken" id="csrfToken" value="abdb4264-6aab-4e1a-a830-63c9188e2395" encode="false" />
<input type="hidden" name="status" id="status" encode="false" />
<noscript><input type="submit" value="Resume"/></noscript>
</form>
<form method="GET" action="https://authenticator.pingone.com/pingid/ppm/auth/response" id="errorReponseView">
<input type="hidden" name="csrfToken" id="csrfToken" value="abdb4264-6aab-4e1a-a830-63c9188e2395" encode="false" />
</form>
<div id="authModelSection">
<input type="hidden" name="isAsync" id="isAsync" value="true" encode="false" />
<input type="hidden" name="actionLink" id="actionLink" value="https://authenticator.pingone.com/pingid/ppm/auth/status" encode="false" />
<input type="hidden" name="useCodeUrl" id="useCodeUrl" value="/pingid/ppm/auth/usecode" encode="false" />
</div>
<script type="text/javascript" src="/pingid/assets/js/utils/spinner.js"></script>
<script type="text/javascript" src="/pingid/assets/js/utils/getAuthStatus.js"></script>
<script type="text/javascript" src="/pingid/assets/js/utils/authenticationselfsubmit.js"></script>
<script type="text/javascript" src="/pingid/assets/js/utils/usecodesubmit.js"></script>
</div>
</body>
</html>
5 changes: 5 additions & 0 deletions pkg/provider/pingfed/pingfed.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/base64"
"fmt"
"io"
"log"
"net/http"
"net/url"
"time"
Expand Down Expand Up @@ -172,6 +173,10 @@ func (ac *Client) handleSwipe(ctx context.Context, doc *goquery.Document, _ *url
return ctx, nil, errors.Wrap(err, "error extracting swipe status form")
}

if number := doc.Find("div.numbermatching").Text(); number != "" {
log.Printf("Select %v in your PingID mobile app ...\n", number)
}

// poll status. request must specifically be a GET
form.Method = "GET"
req, err := form.BuildRequest()
Expand Down
61 changes: 61 additions & 0 deletions pkg/provider/pingfed/pingfed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package pingfed
import (
"bytes"
"context"
"crypto/tls"
"io"
"log"
"net/http"
"net/http/cookiejar"
"net/http/httptest"
"net/url"
"os"
"testing"
Expand Down Expand Up @@ -33,26 +36,31 @@ var docTests = []struct {
{docIsLogin, "example/login2.html", true},
{docIsLogin, "example/otp.html", false},
{docIsLogin, "example/swipe.html", false},
{docIsLogin, "example/swipe-number.html", false},
{docIsLogin, "example/form-redirect.html", false},
{docIsLogin, "example/webauthn.html", false},
{docIsOTP, "example/login.html", false},
{docIsOTP, "example/otp.html", true},
{docIsOTP, "example/swipe.html", false},
{docIsOTP, "example/swipe-number.html", false},
{docIsOTP, "example/form-redirect.html", false},
{docIsOTP, "example/webauthn.html", false},
{docIsSwipe, "example/login.html", false},
{docIsSwipe, "example/otp.html", false},
{docIsSwipe, "example/swipe.html", true},
{docIsSwipe, "example/swipe-number.html", true},
{docIsSwipe, "example/form-redirect.html", false},
{docIsSwipe, "example/webauthn.html", false},
{docIsFormRedirect, "example/login.html", false},
{docIsFormRedirect, "example/otp.html", false},
{docIsFormRedirect, "example/swipe.html", false},
{docIsFormRedirect, "example/swipe-number.html", false},
{docIsFormRedirect, "example/form-redirect.html", true},
{docIsFormRedirect, "example/webauthn.html", false},
{docIsWebAuthn, "example/login.html", false},
{docIsWebAuthn, "example/otp.html", false},
{docIsWebAuthn, "example/swipe.html", false},
{docIsWebAuthn, "example/swipe-number.html", false},
{docIsWebAuthn, "example/form-redirect.html", false},
{docIsWebAuthn, "example/webauthn.html", true},
}
Expand Down Expand Up @@ -135,6 +143,59 @@ func TestHandleOTP(t *testing.T) {
require.Contains(t, s, "csrfToken=some-token")
}

func TestHandleSwipe(t *testing.T) {
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/pingid/ppm/auth/status":
_, err := w.Write([]byte("{\"status\":\"OK\"}"))
require.Nil(t, err)
default:
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
}
}))
defer ts.Close()

performTest := func(data []byte) bytes.Buffer {
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(bytes.ReplaceAll(data, []byte("https://authenticator.pingone.com"), []byte(ts.URL))))
require.Nil(t, err)

testTransport := http.DefaultTransport.(*http.Transport).Clone()
testTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
ac := Client{
client: &provider.HTTPClient{Client: http.Client{Transport: testTransport}, Options: &provider.HTTPClientOptions{IsWithRetries: false}},
}

var out bytes.Buffer
log.SetOutput(&out)
_, req, err := ac.handleSwipe(context.Background(), doc, &url.URL{})
log.SetOutput(os.Stderr)
require.Nil(t, err)

b, err := io.ReadAll(req.Body)
require.Nil(t, err)

s := string(b[:])
require.Contains(t, s, "csrfToken=abdb4264-6aab-4e1a-a830-63c9188e2395")

return out
}

t.Run("Swipe", func(t *testing.T) {
data, err := os.ReadFile("example/swipe.html")
require.Nil(t, err)

performTest(data)
})

t.Run("Swipe with number", func(t *testing.T) {
data, err := os.ReadFile("example/swipe-number.html")
require.Nil(t, err)

out := performTest(data)
require.Contains(t, out.String(), "Select 10 in your PingID mobile app ...")
})
}

func TestHandleFormRedirect(t *testing.T) {
data, err := os.ReadFile("example/form-redirect.html")
require.Nil(t, err)
Expand Down

0 comments on commit afc2d52

Please sign in to comment.