SEBSERV-45 password field implementation
This commit is contained in:
parent
529e8c2f83
commit
0a648d8c84
7 changed files with 112 additions and 25 deletions
|
@ -37,8 +37,16 @@ public interface InputFieldBuilder {
|
||||||
final Composite parent,
|
final Composite parent,
|
||||||
final Orientation orientation) {
|
final Orientation orientation) {
|
||||||
|
|
||||||
|
return createInnerGrid(parent, orientation, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Composite createInnerGrid(
|
||||||
|
final Composite parent,
|
||||||
|
final Orientation orientation,
|
||||||
|
final int numColumns) {
|
||||||
|
|
||||||
final Composite comp = new Composite(parent, SWT.NONE);
|
final Composite comp = new Composite(parent, SWT.NONE);
|
||||||
final GridLayout gridLayout = new GridLayout();
|
final GridLayout gridLayout = new GridLayout(numColumns, true);
|
||||||
gridLayout.verticalSpacing = 0;
|
gridLayout.verticalSpacing = 0;
|
||||||
gridLayout.marginHeight = 1;
|
gridLayout.marginHeight = 1;
|
||||||
comp.setLayout(gridLayout);
|
comp.setLayout(gridLayout);
|
||||||
|
|
|
@ -160,7 +160,8 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
||||||
pageContext,
|
pageContext,
|
||||||
this.restService,
|
this.restService,
|
||||||
this.jsonMapper,
|
this.jsonMapper,
|
||||||
this.valueChangeRules));
|
this.valueChangeRules),
|
||||||
|
this.widgetFactory.getI18nSupport());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Hex;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
@ -15,15 +20,29 @@ import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.swt.widgets.Listener;
|
import org.eclipse.swt.widgets.Listener;
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
public class PassworFieldBuilder implements InputFieldBuilder {
|
public class PassworFieldBuilder implements InputFieldBuilder {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(PassworFieldBuilder.class);
|
||||||
|
|
||||||
|
private static final LocTextKey VAL_CONFIRM_PWD_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.examconfig.props.validation.password.confirm");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean builderFor(
|
public boolean builderFor(
|
||||||
final ConfigurationAttribute attribute,
|
final ConfigurationAttribute attribute,
|
||||||
|
@ -50,7 +69,9 @@ public class PassworFieldBuilder implements InputFieldBuilder {
|
||||||
final Text passwordInput = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.PASSWORD);
|
final Text passwordInput = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.PASSWORD);
|
||||||
passwordInput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
passwordInput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||||
final Text confirmInput = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.PASSWORD);
|
final Text confirmInput = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.PASSWORD);
|
||||||
confirmInput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
|
||||||
|
gridData.verticalIndent = 5;
|
||||||
|
confirmInput.setLayoutData(gridData);
|
||||||
|
|
||||||
final PasswordInputField passwordInputField = new PasswordInputField(
|
final PasswordInputField passwordInputField = new PasswordInputField(
|
||||||
attribute,
|
attribute,
|
||||||
|
@ -69,18 +90,29 @@ public class PassworFieldBuilder implements InputFieldBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pwd.equals(confirm)) {
|
if (!pwd.equals(confirm)) {
|
||||||
passwordInputField.showError("TODO confirm password message");
|
passwordInputField.showError(viewContext
|
||||||
|
.getI18nSupport()
|
||||||
|
.getText(VAL_CONFIRM_PWD_TEXT_KEY));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO hash password
|
String hashedPWD;
|
||||||
|
try {
|
||||||
|
hashedPWD = hashPassword(pwd);
|
||||||
|
} catch (final NoSuchAlgorithmException e) {
|
||||||
|
log.error("Failed to hash password: ", e);
|
||||||
|
passwordInputField.showError("Failed to hash password");
|
||||||
|
hashedPWD = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hashedPWD != null) {
|
||||||
passwordInputField.clearError();
|
passwordInputField.clearError();
|
||||||
viewContext.getValueChangeListener().valueChanged(
|
viewContext.getValueChangeListener().valueChanged(
|
||||||
viewContext,
|
viewContext,
|
||||||
attribute,
|
attribute,
|
||||||
pwd,
|
hashedPWD,
|
||||||
passwordInputField.listIndex);
|
passwordInputField.listIndex);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
passwordInput.addListener(SWT.FocusOut, valueChangeEventListener);
|
passwordInput.addListener(SWT.FocusOut, valueChangeEventListener);
|
||||||
|
@ -90,6 +122,14 @@ public class PassworFieldBuilder implements InputFieldBuilder {
|
||||||
return passwordInputField;
|
return passwordInputField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String hashPassword(final String pwd) throws NoSuchAlgorithmException {
|
||||||
|
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||||
|
final byte[] encodedhash = digest.digest(
|
||||||
|
pwd.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
return Hex.encodeHexString(encodedhash);
|
||||||
|
}
|
||||||
|
|
||||||
static final class PasswordInputField extends AbstractInputField<Text> {
|
static final class PasswordInputField extends AbstractInputField<Text> {
|
||||||
|
|
||||||
private final Text confirm;
|
private final Text confirm;
|
||||||
|
@ -108,9 +148,11 @@ public class PassworFieldBuilder implements InputFieldBuilder {
|
||||||
@Override
|
@Override
|
||||||
protected void setDefaultValue() {
|
protected void setDefaultValue() {
|
||||||
// TODO clarify setting some "fake" input when a password is set (like in config tool)
|
// TODO clarify setting some "fake" input when a password is set (like in config tool)
|
||||||
|
if (this.initValue != null) {
|
||||||
this.control.setText(this.initValue);
|
this.control.setText(this.initValue);
|
||||||
this.confirm.setText(this.initValue);
|
this.confirm.setText(this.initValue);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
|
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||||
|
|
||||||
public final class ViewContext {
|
public final class ViewContext {
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ public final class ViewContext {
|
||||||
public final AttributeMapping attributeMapping;
|
public final AttributeMapping attributeMapping;
|
||||||
private final Map<Long, InputField> inputFieldMapping;
|
private final Map<Long, InputField> inputFieldMapping;
|
||||||
private final ValueChangeListener valueChangeListener;
|
private final ValueChangeListener valueChangeListener;
|
||||||
|
private final I18nSupport i18nSupport;
|
||||||
|
|
||||||
ViewContext(
|
ViewContext(
|
||||||
final Configuration configuration,
|
final Configuration configuration,
|
||||||
|
@ -35,7 +37,8 @@ public final class ViewContext {
|
||||||
final int columns,
|
final int columns,
|
||||||
final int rows,
|
final int rows,
|
||||||
final AttributeMapping attributeContext,
|
final AttributeMapping attributeContext,
|
||||||
final ValueChangeListener valueChangeListener) {
|
final ValueChangeListener valueChangeListener,
|
||||||
|
final I18nSupport i18nSupport) {
|
||||||
|
|
||||||
Objects.requireNonNull(configuration);
|
Objects.requireNonNull(configuration);
|
||||||
Objects.requireNonNull(view);
|
Objects.requireNonNull(view);
|
||||||
|
@ -50,6 +53,11 @@ public final class ViewContext {
|
||||||
this.attributeMapping = attributeContext;
|
this.attributeMapping = attributeContext;
|
||||||
this.inputFieldMapping = new HashMap<>();
|
this.inputFieldMapping = new HashMap<>();
|
||||||
this.valueChangeListener = valueChangeListener;
|
this.valueChangeListener = valueChangeListener;
|
||||||
|
this.i18nSupport = i18nSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public I18nSupport getI18nSupport() {
|
||||||
|
return this.i18nSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Group;
|
import org.eclipse.swt.widgets.Group;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||||
|
@ -92,10 +93,16 @@ public class ViewGridBuilder {
|
||||||
case RIGHT: {
|
case RIGHT: {
|
||||||
this.grid[ypos][xpos] = fieldBuilderAdapter;
|
this.grid[ypos][xpos] = fieldBuilderAdapter;
|
||||||
this.grid[ypos][xpos + 1] = labelBuilder(attribute, orientation);
|
this.grid[ypos][xpos + 1] = labelBuilder(attribute, orientation);
|
||||||
|
if (attribute.type == AttributeType.PASSWORD_FIELD) {
|
||||||
|
this.grid[ypos + 1][xpos + 1] = passwordConfirmLabel(attribute, orientation);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LEFT: {
|
case LEFT: {
|
||||||
this.grid[ypos][xpos] = labelBuilder(attribute, orientation);
|
this.grid[ypos][xpos] = labelBuilder(attribute, orientation);
|
||||||
|
if (attribute.type == AttributeType.PASSWORD_FIELD) {
|
||||||
|
this.grid[ypos + 1][xpos] = passwordConfirmLabel(attribute, orientation);
|
||||||
|
}
|
||||||
this.grid[ypos][xpos + 1] = fieldBuilderAdapter;
|
this.grid[ypos][xpos + 1] = fieldBuilderAdapter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -157,6 +164,27 @@ public class ViewGridBuilder {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CellFieldBuilderAdapter passwordConfirmLabel(
|
||||||
|
final ConfigurationAttribute attribute,
|
||||||
|
final Orientation orientation) {
|
||||||
|
|
||||||
|
return new CellFieldBuilderAdapter() {
|
||||||
|
@Override
|
||||||
|
public void createCell(final ViewGridBuilder builder) {
|
||||||
|
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
|
||||||
|
final Label label = widgetFactory.labelLocalized(
|
||||||
|
ViewGridBuilder.this.parent,
|
||||||
|
new LocTextKey(
|
||||||
|
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".confirm"),
|
||||||
|
"Confirm Password");
|
||||||
|
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||||
|
label.setAlignment(SWT.LEFT);
|
||||||
|
gridData.verticalIndent = 10;
|
||||||
|
label.setLayoutData(gridData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private CellFieldBuilderAdapter labelBuilder(
|
private CellFieldBuilderAdapter labelBuilder(
|
||||||
final ConfigurationAttribute attribute,
|
final ConfigurationAttribute attribute,
|
||||||
final Orientation orientation) {
|
final Orientation orientation) {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
import org.mybatis.dynamic.sql.SqlBuilder;
|
import org.mybatis.dynamic.sql.SqlBuilder;
|
||||||
|
@ -368,7 +367,7 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
||||||
attrRec.getId(),
|
attrRec.getId(),
|
||||||
attrRec.getDefaultValue());
|
attrRec.getDefaultValue());
|
||||||
|
|
||||||
if (StringUtils.isNoneBlank(value)) {
|
//if (StringUtils.isNoneBlank(value)) {
|
||||||
this.configurationValueRecordMapper.insert(new ConfigurationValueRecord(
|
this.configurationValueRecordMapper.insert(new ConfigurationValueRecord(
|
||||||
null,
|
null,
|
||||||
configNode.institutionId,
|
configNode.institutionId,
|
||||||
|
@ -377,7 +376,7 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
||||||
0,
|
0,
|
||||||
bigValue ? null : value,
|
bigValue ? null : value,
|
||||||
bigValue ? value : null));
|
bigValue ? value : null));
|
||||||
}
|
//}
|
||||||
});
|
});
|
||||||
|
|
||||||
return configNode;
|
return configNode;
|
||||||
|
|
|
@ -377,6 +377,7 @@ sebserver.examconfig.props.action.list.modify=Edit Properties
|
||||||
sebserver.examconfig.props.label.testNumber1=Test Number 1
|
sebserver.examconfig.props.label.testNumber1=Test Number 1
|
||||||
sebserver.examconfig.props.label.testNumber2=Test Number 2
|
sebserver.examconfig.props.label.testNumber2=Test Number 2
|
||||||
|
|
||||||
|
sebserver.examconfig.props.validation.password.confirm=Please enter correct confirm password
|
||||||
sebserver.examconfig.props.validation.unexpected=Unexpected error happened. Value was not set correctly
|
sebserver.examconfig.props.validation.unexpected=Unexpected error happened. Value was not set correctly
|
||||||
sebserver.examconfig.props.validation.INTEGER=Invalid number
|
sebserver.examconfig.props.validation.INTEGER=Invalid number
|
||||||
sebserver.examconfig.props.validation.DECIMAL=Invalid decimal number
|
sebserver.examconfig.props.validation.DECIMAL=Invalid decimal number
|
||||||
|
|
Loading…
Reference in a new issue