Artifact Encryption plug point (#1202)

* added ArtifactEncryption interface, injected it into SM creation UI module, added encryption metadata key generation upon SM creation, used encryptor during file upload

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* add default artifact encryption implementation based on gcm aes algorithm

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* changed ArtifactEncryptor interface to manage encryption secrets by itself

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* cleaned up stale code, fixed sonar

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* fixed software module encryption within transaction

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added artifact encryption secrets store

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* extended ArtifactEncryption interface to allow decryption, secrets store provides removeSecret, added missing javadocs

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* intriduced DbArtifact interface, use EncryptionAwareDbArtifact for artifact decryption during download

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* introduced ArtifactEncryptionService to minimize duplications and unneccessary dependency injections

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* declared ArtifactEncryptionService as a bean

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added persistant encryption flag to software module

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* further adptations for encryption flag persistence

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added ArtifactEncryptionException, fixed encryption check in UI

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added encryption error handling

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added encrypted flag to DDI/DMF, adapted exception handling

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* adapted rest docs

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* Add test to verify artifact encryption is not given by default

Signed-off-by: Florian Ruschbaschan <Florian.Ruschbaschan@bosch.io>

* Add isEncrypted() to toString() of JpaSoftwareModule, fix typos

Signed-off-by: Florian Ruschbaschan <Florian.Ruschbaschan@bosch.io>

* Fix sql migration scripts

Signed-off-by: Florian Ruschbaschan <Florian.Ruschbaschan@bosch.io>

* Calculate encrypted artifact size by subtract encryption size overhead

Signed-off-by: Florian Ruschbaschan <Florian.Ruschbaschan@bosch.io>

* publish upload failed without waiting for interuption during UI file upload

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* upgraded cron utils to 9.1.6

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

Co-authored-by: Florian Ruschbaschan <Florian.Ruschbaschan@bosch.io>
This commit is contained in:
Bondar Bogdan
2021-11-18 09:07:05 +01:00
committed by GitHub
parent 7e28fba104
commit 146735012a
74 changed files with 1214 additions and 324 deletions

View File

@@ -8,6 +8,18 @@
*/
package org.eclipse.hawkbit.amqp;
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.api.ApiType;
import org.eclipse.hawkbit.api.ArtifactUrl;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
@@ -55,18 +67,6 @@ import org.springframework.context.event.EventListener;
import org.springframework.data.domain.PageRequest;
import org.springframework.util.CollectionUtils;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
/**
* {@link AmqpMessageDispatcherService} create all outgoing AMQP messages and
* delegate the messages to a {@link AmqpMessageSenderService}.
@@ -105,8 +105,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
* @param targetManagement
* to access target information
* @param serviceMatcher
* to check in cluster case if the message is from the same cluster
* node
* to check in cluster case if the message is from the same
* cluster node
* @param distributionSetManagement
* to retrieve modules
*/
@@ -129,8 +129,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
/**
* Method to send a message to a RabbitMQ Exchange after the Distribution set
* has been assign to a Target.
* Method to send a message to a RabbitMQ Exchange after the Distribution
* set has been assign to a Target.
*
* @param assignedEvent
* the object to be send.
@@ -257,9 +257,9 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
/**
* Method to get the type of event depending on whether the action is a
* DOWNLOAD_ONLY action or if it has a valid maintenance window available or not
* based on defined maintenance schedule. In case of no maintenance schedule or
* if there is a valid window available, the topic
* DOWNLOAD_ONLY action or if it has a valid maintenance window available or
* not based on defined maintenance schedule. In case of no maintenance
* schedule or if there is a valid window available, the topic
* {@link EventTopic#DOWNLOAD_AND_INSTALL} is returned else
* {@link EventTopic#DOWNLOAD} is returned.
*
@@ -275,8 +275,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
/**
* Determines the {@link EventTopic} for the given {@link Action}, depending on
* its action type.
* Determines the {@link EventTopic} for the given {@link Action}, depending
* on its action type.
*
* @param action
* to obtain the corresponding {@link EventTopic} for
@@ -291,8 +291,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
/**
* Method to send a message to a RabbitMQ Exchange after the assignment of the
* Distribution set to a Target has been canceled.
* Method to send a message to a RabbitMQ Exchange after the assignment of
* the Distribution set to a Target has been canceled.
*
* @param cancelEvent
* that is to be converted to a DMF message
@@ -315,11 +315,12 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
/**
* Method to send a message to a RabbitMQ Exchange after a Target was deleted.
* Method to send a message to a RabbitMQ Exchange after a Target was
* deleted.
*
* @param deleteEvent
* the TargetDeletedEvent which holds the necessary data for sending
* a target delete message.
* the TargetDeletedEvent which holds the necessary data for
* sending a target delete message.
*/
@EventListener(classes = TargetDeletedEvent.class)
protected void targetDelete(final TargetDeletedEvent deleteEvent) {
@@ -345,7 +346,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
return;
}
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = createDownloadAndUpdateRequest(target, action.getId(), modules);
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = createDownloadAndUpdateRequest(target,
action.getId(), modules);
final Message message = getMessageConverter().toMessage(downloadAndUpdateRequest,
createConnectorMessagePropertiesEvent(tenant, target.getControllerId(), getEventTypeForTarget(action)));
amqpSenderService.sendMessage(message, targetAddress);
@@ -445,6 +447,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
amqpSoftwareModule.setModuleId(entry.getKey().getId());
amqpSoftwareModule.setModuleType(entry.getKey().getType().getKey());
amqpSoftwareModule.setModuleVersion(entry.getKey().getVersion());
amqpSoftwareModule.setEncrypted(entry.getKey().isEncrypted() ? Boolean.TRUE : null);
amqpSoftwareModule.setArtifacts(convertArtifacts(target, entry.getKey().getArtifacts()));
if (!CollectionUtils.isEmpty(entry.getValue())) {

View File

@@ -150,8 +150,8 @@ public class AmqpControllerAuthenticationTest {
authenticationManager.postConstruct();
testArtifact = new JpaArtifact(SHA1, "afilename", new JpaSoftwareModule(
new JpaSoftwareModuleType("a key", "a name", null, 1), "a name", null, null, null));
testArtifact = new JpaArtifact(SHA1, "afilename",
new JpaSoftwareModule(new JpaSoftwareModuleType("a key", "a name", null, 1), "a name", "a version"));
testArtifact.setId(1L);
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate,
@@ -260,7 +260,7 @@ public class AmqpControllerAuthenticationTest {
when(tenantConfigurationManagementMock.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE);
.thenReturn(CONFIG_VALUE_TRUE);
when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter);

View File

@@ -32,6 +32,8 @@ public class DmfSoftwareModule {
@JsonProperty
private String moduleVersion;
@JsonProperty
private Boolean encrypted;
@JsonProperty
private List<DmfArtifact> artifacts;
@JsonProperty
private List<DmfMetadata> metadata;
@@ -83,11 +85,18 @@ public class DmfSoftwareModule {
}
}
public Boolean getEncrypted() {
return encrypted;
}
public void setEncrypted(final Boolean encrypted) {
this.encrypted = encrypted;
}
@Override
public String toString() {
return String.format(
"DmfSoftwareModule [moduleId=%d, moduleType='%s', moduleVersion='%s', artifacts=%s, metadata=%s]",
moduleId, moduleType, moduleVersion, artifacts, metadata);
"DmfSoftwareModule [moduleId=%d, moduleType='%s', moduleVersion='%s', encrypted='%s' artifacts=%s, metadata=%s]",
moduleId, moduleType, moduleVersion, encrypted, artifacts, metadata);
}
}