SEBSERV-45 password field implementation

This commit is contained in:
anhefti 2019-05-06 10:04:34 +02:00
parent 529e8c2f83
commit 0a648d8c84
7 changed files with 112 additions and 25 deletions

View file

@ -37,8 +37,16 @@ public interface InputFieldBuilder {
final Composite parent,
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 GridLayout gridLayout = new GridLayout();
final GridLayout gridLayout = new GridLayout(numColumns, true);
gridLayout.verticalSpacing = 0;
gridLayout.marginHeight = 1;
comp.setLayout(gridLayout);

View file

@ -160,7 +160,8 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
pageContext,
this.restService,
this.jsonMapper,
this.valueChangeRules));
this.valueChangeRules),
this.widgetFactory.getI18nSupport());
}

View file

@ -8,6 +8,11 @@
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.eclipse.swt.SWT;
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.Listener;
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.ConfigurationAttribute;
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.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
@Lazy
@Component
@GuiProfile
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
public boolean builderFor(
final ConfigurationAttribute attribute,
@ -50,7 +69,9 @@ public class PassworFieldBuilder implements InputFieldBuilder {
final Text passwordInput = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.PASSWORD);
passwordInput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
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(
attribute,
@ -69,18 +90,29 @@ public class PassworFieldBuilder implements InputFieldBuilder {
}
if (!pwd.equals(confirm)) {
passwordInputField.showError("TODO confirm password message");
passwordInputField.showError(viewContext
.getI18nSupport()
.getText(VAL_CONFIRM_PWD_TEXT_KEY));
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;
}
passwordInputField.clearError();
viewContext.getValueChangeListener().valueChanged(
viewContext,
attribute,
pwd,
passwordInputField.listIndex);
if (hashedPWD != null) {
passwordInputField.clearError();
viewContext.getValueChangeListener().valueChanged(
viewContext,
attribute,
hashedPWD,
passwordInputField.listIndex);
}
};
passwordInput.addListener(SWT.FocusOut, valueChangeEventListener);
@ -90,6 +122,14 @@ public class PassworFieldBuilder implements InputFieldBuilder {
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> {
private final Text confirm;
@ -108,8 +148,10 @@ public class PassworFieldBuilder implements InputFieldBuilder {
@Override
protected void setDefaultValue() {
// TODO clarify setting some "fake" input when a password is set (like in config tool)
this.control.setText(this.initValue);
this.confirm.setText(this.initValue);
if (this.initValue != null) {
this.control.setText(this.initValue);
this.confirm.setText(this.initValue);
}
}
}

View file

@ -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.gui.service.examconfig.InputField;
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
public final class ViewContext {
@ -28,6 +29,7 @@ public final class ViewContext {
public final AttributeMapping attributeMapping;
private final Map<Long, InputField> inputFieldMapping;
private final ValueChangeListener valueChangeListener;
private final I18nSupport i18nSupport;
ViewContext(
final Configuration configuration,
@ -35,7 +37,8 @@ public final class ViewContext {
final int columns,
final int rows,
final AttributeMapping attributeContext,
final ValueChangeListener valueChangeListener) {
final ValueChangeListener valueChangeListener,
final I18nSupport i18nSupport) {
Objects.requireNonNull(configuration);
Objects.requireNonNull(view);
@ -50,6 +53,11 @@ public final class ViewContext {
this.attributeMapping = attributeContext;
this.inputFieldMapping = new HashMap<>();
this.valueChangeListener = valueChangeListener;
this.i18nSupport = i18nSupport;
}
public I18nSupport getI18nSupport() {
return this.i18nSupport;
}
public Long getId() {

View file

@ -20,6 +20,7 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
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.Orientation;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
@ -92,10 +93,16 @@ public class ViewGridBuilder {
case RIGHT: {
this.grid[ypos][xpos] = fieldBuilderAdapter;
this.grid[ypos][xpos + 1] = labelBuilder(attribute, orientation);
if (attribute.type == AttributeType.PASSWORD_FIELD) {
this.grid[ypos + 1][xpos + 1] = passwordConfirmLabel(attribute, orientation);
}
break;
}
case LEFT: {
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;
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(
final ConfigurationAttribute attribute,
final Orientation orientation) {

View file

@ -21,7 +21,6 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.mybatis.dynamic.sql.SqlBuilder;
@ -368,16 +367,16 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
attrRec.getId(),
attrRec.getDefaultValue());
if (StringUtils.isNoneBlank(value)) {
this.configurationValueRecordMapper.insert(new ConfigurationValueRecord(
null,
configNode.institutionId,
config.getId(),
attrRec.getId(),
0,
bigValue ? null : value,
bigValue ? value : null));
}
//if (StringUtils.isNoneBlank(value)) {
this.configurationValueRecordMapper.insert(new ConfigurationValueRecord(
null,
configNode.institutionId,
config.getId(),
attrRec.getId(),
0,
bigValue ? null : value,
bigValue ? value : null));
//}
});
return configNode;

View file

@ -377,6 +377,7 @@ sebserver.examconfig.props.action.list.modify=Edit Properties
sebserver.examconfig.props.label.testNumber1=Test Number 1
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.INTEGER=Invalid number
sebserver.examconfig.props.validation.DECIMAL=Invalid decimal number