Commit 96763ad6 authored by Maksim Ivanov's avatar Maksim Ivanov Committed by Commit Bot

Fix focus lost after wrong PIN in SAML smart card

Fix the a11y regression introduced in https://crrev.com/c/2030411, which
was that the focus was lost after the wrong PIN is entered.

The problem was caused by the fact that the whole PIN dialog, including
the input field, gets hidden while showing the "progress bar" animation
during PIN verification. The focus on the input field becomes lost when
it's hidden, and it's not restored automatically when it's re-shown
again.

The fix is to programmatically set the focus every time the PIN dialog
is updated, so that this happens after the PIN verification completes
too. Note that this is done unconditionally, so that entering a wrong
PIN is guaranteed to trigger the a11y event with the error message for
the user.

Bug: 1016839
Test: start smart card SAML login, enter wrong PIN, check that the focus stays on PIN input after the progress bar animation stops
Change-Id: I6a712c79eedc961f7da26dacfbb6f3df5db01396
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2087920Reviewed-by: default avatarDenis Kuznetsov [CET] <antrim@chromium.org>
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748573}
parent fc566e47
...@@ -181,6 +181,8 @@ Polymer({ ...@@ -181,6 +181,8 @@ Polymer({
this.processingCompletion_ = false; this.processingCompletion_ = false;
this.hasValue_ = false; this.hasValue_ = false;
this.userEdited_ = false; this.userEdited_ = false;
this.focus();
}, },
/** /**
......
...@@ -26,16 +26,30 @@ TEST_F('PolymerSecurityTokenPinTest', 'All', function() { ...@@ -26,16 +26,30 @@ TEST_F('PolymerSecurityTokenPinTest', 'All', function() {
}; };
let securityTokenPin; let securityTokenPin;
let pinKeyboardContainer;
let pinKeyboard;
let progressElement;
let pinInput;
let inputField; let inputField;
let submitElement;
setup(() => { setup(() => {
securityTokenPin = document.createElement('security-token-pin'); securityTokenPin = document.createElement('security-token-pin');
document.body.appendChild(securityTokenPin); document.body.appendChild(securityTokenPin);
securityTokenPin.parameters = DEFAULT_PARAMETERS; securityTokenPin.parameters = DEFAULT_PARAMETERS;
inputField = pinKeyboardContainer = securityTokenPin.$$('#pinKeyboardContainer');
securityTokenPin.$$('#pinKeyboard').$$('#pinInput').$$('input'); assert(pinKeyboardContainer);
pinKeyboard = securityTokenPin.$$('#pinKeyboard');
assert(pinKeyboard);
progressElement = securityTokenPin.$$('#progress');
assert(progressElement);
pinInput = pinKeyboard.$$('#pinInput');
assert(pinInput);
inputField = pinInput.$$('input');
assert(inputField); assert(inputField);
submitElement = securityTokenPin.$$('#submit');
assert(submitElement);
}); });
// Test that no scrolling is necessary in order to see all dots after entering // Test that no scrolling is necessary in order to see all dots after entering
...@@ -55,5 +69,66 @@ TEST_F('PolymerSecurityTokenPinTest', 'All', function() { ...@@ -55,5 +69,66 @@ TEST_F('PolymerSecurityTokenPinTest', 'All', function() {
'normal'); 'normal');
}); });
test('focus restores after progress animation', () => {
// The PIN keyboard is displayed initially.
expectFalse(pinKeyboardContainer.hidden);
expectTrue(progressElement.hidden);
// The PIN keyboard gets focused.
securityTokenPin.focus();
expectEquals(securityTokenPin.shadowRoot.activeElement, pinKeyboard);
expectEquals(inputField.getRootNode().activeElement, inputField);
// The user submits some value while keeping the focus on the input field.
pinInput.value = '123';
const enterEvent = new Event('keydown');
enterEvent.keyCode = 13;
pinInput.dispatchEvent(enterEvent);
// The PIN keyboard is replaced by the animation UI.
expectTrue(pinKeyboardContainer.hidden);
expectFalse(progressElement.hidden);
// The response arrives, requesting to prompt for the PIN again.
securityTokenPin.parameters = {
codeType: OobeTypes.SecurityTokenPinDialogType.PIN,
enableUserInput: true,
errorLabel: OobeTypes.SecurityTokenPinDialogErrorType.INVALID_PIN,
attemptsLeft: -1
};
// The PIN keyboard is shown again, replacing the animation UI.
expectFalse(pinKeyboardContainer.hidden);
expectTrue(progressElement.hidden);
// The focus is on the input field.
expectEquals(securityTokenPin.shadowRoot.activeElement, pinKeyboard);
expectEquals(inputField.getRootNode().activeElement, inputField);
});
test('focus set after progress animation', () => {
// The PIN keyboard is displayed initially.
expectFalse(pinKeyboardContainer.hidden);
expectTrue(progressElement.hidden);
// The user submits some value using the "Submit" UI button.
pinInput.value = '123';
submitElement.click();
// The PIN keyboard is replaced by the animation UI.
expectTrue(pinKeyboardContainer.hidden);
expectFalse(progressElement.hidden);
// The response arrives, requesting to prompt for the PIN again.
securityTokenPin.parameters = {
codeType: OobeTypes.SecurityTokenPinDialogType.PIN,
enableUserInput: true,
errorLabel: OobeTypes.SecurityTokenPinDialogErrorType.INVALID_PIN,
attemptsLeft: -1
};
// The PIN keyboard is shown again, replacing the animation UI.
expectFalse(pinKeyboardContainer.hidden);
expectTrue(progressElement.hidden);
// The focus is on the input field.
expectEquals(securityTokenPin.shadowRoot.activeElement, pinKeyboard);
expectEquals(inputField.getRootNode().activeElement, inputField);
});
mocha.run(); mocha.run();
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment