Skip to content

Commit 2dbce26

Browse files
authored
Merge pull request #6668 from thc202/authhelper/ms-proof-skip
authhelper: skip MS login proof
2 parents b99ea8f + bd7fa41 commit 2dbce26

File tree

2 files changed

+81
-3
lines changed

2 files changed

+81
-3
lines changed

addOns/authhelper/src/main/java/org/zaproxy/addon/authhelper/internal/auth/MsLoginAuthenticator.java

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.openqa.selenium.TimeoutException;
3030
import org.openqa.selenium.WebDriver;
3131
import org.openqa.selenium.WebElement;
32+
import org.openqa.selenium.support.ui.ExpectedCondition;
3233
import org.openqa.selenium.support.ui.ExpectedConditions;
3334
import org.openqa.selenium.support.ui.WebDriverWait;
3435
import org.parosproxy.paros.Constant;
@@ -51,6 +52,8 @@ public final class MsLoginAuthenticator implements Authenticator {
5152
private static final By PASSWORD_FIELD = By.id("i0118");
5253
private static final By SUBMIT_BUTTON = By.id("idSIButton9");
5354
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");
5457

5558
private enum State {
5659
START,
@@ -61,6 +64,9 @@ private enum State {
6164

6265
POST_PASSWORD,
6366
STAY_SIGNED_IN,
67+
68+
PROOF_REDIRECT,
69+
PROOF,
6470
}
6571

6672
@Override
@@ -177,7 +183,13 @@ private Result authenticateImpl(
177183
Constant.messages.getString(
178184
"authhelper.auth.method.diags.steps.ms.stepchoice"));
179185

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+
}
181193

182194
try {
183195
waitForElement(wd, KMSI_FIELD);
@@ -206,15 +218,54 @@ private Result authenticateImpl(
206218
states.add(State.SUBMIT);
207219
states.add(State.POST_PASSWORD);
208220
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+
}
209257
}
210258
} while (!states.isEmpty());
211259

212260
return new Result(true, successful, userField, pwdField);
213261
}
214262

215263
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);
218269
}
219270

220271
private static boolean isMsLoginFlow(WebDriver wd) {
@@ -230,4 +281,28 @@ private static boolean isMsLoginFlow(WebDriver wd, Duration duration) {
230281
return false;
231282
}
232283
}
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+
}
233308
}

addOns/authhelper/src/main/resources/org/zaproxy/addon/authhelper/resources/Messages.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ authhelper.auth.method.diags.steps.finish = Finished Steps
6666
authhelper.auth.method.diags.steps.loginlink = Login Link
6767
authhelper.auth.method.diags.steps.ms.clickbutton = [MS] Click Button
6868
authhelper.auth.method.diags.steps.ms.clickkmsi = [MS] Click KMSI
69+
authhelper.auth.method.diags.steps.ms.clickproofdone = [MS] Click Proof Done
70+
authhelper.auth.method.diags.steps.ms.clickproofredirect = [MS] Click Proof Redirect
6971
authhelper.auth.method.diags.steps.ms.missingbutton = [MS] Missing Button
7072
authhelper.auth.method.diags.steps.ms.missingpassword = [MS] Missing Password Field
7173
authhelper.auth.method.diags.steps.ms.missingusername = [MS] Missing Username Field
7274
authhelper.auth.method.diags.steps.ms.stepchoice = [MS] Step Choice
75+
authhelper.auth.method.diags.steps.ms.stepproofunknown = [MS] Step Proof Unknown
7376
authhelper.auth.method.diags.steps.ms.stepunknown = [MS] Step Unknown
7477
authhelper.auth.method.diags.steps.password = Auto Fill Password
7578
authhelper.auth.method.diags.steps.refresh = Auto Refresh

0 commit comments

Comments
 (0)