Skip to content

Commit e9ac86c

Browse files
authored
add device picker for Ping
1 parent 148bb41 commit e9ac86c

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

pkg/provider/pingfed/pingfed.go

+76
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ func (ac *Client) follow(ctx context.Context, req *http.Request) (string, error)
9898
} else if docIsLogin(doc) {
9999
logger.WithField("type", "login").Debug("doc detect")
100100
handler = ac.handleLogin
101+
} else if docIsCheckWebAuthn(doc) {
102+
logger.WithField("type", "check-webauthn").Debug("doc detect")
103+
handler = ac.handleCheckWebAuthn
104+
} else if docIsFormSelectDevice(doc) {
105+
logger.WithField("type", "select-device").Debug("doc detect")
106+
handler = ac.handleFormSelectDevice
107+
} else if docIsAuthPostback(doc) {
108+
logger.WithField("type", "auth-postback").Debug("doc detect")
109+
handler = ac.handleFormRedirect
101110
} else if docIsOTP(doc) {
102111
logger.WithField("type", "otp").Debug("doc detect")
103112
handler = ac.handleOTP
@@ -148,6 +157,18 @@ func (ac *Client) handleLogin(ctx context.Context, doc *goquery.Document, _ *url
148157
return ctx, req, err
149158
}
150159

160+
func (ac *Client) handleCheckWebAuthn(ctx context.Context, doc *goquery.Document, requestURL *url.URL) (context.Context, *http.Request, error) {
161+
form, err := page.NewFormFromDocument(doc, "form")
162+
if err != nil {
163+
return ctx, nil, errors.Wrap(err, "error extracting login form")
164+
}
165+
166+
form.Values.Set("isWebAuthnSupportedByBrowser", "false")
167+
168+
req, err := form.BuildRequest()
169+
return ctx, req, err
170+
}
171+
151172
func (ac *Client) handleOTP(ctx context.Context, doc *goquery.Document, requestURL *url.URL) (context.Context, *http.Request, error) {
152173
form, err := page.NewFormFromDocument(doc, "#otp-form")
153174
if err != nil {
@@ -235,6 +256,29 @@ func (ac *Client) handleRefresh(ctx context.Context, doc *goquery.Document, _ *u
235256
return ctx, req, err
236257
}
237258

259+
func (ac *Client) handleFormSelectDevice(ctx context.Context, doc *goquery.Document, requestURL *url.URL) (context.Context, *http.Request, error) {
260+
var deviceMap = findDeviceMap(doc)
261+
deviceNameList := make([]string, len(deviceMap))
262+
i := 0
263+
for key := range deviceMap {
264+
deviceNameList[i] = key
265+
i++
266+
}
267+
var chooseDevice = prompter.Choose("Select which MFA Device to use", deviceNameList)
268+
269+
form, err := page.NewFormFromDocument(doc, "")
270+
if err != nil {
271+
return ctx, nil, errors.Wrap(err, "error extracting select device form")
272+
}
273+
274+
form.Values.Set("deviceId", deviceMap[deviceNameList[chooseDevice]])
275+
form.URL = makeAbsoluteURL(form.URL, makeBaseURL(requestURL))
276+
277+
logger.WithField("value", form.Values.Encode()).Debug("Select Device")
278+
req, err := form.BuildRequest()
279+
return ctx, req, err
280+
}
281+
238282
func (ac *Client) handleFormRedirect(ctx context.Context, doc *goquery.Document, _ *url.URL) (context.Context, *http.Request, error) {
239283
form, err := page.NewFormFromDocument(doc, "")
240284
if err != nil {
@@ -262,6 +306,14 @@ func docIsOTP(doc *goquery.Document) bool {
262306
return doc.Has("form#otp-form").Size() == 1
263307
}
264308

309+
func docIsCheckWebAuthn(doc *goquery.Document) bool {
310+
return doc.Has("input[name=\"isWebAuthnSupportedByBrowser\"]").Size() == 1
311+
}
312+
313+
func docIsAuthPostback(doc *goquery.Document) bool {
314+
return doc.Has("form#form1").Size() == 1 && doc.Has("form#reponseView").Size() == 0
315+
}
316+
265317
func docIsSwipe(doc *goquery.Document) bool {
266318
return doc.Has("form#form1").Size() == 1 && doc.Has("form#reponseView").Size() == 1
267319
}
@@ -294,6 +346,10 @@ func docIsFormRedirectToTarget(doc *goquery.Document, target string) bool {
294346
return doc.Find(urlForm).Size() == 1
295347
}
296348

349+
func docIsFormSelectDevice(doc *goquery.Document) bool {
350+
return doc.Has("form[name=\"device-form\"]").Size() == 1
351+
}
352+
297353
func docIsRefresh(doc *goquery.Document) bool {
298354
return doc.Has("meta[http-equiv=\"refresh\"]").Size() == 1
299355
}
@@ -309,3 +365,23 @@ func makeAbsoluteURL(v string, base string) string {
309365
}
310366
return v
311367
}
368+
369+
func makeBaseURL(url *url.URL) string {
370+
return url.Scheme + "://" + url.Hostname()
371+
}
372+
373+
func findDeviceMap(doc *goquery.Document) map[string]string {
374+
deviceList := make(map[string]string)
375+
376+
doc.Find("ul.device-list > li").Each(func(_ int, s *goquery.Selection) {
377+
deviceId, _ := s.Attr("data-id")
378+
deviceName, _ := s.Find("a > div.device-name").Html()
379+
if deviceName == "" {
380+
deviceName, _ = s.Find("button > div.device-name").Html()
381+
}
382+
383+
logger.WithField("device name", deviceName).WithField("device id", deviceId).Debug("Select Device")
384+
deviceList[deviceName] = deviceId
385+
})
386+
return deviceList
387+
}

0 commit comments

Comments
 (0)