Skip to content

authhelper: skip MS login proof #6668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.parosproxy.paros.Constant;
Expand All @@ -51,6 +52,8 @@ public final class MsLoginAuthenticator implements Authenticator {
private static final By PASSWORD_FIELD = By.id("i0118");
private static final By SUBMIT_BUTTON = By.id("idSIButton9");
private static final By KMSI_FIELD = By.id("KmsiCheckboxField");
private static final By PROOF_REDIRECT_FIELD = By.id("idSubmit_ProofUp_Redirect");
private static final By PROOF_DONE_FIELD = By.id("id__5");

private enum State {
START,
Expand All @@ -61,6 +64,9 @@ private enum State {

POST_PASSWORD,
STAY_SIGNED_IN,

PROOF_REDIRECT,
PROOF,
}

@Override
Expand Down Expand Up @@ -177,7 +183,13 @@ private Result authenticateImpl(
Constant.messages.getString(
"authhelper.auth.method.diags.steps.ms.stepchoice"));

// XXX There might be a proof step too…
try {
waitForElement(wd, PROOF_REDIRECT_FIELD);
states.add(State.PROOF_REDIRECT);
break;
} catch (TimeoutException e) {
// Ignore, there's still the next step to check.
}

try {
waitForElement(wd, KMSI_FIELD);
Expand Down Expand Up @@ -206,15 +218,54 @@ private Result authenticateImpl(
states.add(State.SUBMIT);
states.add(State.POST_PASSWORD);
break;

case PROOF_REDIRECT:
WebElement proofElement = wd.findElement(PROOF_REDIRECT_FIELD);
proofElement.click();
diags.recordStep(
wd,
Constant.messages.getString(
"authhelper.auth.method.diags.steps.ms.clickproofredirect"),
proofElement);

states.add(State.PROOF);
break;

case PROOF:
try {
waitForElement(wd, new ElementWithText(By.tagName("button"), "Skip setup"));
WebElement doneElement =
waitForElement(wd, new ElementWithText(PROOF_DONE_FIELD, "Done"));
doneElement.click();
diags.recordStep(
wd,
Constant.messages.getString(
"authhelper.auth.method.diags.steps.ms.clickproofdone"),
doneElement);

states.add(State.POST_PASSWORD);
break;
} catch (TimeoutException e) {
diags.recordStep(
wd,
Constant.messages.getString(
"authhelper.auth.method.diags.steps.ms.stepproofunknown"));
LOGGER.debug(
"Still in proof but no skip/done button found, assuming unsuccessful login.");
break;
}
}
} while (!states.isEmpty());

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

private WebElement waitForElement(WebDriver wd, By by) {
return new WebDriverWait(wd, DEFAULT_WAIT_UNTIL)
.until(ExpectedConditions.elementToBeClickable(by));
return waitForElement(wd, ExpectedConditions.elementToBeClickable(by));
}

private WebElement waitForElement(WebDriver wd, ExpectedCondition<WebElement> condition) {
return new WebDriverWait(wd, DEFAULT_WAIT_UNTIL).until(condition);
}

private static boolean isMsLoginFlow(WebDriver wd) {
Expand All @@ -230,4 +281,28 @@ private static boolean isMsLoginFlow(WebDriver wd, Duration duration) {
return false;
}
}

private static class ElementWithText implements ExpectedCondition<WebElement> {

private final By locator;
private final String text;

ElementWithText(By locator, String text) {
this.locator = locator;
this.text = text;
}

@Override
public WebElement apply(WebDriver driver) {
return driver.findElements(locator).stream()
.filter(e -> text.equalsIgnoreCase(e.getText()))
.findFirst()
.orElse(null);
}

@Override
public String toString() {
return String.format("element '%s' with text '%s' is not present", locator, text);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,13 @@ authhelper.auth.method.diags.steps.finish = Finished Steps
authhelper.auth.method.diags.steps.loginlink = Login Link
authhelper.auth.method.diags.steps.ms.clickbutton = [MS] Click Button
authhelper.auth.method.diags.steps.ms.clickkmsi = [MS] Click KMSI
authhelper.auth.method.diags.steps.ms.clickproofdone = [MS] Click Proof Done
authhelper.auth.method.diags.steps.ms.clickproofredirect = [MS] Click Proof Redirect
authhelper.auth.method.diags.steps.ms.missingbutton = [MS] Missing Button
authhelper.auth.method.diags.steps.ms.missingpassword = [MS] Missing Password Field
authhelper.auth.method.diags.steps.ms.missingusername = [MS] Missing Username Field
authhelper.auth.method.diags.steps.ms.stepchoice = [MS] Step Choice
authhelper.auth.method.diags.steps.ms.stepproofunknown = [MS] Step Proof Unknown
authhelper.auth.method.diags.steps.ms.stepunknown = [MS] Step Unknown
authhelper.auth.method.diags.steps.password = Auto Fill Password
authhelper.auth.method.diags.steps.refresh = Auto Refresh
Expand Down