SEBSERV-145 additional attributes in connection config

This commit is contained in:
anhefti 2021-01-27 16:57:10 +01:00
parent d4668eeeee
commit 199ba53688
11 changed files with 350 additions and 67 deletions

View file

@ -31,6 +31,12 @@ import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
public final class SEBClientConfig implements GrantEntity, Activatable {
public static final String ATTR_CONFIG_PURPOSE = "sebConfigPurpose";
public static final String ATTR_PING_INTERVAL = "sebServerPingTime";
public static final String ATTR_VDI_TYPE = "vdiSetup";
public static final String ATTR_VDI_EXECUTABLE = "vdiExecutable";
public static final String ATTR_VDI_PATH = "vdiPath";
public static final String ATTR_VDI_ARGUMENTS = "vdiArguments";
public static final String ATTR_FALLBACK = "sebServerFallback ";
public static final String ATTR_FALLBACK_START_URL = "startURL";
public static final String ATTR_FALLBACK_TIMEOUT = "sebServerFallbackTimeout";
@ -49,6 +55,40 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
CONFIGURE_CLIENT
}
public enum VDIType {
NO,
VM_WARE(
"VMware View",
"vmware-view.exe",
"VMware\\VMware Horizon View Client",
"--LoginAsCurrentUser true\n--serverurl view.example.com\n--desktopLayout fullscreen\n--desktopProtocol PCOIP\n--desktopName \"let-vdi-1-exam");
public final String title;
public final String defaultExecutable;
public final String defaultPath;
public final String defaultArguments;
private VDIType() {
this.title = "NONE";
this.defaultExecutable = null;
this.defaultPath = null;
this.defaultArguments = null;
}
private VDIType(
final String title,
final String defaultExecutable,
final String defaultPath,
final String defaultArguments) {
this.title = title;
this.defaultExecutable = defaultExecutable;
this.defaultPath = defaultPath;
this.defaultArguments = defaultArguments;
}
}
@JsonProperty(SEB_CLIENT_CONFIGURATION.ATTR_ID)
public final Long id;
@ -65,6 +105,21 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
@JsonProperty(ATTR_CONFIG_PURPOSE)
public final ConfigPurpose configPurpose;
@JsonProperty(ATTR_PING_INTERVAL)
public final Long sebServerPingTime;
@JsonProperty(ATTR_VDI_TYPE)
public final VDIType vdiType;
@JsonProperty(ATTR_VDI_EXECUTABLE)
public final String vdiExecutable;
@JsonProperty(ATTR_VDI_PATH)
public final String vdiPath;
@JsonProperty(ATTR_VDI_ARGUMENTS)
public final String vdiArguments;
@JsonProperty(ATTR_FALLBACK)
public final Boolean fallback;
@ -111,6 +166,13 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
@JsonProperty(SEB_CLIENT_CONFIGURATION.ATTR_INSTITUTION_ID) final Long institutionId,
@JsonProperty(SEB_CLIENT_CONFIGURATION.ATTR_NAME) final String name,
@JsonProperty(ATTR_CONFIG_PURPOSE) final ConfigPurpose configPurpose,
@JsonProperty(ATTR_PING_INTERVAL) final Long sebServerPingTime,
@JsonProperty(ATTR_VDI_TYPE) final VDIType vdiType,
@JsonProperty(ATTR_VDI_EXECUTABLE) final String vdiExecutable,
@JsonProperty(ATTR_VDI_PATH) final String vdiPath,
@JsonProperty(ATTR_VDI_ARGUMENTS) final String vdiArguments,
@JsonProperty(ATTR_FALLBACK) final Boolean fallback,
@JsonProperty(ATTR_FALLBACK_START_URL) final String fallbackStartURL,
@JsonProperty(ATTR_FALLBACK_TIMEOUT) final Long fallbackTimeout,
@ -129,6 +191,13 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
this.institutionId = institutionId;
this.name = name;
this.configPurpose = configPurpose;
this.sebServerPingTime = sebServerPingTime;
this.vdiType = vdiType;
this.vdiExecutable = vdiExecutable != null ? vdiExecutable : vdiType.defaultExecutable;
this.vdiPath = vdiPath != null ? vdiPath : vdiType.defaultPath;
this.vdiArguments = vdiArguments != null ? vdiArguments : vdiType.defaultArguments;
this.fallback = fallback;
this.fallbackStartURL = fallbackStartURL;
this.fallbackTimeout = fallbackTimeout;
@ -149,6 +218,23 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
this.institutionId = institutionId;
this.name = postParams.getString(Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME);
this.configPurpose = postParams.getEnum(ATTR_CONFIG_PURPOSE, ConfigPurpose.class);
this.sebServerPingTime = postParams.getLong(ATTR_PING_INTERVAL) != null
? postParams.getLong(ATTR_PING_INTERVAL)
: 1000;
this.vdiType = postParams.getEnum(ATTR_VDI_TYPE, VDIType.class) != null
? postParams.getEnum(ATTR_VDI_TYPE, VDIType.class)
: VDIType.NO;
this.vdiExecutable = postParams.getString(ATTR_VDI_EXECUTABLE) != null
? postParams.getString(ATTR_VDI_EXECUTABLE)
: this.vdiType.defaultExecutable;
this.vdiPath = postParams.getString(ATTR_VDI_PATH) != null
? postParams.getString(ATTR_VDI_PATH)
: this.vdiType.defaultPath;
this.vdiArguments = postParams.getString(ATTR_VDI_ARGUMENTS) != null
? postParams.getString(ATTR_VDI_ARGUMENTS)
: this.vdiType.defaultArguments;
this.fallback = postParams.getBoolean(ATTR_FALLBACK);
this.fallbackStartURL = postParams.getString(ATTR_FALLBACK_START_URL);
this.fallbackTimeout = postParams.getLong(ATTR_FALLBACK_TIMEOUT);
@ -269,26 +355,77 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
return this.active;
}
// @Override
// public String toString() {
// final StringBuilder sb = new StringBuilder("SEBClientConfig{");
// sb.append("id=").append(this.id);
// sb.append(", institutionId=").append(this.institutionId);
// sb.append(", name='").append(this.name).append('\'');
// sb.append(", configPurpose=").append(this.configPurpose);
// sb.append(", fallback=").append(this.fallback);
// sb.append(", fallbackStartURL='").append(this.fallbackStartURL).append('\'');
// sb.append(", fallbackTimeout=").append(this.fallbackTimeout);
// sb.append(", fallbackAttempts=").append(this.fallbackAttempts);
// sb.append(", fallbackAttemptInterval=").append(this.fallbackAttemptInterval);
// sb.append(", fallbackPassword=").append(this.fallbackPassword);
// sb.append(", fallbackPasswordConfirm=").append(this.fallbackPasswordConfirm);
// sb.append(", date=").append(this.date);
// sb.append(", encryptSecret=").append(this.encryptSecret);
// sb.append(", encryptSecretConfirm=").append(this.encryptSecretConfirm);
// sb.append(", active=").append(this.active);
// sb.append('}');
// return sb.toString();
// }
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("SEBClientConfig{");
sb.append("id=").append(this.id);
sb.append(", institutionId=").append(this.institutionId);
sb.append(", name='").append(this.name).append('\'');
sb.append(", configPurpose=").append(this.configPurpose);
sb.append(", fallback=").append(this.fallback);
sb.append(", fallbackStartURL='").append(this.fallbackStartURL).append('\'');
sb.append(", fallbackTimeout=").append(this.fallbackTimeout);
sb.append(", fallbackAttempts=").append(this.fallbackAttempts);
sb.append(", fallbackAttemptInterval=").append(this.fallbackAttemptInterval);
sb.append(", fallbackPassword=").append(this.fallbackPassword);
sb.append(", fallbackPasswordConfirm=").append(this.fallbackPasswordConfirm);
sb.append(", date=").append(this.date);
sb.append(", encryptSecret=").append(this.encryptSecret);
sb.append(", encryptSecretConfirm=").append(this.encryptSecretConfirm);
sb.append(", active=").append(this.active);
sb.append('}');
return sb.toString();
final StringBuilder builder = new StringBuilder();
builder.append("SEBClientConfig [id=");
builder.append(this.id);
builder.append(", institutionId=");
builder.append(this.institutionId);
builder.append(", name=");
builder.append(this.name);
builder.append(", configPurpose=");
builder.append(this.configPurpose);
builder.append(", sebServerPingTime=");
builder.append(this.sebServerPingTime);
builder.append(", vdiType=");
builder.append(this.vdiType);
builder.append(", vdiExecutable=");
builder.append(this.vdiExecutable);
builder.append(", vdiPath=");
builder.append(this.vdiPath);
builder.append(", vdiArguments=");
builder.append(this.vdiArguments);
builder.append(", fallback=");
builder.append(this.fallback);
builder.append(", fallbackStartURL=");
builder.append(this.fallbackStartURL);
builder.append(", fallbackTimeout=");
builder.append(this.fallbackTimeout);
builder.append(", fallbackAttempts=");
builder.append(this.fallbackAttempts);
builder.append(", fallbackAttemptInterval=");
builder.append(this.fallbackAttemptInterval);
builder.append(", fallbackPassword=");
builder.append(this.fallbackPassword);
builder.append(", fallbackPasswordConfirm=");
builder.append(this.fallbackPasswordConfirm);
builder.append(", quitPassword=");
builder.append(this.quitPassword);
builder.append(", quitPasswordConfirm=");
builder.append(this.quitPasswordConfirm);
builder.append(", date=");
builder.append(this.date);
builder.append(", encryptSecret=");
builder.append(this.encryptSecret);
builder.append(", encryptSecretConfirm=");
builder.append(this.encryptSecretConfirm);
builder.append(", active=");
builder.append(this.active);
builder.append("]");
return builder.toString();
}
@Override
@ -298,6 +435,11 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
this.institutionId,
this.name,
this.configPurpose,
this.sebServerPingTime,
this.vdiType,
this.vdiExecutable,
this.vdiPath,
this.vdiArguments,
this.fallback,
this.fallbackStartURL,
this.fallbackTimeout,
@ -319,6 +461,11 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
institutionId,
null,
ConfigPurpose.CONFIGURE_CLIENT,
1000L,
VDIType.NO,
null,
null,
null,
false,
null,
null,

View file

@ -29,6 +29,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
@ -50,6 +51,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.SaveClientConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.Selection;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@ -66,9 +68,20 @@ public class SEBClientConfigForm implements TemplateComposer {
private static final LocTextKey FORM_DATE_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.date");
private static final LocTextKey CLIENT_PURPOSE_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.sebConfigPurpose");
private static final LocTextKey PING_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.pinginterval");
private static final LocTextKey VDI_TYPE_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.vditype");
private static final LocTextKey VDI_EXEC_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.vdi.executable");
private static final LocTextKey VDI_PATH_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.vdi.path");
private static final LocTextKey VDI_ARGS_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.vdi.args");
private static final LocTextKey FALLBACK_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.fallback");
private static final LocTextKey FALLBACK_URL_TEXT_KEY =
@ -93,6 +106,10 @@ public class SEBClientConfigForm implements TemplateComposer {
private static final LocTextKey FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.encryptSecret.confirm");
private static final Set<String> VDI_ATTRIBUTES = new HashSet<>(Arrays.asList(
SEBClientConfig.ATTR_VDI_EXECUTABLE,
SEBClientConfig.ATTR_VDI_PATH,
SEBClientConfig.ATTR_VDI_ARGUMENTS));
private static final Set<String> FALLBACK_ATTRIBUTES = new HashSet<>(Arrays.asList(
SEBClientConfig.ATTR_FALLBACK_START_URL,
SEBClientConfig.ATTR_FALLBACK_ATTEMPT_INTERVAL,
@ -103,6 +120,7 @@ public class SEBClientConfigForm implements TemplateComposer {
SEBClientConfig.ATTR_QUIT_PASSWORD,
SEBClientConfig.ATTR_QUIT_PASSWORD_CONFIRM));
private static final String DEFAULT_PING_INTERVAL = String.valueOf(1000);
private static final String FALLBACK_DEFAULT_TIME = String.valueOf(30 * Constants.SECOND_IN_MILLIS);
private static final String FALLBACK_DEFAULT_ATTEMPTS = String.valueOf(5);
private static final String FALLBACK_DEFAULT_ATTEMPT_INTERVAL = String.valueOf(2 * Constants.SECOND_IN_MILLIS);
@ -211,6 +229,51 @@ public class SEBClientConfigForm implements TemplateComposer {
FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY,
clientConfig.getEncryptSecret()))
.withDefaultSpanInput(1)
.addField(FormBuilder.text(
SEBClientConfig.ATTR_PING_INTERVAL,
PING_TEXT_KEY,
clientConfig.sebServerPingTime != null
? String.valueOf(clientConfig.sebServerPingTime)
: DEFAULT_PING_INTERVAL)
.asNumber(this::checkNaturalNumber)
.mandatory(!isReadonly))
.withDefaultSpanEmptyCell(4)
.withDefaultSpanInput(2)
.addField(FormBuilder.singleSelection(
SEBClientConfig.ATTR_VDI_TYPE,
VDI_TYPE_TEXT_KEY,
clientConfig.vdiType != null
? clientConfig.vdiType.name()
: SEBClientConfig.VDIType.NO.name(),
() -> this.pageService.getResourceService().vdiTypeResources())
.mandatory(!isReadonly))
.withDefaultSpanEmptyCell(3)
.withDefaultSpanInput(3)
.addField(FormBuilder.text(
SEBClientConfig.ATTR_VDI_EXECUTABLE,
VDI_EXEC_TEXT_KEY,
clientConfig.vdiExecutable)
.mandatory(!isReadonly))
.withDefaultSpanEmptyCell(2)
.withDefaultSpanInput(4)
.addField(FormBuilder.text(
SEBClientConfig.ATTR_VDI_PATH,
VDI_PATH_TEXT_KEY,
clientConfig.vdiPath)
.mandatory(!isReadonly))
.withDefaultSpanEmptyCell(1)
.withDefaultSpanInput(4)
.addField(FormBuilder.text(
SEBClientConfig.ATTR_VDI_ARGUMENTS,
VDI_ARGS_TEXT_KEY,
clientConfig.vdiArguments)
.asArea()
.mandatory(!isReadonly))
.withDefaultSpanEmptyCell(1)
.addField(FormBuilder.checkbox(
SEBClientConfig.ATTR_FALLBACK,
FALLBACK_TEXT_KEY,
@ -304,6 +367,10 @@ public class SEBClientConfigForm implements TemplateComposer {
FALLBACK_ATTRIBUTES::contains,
ffa -> ffa.setVisible(BooleanUtils.isTrue(clientConfig.fallback)));
formHandle.process(
VDI_ATTRIBUTES::contains,
ffa -> ffa.setVisible(BooleanUtils.isTrue(clientConfig.vdiType != VDIType.NO)));
if (!isReadonly) {
formHandle.getForm().getFieldInput(SEBClientConfig.ATTR_FALLBACK)
.addListener(SWT.Selection, event -> formHandle.process(
@ -316,6 +383,18 @@ public class SEBClientConfigForm implements TemplateComposer {
ffa.setStringValue(StringUtils.EMPTY);
}
}));
formHandle.getForm().getFieldInput(SEBClientConfig.ATTR_VDI_TYPE)
.addListener(SWT.Selection, event -> formHandle.process(
VDI_ATTRIBUTES::contains,
ffa -> {
final boolean show =
!VDIType.NO.name().equals(((Selection) event.widget).getSelectionValue());
ffa.setVisible(show);
if (!show && ffa.hasError()) {
ffa.resetError();
ffa.setStringValue(StringUtils.EMPTY);
}
}));
}
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);

View file

@ -18,8 +18,6 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
import ch.ethz.seb.sebserver.gbl.util.Cryptor;
import ch.ethz.seb.sebserver.gui.widget.PasswordInput;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT;
@ -38,11 +36,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
import ch.ethz.seb.sebserver.gbl.util.Cryptor;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
import ch.ethz.seb.sebserver.gui.widget.FileUploadSelection;
import ch.ethz.seb.sebserver.gui.widget.ImageUploadSelection;
import ch.ethz.seb.sebserver.gui.widget.PasswordInput;
import ch.ethz.seb.sebserver.gui.widget.Selection;
import ch.ethz.seb.sebserver.gui.widget.Selection.Type;
import ch.ethz.seb.sebserver.gui.widget.ThresholdList;
@ -166,7 +166,8 @@ public final class Form implements FormBinding {
return this;
}
Form putField(final String name, final Control label, final FileUploadSelection fileUpload, final Label errorLabel) {
Form putField(final String name, final Control label, final FileUploadSelection fileUpload,
final Label errorLabel) {
final FormFieldAccessor createAccessor = createAccessor(label, fileUpload, errorLabel);
fileUpload.setErrorHandler(createAccessor::setError);
this.formFields.add(name, createAccessor);
@ -319,7 +320,7 @@ public final class Form implements FormBinding {
@Override public String getStringValue() {return pwdInput.getValue() != null ? pwdInput.getValue().toString() : null;}
@Override public void setStringValue(final String value) {
if (StringUtils.isNotBlank(value)) {
pwdInput.setValue(cryptor.decrypt(value));
pwdInput.setValue(Form.this.cryptor.decrypt(value));
} else {
pwdInput.setValue(value);
}
@ -508,6 +509,13 @@ public final class Form implements FormBinding {
this.input.setVisible(visible);
}
public void setEnabled(final boolean enable) {
if (this.label != null) {
this.label.setEnabled(enable);
}
this.input.setEnabled(enable);
}
public void putJsonValue(final String key, final ObjectNode objectRoot) {
this.jsonValueAdapter.accept(new Tuple<>(key, getStringValue()), objectRoot);
}

View file

@ -195,6 +195,8 @@ public class FormBuilder {
final GridData gridData = new GridData(SWT.LEFT, SWT.TOP, false, false, hspan, vspan);
gridData.minimumWidth = 0;
gridData.widthHint = 0;
gridData.heightHint = 0;
gridData.minimumHeight = 0;
empty.setLayoutData(gridData);
}

View file

@ -46,6 +46,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
@ -113,6 +114,7 @@ public class ResourceService {
public static final String SEB_RESTRICTION_PERMISSIONS_PREFIX = "sebserver.exam.form.sebrestriction.permissions.";
public static final String SEB_CLIENT_CONFIG_PURPOSE_PREFIX = "sebserver.clientconfig.config.purpose.";
public static final String EXAM_PROCTORING_TYPE_PREFIX = "sebserver.exam.proctoring.type.servertype.";
public static final String VDI_TYPE_PREFIX = "sebserver.clientconfig.form.vditype.";
public static final EnumSet<AttributeType> ATTRIBUTE_TYPES_NOT_DISPLAYED = EnumSet.of(
AttributeType.LABEL,
@ -416,6 +418,18 @@ public class ResourceService {
.collect(Collectors.toList());
}
public List<Tuple<String>> vdiTypeResources() {
return Arrays.stream(VDIType.values())
.map(type -> new Tuple3<>(
type.name(),
this.i18nSupport.getText(VDI_TYPE_PREFIX + type.name()),
Utils.formatLineBreaks(this.i18nSupport.getText(
VDI_TYPE_PREFIX + type.name() + Constants.TOOLTIP_TEXT_KEY_SUFFIX,
StringUtils.EMPTY))))
.sorted(RESOURCE_COMPARATOR)
.collect(Collectors.toList());
}
public List<Tuple<String>> examConfigStatusResources() {
return examConfigStatusResources(false);
}

View file

@ -39,6 +39,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.ConfigPurpose;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
@ -384,6 +385,23 @@ public class SEBClientConfigDAOImpl implements SEBClientConfigDAO {
? ConfigPurpose
.valueOf(additionalAttributes.get(SEBClientConfig.ATTR_CONFIG_PURPOSE).getValue())
: ConfigPurpose.START_EXAM,
additionalAttributes.containsKey(SEBClientConfig.ATTR_PING_INTERVAL)
? Long
.valueOf(additionalAttributes.get(SEBClientConfig.ATTR_PING_INTERVAL).getValue())
: 1000L,
additionalAttributes.containsKey(SEBClientConfig.ATTR_VDI_TYPE)
? VDIType
.valueOf(additionalAttributes.get(SEBClientConfig.ATTR_VDI_TYPE).getValue())
: VDIType.NO,
additionalAttributes.containsKey(SEBClientConfig.ATTR_VDI_EXECUTABLE)
? additionalAttributes.get(SEBClientConfig.ATTR_VDI_EXECUTABLE).getValue()
: null,
additionalAttributes.containsKey(SEBClientConfig.ATTR_VDI_PATH)
? additionalAttributes.get(SEBClientConfig.ATTR_VDI_PATH).getValue()
: null,
additionalAttributes.containsKey(SEBClientConfig.ATTR_VDI_ARGUMENTS)
? additionalAttributes.get(SEBClientConfig.ATTR_VDI_ARGUMENTS).getValue()
: null,
additionalAttributes.containsKey(SEBClientConfig.ATTR_FALLBACK) &&
BooleanUtils.toBoolean(additionalAttributes.get(SEBClientConfig.ATTR_FALLBACK).getValue()),
additionalAttributes.containsKey(SEBClientConfig.ATTR_FALLBACK_START_URL)
@ -453,6 +471,42 @@ public class SEBClientConfigDAOImpl implements SEBClientConfigDAO {
? sebClientConfig.configPurpose.name()
: ConfigPurpose.CONFIGURE_CLIENT.name());
this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.SEB_CLIENT_CONFIGURATION,
configId,
SEBClientConfig.ATTR_PING_INTERVAL,
sebClientConfig.sebServerPingTime.toString());
this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.SEB_CLIENT_CONFIGURATION,
configId,
SEBClientConfig.ATTR_VDI_TYPE,
sebClientConfig.vdiType.name());
if (sebClientConfig.vdiExecutable != null) {
this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.SEB_CLIENT_CONFIGURATION,
configId,
SEBClientConfig.ATTR_VDI_EXECUTABLE,
sebClientConfig.vdiExecutable);
}
if (sebClientConfig.vdiExecutable != null) {
this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.SEB_CLIENT_CONFIGURATION,
configId,
SEBClientConfig.ATTR_VDI_PATH,
sebClientConfig.vdiPath);
}
if (sebClientConfig.vdiExecutable != null) {
this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.SEB_CLIENT_CONFIGURATION,
configId,
SEBClientConfig.ATTR_VDI_ARGUMENTS,
sebClientConfig.vdiArguments);
}
this.additionalAttributesDAO.saveAdditionalAttribute(
EntityType.SEB_CLIENT_CONFIGURATION,
configId,

View file

@ -33,20 +33,14 @@ public interface ClientConfigService {
* @return true if there is any SEBClientConfiguration for a specified institution. False otherwise */
boolean hasSEBClientConfigurationForInstitution(Long institutionId);
/** Use this to auto-generate a SEBClientConfiguration for a specified institution.
* clientName and clientSecret are randomly generated.
*
* @param institutionId the institution identifier
* @return the created SEBClientConfiguration */
Result<SEBClientConfig> autoCreateSEBClientConfigurationForInstitution(Long institutionId);
/** Use this to export a specified SEBClientConfiguration within a given OutputStream.
* The SEB Client Configuration is exported in the defined SEB Configuration format
* as described here: https://www.safeexambrowser.org/developer/seb-file-format.html
*
* @param out OutputStream to write the export to
* @param modelId the model identifier of the SEBClientConfiguration to export
* @param examId The exam identifier. May be null, if not the exported client config will contain the exam information*/
* @param modelId the model identifier of the SEBClientConfiguration to export
* @param examId The exam identifier. May be null, if not the exported client config will contain the exam
* information */
void exportSEBClientConfiguration(
OutputStream out,
final String modelId,

View file

@ -18,7 +18,6 @@ import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.BooleanUtils;
@ -47,14 +46,12 @@ import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.ConfigPurpose;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ClientConfigService;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionService;
@ -103,7 +100,6 @@ public class ClientConfigServiceImpl implements ClientConfigService {
" <key>%s</key>%n" +
" <string>%s</string>%n";
private final InstitutionDAO institutionDAO;
private final SEBClientConfigDAO sebClientConfigDAO;
private final ClientCredentialService clientCredentialService;
private final SEBConfigEncryptionService sebConfigEncryptionService;
@ -112,7 +108,6 @@ public class ClientConfigServiceImpl implements ClientConfigService {
private final WebserviceInfo webserviceInfo;
protected ClientConfigServiceImpl(
final InstitutionDAO institutionDAO,
final SEBClientConfigDAO sebClientConfigDAO,
final ClientCredentialService clientCredentialService,
final SEBConfigEncryptionService sebConfigEncryptionService,
@ -120,7 +115,6 @@ public class ClientConfigServiceImpl implements ClientConfigService {
@Qualifier(WebSecurityConfig.CLIENT_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder clientPasswordEncoder,
final WebserviceInfo webserviceInfo) {
this.institutionDAO = institutionDAO;
this.sebClientConfigDAO = sebClientConfigDAO;
this.clientCredentialService = clientCredentialService;
this.sebConfigEncryptionService = sebConfigEncryptionService;
@ -135,35 +129,6 @@ public class ClientConfigServiceImpl implements ClientConfigService {
return all != null && !all.hasError() && !all.getOrThrow().isEmpty();
}
@Override
public Result<SEBClientConfig> autoCreateSEBClientConfigurationForInstitution(final Long institutionId) {
return Result.tryCatch(() -> {
final Institution institution = this.institutionDAO
.byPK(institutionId)
.getOrThrow();
return new SEBClientConfig(
null,
institutionId,
institution.name + "_" + UUID.randomUUID(),
null,
false,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
true);
})
.flatMap(this.sebClientConfigDAO::createNew);
}
@Override
public Result<ClientDetails> getClientConfigDetails(final String clientName) {
return this.getEncodedClientConfigSecret(clientName)

View file

@ -679,6 +679,18 @@ sebserver.clientconfig.form.title=Connection Configuration
sebserver.clientconfig.form.title.subtitle=
sebserver.clientconfig.form.name=Name
sebserver.clientconfig.form.name.tooltip=The name of the connection configuration.<br/>Any name that not already is in use for another connection configuration
sebserver.clientconfig.form.pinginterval=Ping Interval
sebserver.clientconfig.form.pinginterval.tooltip=Defines an interval time in milliseconds for a SEB client to send a ping to the SEB Server
sebserver.clientconfig.form.vditype=VDI Setup
sebserver.clientconfig.form.vditype.tooltip=Select a VDI Type to apply this connection configuration to SEB client select a VDI environment on startup
sebserver.clientconfig.form.vditype.NO=No VDI
sebserver.clientconfig.form.vditype.VM_WARE=VDI with VMWare
sebserver.clientconfig.form.vdi.executable=Executable
sebserver.clientconfig.form.vdi.path=Path to Executable
sebserver.clientconfig.form.vdi.args=Arguments
sebserver.clientconfig.form.vdi.args.tooltip=A list of arguments to use with the executable to startup the virtual client software
sebserver.clientconfig.form.fallback=With Fallback
sebserver.clientconfig.form.fallback.tooltip=Indicates whether this connection configuration has a fallback definition or not
sebserver.clientconfig.form.fallback-url=Fallback Start URL

View file

@ -50,6 +50,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.ConfigPurpose;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
@ -114,6 +115,8 @@ public class ModelObjectJSONGenerator {
domainObject = new SEBClientConfig(
1L, 1L, "name", ConfigPurpose.CONFIGURE_CLIENT,
1000L,
VDIType.NO, null, null, null,
true, "fallbackStartURL", 20000L, (short) 3, (short) 1000, "fallbackPassword",
"fallbackPasswordConfirm",
"quitPassword", "quitPasswordConfirm", DateTime.now(), "encryptSecret", "encryptSecretConfirm", true);

View file

@ -17,6 +17,7 @@ import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestServiceImpl;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ActivateClientConfig;
@ -109,6 +110,8 @@ public class ClientConfigTest extends GuiIntegrationTest {
config.institutionId,
"new client config",
SEBClientConfig.ConfigPurpose.START_EXAM,
1000L,
VDIType.NO, null, null, null,
null,
null,
null,
@ -136,6 +139,8 @@ public class ClientConfigTest extends GuiIntegrationTest {
config.institutionId,
"new client config",
SEBClientConfig.ConfigPurpose.START_EXAM,
1000L,
VDIType.NO, null, null, null,
null,
null,
null,