import, configuration
This commit is contained in:
parent
f3b44d9cbe
commit
2bb0ae1c0d
17 changed files with 220 additions and 145 deletions
|
@ -80,4 +80,10 @@ public final class Constants {
|
|||
public static final int RWT_MOUSE_BUTTON_1 = 1;
|
||||
public static final int RWT_MOUSE_BUTTON_2 = 2;
|
||||
public static final int RWT_MOUSE_BUTTON_3 = 3;
|
||||
|
||||
public static final int GZIP_HEADER_LENGTH = 10;
|
||||
public static final int GZIP_ID1 = 0x1F;
|
||||
public static final int GZIP_ID2 = 0x8B;
|
||||
public static final int GZIP_CM = 8;
|
||||
|
||||
}
|
||||
|
|
|
@ -306,6 +306,9 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
final Configuration configuration = pageService.getRestService()
|
||||
.getBuilder(ImportExamConfig.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.withHeader(
|
||||
API.IMPORT_PASSWORD_ATTR_NAME,
|
||||
form.getFieldValue(API.IMPORT_PASSWORD_ATTR_NAME))
|
||||
.withBody(inputStream)
|
||||
.call()
|
||||
.get(context::notifyError);
|
||||
|
|
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
|
@ -80,7 +81,7 @@ public interface SebConfigEncryptionService {
|
|||
* @param input the input stream to read the cipher text from
|
||||
* @param context the SebConfigEncryptionContext to access strategy specific data needed for encryption */
|
||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
void streamDecrypted(
|
||||
Future<Exception> streamDecrypted(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SebConfigEncryptionContext context);
|
||||
|
|
|
@ -111,6 +111,6 @@ public interface SebExamConfigService {
|
|||
* @param input The InputStream to get the SEB config file as byte-stream
|
||||
* @param password A password is only needed if the file is in an encrypted format
|
||||
* @return The newly created Configuration instance */
|
||||
Result<Configuration> importFromXML(Long configNodeId, InputStream input, CharSequence password);
|
||||
Result<Configuration> importFromSEBFile(Long configNodeId, InputStream input, CharSequence password);
|
||||
|
||||
}
|
||||
|
|
|
@ -166,7 +166,6 @@ public class ExamConfigIO {
|
|||
* @param in The InputString to constantly read the XML from
|
||||
* @param institutionId the institionId of the import
|
||||
* @param configurationId the identifier of the internal configuration to apply the imported values to */
|
||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
void importPlainXML(final InputStream in, final Long institutionId, final Long configurationId) {
|
||||
try {
|
||||
// get all attributes and map the names to ids
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.Stack;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.Attributes;
|
||||
|
@ -164,8 +165,8 @@ public class ExamConfigImportHandler extends DefaultHandler {
|
|||
|
||||
private void startValueElement(final Type type, final PListNode top) {
|
||||
final PListNode value = new PListNode(type);
|
||||
|
||||
if (top.type == Type.KEY) {
|
||||
|
||||
if (Type.isBooleanValue(type)) {
|
||||
this.stack.pop();
|
||||
value.name = top.name;
|
||||
|
@ -210,40 +211,64 @@ public class ExamConfigImportHandler extends DefaultHandler {
|
|||
final PListNode grandParent = this.stack.peek();
|
||||
this.stack.push(parent);
|
||||
|
||||
// if we are in an values-array
|
||||
if (parent.type == Type.ARRAY) {
|
||||
if (StringUtils.isBlank(parent.value)) {
|
||||
parent.value = top.value;
|
||||
} else {
|
||||
parent.value += "," + top.value;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final String attrName = (parent.type == Type.DICT && grandParent.type == Type.ARRAY)
|
||||
? parent.name + "." + top.name
|
||||
: top.name;
|
||||
|
||||
final Long attributeId = this.attributeNameIdResolver.apply(attrName);
|
||||
if (attributeId == null) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Skip unknown configuration attribute: {}", attrName);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// TODO use AttributeValueConverterService here. Extend the converters with fromXML functionality
|
||||
final ConfigurationValue configurationValue = new ConfigurationValue(
|
||||
null,
|
||||
this.institutionId,
|
||||
this.configId,
|
||||
attributeId,
|
||||
top.listIndex,
|
||||
top.value);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Save imported value: {} : {}", attrName, configurationValue);
|
||||
}
|
||||
|
||||
this.valueConsumer.accept(configurationValue);
|
||||
saveValue(attrName, attributeId, top.listIndex, top.value);
|
||||
}
|
||||
}
|
||||
} else if (top.type == Type.ARRAY && StringUtils.isNoneBlank(top.value)) {
|
||||
this.stack.pop();
|
||||
final PListNode parent = this.stack.pop();
|
||||
final PListNode grandParent = this.stack.peek();
|
||||
this.stack.push(parent);
|
||||
final String attrName = (parent.type == Type.DICT && grandParent.type == Type.ARRAY)
|
||||
? parent.name + "." + top.name
|
||||
: top.name;
|
||||
final Long attributeId = this.attributeNameIdResolver.apply(attrName);
|
||||
|
||||
saveValue(attrName, attributeId, top.listIndex, top.value);
|
||||
|
||||
} else if (!Constants.XML_PLIST_KEY_NAME.equals(qName)) {
|
||||
this.stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveValue(final String name, final Long attributeId, final int listIndex, final String value) {
|
||||
// TODO use AttributeValueConverterService here. Extend the converters with fromXML functionality
|
||||
final ConfigurationValue configurationValue = new ConfigurationValue(
|
||||
null,
|
||||
this.institutionId,
|
||||
this.configId,
|
||||
attributeId,
|
||||
listIndex,
|
||||
value);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Save imported value: {} : {}", name, configurationValue);
|
||||
}
|
||||
|
||||
this.valueConsumer.accept(configurationValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(
|
||||
final char[] ch,
|
||||
|
|
|
@ -8,15 +8,20 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||
import org.cryptonode.jncryptor.AES256JNCryptor;
|
||||
import org.cryptonode.jncryptor.AES256JNCryptorInputStream;
|
||||
import org.cryptonode.jncryptor.AES256JNCryptorOutputStream;
|
||||
import org.cryptonode.jncryptor.CryptorException;
|
||||
import org.cryptonode.jncryptor.PasswordKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
@ -91,31 +96,66 @@ public class PasswordEncryptor implements SebConfigCryptor {
|
|||
final InputStream input,
|
||||
final SebConfigEncryptionContext context) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous decryption");
|
||||
}
|
||||
final CharSequence password = context.getPassword();
|
||||
|
||||
AES256JNCryptorInputStream encryptInput = null;
|
||||
try {
|
||||
final byte[] version = new byte[1];
|
||||
input.read(version);
|
||||
|
||||
encryptInput = new AES256JNCryptorInputStream(
|
||||
input,
|
||||
Utils.toCharArray(context.getPassword()));
|
||||
final SequenceInputStream sequenceInputStream = new SequenceInputStream(
|
||||
new ByteArrayInputStream(version),
|
||||
input);
|
||||
|
||||
IOUtils.copyLarge(encryptInput, output);
|
||||
if (version[0] == 3) {
|
||||
|
||||
encryptInput.close();
|
||||
output.flush();
|
||||
output.close();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous decryption");
|
||||
}
|
||||
|
||||
AES256JNCryptorInputStream encryptInput = null;
|
||||
try {
|
||||
|
||||
encryptInput = new AES256JNCryptorInputStream(
|
||||
sequenceInputStream,
|
||||
Utils.toCharArray(password));
|
||||
|
||||
IOUtils.copyLarge(encryptInput, output);
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while trying to read/write form/to streams: ", e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(encryptInput);
|
||||
}
|
||||
} else {
|
||||
// AES256JNCryptorInputStream supports only decryption of AES256 version 3 encrypted data
|
||||
// Workaround: stop streaming and use AES256JNCryptor which supports both, version 2 and 3
|
||||
log.info("Trying to decrypt with AES256JNCryptor by load all data into memory...");
|
||||
|
||||
try {
|
||||
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
IOUtils.copyLarge(sequenceInputStream, out);
|
||||
final byte[] ciphertext = out.toByteArray();
|
||||
final AES256JNCryptor cryptor = new AES256JNCryptor();
|
||||
cryptor.setPBKDFIterations(10000);
|
||||
final PasswordKey passwordKey = cryptor.getPasswordKey(Utils.toCharArray(password));
|
||||
final int versionNumber = cryptor.getVersionNumber();
|
||||
final byte[] decryptData = cryptor.decryptData(ciphertext, Utils.toCharArray(password));
|
||||
final ByteArrayInputStream decryptedIn = new ByteArrayInputStream(decryptData);
|
||||
IOUtils.copyLarge(decryptedIn, output);
|
||||
|
||||
} catch (final IOException | CryptorException e) {
|
||||
log.error("Error while trying to none-streaming decrypt: ", e);
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while trying to read/write form/to streams: ", e);
|
||||
log.error("Unexpected error while decryption: ", e);
|
||||
} finally {
|
||||
try {
|
||||
if (encryptInput != null)
|
||||
encryptInput.close();
|
||||
output.flush();
|
||||
output.close();
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to close AES256JNCryptorOutputStream: ", e);
|
||||
log.error("Failed to close streams");
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
|
|
|
@ -8,23 +8,28 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
|
@ -99,7 +104,7 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
}
|
||||
|
||||
@Override
|
||||
public void streamDecrypted(
|
||||
public Future<Exception> streamDecrypted(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SebConfigEncryptionContext context) {
|
||||
|
@ -110,20 +115,48 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
pout = new PipedOutputStream();
|
||||
pin = new PipedInputStream(pout);
|
||||
|
||||
final Strategy strategy = verifyStrategy(input);
|
||||
Strategy strategy = null;
|
||||
final byte[] header = new byte[HEADER_SIZE];
|
||||
input.read(header);
|
||||
for (final Strategy s : Strategy.values()) {
|
||||
if (Arrays.equals(s.header, header)) {
|
||||
strategy = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InputStream newIn = null;
|
||||
if (strategy == null) {
|
||||
strategy = Strategy.PLAIN_TEXT;
|
||||
newIn = new SequenceInputStream(
|
||||
new ByteArrayInputStream(header),
|
||||
input);
|
||||
} else {
|
||||
newIn = input;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Password decryption with strategy: {}", strategy);
|
||||
}
|
||||
|
||||
if ((strategy == Strategy.PASSWORD_PSWD || strategy == Strategy.PASSWORD_PWCC)
|
||||
&& StringUtils.isBlank(context.getPassword())) {
|
||||
return new AsyncResult<>(new IllegalArgumentException("Missing Password"));
|
||||
}
|
||||
|
||||
getEncryptor(strategy)
|
||||
.getOrThrow()
|
||||
.decrypt(pout, input, context);
|
||||
.decrypt(pout, newIn, context);
|
||||
|
||||
IOUtils.copyLarge(pin, output);
|
||||
|
||||
return new AsyncResult<>(null);
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while stream decrypted data: ", e);
|
||||
return new AsyncResult<>(e);
|
||||
} catch (final Exception iae) {
|
||||
return new AsyncResult<>(iae);
|
||||
} finally {
|
||||
try {
|
||||
if (pin != null) {
|
||||
|
@ -145,22 +178,6 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
}
|
||||
}
|
||||
|
||||
private Strategy verifyStrategy(final InputStream input) {
|
||||
try {
|
||||
final byte[] header = new byte[HEADER_SIZE];
|
||||
input.read(header);
|
||||
for (final Strategy s : Strategy.values()) {
|
||||
if (Arrays.equals(s.header, header)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Failed to verify decryption strategy from input stream");
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to read decryption strategy from input stream");
|
||||
throw new IllegalStateException("Failed to verify decryption strategy from input stream");
|
||||
}
|
||||
}
|
||||
|
||||
private Result<SebConfigCryptor> getEncryptor(final Strategy strategy) {
|
||||
final SebConfigCryptor encryptor = this.encryptors.get(strategy);
|
||||
if (encryptor == null) {
|
||||
|
@ -233,6 +250,10 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
return new EncryptionContext(Strategy.PLAIN_TEXT, null, null);
|
||||
}
|
||||
|
||||
public static SebConfigEncryptionContext contextOf(final CharSequence password) {
|
||||
return new EncryptionContext(null, password, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ import java.io.OutputStream;
|
|||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
|
||||
|
@ -321,7 +322,7 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Result<Configuration> importFromXML(
|
||||
public Result<Configuration> importFromSEBFile(
|
||||
final Long configNodeId,
|
||||
final InputStream input,
|
||||
final CharSequence password) {
|
||||
|
@ -332,44 +333,22 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
.saveToHistory(configNodeId)
|
||||
.getOrThrow();
|
||||
|
||||
Future<Exception> streamDecrypted = null;
|
||||
try {
|
||||
|
||||
final byte[] header = new byte[4];
|
||||
input.read(header);
|
||||
final InputStream cryptIn = this.unzip(input);
|
||||
final PipedInputStream plainIn = new PipedInputStream();
|
||||
final PipedOutputStream cryptOut = new PipedOutputStream(plainIn);
|
||||
|
||||
Strategy strategy = null;
|
||||
try {
|
||||
strategy = SebConfigEncryptionService.Strategy.getStrategy(header);
|
||||
} catch (final IllegalArgumentException iae) {
|
||||
streamDecrypted = this.sebConfigEncryptionService.streamDecrypted(
|
||||
cryptOut,
|
||||
cryptIn,
|
||||
EncryptionContext.contextOf(password));
|
||||
|
||||
log.info("{} : Trying to import as unzipped plain text configuration", iae.getMessage());
|
||||
|
||||
importPlainOnly(input, newConfig, header);
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
if (strategy != null) {
|
||||
final InputStream cryptIn = this.unzip(input);
|
||||
final PipedInputStream plainIn = new PipedInputStream();
|
||||
final PipedOutputStream cryptOut = new PipedOutputStream(plainIn);
|
||||
|
||||
try {
|
||||
|
||||
this.sebConfigEncryptionService.streamDecrypted(
|
||||
cryptOut,
|
||||
cryptIn,
|
||||
EncryptionContext.contextOf(strategy, password));
|
||||
|
||||
this.examConfigIO.importPlainXML(
|
||||
plainIn,
|
||||
newConfig.institutionId,
|
||||
newConfig.id);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(cryptIn);
|
||||
IOUtils.closeQuietly(cryptOut);
|
||||
IOUtils.closeQuietly(plainIn);
|
||||
}
|
||||
}
|
||||
this.examConfigIO.importPlainXML(
|
||||
plainIn,
|
||||
newConfig.institutionId,
|
||||
newConfig.id);
|
||||
|
||||
return newConfig;
|
||||
|
||||
|
@ -380,16 +359,26 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
.undo(configNodeId)
|
||||
.getOrThrow();
|
||||
|
||||
throw new RuntimeException("Failed to import SEB configuration. Cause is: " + e.getMessage(), e);
|
||||
if (streamDecrypted != null) {
|
||||
final Exception exception = streamDecrypted.get();
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Failed to import SEB configuration. Cause is: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private InputStream unzip(final InputStream input) throws Exception {
|
||||
final byte[] zipHeader = new byte[4];
|
||||
final byte[] zipHeader = new byte[Constants.GZIP_HEADER_LENGTH];
|
||||
input.read(zipHeader);
|
||||
final int zipType = ByteBuffer.wrap(zipHeader).getInt();
|
||||
final boolean isZipped = zipType == 0x504B0304 || zipType == 0x504B0506 || zipType == 0x504B0708;
|
||||
|
||||
//final int zipType = ByteBuffer.wrap(zipHeader).getInt();
|
||||
final boolean isZipped = Byte.toUnsignedInt(zipHeader[0]) == Constants.GZIP_ID1
|
||||
&& Byte.toUnsignedInt(zipHeader[1]) == Constants.GZIP_ID2
|
||||
&& Byte.toUnsignedInt(zipHeader[2]) == Constants.GZIP_CM;
|
||||
|
||||
if (isZipped) {
|
||||
|
||||
|
@ -409,33 +398,6 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
}
|
||||
}
|
||||
|
||||
private void importPlainOnly(
|
||||
final InputStream input,
|
||||
final Configuration newConfig,
|
||||
final byte[] header) throws IOException {
|
||||
|
||||
PipedInputStream plainIn = null;
|
||||
PipedOutputStream out = null;
|
||||
|
||||
try {
|
||||
plainIn = new PipedInputStream();
|
||||
out = new PipedOutputStream(plainIn);
|
||||
|
||||
this.examConfigIO.importPlainXML(
|
||||
plainIn,
|
||||
newConfig.institutionId,
|
||||
newConfig.id);
|
||||
|
||||
out.write(header);
|
||||
IOUtils.copyLarge(input, out);
|
||||
} catch (final Exception e) {
|
||||
log.error("Error while stream plain text SEB Configuration import data: ", e);
|
||||
throw e;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
}
|
||||
|
||||
private void exportPlainOnly(
|
||||
final ConfigurationFormat exportFormat,
|
||||
final OutputStream out,
|
||||
|
|
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||
|
@ -66,7 +67,31 @@ public class ZipServiceImpl implements ZipService {
|
|||
|
||||
@Override
|
||||
public void read(final OutputStream out, final InputStream in) {
|
||||
// TODO Auto-generated method stub
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous unzipping of SEB exam configuration data");
|
||||
}
|
||||
|
||||
GZIPInputStream zipInputStream = null;
|
||||
try {
|
||||
|
||||
zipInputStream = new GZIPInputStream(in);
|
||||
|
||||
IOUtils.copyLarge(zipInputStream, out);
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while streaming data to unzipped output: ", e);
|
||||
} finally {
|
||||
try {
|
||||
out.flush();
|
||||
out.close();
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to close OutputStream: ", e);
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Finish streaming asynchronous unzipping of SEB exam configuration data");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
|
|||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
||||
final HttpServletRequest request) throws IOException {
|
||||
|
||||
return this.sebExamConfigService.importFromXML(
|
||||
return this.sebExamConfigService.importFromSEBFile(
|
||||
modelId,
|
||||
request.getInputStream(),
|
||||
password)
|
||||
|
|
|
@ -133,7 +133,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
|
|||
|
||||
(73, 'permittedProcesses', 'TABLE', null, null, null, null, null),
|
||||
(74, 'permittedProcesses.active', 'CHECKBOX', 73, null, null, null, 'true'),
|
||||
(75, 'permittedProcesses.os', 'SINGLE_SELECTION', 73, '0,1', null, null, '0'),
|
||||
(75, 'permittedProcesses.os', 'SINGLE_SELECTION', 73, '0,1', null, null, '1'),
|
||||
(76, 'permittedProcesses.title', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
(77, 'permittedProcesses.description', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
(78, 'permittedProcesses.executable', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
|
@ -152,7 +152,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
|
|||
|
||||
(93, 'prohibitedProcesses', 'TABLE', null, null, null, null, null),
|
||||
(94, 'prohibitedProcesses.active', 'CHECKBOX', 93, null, null, null, 'true'),
|
||||
(95, 'prohibitedProcesses.os', 'SINGLE_SELECTION', 93, '0,1', null, null, '0'),
|
||||
(95, 'prohibitedProcesses.os', 'SINGLE_SELECTION', 93, '0,1', null, null, '1'),
|
||||
(96, 'prohibitedProcesses.executable', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
(97, 'prohibitedProcesses.description', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
(98, 'prohibitedProcesses.originalName', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
|
|
|
@ -107,7 +107,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
|
|||
|
||||
(73, 'permittedProcesses', 'TABLE', null, null, null, null, null),
|
||||
(74, 'permittedProcesses.active', 'CHECKBOX', 73, null, null, null, 'true'),
|
||||
(75, 'permittedProcesses.os', 'SINGLE_SELECTION', 73, '0,1', null, null, '0'),
|
||||
(75, 'permittedProcesses.os', 'SINGLE_SELECTION', 73, '0,1', null, null, '1'),
|
||||
(76, 'permittedProcesses.title', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
(77, 'permittedProcesses.description', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
(78, 'permittedProcesses.executable', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
|
@ -126,7 +126,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
|
|||
|
||||
(93, 'prohibitedProcesses', 'TABLE', null, null, null, null, null),
|
||||
(94, 'prohibitedProcesses.active', 'CHECKBOX', 93, null, null, null, 'true'),
|
||||
(95, 'prohibitedProcesses.os', 'SINGLE_SELECTION', 93, '0,1', null, null, '0'),
|
||||
(95, 'prohibitedProcesses.os', 'SINGLE_SELECTION', 93, '0,1', null, null, '1'),
|
||||
(96, 'prohibitedProcesses.executable', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
(97, 'prohibitedProcesses.description', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
(98, 'prohibitedProcesses.originalName', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
|
|
|
@ -681,8 +681,8 @@ sebserver.examconfig.props.label.permittedProcesses.active=Active
|
|||
sebserver.examconfig.props.label.permittedProcesses.active.tooltip=This permitted process item is active.
|
||||
sebserver.examconfig.props.label.permittedProcesses.os=OS
|
||||
sebserver.examconfig.props.label.permittedProcesses.os.tooltip=Indicates on which operating system the permitted process runs.
|
||||
sebserver.examconfig.props.label.permittedProcesses.os.0=Win
|
||||
sebserver.examconfig.props.label.permittedProcesses.os.1=OS X
|
||||
sebserver.examconfig.props.label.permittedProcesses.os.0=OS X
|
||||
sebserver.examconfig.props.label.permittedProcesses.os.1=Win
|
||||
sebserver.examconfig.props.label.permittedProcesses.title=Title
|
||||
sebserver.examconfig.props.label.permittedProcesses.title.tooltip=Application title which is displayed in the application chooser. Background processes don't have a title, because they can't be selected by users.
|
||||
sebserver.examconfig.props.label.permittedProcesses.description=Description
|
||||
|
@ -714,8 +714,8 @@ sebserver.examconfig.props.label.prohibitedProcesses=Prohibited Processes
|
|||
sebserver.examconfig.props.label.prohibitedProcesses.active=Active
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.active.tooltip=Indicates if this prohibited process item is active.
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.os=OS
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.os.0=Win
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.os.1=OS X
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.os.0=OS X
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.os.1=Win
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.description=Description
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.description.tooltip=Optional, to explain what kind of process this is, because this might not be obvious only from the executable's name.
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.executable=Executable
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
|
||||
|
@ -155,18 +155,11 @@ public class ExamConfigImportHandlerTest {
|
|||
candidate.endElement(null, null, "plist");
|
||||
|
||||
assertFalse(valueCollector.values.isEmpty());
|
||||
assertTrue(valueCollector.values.size() == 3);
|
||||
assertTrue(valueCollector.values.size() == 1);
|
||||
final ConfigurationValue configurationValue1 = valueCollector.values.get(0);
|
||||
assertEquals("val1", configurationValue1.value);
|
||||
assertEquals("val1,val2,val3", configurationValue1.value);
|
||||
assertTrue(configurationValue1.listIndex == 0);
|
||||
|
||||
final ConfigurationValue configurationValue2 = valueCollector.values.get(1);
|
||||
assertEquals("val2", configurationValue2.value);
|
||||
assertTrue(configurationValue2.listIndex == 1);
|
||||
|
||||
final ConfigurationValue configurationValue3 = valueCollector.values.get(2);
|
||||
assertEquals("val3", configurationValue3.value);
|
||||
assertTrue(configurationValue3.listIndex == 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -114,7 +114,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
|
|||
|
||||
(73, 'permittedProcesses', 'TABLE', null, null, null, null, null),
|
||||
(74, 'permittedProcesses.active', 'CHECKBOX', 73, null, null, null, 'true'),
|
||||
(75, 'permittedProcesses.os', 'SINGLE_SELECTION', 73, '0,1', null, null, '0'),
|
||||
(75, 'permittedProcesses.os', 'SINGLE_SELECTION', 73, '0,1', null, null, '1'),
|
||||
(76, 'permittedProcesses.title', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
(77, 'permittedProcesses.description', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
(78, 'permittedProcesses.executable', 'TEXT_FIELD', 73, null, null, null, ''),
|
||||
|
@ -133,7 +133,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
|
|||
|
||||
(93, 'prohibitedProcesses', 'TABLE', null, null, null, null, null),
|
||||
(94, 'prohibitedProcesses.active', 'CHECKBOX', 93, null, null, null, 'true'),
|
||||
(95, 'prohibitedProcesses.os', 'SINGLE_SELECTION', 93, '0,1', null, null, '0'),
|
||||
(95, 'prohibitedProcesses.os', 'SINGLE_SELECTION', 93, '0,1', null, null, '1'),
|
||||
(96, 'prohibitedProcesses.executable', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
(97, 'prohibitedProcesses.description', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
(98, 'prohibitedProcesses.originalName', 'TEXT_FIELD', 93, null, null, null, ''),
|
||||
|
|
Loading…
Reference in a new issue