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;
|
||||
|
||||
Reference in New Issue
Block a user