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 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);

View file

@ -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());
} }

View file

@ -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);
} }
}
} }

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.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() {

View file

@ -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) {

View file

@ -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;

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.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