Skip to content

Commit 3b86d13

Browse files
committed
authhelper: skip MS login proof
Skip the MS login proof when possible. Signed-off-by: thc202 <thc202@gmail.com>
1 parent 7bed6b9 commit 3b86d13

2 files changed

Lines changed: 81 additions & 3 deletions

File tree

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,7 @@ 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");
5456

5557
private enum State {
5658
START,
@@ -61,6 +63,9 @@ private enum State {
6163

6264
POST_PASSWORD,
6365
STAY_SIGNED_IN,
66+
67+
PROOF_REDIRECT,
68+
PROOF,
6469
}
6570

6671
@Override
@@ -177,7 +182,13 @@ private Result authenticateImpl(
177182
Constant.messages.getString(
178183
"authhelper.auth.method.diags.steps.ms.stepchoice"));
179184

180-
// XXX There might be a proof step too…
185+
try {
186+
waitForElement(wd, PROOF_REDIRECT_FIELD);
187+
states.add(State.PROOF_REDIRECT);
188+
break;
189+
} catch (TimeoutException e) {
190+
// Ignore, there's still the next step to check.
191+
}
181192

182193
try {
183194
waitForElement(wd, KMSI_FIELD);
@@ -206,15 +217,55 @@ private Result authenticateImpl(
206217
states.add(State.SUBMIT);
207218
states.add(State.POST_PASSWORD);
208219
break;
220+
221+
case PROOF_REDIRECT:
222+
WebElement proofElement = wd.findElement(PROOF_REDIRECT_FIELD);
223+
proofElement.click();
224+
diags.recordStep(
225+
wd,
226+
Constant.messages.getString(
227+
"authhelper.auth.method.diags.steps.ms.clickproofredirect"),
228+
proofElement);
229+
230+
states.add(State.PROOF);
231+
break;
232+
233+
case PROOF:
234+
try {
235+
WebElement skipElement =
236+
waitForElement(
237+
wd,
238+
new ElementWithText(By.tagName("button"), "Skip setup"));
239+
skipElement.click();
240+
diags.recordStep(
241+
wd,
242+
Constant.messages.getString(
243+
"authhelper.auth.method.diags.steps.ms.clickproofskip"),
244+
skipElement);
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 setup 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.clickproofredirect = [MS] Click Proof Redirect
70+
authhelper.auth.method.diags.steps.ms.clickproofskip = [MS] Click Proof Skip
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)