Remove DMF API dependency from security integration (#604)
* Dmf security token out of API. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Allow to override dispatching routines. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * TargetAssign event is bulk ready. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Completed Javadoc. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * readibility and fix serialization bug. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Fix sonar issue. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Simplify artifact management usage. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -13,20 +13,18 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.eclipse.hawkbit.api.HostnameResolver;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.AbstractDbArtifact;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
||||
import org.eclipse.hawkbit.cache.DownloadArtifactCache;
|
||||
import org.eclipse.hawkbit.cache.DownloadIdCache;
|
||||
import org.eclipse.hawkbit.cache.DownloadType;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfArtifact;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfArtifactHash;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadResponse;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -188,54 +186,53 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static DmfArtifact convertDbArtifact(final AbstractDbArtifact dbArtifact) {
|
||||
private static DmfArtifact convertDbArtifact(final Artifact dbArtifact) {
|
||||
final DmfArtifact artifact = new DmfArtifact();
|
||||
artifact.setSize(dbArtifact.getSize());
|
||||
final DbArtifactHash dbArtifactHash = dbArtifact.getHashes();
|
||||
artifact.setHashes(new DmfArtifactHash(dbArtifactHash.getSha1(), dbArtifactHash.getMd5()));
|
||||
artifact.setHashes(new DmfArtifactHash(dbArtifact.getSha1Hash(), dbArtifact.getMd5Hash()));
|
||||
return artifact;
|
||||
}
|
||||
|
||||
private Message handleAuthenticationMessage(final Message message) {
|
||||
final DmfDownloadResponse authentificationResponse = new DmfDownloadResponse();
|
||||
final DmfDownloadResponse authenticationResponse = new DmfDownloadResponse();
|
||||
final DmfTenantSecurityToken secruityToken = convertMessage(message, DmfTenantSecurityToken.class);
|
||||
final FileResource fileResource = secruityToken.getFileResource();
|
||||
try {
|
||||
SecurityContextHolder.getContext().setAuthentication(authenticationManager.doAuthenticate(secruityToken));
|
||||
|
||||
final String sha1Hash = findArtifactByFileResource(fileResource).map(Artifact::getSha1Hash)
|
||||
final Artifact artifact = findArtifactByFileResource(fileResource)
|
||||
.orElseThrow(EntityNotFoundException::new);
|
||||
|
||||
checkIfArtifactIsAssignedToTarget(secruityToken, sha1Hash);
|
||||
checkIfArtifactIsAssignedToTarget(secruityToken, artifact.getSha1Hash());
|
||||
|
||||
final DmfArtifact artifact = convertDbArtifact(artifactManagement.loadArtifactBinary(sha1Hash)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Artifact.class, sha1Hash)));
|
||||
final DmfArtifact dmfArtifact = convertDbArtifact(artifact);
|
||||
|
||||
authentificationResponse.setArtifact(artifact);
|
||||
authenticationResponse.setArtifact(dmfArtifact);
|
||||
final String downloadId = UUID.randomUUID().toString();
|
||||
// SHA1 key is set, download by SHA1
|
||||
final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1, sha1Hash);
|
||||
final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1,
|
||||
artifact.getSha1Hash());
|
||||
cache.put(downloadId, downloadCache);
|
||||
authentificationResponse.setDownloadUrl(UriComponentsBuilder
|
||||
authenticationResponse.setDownloadUrl(UriComponentsBuilder
|
||||
.fromUri(hostnameResolver.resolveHostname().toURI()).path("/api/v1/downloadserver/downloadId/")
|
||||
.path(tenantAware.getCurrentTenant()).path("/").path(downloadId).build().toUriString());
|
||||
authentificationResponse.setResponseCode(HttpStatus.OK.value());
|
||||
authenticationResponse.setResponseCode(HttpStatus.OK.value());
|
||||
} catch (final BadCredentialsException | AuthenticationServiceException | CredentialsExpiredException e) {
|
||||
LOG.error("Login failed", e);
|
||||
authentificationResponse.setResponseCode(HttpStatus.FORBIDDEN.value());
|
||||
authentificationResponse.setMessage("Login failed");
|
||||
authenticationResponse.setResponseCode(HttpStatus.FORBIDDEN.value());
|
||||
authenticationResponse.setMessage("Login failed");
|
||||
} catch (final URISyntaxException e) {
|
||||
LOG.error("URI build exception", e);
|
||||
authentificationResponse.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
authentificationResponse.setMessage("Building download URI failed");
|
||||
authenticationResponse.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
authenticationResponse.setMessage("Building download URI failed");
|
||||
} catch (final EntityNotFoundException e) {
|
||||
final String errorMessage = "Artifact for resource " + fileResource + "not found ";
|
||||
LOG.warn(errorMessage, e);
|
||||
authentificationResponse.setResponseCode(HttpStatus.NOT_FOUND.value());
|
||||
authentificationResponse.setMessage(errorMessage);
|
||||
authenticationResponse.setResponseCode(HttpStatus.NOT_FOUND.value());
|
||||
authenticationResponse.setMessage(errorMessage);
|
||||
}
|
||||
|
||||
return getMessageConverter().toMessage(authentificationResponse, message.getMessageProperties());
|
||||
return getMessageConverter().toMessage(authenticationResponse, message.getMessageProperties());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.eclipse.hawkbit.cache.DownloadIdCache;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
@@ -305,31 +306,14 @@ public class AmqpConfiguration {
|
||||
tenantAware, ddiSecruityProperties, systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the dispatcher bean.
|
||||
*
|
||||
* @param rabbitTemplate
|
||||
* the rabbitTemplate
|
||||
* @param amqpSenderService
|
||||
* to send AMQP message
|
||||
* @param artifactUrlHandler
|
||||
* for generating download URLs
|
||||
* @param systemSecurityContext
|
||||
* for execution with system permissions
|
||||
* @param systemManagement
|
||||
* the systemManagement
|
||||
* @param targetManagement
|
||||
* to access target information
|
||||
* @return the bean
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AmqpMessageDispatcherService.class)
|
||||
public AmqpMessageDispatcherService amqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
|
||||
AmqpMessageDispatcherService amqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
|
||||
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
|
||||
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
|
||||
final TargetManagement targetManagement) {
|
||||
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement) {
|
||||
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
|
||||
systemSecurityContext, systemManagement, targetManagement, serviceMatcher);
|
||||
systemSecurityContext, systemManagement, targetManagement, serviceMatcher, distributionSetManagement);
|
||||
}
|
||||
|
||||
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {
|
||||
|
||||
@@ -12,7 +12,6 @@ import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
@@ -23,6 +22,7 @@ import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousFilter;
|
||||
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedGatewaySecurityTokenFilter;
|
||||
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedSecurityHeaderFilter;
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
|
||||
import org.eclipse.hawkbit.security.PreAuthentificationFilter;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfArtifact;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfArtifactHash;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||
@@ -64,6 +65,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
private final SystemManagement systemManagement;
|
||||
private final TargetManagement targetManagement;
|
||||
private final ServiceMatcher serviceMatcher;
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -83,11 +85,14 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
* @param serviceMatcher
|
||||
* to check in cluster case if the message is from the same
|
||||
* cluster node
|
||||
* @param distributionSetManagement
|
||||
* to retrieve modules
|
||||
*/
|
||||
public AmqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
|
||||
protected AmqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
|
||||
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
|
||||
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
|
||||
final TargetManagement targetManagement, final ServiceMatcher serviceMatcher) {
|
||||
final TargetManagement targetManagement, final ServiceMatcher serviceMatcher,
|
||||
final DistributionSetManagement distributionSetManagement) {
|
||||
super(rabbitTemplate);
|
||||
this.artifactUrlHandler = artifactUrlHandler;
|
||||
this.amqpSenderService = amqpSenderService;
|
||||
@@ -95,6 +100,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
this.systemManagement = systemManagement;
|
||||
this.targetManagement = targetManagement;
|
||||
this.serviceMatcher = serviceMatcher;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,21 +111,54 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
* the object to be send.
|
||||
*/
|
||||
@EventListener(classes = TargetAssignDistributionSetEvent.class)
|
||||
public void targetAssignDistributionSet(final TargetAssignDistributionSetEvent assignedEvent) {
|
||||
protected void targetAssignDistributionSet(final TargetAssignDistributionSetEvent assignedEvent) {
|
||||
if (isNotFromSelf(assignedEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.debug("targetAssignDistributionSet retrieved for controller {}. I will forward it to DMF broker.",
|
||||
assignedEvent.getControllerId());
|
||||
LOG.debug("targetAssignDistributionSet retrieved. I will forward it to DMF broker.");
|
||||
|
||||
targetManagement.getByControllerID(assignedEvent.getControllerId())
|
||||
.ifPresent(target -> sendUpdateMessageToTarget(assignedEvent.getTenant(), target,
|
||||
assignedEvent.getActionId(), assignedEvent.getModules()));
|
||||
distributionSetManagement.get(assignedEvent.getDistributionSetId()).ifPresent(set ->
|
||||
|
||||
targetManagement.getByControllerID(assignedEvent.getActions().keySet())
|
||||
.forEach(target -> sendUpdateMessageToTarget(assignedEvent.getTenant(), target,
|
||||
assignedEvent.getActions().get(target.getControllerId()), set.getModules())));
|
||||
}
|
||||
|
||||
void sendUpdateMessageToTarget(final String tenant, final Target target, final Long actionId,
|
||||
/**
|
||||
* Method to send a message to a RabbitMQ Exchange after the assignment of
|
||||
* the Distribution set to a Target has been canceled.
|
||||
*
|
||||
* @param cancelEvent
|
||||
* the object to be send.
|
||||
*/
|
||||
@EventListener(classes = CancelTargetAssignmentEvent.class)
|
||||
protected void targetCancelAssignmentToDistributionSet(final CancelTargetAssignmentEvent cancelEvent) {
|
||||
if (isNotFromSelf(cancelEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendCancelMessageToTarget(cancelEvent.getTenant(), cancelEvent.getEntity().getControllerId(),
|
||||
cancelEvent.getActionId(), cancelEvent.getEntity().getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@EventListener(classes = TargetDeletedEvent.class)
|
||||
protected void targetDelete(final TargetDeletedEvent deleteEvent) {
|
||||
if (isNotFromSelf(deleteEvent)) {
|
||||
return;
|
||||
}
|
||||
sendDeleteMessage(deleteEvent.getTenant(), deleteEvent.getControllerId(), deleteEvent.getTargetAddress());
|
||||
}
|
||||
|
||||
protected void sendUpdateMessageToTarget(final String tenant, final Target target, final Long actionId,
|
||||
final Collection<SoftwareModule> modules) {
|
||||
|
||||
final URI targetAdress = target.getAddress();
|
||||
@@ -144,7 +183,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
amqpSenderService.sendMessage(message, targetAdress);
|
||||
}
|
||||
|
||||
void sendPingReponseToDmfReceiver(final Message ping, final String tenant, final String virtualHost) {
|
||||
protected void sendPingReponseToDmfReceiver(final Message ping, final String tenant, final String virtualHost) {
|
||||
final Message message = MessageBuilder.withBody(String.valueOf(System.currentTimeMillis()).getBytes())
|
||||
.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
|
||||
.setCorrelationId(ping.getMessageProperties().getCorrelationId())
|
||||
@@ -155,40 +194,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
IpUtil.createAmqpUri(virtualHost, ping.getMessageProperties().getReplyTo()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to send a message to a RabbitMQ Exchange after the assignment of
|
||||
* the Distribution set to a Target has been canceled.
|
||||
*
|
||||
* @param cancelEvent
|
||||
* the object to be send.
|
||||
*/
|
||||
@EventListener(classes = CancelTargetAssignmentEvent.class)
|
||||
public void targetCancelAssignmentToDistributionSet(final CancelTargetAssignmentEvent cancelEvent) {
|
||||
if (isNotFromSelf(cancelEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendCancelMessageToTarget(cancelEvent.getTenant(), cancelEvent.getEntity().getControllerId(),
|
||||
cancelEvent.getActionId(), cancelEvent.getEntity().getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@EventListener(classes = TargetDeletedEvent.class)
|
||||
public void targetDelete(final TargetDeletedEvent deleteEvent) {
|
||||
if (isNotFromSelf(deleteEvent)) {
|
||||
return;
|
||||
}
|
||||
sendDeleteMessage(deleteEvent.getTenant(), deleteEvent.getControllerId(), deleteEvent.getTargetAddress());
|
||||
}
|
||||
|
||||
void sendDeleteMessage(final String tenant, final String controllerId, final String targetAddress) {
|
||||
protected void sendDeleteMessage(final String tenant, final String controllerId, final String targetAddress) {
|
||||
|
||||
if (!hasValidAddress(targetAddress)) {
|
||||
return;
|
||||
@@ -206,7 +212,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
return serviceMatcher != null && !serviceMatcher.isFromSelf(event);
|
||||
}
|
||||
|
||||
void sendCancelMessageToTarget(final String tenant, final String controllerId, final Long actionId,
|
||||
protected void sendCancelMessageToTarget(final String tenant, final String controllerId, final Long actionId,
|
||||
final URI address) {
|
||||
if (!IpUtil.isAmqpUri(address)) {
|
||||
return;
|
||||
|
||||
@@ -28,8 +28,6 @@ import org.eclipse.hawkbit.cache.DownloadIdCache;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadResponse;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
@@ -42,7 +40,9 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.repository.model.TenantMetaData;
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication.Anonymous;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp;
|
||||
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
|
||||
@@ -108,28 +108,14 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
||||
when(systemManagement.getTenantMetadata()).thenReturn(tenantMetaData);
|
||||
|
||||
amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService,
|
||||
artifactUrlHandlerMock, systemSecurityContext, systemManagement, targetManagement, serviceMatcher);
|
||||
artifactUrlHandlerMock, systemSecurityContext, systemManagement, targetManagement, serviceMatcher,
|
||||
distributionSetManagement);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that download and install event with no software modul works")
|
||||
public void testSendDownloadRequesWithEmptySoftwareModules() {
|
||||
|
||||
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
|
||||
"DEFAULT", 1L, 1L, CONTROLLER_ID, serviceMatcher.getServiceId());
|
||||
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
|
||||
|
||||
final Message sendMessage = getCaptureAdressEvent(targetAssignDistributionSetEvent);
|
||||
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, 1L);
|
||||
assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN);
|
||||
assertTrue("No softwaremmodule should be contained in the request",
|
||||
downloadAndUpdateRequest.getSoftwareModules().isEmpty());
|
||||
}
|
||||
|
||||
private Message getCaptureAdressEvent(final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent) {
|
||||
final Target target = targetManagement.getByControllerID(targetAssignDistributionSetEvent.getControllerId())
|
||||
.get();
|
||||
final Target target = targetManagement
|
||||
.getByControllerID(targetAssignDistributionSetEvent.getActions().keySet().iterator().next()).get();
|
||||
final Message sendMessage = createArgumentCapture(target.getAddress());
|
||||
return sendMessage;
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.api.HostnameResolver;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.AbstractDbArtifact;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
||||
import org.eclipse.hawkbit.cache.DownloadIdCache;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
|
||||
@@ -38,8 +36,6 @@ import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfActionUpdateStatus;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadResponse;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
@@ -52,6 +48,8 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.junit.Before;
|
||||
@@ -370,15 +368,12 @@ public class AmqpMessageHandlerServiceTest {
|
||||
// mock
|
||||
final Artifact localArtifactMock = mock(Artifact.class);
|
||||
when(localArtifactMock.getSha1Hash()).thenReturn(SHA1);
|
||||
when(localArtifactMock.getMd5Hash()).thenReturn("md5");
|
||||
when(localArtifactMock.getSize()).thenReturn(1L);
|
||||
|
||||
final AbstractDbArtifact dbArtifactMock = mock(AbstractDbArtifact.class);
|
||||
when(artifactManagementMock.findFirstBySHA1(SHA1)).thenReturn(Optional.of(localArtifactMock));
|
||||
when(controllerManagementMock.hasTargetArtifactAssigned(securityToken.getControllerId(), SHA1))
|
||||
.thenReturn(true);
|
||||
when(artifactManagementMock.loadArtifactBinary(anyString())).thenReturn(Optional.of(dbArtifactMock));
|
||||
when(dbArtifactMock.getArtifactId()).thenReturn("artifactId");
|
||||
when(dbArtifactMock.getSize()).thenReturn(1L);
|
||||
when(dbArtifactMock.getHashes()).thenReturn(new DbArtifactHash(SHA1, "md5"));
|
||||
when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost"));
|
||||
|
||||
// test
|
||||
|
||||
@@ -18,8 +18,6 @@ import org.eclipse.hawkbit.amqp.AmqpProperties;
|
||||
import org.eclipse.hawkbit.amqp.DmfApiConfiguration;
|
||||
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadResponse;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.dmf.json.model.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.rabbitmq.test.AbstractAmqpIntegrationTest;
|
||||
import org.eclipse.hawkbit.rabbitmq.test.AmqpTestConfiguration;
|
||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||
@@ -28,6 +26,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.dmf.json.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* JSON representation to authenticate a tenant.
|
||||
*/
|
||||
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class DmfTenantSecurityToken {
|
||||
|
||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
@JsonProperty(required = false)
|
||||
private String tenant;
|
||||
@JsonProperty(required = false)
|
||||
private final Long tenantId;
|
||||
@JsonProperty(required = false)
|
||||
private final String controllerId;
|
||||
@JsonProperty(required = false)
|
||||
private final Long targetId;
|
||||
|
||||
@JsonProperty(required = false)
|
||||
private Map<String, String> headers;
|
||||
|
||||
@JsonProperty(required = false)
|
||||
private final FileResource fileResource;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param tenant
|
||||
* the tenant for the security token
|
||||
* @param tenantId
|
||||
* alternative tenant identification by technical ID
|
||||
* @param controllerId
|
||||
* the ID of the controller for the security token
|
||||
* @param targetId
|
||||
* alternative target identification by technical ID
|
||||
* @param fileResource
|
||||
* the file to obtain
|
||||
*/
|
||||
@JsonCreator
|
||||
public DmfTenantSecurityToken(@JsonProperty("tenant") final String tenant,
|
||||
@JsonProperty("tenantId") final Long tenantId, @JsonProperty("controllerId") final String controllerId,
|
||||
@JsonProperty("targetId") final Long targetId,
|
||||
@JsonProperty("fileResource") final FileResource fileResource) {
|
||||
this.tenant = tenant;
|
||||
this.tenantId = tenantId;
|
||||
this.controllerId = controllerId;
|
||||
this.targetId = targetId;
|
||||
this.fileResource = fileResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param tenant
|
||||
* the tenant for the security token
|
||||
* @param controllerId
|
||||
* the ID of the controller for the security token
|
||||
* @param fileResource
|
||||
* the file to obtain
|
||||
*/
|
||||
public DmfTenantSecurityToken(final String tenant, final String controllerId, final FileResource fileResource) {
|
||||
this(tenant, null, controllerId, null, fileResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param tenantId
|
||||
* the tenant for the security token
|
||||
* @param targetId
|
||||
* target identification by technical ID
|
||||
* @param fileResource
|
||||
* the file to obtain
|
||||
*/
|
||||
public DmfTenantSecurityToken(final Long tenantId, final Long targetId, final FileResource fileResource) {
|
||||
this(null, tenantId, null, targetId, fileResource);
|
||||
}
|
||||
|
||||
public void setTenant(final String tenant) {
|
||||
this.tenant = tenant;
|
||||
}
|
||||
|
||||
public String getTenant() {
|
||||
return tenant;
|
||||
}
|
||||
|
||||
public String getControllerId() {
|
||||
return controllerId;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
if (headers == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(headers);
|
||||
}
|
||||
|
||||
public FileResource getFileResource() {
|
||||
return fileResource;
|
||||
}
|
||||
|
||||
public Long getTenantId() {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
public Long getTargetId() {
|
||||
return targetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a header value.
|
||||
*
|
||||
* @param name
|
||||
* of header
|
||||
* @return the value
|
||||
*/
|
||||
public String getHeader(final String name) {
|
||||
if (headers == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return headers.get(name);
|
||||
}
|
||||
|
||||
public void setHeaders(final Map<String, String> headers) {
|
||||
this.headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
this.headers.putAll(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the specified header value with the specified name.
|
||||
*
|
||||
* @param name
|
||||
* of the header
|
||||
* @param value
|
||||
* of the header
|
||||
*
|
||||
* @return the previous value associated with the <tt>name</tt>, or
|
||||
* <tt>null</tt> if there was no mapping for <tt>name</tt>.
|
||||
*/
|
||||
public String putHeader(final String name, final String value) {
|
||||
if (headers == null) {
|
||||
headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
}
|
||||
return headers.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* File resource descriptor which is used to ask for the resource to
|
||||
* download e.g. The lookup of the file can be different e.g. by SHA1 hash
|
||||
* or by filename.
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class FileResource {
|
||||
@JsonProperty(required = false)
|
||||
private String sha1;
|
||||
@JsonProperty(required = false)
|
||||
private Long artifactId;
|
||||
@JsonProperty(required = false)
|
||||
private String filename;
|
||||
@JsonProperty(required = false)
|
||||
private SoftwareModuleFilenameResource softwareModuleFilenameResource;
|
||||
|
||||
public String getSha1() {
|
||||
return sha1;
|
||||
}
|
||||
|
||||
public void setSha1(final String sha1) {
|
||||
this.sha1 = sha1;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public void setFilename(final String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public SoftwareModuleFilenameResource getSoftwareModuleFilenameResource() {
|
||||
return softwareModuleFilenameResource;
|
||||
}
|
||||
|
||||
public void setSoftwareModuleFilenameResource(
|
||||
final SoftwareModuleFilenameResource softwareModuleFilenameResource) {
|
||||
this.softwareModuleFilenameResource = softwareModuleFilenameResource;
|
||||
}
|
||||
|
||||
public Long getArtifactId() {
|
||||
return artifactId;
|
||||
}
|
||||
|
||||
public void setArtifactId(final Long artifactId) {
|
||||
this.artifactId = artifactId;
|
||||
}
|
||||
|
||||
/**
|
||||
* factory method to create a file resource for an SHA1 lookup.
|
||||
*
|
||||
* @param sha1
|
||||
* the SHA1 key of the file to obtain
|
||||
* @return the {@link FileResource} with SHA1 key set
|
||||
*/
|
||||
public static FileResource createFileResourceBySha1(final String sha1) {
|
||||
final FileResource resource = new FileResource();
|
||||
resource.sha1 = sha1;
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* factory method to create a file resource for an artifact ID lookup.
|
||||
*
|
||||
* @param artifactId
|
||||
* the artifact IF key of the file to obtain
|
||||
* @return the {@link FileResource} with SHA1 key set
|
||||
*/
|
||||
public static FileResource createFileResourceByArtifactId(final Long artifactId) {
|
||||
final FileResource resource = new FileResource();
|
||||
resource.artifactId = artifactId;
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* factory method to create a file resource for an filename lookup.
|
||||
*
|
||||
* @param filename
|
||||
* the filename of the file to obtain
|
||||
* @return the {@link FileResource} with filename set
|
||||
*/
|
||||
public static FileResource createFileResourceByFilename(final String filename) {
|
||||
final FileResource resource = new FileResource();
|
||||
resource.filename = filename;
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* factory method to create a file resource for an softwaremodule +
|
||||
* filename lookup, because an filename is not globally unique but
|
||||
* within a softwaremodule.
|
||||
*
|
||||
* @param softwareModuleId
|
||||
* the ID of the software module which contains the artifact
|
||||
* @param filename
|
||||
* the name of file to obtain within the software module
|
||||
* @return the {@link FileResource} with artifactId set
|
||||
*/
|
||||
public static FileResource softwareModuleFilename(final Long softwareModuleId, final String filename) {
|
||||
final FileResource resource = new FileResource();
|
||||
resource.softwareModuleFilenameResource = new SoftwareModuleFilenameResource(softwareModuleId, filename);
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FileResource [sha1=" + sha1 + ", artifactId=" + artifactId + ", filename=" + filename + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class which holds the pointer to an artifact based on the
|
||||
* softwaremoduleId and the filename.
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class SoftwareModuleFilenameResource {
|
||||
@JsonProperty(required = false)
|
||||
private Long softwareModuleId;
|
||||
@JsonProperty(required = false)
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param softwareModuleId
|
||||
* the ID of the softwaremodule
|
||||
* @param filename
|
||||
* the name of the file of the artifact within the
|
||||
* softwaremodule
|
||||
*/
|
||||
@JsonCreator
|
||||
public SoftwareModuleFilenameResource(@JsonProperty("softwareModuleId") final Long softwareModuleId,
|
||||
@JsonProperty("filename") final String filename) {
|
||||
this.softwareModuleId = softwareModuleId;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public Long getSoftwareModuleId() {
|
||||
return softwareModuleId;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public void setSoftwareModuleId(final Long softwareModuleId) {
|
||||
this.softwareModuleId = softwareModuleId;
|
||||
}
|
||||
|
||||
public void setFilename(final String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user