Skip to content

Commit c218460

Browse files
committed
authhelper: skip MS login proof
Skip the MS login proof when possible. Signed-off-by: thc202 <thc202@gmail.com>
1 parent 8a7c26f commit c218460

File tree

2 files changed

+82
-3
lines changed

2 files changed

+82
-3
lines changed

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

Lines changed: 79 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,55 @@ 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+
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+
}
209258
}
210259
} while (!states.isEmpty());
211260

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

215264
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);
218270
}
219271

220272
private static boolean isMsLoginFlow(WebDriver wd) {
@@ -230,4 +282,28 @@ private static boolean isMsLoginFlow(WebDriver wd, Duration duration) {
230282
return false;
231283
}
232284
}
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+
}
233309
}

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.clickproofdone = [MS] Click Proof Done
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)