SEBSERV-135 finished implementation
This commit is contained in:
parent
a46e2c0b27
commit
a853c02947
25 changed files with 445 additions and 96 deletions
|
@ -282,4 +282,17 @@ public class APIMessage implements Serializable {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
public static boolean checkError(final Exception error, final ErrorMessage errorMessage) {
|
||||
if (!(error instanceof APIMessageException)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final APIMessageException _error = (APIMessageException) error;
|
||||
return _error.getAPIMessages()
|
||||
.stream()
|
||||
.filter(msg -> errorMessage.messageCode.equals(msg.messageCode))
|
||||
.findFirst()
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
|
|||
public static final String ATTR_QUIT_PASSWORD_CONFIRM = "hashedQuitPasswordConfirm";
|
||||
public static final String ATTR_ENCRYPT_SECRET_CONFIRM = "confirm_encrypt_secret";
|
||||
public static final String ATTR_ENCRYPT_CERTIFICATE_ALIAS = "cert_alias";
|
||||
public static final String ATTR_ENCRYPT_CERTIFICATE_ASYM = "cert_encryption_asym";
|
||||
|
||||
public static final String FILTER_ATTR_CREATION_DATE = "creation_date";
|
||||
|
||||
|
@ -161,6 +162,9 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
|
|||
@JsonProperty(ATTR_ENCRYPT_CERTIFICATE_ALIAS)
|
||||
public final String encryptCertificateAlias;
|
||||
|
||||
@JsonProperty(ATTR_ENCRYPT_CERTIFICATE_ASYM)
|
||||
public final Boolean encryptCertificateAsym;
|
||||
|
||||
@JsonProperty(SEB_CLIENT_CONFIGURATION.ATTR_ACTIVE)
|
||||
public final Boolean active;
|
||||
|
||||
|
@ -190,6 +194,7 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
|
|||
@JsonProperty(SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET) final CharSequence encryptSecret,
|
||||
@JsonProperty(ATTR_ENCRYPT_SECRET_CONFIRM) final CharSequence encryptSecretConfirm,
|
||||
@JsonProperty(ATTR_ENCRYPT_CERTIFICATE_ALIAS) final String encryptCertificateAlias,
|
||||
@JsonProperty(ATTR_ENCRYPT_CERTIFICATE_ASYM) final Boolean encryptCertificateAsym,
|
||||
@JsonProperty(SEB_CLIENT_CONFIGURATION.ATTR_ACTIVE) final Boolean active) {
|
||||
|
||||
this.id = id;
|
||||
|
@ -216,6 +221,7 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
|
|||
this.encryptSecret = encryptSecret;
|
||||
this.encryptSecretConfirm = encryptSecretConfirm;
|
||||
this.encryptCertificateAlias = encryptCertificateAlias;
|
||||
this.encryptCertificateAsym = encryptCertificateAsym;
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
|
@ -254,6 +260,7 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
|
|||
this.encryptSecret = postParams.getCharSequence(Domain.SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET);
|
||||
this.encryptSecretConfirm = postParams.getCharSequence(ATTR_ENCRYPT_SECRET_CONFIRM);
|
||||
this.encryptCertificateAlias = postParams.getString(ATTR_ENCRYPT_CERTIFICATE_ALIAS);
|
||||
this.encryptCertificateAsym = postParams.getBooleanObject(ATTR_ENCRYPT_CERTIFICATE_ASYM);
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
|
@ -442,6 +449,7 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
|
|||
Constants.EMPTY_NOTE,
|
||||
Constants.EMPTY_NOTE,
|
||||
Constants.EMPTY_NOTE,
|
||||
this.encryptCertificateAsym,
|
||||
this.active);
|
||||
}
|
||||
|
||||
|
@ -469,6 +477,7 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
|
|
|
@ -169,6 +169,11 @@ public final class Utils {
|
|||
: Collections.emptyList();
|
||||
}
|
||||
|
||||
public static <T extends Collection<V>, V> T addAll(final T target, final T source) {
|
||||
target.addAll(source);
|
||||
return target;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> immutableMapOf(final Map<K, V> params) {
|
||||
return (params != null)
|
||||
? Collections.unmodifiableMap(params)
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo;
|
||||
|
@ -72,6 +73,8 @@ public class CertificateList implements TemplateComposer {
|
|||
new LocTextKey("sebserver.certificate.message.error.file");
|
||||
static final LocTextKey FORM_IMPORT_CONFIRM_TEXT_KEY =
|
||||
new LocTextKey("sebserver.certificate.action.import-config.confirm");
|
||||
static final LocTextKey FORM_ACTION_MESSAGE_IN_USE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.certificate.action.remove.in-use");
|
||||
|
||||
private final TableFilterAttribute aliasFilter = new TableFilterAttribute(
|
||||
CriteriaType.TEXT,
|
||||
|
@ -169,7 +172,13 @@ public class CertificateList implements TemplateComposer {
|
|||
this.restService.getBuilder(RemoveCertificate.class)
|
||||
.withFormParam(API.CERTIFICATE_ALIAS, ids)
|
||||
.call()
|
||||
.onError(erorr -> action.pageContext().notifyRemoveError(EntityType.CERTIFICATE, erorr));
|
||||
.onError(error -> {
|
||||
if (APIMessage.checkError(error, APIMessage.ErrorMessage.INTEGRITY_VALIDATION)) {
|
||||
action.pageContext().publishInfo(FORM_ACTION_MESSAGE_IN_USE_TEXT_KEY);
|
||||
} else {
|
||||
action.pageContext().notifyRemoveError(EntityType.CERTIFICATE, error);
|
||||
}
|
||||
});
|
||||
|
||||
return action;
|
||||
}
|
||||
|
|
|
@ -106,6 +106,8 @@ public class SEBClientConfigForm implements TemplateComposer {
|
|||
|
||||
private static final LocTextKey FORM_ENCRYPT_CERT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.certificate");
|
||||
private static final LocTextKey FORM_ENCRYPT_CERTIFICATE_ASYM =
|
||||
new LocTextKey("sebserver.clientconfig.form.type.async");
|
||||
private static final LocTextKey FORM_ENCRYPT_SECRET_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.encryptSecret");
|
||||
private static final LocTextKey FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY =
|
||||
|
@ -285,15 +287,6 @@ public class SEBClientConfigForm implements TemplateComposer {
|
|||
.mandatory(!isReadonly))
|
||||
.withDefaultSpanEmptyCell(3)
|
||||
|
||||
.withDefaultSpanInput(3)
|
||||
.addField(FormBuilder.singleSelection(
|
||||
SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ALIAS,
|
||||
FORM_ENCRYPT_CERT_KEY,
|
||||
clientConfig.encryptCertificateAlias,
|
||||
() -> this.pageService.getResourceService().identityCertificatesResources()))
|
||||
.withDefaultSpanEmptyCell(3)
|
||||
|
||||
.withDefaultSpanInput(3)
|
||||
.addField(FormBuilder.password(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET,
|
||||
FORM_ENCRYPT_SECRET_TEXT_KEY,
|
||||
|
@ -307,6 +300,24 @@ public class SEBClientConfigForm implements TemplateComposer {
|
|||
FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY,
|
||||
pwd))
|
||||
|
||||
.withDefaultSpanInput(2)
|
||||
.addField(FormBuilder.singleSelection(
|
||||
SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ALIAS,
|
||||
FORM_ENCRYPT_CERT_KEY,
|
||||
clientConfig.encryptCertificateAlias,
|
||||
() -> this.pageService.getResourceService().identityCertificatesResources()))
|
||||
.withDefaultSpanInput(3)
|
||||
.withDefaultSpanLabel(1)
|
||||
.addField(FormBuilder.checkbox(
|
||||
SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ASYM,
|
||||
FORM_ENCRYPT_CERTIFICATE_ASYM,
|
||||
(BooleanUtils.isTrue(clientConfig.encryptCertificateAsym))
|
||||
? Constants.TRUE_STRING
|
||||
: Constants.FALSE_STRING)
|
||||
.withRightLabel()
|
||||
.withEmptyCellSeparation(false))
|
||||
.withDefaultSpanEmptyCell(1)
|
||||
.withDefaultSpanLabel(2)
|
||||
.withDefaultSpanInput(2)
|
||||
.addField(FormBuilder.text(
|
||||
SEBClientConfig.ATTR_PING_INTERVAL,
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.form;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
|
@ -17,6 +15,9 @@ import org.eclipse.swt.widgets.Button;
|
|||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
|
||||
public class CheckboxFieldBuilder extends FieldBuilder<String> {
|
||||
|
||||
protected CheckboxFieldBuilder(
|
||||
|
@ -27,15 +28,31 @@ public class CheckboxFieldBuilder extends FieldBuilder<String> {
|
|||
super(name, label, value);
|
||||
}
|
||||
|
||||
public FieldBuilder<?> withRightLabel() {
|
||||
this.rightLabel = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
void build(final FormBuilder builder) {
|
||||
final boolean readonly = builder.readonly || this.readonly;
|
||||
final Control titleLabel = createTitleLabel(builder.formParent, builder, this);
|
||||
final Composite fieldGrid = createFieldGrid(builder.formParent, this.spanInput);
|
||||
final Button checkbox = builder.widgetFactory.buttonLocalized(
|
||||
fieldGrid,
|
||||
SWT.CHECK,
|
||||
null, null);
|
||||
Control titleLabel = null;
|
||||
Composite fieldGrid;
|
||||
Button checkbox;
|
||||
if (this.rightLabel) {
|
||||
fieldGrid = createFieldGrid(builder.formParent, this.spanInput, false);
|
||||
checkbox = builder.widgetFactory.buttonLocalized(
|
||||
fieldGrid,
|
||||
SWT.CHECK,
|
||||
this.label, this.tooltip);
|
||||
} else {
|
||||
titleLabel = createTitleLabel(builder.formParent, builder, this);
|
||||
fieldGrid = createFieldGrid(builder.formParent, this.spanInput);
|
||||
checkbox = builder.widgetFactory.buttonLocalized(
|
||||
fieldGrid,
|
||||
SWT.CHECK,
|
||||
null, null);
|
||||
}
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
|
||||
checkbox.setLayoutData(gridData);
|
||||
|
|
|
@ -39,6 +39,7 @@ public abstract class FieldBuilder<T> {
|
|||
boolean visible = true;
|
||||
String defaultLabel = null;
|
||||
boolean isMandatory = false;
|
||||
boolean rightLabel = false;
|
||||
|
||||
final String name;
|
||||
final LocTextKey label;
|
||||
|
@ -195,8 +196,12 @@ public abstract class FieldBuilder<T> {
|
|||
}
|
||||
|
||||
public static Composite createFieldGrid(final Composite parent, final int hspan) {
|
||||
return createFieldGrid(parent, hspan, false);
|
||||
}
|
||||
|
||||
public static Composite createFieldGrid(final Composite parent, final int hspan, final boolean rightLabel) {
|
||||
final Composite fieldGrid = new Composite(parent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout();
|
||||
final GridLayout gridLayout = new GridLayout((rightLabel) ? 2 : 1, true);
|
||||
gridLayout.verticalSpacing = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
|
|
|
@ -222,7 +222,7 @@ public class CertificateDAOImpl implements CertificateDAO {
|
|||
}
|
||||
|
||||
// dataEncipherment
|
||||
if (keyUsage[3]) {
|
||||
if (keyUsage[2] || keyUsage[3]) {
|
||||
final String alias = certificates.keyStore.engineGetCertificateAlias(cert);
|
||||
if (this.cryptor.getPrivateKey(certificates.keyStore, alias).hasValue()) {
|
||||
result.add(CertificateType.DATA_ENCIPHERMENT_PRIVATE_KEY);
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
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.ErrorMessage;
|
||||
|
@ -431,6 +432,7 @@ public class SEBClientConfigDAOImpl implements SEBClientConfigDAO {
|
|||
additionalAttributes.containsKey(SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ALIAS)
|
||||
? additionalAttributes.get(SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ALIAS).getValue()
|
||||
: null,
|
||||
additionalAttributes.containsKey(SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ASYM),
|
||||
BooleanUtils.toBooleanObject(record.getActive())));
|
||||
}
|
||||
|
||||
|
@ -608,6 +610,19 @@ public class SEBClientConfigDAOImpl implements SEBClientConfigDAO {
|
|||
configId,
|
||||
SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ALIAS);
|
||||
}
|
||||
|
||||
if (BooleanUtils.isTrue(sebClientConfig.encryptCertificateAsym)) {
|
||||
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||
EntityType.SEB_CLIENT_CONFIGURATION,
|
||||
configId,
|
||||
SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ASYM,
|
||||
Constants.TRUE_STRING);
|
||||
} else {
|
||||
this.additionalAttributesDAO.delete(
|
||||
EntityType.SEB_CLIENT_CONFIGURATION,
|
||||
configId,
|
||||
SEBClientConfig.ATTR_ENCRYPT_CERTIFICATE_ASYM);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncrypti
|
|||
* within a concrete strategy. */
|
||||
public interface SEBConfigEncryptionContext {
|
||||
|
||||
/** Get the institution identifier */
|
||||
Long institutionId();
|
||||
|
||||
/** Get the current encryption/decryption strategy
|
||||
*
|
||||
* @return the current encryption/decryption strategy */
|
||||
|
|
|
@ -40,7 +40,6 @@ public interface SEBConfigEncryptionService {
|
|||
PASSWORD_PWCC(Type.PASSWORD, "pwcc"),
|
||||
/** Encryption with public/private asymmetric keys and symmetric key */
|
||||
PUBLIC_KEY_HASH_SYMMETRIC_KEY(Type.CERTIFICATE, "phsk"),
|
||||
// NOTE not supported yet but eventually needed for SEB config import.
|
||||
/** Encryption with public/private key */
|
||||
PUBLIC_KEY_HASH(Type.CERTIFICATE, "pkhs");
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.cert.Certificate;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
public abstract class AbstractCertificateCryptor {
|
||||
|
||||
protected static final int PUBLIC_KEY_HASH_SIZE = 20;
|
||||
protected static final int ENCRYPTION_KEY_BITS = 256;
|
||||
protected static final int KEY_LENGTH_SIZE = 4;
|
||||
|
||||
protected byte[] generatePublicKeyHash(final Certificate cert) {
|
||||
|
||||
try {
|
||||
final org.bouncycastle.asn1.x509.Certificate bcCert =
|
||||
org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded());
|
||||
final byte[] bytes = bcCert.getSubjectPublicKeyInfo().getPublicKeyData().getBytes();
|
||||
return DigestUtils.sha1(bytes);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Failed to generate public key hash:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] encryptWithCert(final Certificate cert, final byte[] data) throws Exception {
|
||||
return encryptWithCert(cert, data, data.length);
|
||||
}
|
||||
|
||||
protected byte[] encryptWithCert(final Certificate cert, final byte[] data, final int length) throws Exception {
|
||||
final String algorithm = cert.getPublicKey().getAlgorithm();
|
||||
final Cipher encryptCipher = Cipher.getInstance(algorithm);
|
||||
encryptCipher.init(Cipher.ENCRYPT_MODE, cert);
|
||||
return encryptCipher.doFinal(data, 0, length);
|
||||
}
|
||||
|
||||
protected byte[] decryptWithCert(final Certificate cert, final byte[] encryptedData) throws Exception {
|
||||
final String algorithm = cert.getPublicKey().getAlgorithm();
|
||||
final Cipher encryptCipher = Cipher.getInstance(algorithm);
|
||||
encryptCipher.init(Cipher.DECRYPT_MODE, cert);
|
||||
return encryptCipher.doFinal(encryptedData);
|
||||
}
|
||||
|
||||
protected byte[] parsePublicKeyHash(final InputStream input) throws IOException {
|
||||
final byte[] publicKeyHash = new byte[PUBLIC_KEY_HASH_SIZE];
|
||||
input.read(publicKeyHash, 0, publicKeyHash.length);
|
||||
return publicKeyHash;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
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.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionContext;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionService.Strategy;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@WebServiceProfile
|
||||
public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor implements SEBConfigCryptor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CertificateAsymetricKeyCryptor.class);
|
||||
|
||||
private static final Set<Strategy> STRATEGIES = Utils.immutableSetOf(
|
||||
Strategy.PUBLIC_KEY_HASH);
|
||||
|
||||
@Override
|
||||
public Set<Strategy> strategies() {
|
||||
return STRATEGIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encrypt(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SEBConfigEncryptionContext context) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous certificate asymmetric-key encryption");
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
final Certificate certificate = context.getCertificate();
|
||||
final byte[] publicKeyHash = generatePublicKeyHash(certificate);
|
||||
|
||||
output.write(publicKeyHash, 0, publicKeyHash.length);
|
||||
|
||||
final byte[] buffer = new byte[128];
|
||||
|
||||
int readBytes = input.read(buffer, 0, buffer.length);
|
||||
while (readBytes > 0) {
|
||||
final byte[] encryptedBlock = encryptWithCert(certificate, buffer, readBytes);
|
||||
output.write(encryptedBlock, 0, encryptedBlock.length);
|
||||
readBytes = input.read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Error while trying to stream and encrypt data: ", e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(input);
|
||||
try {
|
||||
output.flush();
|
||||
output.close();
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to close output: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrypt(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SEBConfigEncryptionContext context) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous certificate asymmetric-key decryption");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,12 +11,14 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
|||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Security;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -25,6 +27,8 @@ 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.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo.CertificateFileType;
|
||||
|
@ -35,6 +39,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
|
|||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.CertificateDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService;
|
||||
|
||||
@Lazy
|
||||
|
@ -43,9 +48,15 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateServic
|
|||
public class CertificateServiceImpl implements CertificateService {
|
||||
|
||||
private final CertificateDAO certificateDAO;
|
||||
private final SEBClientConfigDAO sebClientConfigDAO;
|
||||
|
||||
public CertificateServiceImpl(
|
||||
final CertificateDAO certificateDAO,
|
||||
final SEBClientConfigDAO sebClientConfigDAO) {
|
||||
|
||||
public CertificateServiceImpl(final CertificateDAO certificateDAO) {
|
||||
this.certificateDAO = certificateDAO;
|
||||
this.sebClientConfigDAO = sebClientConfigDAO;
|
||||
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -103,6 +114,18 @@ public class CertificateServiceImpl implements CertificateService {
|
|||
|
||||
@Override
|
||||
public Result<EntityKey> removeCertificate(final Long institutionId, final String alias) {
|
||||
|
||||
// TODO check if certificate is in use
|
||||
if (this.sebClientConfigDAO.all(institutionId, true)
|
||||
.getOr(Collections.emptyList())
|
||||
.stream()
|
||||
.filter(config -> alias.equals(config.encryptCertificateAlias))
|
||||
.findFirst()
|
||||
.isPresent()) {
|
||||
|
||||
throw new APIMessageException(APIMessage.ErrorMessage.INTEGRITY_VALIDATION);
|
||||
}
|
||||
|
||||
return this.certificateDAO.removeCertificate(institutionId, alias);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,20 +12,17 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.KeyFactory;
|
||||
import java.nio.ByteOrder;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -33,8 +30,10 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionContext;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionService.Strategy;
|
||||
|
@ -42,26 +41,34 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncrypti
|
|||
@Lazy
|
||||
@Component
|
||||
@WebServiceProfile
|
||||
public class CertificateSymetricKeyCryptor implements SEBConfigCryptor {
|
||||
/** Uses symetric key for encryption of the data and a certificate asymetric key to encrypt
|
||||
* and decrypt the symetric key. All is put together as described here:
|
||||
* https://www.safeexambrowser.org/developer/seb-file-format.html
|
||||
*
|
||||
* <pre>
|
||||
* | “phsk” | public key hash | key length | encrypted key | ... encrypted data ... |
|
||||
* | 0 - 3 | 4 - 23 | 24 - 27 | 28 - (28+kl) | (29+kl) - n |
|
||||
* </pre>
|
||||
*/
|
||||
public class CertificateSymetricKeyCryptor extends AbstractCertificateCryptor implements SEBConfigCryptor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CertificateSymetricKeyCryptor.class);
|
||||
|
||||
private static final Set<Strategy> STRATEGIES = Utils.immutableSetOf(
|
||||
Strategy.PUBLIC_KEY_HASH_SYMMETRIC_KEY);
|
||||
private static final int PUBLIC_KEY_HASH_SIZE = 20;
|
||||
private static final int ENCRYPTION_KEY_BITS = 256;
|
||||
private static final int ENCRYPTION_KEY_LENGTH = 32;
|
||||
private static final int KEY_LENGTH_SIZE = 4;
|
||||
|
||||
private final PasswordEncryptor passwordEncryptor;
|
||||
private final PasswordDecryptor passwordDecryptor;
|
||||
private final CertificateService certificateService;
|
||||
|
||||
public CertificateSymetricKeyCryptor(
|
||||
final PasswordEncryptor passwordEncryptor,
|
||||
final PasswordDecryptor passwordDecryptor) {
|
||||
final PasswordDecryptor passwordDecryptor,
|
||||
final CertificateService certificateService) {
|
||||
|
||||
this.passwordEncryptor = passwordEncryptor;
|
||||
this.passwordDecryptor = passwordDecryptor;
|
||||
this.certificateService = certificateService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,7 +83,7 @@ public class CertificateSymetricKeyCryptor implements SEBConfigCryptor {
|
|||
final SEBConfigEncryptionContext context) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous certificate encryption");
|
||||
log.debug("*** Start streaming asynchronous certificate symmetric-key encryption");
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -93,6 +100,14 @@ public class CertificateSymetricKeyCryptor implements SEBConfigCryptor {
|
|||
|
||||
} catch (final Exception e) {
|
||||
log.error("Error while trying to stream and encrypt data: ", e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(input);
|
||||
try {
|
||||
output.flush();
|
||||
output.close();
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to close output: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,31 +117,75 @@ public class CertificateSymetricKeyCryptor implements SEBConfigCryptor {
|
|||
final InputStream input,
|
||||
final SEBConfigEncryptionContext context) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous certificate symmetric-key decryption");
|
||||
}
|
||||
|
||||
try {
|
||||
final Certificate certificate = context.getCertificate();
|
||||
|
||||
final byte[] publicKeyHash = parsePublicKeyHash(input);
|
||||
final Certificate cert = getCertificateByPublicKeyHash(
|
||||
context.institutionId(),
|
||||
publicKeyHash);
|
||||
final byte[] encryptedKey = getEncryptedKey(input);
|
||||
final byte[] symetricKey = decryptWithCert(cert, encryptedKey);
|
||||
final CharSequence symetricKeyBase64 = Base64.getEncoder().encodeToString(symetricKey);
|
||||
|
||||
this.passwordDecryptor.decrypt(output, input, symetricKeyBase64);
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Error while trying to stream and decrypt data: ", e);
|
||||
} finally {
|
||||
try {
|
||||
output.flush();
|
||||
output.close();
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to close output: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private byte[] generatePublicKeyHash(final Certificate cert)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
byte[] publicKey = cert.getPublicKey().getEncoded();
|
||||
final PublicKey publicKey2 = cert.getPublicKey();
|
||||
final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
final X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
|
||||
final PublicKey _publicKey = keyFactory.generatePublic(keySpec);
|
||||
publicKey = _publicKey.getEncoded();
|
||||
private byte[] getEncryptedKey(final InputStream input) throws IOException {
|
||||
|
||||
final String algorithm = publicKey2.getAlgorithm();
|
||||
final String encodeHex = String.valueOf(Hex.encodeHex(publicKey));
|
||||
final String sha1Hex = DigestUtils.sha1Hex(publicKey);
|
||||
final String sha256Hex = DigestUtils.sha256Hex(publicKey);
|
||||
return DigestUtils.sha1(publicKey);
|
||||
// first get the length of the encrypted key
|
||||
final byte[] keyLength = new byte[KEY_LENGTH_SIZE];
|
||||
input.read(keyLength, 0, keyLength.length);
|
||||
final int keyLengthInt = ByteBuffer
|
||||
.wrap(keyLength)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.getInt();
|
||||
|
||||
// then get the encrypted symmetric key
|
||||
final byte[] encryptedKey = new byte[keyLengthInt];
|
||||
input.read(encryptedKey, 0, encryptedKey.length);
|
||||
return encryptedKey;
|
||||
}
|
||||
|
||||
private Certificate getCertificateByPublicKeyHash(final Long institutionId, final byte[] publicKeyHash) {
|
||||
try {
|
||||
|
||||
final Certificates certs = this.certificateService
|
||||
.getCertificates(institutionId)
|
||||
.getOrThrow();
|
||||
@SuppressWarnings("unchecked")
|
||||
final Iterator<String> asIterator = certs.keyStore
|
||||
.engineAliases()
|
||||
.asIterator();
|
||||
|
||||
while (asIterator.hasNext()) {
|
||||
final Certificate certificate = certs.keyStore.engineGetCertificate(asIterator.next());
|
||||
final byte[] otherPublicKeyHash = generatePublicKeyHash(certificate);
|
||||
if (Objects.equals(otherPublicKeyHash, publicKeyHash)) {
|
||||
return certificate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to get certificate by public key hash: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] generateSymetricKey() throws NoSuchAlgorithmException {
|
||||
|
@ -143,9 +202,10 @@ public class CertificateSymetricKeyCryptor implements SEBConfigCryptor {
|
|||
final byte[] symetricKey) throws Exception {
|
||||
|
||||
final ByteArrayOutputStream data = new ByteArrayOutputStream();
|
||||
final byte[] encryptedKey = generateEncryptedKey(cert, symetricKey);
|
||||
final byte[] encryptedKey = encryptWithCert(cert, symetricKey);
|
||||
final byte[] encryptedKeyLength = ByteBuffer
|
||||
.allocate(KEY_LENGTH_SIZE)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.putInt(encryptedKey.length)
|
||||
.array();
|
||||
|
||||
|
@ -157,18 +217,4 @@ public class CertificateSymetricKeyCryptor implements SEBConfigCryptor {
|
|||
return byteArray;
|
||||
}
|
||||
|
||||
private byte[] generateEncryptedKey(final Certificate cert, final byte[] symetricKey) throws Exception {
|
||||
final String algorithm = cert.getPublicKey().getAlgorithm();
|
||||
final Cipher encryptCipher = Cipher.getInstance(algorithm);
|
||||
encryptCipher.init(Cipher.ENCRYPT_MODE, cert);
|
||||
final byte[] cipherText = encryptCipher.doFinal(symetricKey);
|
||||
return cipherText;
|
||||
}
|
||||
|
||||
private byte[] parsePublicKeyHash(final InputStream input) throws IOException {
|
||||
final byte[] publicKeyHash = new byte[PUBLIC_KEY_HASH_SIZE];
|
||||
input.read(publicKeyHash, 0, publicKeyHash.length);
|
||||
return publicKeyHash;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
|
@ -273,7 +272,7 @@ public class ClientConfigServiceImpl implements ClientConfigService {
|
|||
this.sebConfigEncryptionService.streamEncrypted(
|
||||
zipOut,
|
||||
pIn,
|
||||
EncryptionContext.contextOfPlainText());
|
||||
EncryptionContext.contextOfPlainText(config.institutionId));
|
||||
}
|
||||
|
||||
// ZIP again to finish up
|
||||
|
@ -300,7 +299,10 @@ public class ClientConfigServiceImpl implements ClientConfigService {
|
|||
.getOrThrow();
|
||||
|
||||
return EncryptionContext.contextOf(
|
||||
SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH_SYMMETRIC_KEY,
|
||||
config.institutionId,
|
||||
(config.encryptCertificateAsym)
|
||||
? SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH
|
||||
: SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH_SYMMETRIC_KEY,
|
||||
certificate);
|
||||
}
|
||||
|
||||
|
@ -314,6 +316,7 @@ public class ClientConfigServiceImpl implements ClientConfigService {
|
|||
config.configPurpose)
|
||||
: null;
|
||||
return EncryptionContext.contextOf(
|
||||
config.institutionId,
|
||||
(config.configPurpose == ConfigPurpose.CONFIGURE_CLIENT)
|
||||
? SEBConfigEncryptionService.Strategy.PASSWORD_PWCC
|
||||
: SEBConfigEncryptionService.Strategy.PASSWORD_PSWD,
|
||||
|
@ -503,7 +506,7 @@ public class ClientConfigServiceImpl implements ClientConfigService {
|
|||
private void certificateEncryption(
|
||||
final OutputStream out,
|
||||
final SEBClientConfig config,
|
||||
final InputStream in) throws IOException {
|
||||
final InputStream in) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** SEB client configuration with certificate based encryption");
|
||||
|
@ -511,20 +514,33 @@ public class ClientConfigServiceImpl implements ClientConfigService {
|
|||
|
||||
final boolean withPasswordEncryption = config.hasEncryptionSecret();
|
||||
|
||||
PipedOutputStream passEncryptionOut = null;
|
||||
PipedInputStream passEncryptionIn = null;
|
||||
PipedOutputStream streamOut = null;
|
||||
PipedInputStream streamIn = null;
|
||||
try {
|
||||
streamOut = new PipedOutputStream();
|
||||
streamIn = new PipedInputStream(streamOut);
|
||||
|
||||
if (withPasswordEncryption) {
|
||||
// encrypt with password first
|
||||
passEncryptionOut = new PipedOutputStream();
|
||||
passEncryptionIn = new PipedInputStream(passEncryptionOut);
|
||||
passwordEncryption(passEncryptionOut, config, in);
|
||||
if (withPasswordEncryption) {
|
||||
// encrypt with password first
|
||||
passwordEncryption(streamOut, config, in);
|
||||
} else {
|
||||
// just add plaintext header
|
||||
this.sebConfigEncryptionService.streamEncrypted(
|
||||
streamOut,
|
||||
in,
|
||||
EncryptionContext.contextOfPlainText(config.institutionId));
|
||||
}
|
||||
|
||||
this.sebConfigEncryptionService.streamEncrypted(
|
||||
out,
|
||||
streamIn,
|
||||
buildCertificateEncryptionContext(config));
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while tying to stream certificate encrypted config: ", e);
|
||||
IOUtils.closeQuietly(streamOut);
|
||||
IOUtils.closeQuietly(streamIn);
|
||||
}
|
||||
|
||||
this.sebConfigEncryptionService.streamEncrypted(
|
||||
out,
|
||||
(withPasswordEncryption) ? passEncryptionIn : in,
|
||||
buildCertificateEncryptionContext(config));
|
||||
}
|
||||
|
||||
private void passwordEncryption(
|
||||
|
|
|
@ -225,6 +225,7 @@ public class ExamConfigServiceImpl implements ExamConfigService {
|
|||
cryptOut,
|
||||
cryptIn,
|
||||
EncryptionContext.contextOf(
|
||||
institutionId,
|
||||
Strategy.PASSWORD_PSWD,
|
||||
encryptionPasswordPlaintext));
|
||||
|
||||
|
@ -342,7 +343,7 @@ public class ExamConfigServiceImpl implements ExamConfigService {
|
|||
streamDecrypted = this.sebConfigEncryptionService.streamDecrypted(
|
||||
cryptOut,
|
||||
cryptIn,
|
||||
EncryptionContext.contextOf(password));
|
||||
EncryptionContext.contextOf(config.institutionId, password));
|
||||
|
||||
// if zipped, unzip attach unzip stream first
|
||||
unzippedIn = this.examConfigIO.unzip(plainIn);
|
||||
|
|
|
@ -190,20 +190,28 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption
|
|||
|
||||
static class EncryptionContext implements SEBConfigEncryptionContext {
|
||||
|
||||
public final Long institutionId;
|
||||
public final Strategy strategy;
|
||||
public final CharSequence password;
|
||||
public final Certificate certificate;
|
||||
|
||||
private EncryptionContext(
|
||||
final Long institutionId,
|
||||
final Strategy strategy,
|
||||
final CharSequence password,
|
||||
final Certificate certificate) {
|
||||
|
||||
this.institutionId = institutionId;
|
||||
this.strategy = strategy;
|
||||
this.password = password;
|
||||
this.certificate = certificate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long institutionId() {
|
||||
return this.institutionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Strategy getStrategy() {
|
||||
return this.strategy;
|
||||
|
@ -220,19 +228,21 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption
|
|||
}
|
||||
|
||||
static SEBConfigEncryptionContext contextOf(
|
||||
final Long institutionId,
|
||||
final Strategy strategy,
|
||||
final CharSequence password) {
|
||||
|
||||
checkPasswordBased(strategy);
|
||||
return new EncryptionContext(strategy, password, null);
|
||||
return new EncryptionContext(institutionId, strategy, password, null);
|
||||
}
|
||||
|
||||
static SEBConfigEncryptionContext contextOf(
|
||||
final Long institutionId,
|
||||
final Strategy strategy,
|
||||
final Certificate certificate) {
|
||||
|
||||
checkCertificateBased(strategy);
|
||||
return new EncryptionContext(strategy, null, certificate);
|
||||
return new EncryptionContext(institutionId, strategy, null, certificate);
|
||||
}
|
||||
|
||||
static void checkPasswordBased(final Strategy strategy) {
|
||||
|
@ -247,12 +257,16 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption
|
|||
}
|
||||
}
|
||||
|
||||
public static SEBConfigEncryptionContext contextOfPlainText() {
|
||||
return new EncryptionContext(Strategy.PLAIN_TEXT, null, null);
|
||||
public static SEBConfigEncryptionContext contextOfPlainText(final Long institutionId) {
|
||||
|
||||
return new EncryptionContext(institutionId, Strategy.PLAIN_TEXT, null, null);
|
||||
}
|
||||
|
||||
public static SEBConfigEncryptionContext contextOf(final CharSequence password) {
|
||||
return new EncryptionContext(null, password, null);
|
||||
public static SEBConfigEncryptionContext contextOf(
|
||||
final Long institutionId,
|
||||
final CharSequence password) {
|
||||
|
||||
return new EncryptionContext(institutionId, null, password, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ZipServiceImpl implements ZipService {
|
|||
log.error("Error while streaming data to zipped output: ", e);
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
IOUtils.closeQuietly(in);
|
||||
if (zipOutputStream != null) {
|
||||
zipOutputStream.flush();
|
||||
zipOutputStream.close();
|
||||
|
|
|
@ -193,7 +193,7 @@ public class CertificateController {
|
|||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public CertificateInfo loadCertificate(
|
||||
public CertificateInfo importCertificate(
|
||||
@RequestParam(
|
||||
name = API.PARAM_INSTITUTION_ID,
|
||||
required = true,
|
||||
|
|
|
@ -731,7 +731,8 @@ sebserver.clientconfig.form.sebConfigPurpose=Configuration Purpose
|
|||
sebserver.clientconfig.form.sebConfigPurpose.tooltip=This indicates whether this connection configuration shall be used to configure the SEB Client or to start an exam
|
||||
sebserver.clientconfig.form.certificate=Encrypt with Certificate
|
||||
sebserver.clientconfig.form.certificate.tooltip=Choose identity certificate to be used for encrypting the connection configuration
|
||||
|
||||
sebserver.clientconfig.form.type.async=Use asymmetric-only encryption
|
||||
sebserver.clientconfig.form.type.async.tooltip=Use old asymmetric-only encryption (for SEB < 2.2)
|
||||
|
||||
sebserver.clientconfig.config.purpose.START_EXAM=Starting an Exam
|
||||
sebserver.clientconfig.config.purpose.START_EXAM.tooltip=If the connection configuration is loaded via a SEB-Link, the local configuration will not be overwritten.
|
||||
|
@ -1562,6 +1563,7 @@ sebserver.certificate.action.import.missing-password=The certificate file needs
|
|||
sebserver.certificate.action.import-config.confirm=Certificate(s) successfully imported
|
||||
sebserver.certificate.message.error.file=Unsupported file type
|
||||
sebserver.certificate.action.import-file-select.no=Please select a valid file
|
||||
sebserver.certificate.action.remove.in-use=This certificate is in use and cannot be removed.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ public class ModelObjectJSONGenerator {
|
|||
"encryptSecret",
|
||||
"encryptSecretConfirm",
|
||||
"certAlias",
|
||||
false,
|
||||
true);
|
||||
System.out.println(domainObject.getClass().getSimpleName() + ":");
|
||||
System.out.println(writerWithDefaultPrettyPrinter.writeValueAsString(domainObject));
|
||||
|
|
|
@ -125,6 +125,7 @@ public class ClientConfigTest extends GuiIntegrationTest {
|
|||
"password",
|
||||
null,
|
||||
"certAlias",
|
||||
false,
|
||||
null))
|
||||
.call();
|
||||
|
||||
|
@ -155,6 +156,7 @@ public class ClientConfigTest extends GuiIntegrationTest {
|
|||
"password",
|
||||
"password",
|
||||
"certAlias",
|
||||
false,
|
||||
null))
|
||||
.call()
|
||||
.getOrThrow();
|
||||
|
|
|
@ -74,6 +74,7 @@ public class PasswordEncryptorTest {
|
|||
final ByteArrayOutputStream out = new ByteArrayOutputStream(512);
|
||||
|
||||
final SEBConfigEncryptionContext context = EncryptionContext.contextOf(
|
||||
1L,
|
||||
Strategy.PASSWORD_PWCC,
|
||||
pwd);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public class SebConfigEncryptionServiceImplTest {
|
|||
.streamEncrypted(
|
||||
out,
|
||||
IOUtils.toInputStream(config, "UTF-8"),
|
||||
EncryptionContext.contextOfPlainText());
|
||||
EncryptionContext.contextOfPlainText(1L));
|
||||
|
||||
final byte[] plainWithHeader = out.toByteArray();
|
||||
assertNotNull(plainWithHeader);
|
||||
|
@ -50,7 +50,7 @@ public class SebConfigEncryptionServiceImplTest {
|
|||
sebConfigEncryptionServiceImpl.streamDecrypted(
|
||||
out2,
|
||||
new ByteArrayInputStream(plainWithHeader),
|
||||
EncryptionContext.contextOf(Strategy.PASSWORD_PSWD, (CharSequence) null));
|
||||
EncryptionContext.contextOf(1L, Strategy.PASSWORD_PSWD, (CharSequence) null));
|
||||
|
||||
out2.close();
|
||||
|
||||
|
@ -74,6 +74,7 @@ public class SebConfigEncryptionServiceImplTest {
|
|||
out,
|
||||
IOUtils.toInputStream(config, "UTF-8"),
|
||||
EncryptionContext.contextOf(
|
||||
1L,
|
||||
Strategy.PASSWORD_PWCC,
|
||||
pwd));
|
||||
|
||||
|
@ -87,7 +88,7 @@ public class SebConfigEncryptionServiceImplTest {
|
|||
sebConfigEncryptionServiceImpl.streamDecrypted(
|
||||
out2,
|
||||
new ByteArrayInputStream(byteArray),
|
||||
EncryptionContext.contextOf(Strategy.PASSWORD_PSWD, pwd));
|
||||
EncryptionContext.contextOf(1L, Strategy.PASSWORD_PSWD, pwd));
|
||||
|
||||
final byte[] byteArray2 = out2.toByteArray();
|
||||
assertNotNull(byteArray2);
|
||||
|
|
Loading…
Reference in a new issue