29
29
import org .openqa .selenium .TimeoutException ;
30
30
import org .openqa .selenium .WebDriver ;
31
31
import org .openqa .selenium .WebElement ;
32
+ import org .openqa .selenium .support .ui .ExpectedCondition ;
32
33
import org .openqa .selenium .support .ui .ExpectedConditions ;
33
34
import org .openqa .selenium .support .ui .WebDriverWait ;
34
35
import org .parosproxy .paros .Constant ;
@@ -51,6 +52,8 @@ public final class MsLoginAuthenticator implements Authenticator {
51
52
private static final By PASSWORD_FIELD = By .id ("i0118" );
52
53
private static final By SUBMIT_BUTTON = By .id ("idSIButton9" );
53
54
private static final By KMSI_FIELD = By .id ("KmsiCheckboxField" );
55
+ private static final By PROOF_REDIRECT_FIELD = By .id ("idSubmit_ProofUp_Redirect" );
56
+ private static final By PROOF_DONE_FIELD = By .id ("id__5" );
54
57
55
58
private enum State {
56
59
START ,
@@ -61,6 +64,9 @@ private enum State {
61
64
62
65
POST_PASSWORD ,
63
66
STAY_SIGNED_IN ,
67
+
68
+ PROOF_REDIRECT ,
69
+ PROOF ,
64
70
}
65
71
66
72
@ Override
@@ -177,7 +183,13 @@ private Result authenticateImpl(
177
183
Constant .messages .getString (
178
184
"authhelper.auth.method.diags.steps.ms.stepchoice" ));
179
185
180
- // XXX There might be a proof step too…
186
+ try {
187
+ waitForElement (wd , PROOF_REDIRECT_FIELD );
188
+ states .add (State .PROOF_REDIRECT );
189
+ break ;
190
+ } catch (TimeoutException e ) {
191
+ // Ignore, there's still the next step to check.
192
+ }
181
193
182
194
try {
183
195
waitForElement (wd , KMSI_FIELD );
@@ -206,15 +218,54 @@ private Result authenticateImpl(
206
218
states .add (State .SUBMIT );
207
219
states .add (State .POST_PASSWORD );
208
220
break ;
221
+
222
+ case PROOF_REDIRECT :
223
+ WebElement proofElement = wd .findElement (PROOF_REDIRECT_FIELD );
224
+ proofElement .click ();
225
+ diags .recordStep (
226
+ wd ,
227
+ Constant .messages .getString (
228
+ "authhelper.auth.method.diags.steps.ms.clickproofredirect" ),
229
+ proofElement );
230
+
231
+ states .add (State .PROOF );
232
+ break ;
233
+
234
+ case PROOF :
235
+ try {
236
+ waitForElement (wd , new ElementWithText (By .tagName ("button" ), "Skip setup" ));
237
+ WebElement doneElement =
238
+ waitForElement (wd , new ElementWithText (PROOF_DONE_FIELD , "Done" ));
239
+ doneElement .click ();
240
+ diags .recordStep (
241
+ wd ,
242
+ Constant .messages .getString (
243
+ "authhelper.auth.method.diags.steps.ms.clickproofdone" ),
244
+ doneElement );
245
+
246
+ states .add (State .POST_PASSWORD );
247
+ break ;
248
+ } catch (TimeoutException e ) {
249
+ diags .recordStep (
250
+ wd ,
251
+ Constant .messages .getString (
252
+ "authhelper.auth.method.diags.steps.ms.stepproofunknown" ));
253
+ LOGGER .debug (
254
+ "Still in proof but no skip/done button found, assuming unsuccessful login." );
255
+ break ;
256
+ }
209
257
}
210
258
} while (!states .isEmpty ());
211
259
212
260
return new Result (true , successful , userField , pwdField );
213
261
}
214
262
215
263
private WebElement waitForElement (WebDriver wd , By by ) {
216
- return new WebDriverWait (wd , DEFAULT_WAIT_UNTIL )
217
- .until (ExpectedConditions .elementToBeClickable (by ));
264
+ return waitForElement (wd , ExpectedConditions .elementToBeClickable (by ));
265
+ }
266
+
267
+ private WebElement waitForElement (WebDriver wd , ExpectedCondition <WebElement > condition ) {
268
+ return new WebDriverWait (wd , DEFAULT_WAIT_UNTIL ).until (condition );
218
269
}
219
270
220
271
private static boolean isMsLoginFlow (WebDriver wd ) {
@@ -230,4 +281,28 @@ private static boolean isMsLoginFlow(WebDriver wd, Duration duration) {
230
281
return false ;
231
282
}
232
283
}
284
+
285
+ private static class ElementWithText implements ExpectedCondition <WebElement > {
286
+
287
+ private final By locator ;
288
+ private final String text ;
289
+
290
+ ElementWithText (By locator , String text ) {
291
+ this .locator = locator ;
292
+ this .text = text ;
293
+ }
294
+
295
+ @ Override
296
+ public WebElement apply (WebDriver driver ) {
297
+ return driver .findElements (locator ).stream ()
298
+ .filter (e -> text .equalsIgnoreCase (e .getText ()))
299
+ .findFirst ()
300
+ .orElse (null );
301
+ }
302
+
303
+ @ Override
304
+ public String toString () {
305
+ return String .format ("element '%s' with text '%s' is not present" , locator , text );
306
+ }
307
+ }
233
308
}
0 commit comments