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,55 @@ 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
+ WebElement skipElement =
237
+ waitForElement (
238
+ wd ,
239
+ new ElementWithText (PROOF_DONE_FIELD , "Done" ));
240
+ skipElement .click ();
241
+ diags .recordStep (
242
+ wd ,
243
+ Constant .messages .getString (
244
+ "authhelper.auth.method.diags.steps.ms.clickproofdone" ),
245
+ skipElement );
246
+
247
+ states .add (State .POST_PASSWORD );
248
+ break ;
249
+ } catch (TimeoutException e ) {
250
+ diags .recordStep (
251
+ wd ,
252
+ Constant .messages .getString (
253
+ "authhelper.auth.method.diags.steps.ms.stepproofunknown" ));
254
+ LOGGER .debug (
255
+ "Still in proof but no done button found, assuming unsuccessful login." );
256
+ break ;
257
+ }
209
258
}
210
259
} while (!states .isEmpty ());
211
260
212
261
return new Result (true , successful , userField , pwdField );
213
262
}
214
263
215
264
private WebElement waitForElement (WebDriver wd , By by ) {
216
- return new WebDriverWait (wd , DEFAULT_WAIT_UNTIL )
217
- .until (ExpectedConditions .elementToBeClickable (by ));
265
+ return waitForElement (wd , ExpectedConditions .elementToBeClickable (by ));
266
+ }
267
+
268
+ private WebElement waitForElement (WebDriver wd , ExpectedCondition <WebElement > condition ) {
269
+ return new WebDriverWait (wd , DEFAULT_WAIT_UNTIL ).until (condition );
218
270
}
219
271
220
272
private static boolean isMsLoginFlow (WebDriver wd ) {
@@ -230,4 +282,28 @@ private static boolean isMsLoginFlow(WebDriver wd, Duration duration) {
230
282
return false ;
231
283
}
232
284
}
285
+
286
+ private static class ElementWithText implements ExpectedCondition <WebElement > {
287
+
288
+ private final By locator ;
289
+ private final String text ;
290
+
291
+ ElementWithText (By locator , String text ) {
292
+ this .locator = locator ;
293
+ this .text = text ;
294
+ }
295
+
296
+ @ Override
297
+ public WebElement apply (WebDriver driver ) {
298
+ return driver .findElements (locator ).stream ()
299
+ .filter (e -> text .equalsIgnoreCase (e .getText ()))
300
+ .findFirst ()
301
+ .orElse (null );
302
+ }
303
+
304
+ @ Override
305
+ public String toString () {
306
+ return String .format ("element '%s' with text '%s' is not present" , locator , text );
307
+ }
308
+ }
233
309
}
0 commit comments