diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java index 02e87f028..06700835d 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java @@ -27,6 +27,7 @@ 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.tenancy.TenantAware; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.AmqpRejectAndDontRequeueException; @@ -63,6 +64,8 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService { private final ControllerManagement controllerManagement; + private final TenantAware tenantAware; + /** * @param rabbitTemplate * the configured amqp template. @@ -76,17 +79,20 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService { * for target authentication * @param controllerManagement * for target repo access + * @param tenantAware + * to access current tenant */ public AmqpAuthenticationMessageHandler(final RabbitTemplate rabbitTemplate, final AmqpControllerAuthentication authenticationManager, final ArtifactManagement artifactManagement, final DownloadIdCache cache, final HostnameResolver hostnameResolver, - final ControllerManagement controllerManagement) { + final ControllerManagement controllerManagement, final TenantAware tenantAware) { super(rabbitTemplate); this.authenticationManager = authenticationManager; this.artifactManagement = artifactManagement; this.cache = cache; this.hostnameResolver = hostnameResolver; this.controllerManagement = controllerManagement; + this.tenantAware = tenantAware; } /** @@ -210,9 +216,9 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService { // SHA1 key is set, download by SHA1 final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1, sha1Hash); cache.put(downloadId, downloadCache); - authentificationResponse - .setDownloadUrl(UriComponentsBuilder.fromUri(hostnameResolver.resolveHostname().toURI()) - .path("/api/v1/downloadserver/downloadId/").path(downloadId).build().toUriString()); + authentificationResponse.setDownloadUrl(UriComponentsBuilder + .fromUri(hostnameResolver.resolveHostname().toURI()).path("/api/v1/downloadserver/downloadId/") + .path(tenantAware.getCurrentTenant()).path(downloadId).build().toUriString()); authentificationResponse.setResponseCode(HttpStatus.OK.value()); } catch (final BadCredentialsException | AuthenticationServiceException | CredentialsExpiredException e) { LOG.error("Login failed", e); diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java index fd35b87a7..88122059f 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java @@ -242,28 +242,16 @@ public class AmqpConfiguration { /** * Create AMQP handler service bean for authentication messages. - * - * @param rabbitTemplate - * for converting messages - * @param authenticationManager - * for target authentication - * @param artifactManagement - * for artifact URI generation - * @param downloadIdCache - * for download IDs - * @param hostnameResolver - * for resolving the host for downloads - * @param controllerManagement - * for target repo access + * * @return handler service bean */ @Bean - public AmqpAuthenticationMessageHandler amqpAuthenticationMessageHandler(final RabbitTemplate rabbitTemplate, + AmqpAuthenticationMessageHandler amqpAuthenticationMessageHandler(final RabbitTemplate rabbitTemplate, final AmqpControllerAuthentication authenticationManager, final ArtifactManagement artifactManagement, final DownloadIdCache downloadIdCache, final HostnameResolver hostnameResolver, - final ControllerManagement controllerManagement) { + final ControllerManagement controllerManagement, final TenantAware tenantAware) { return new AmqpAuthenticationMessageHandler(rabbitTemplate, authenticationManager, artifactManagement, - downloadIdCache, hostnameResolver, controllerManagement); + downloadIdCache, hostnameResolver, controllerManagement, tenantAware); } /** diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java index f8a7d65e2..e26206954 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java @@ -41,10 +41,10 @@ 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.DdiSecurityProperties.Authentication.Anonymous; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp; import org.eclipse.hawkbit.security.SecurityContextTenantAware; import org.eclipse.hawkbit.security.SystemSecurityContext; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -170,7 +170,7 @@ public class AmqpControllerAuthenticationTest { amqpAuthenticationMessageHandlerService = new AmqpAuthenticationMessageHandler(rabbitTemplate, authenticationManager, artifactManagementMock, cacheMock, hostnameResolverMock, - controllerManagementMock); + controllerManagementMock, tenantAware); when(hostnameResolverMock.resolveHostname()).thenReturn(new URL("http://localhost")); @@ -181,8 +181,8 @@ public class AmqpControllerAuthenticationTest { @Test @Description("Tests authentication manager without principal") public void testAuthenticationeBadCredantialsWithoutPricipal() { - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1(SHA1)); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1(SHA1)); try { authenticationManager.doAuthenticate(securityToken); fail("BadCredentialsException was excepeted since principal was missing"); @@ -195,8 +195,8 @@ public class AmqpControllerAuthenticationTest { @Test @Description("Tests authentication manager without wrong credential") public void testAuthenticationBadCredantialsWithWrongCredential() { - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1(SHA1)); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1(SHA1)); when(tenantConfigurationManagementMock.getConfigurationValue( eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class))) .thenReturn(CONFIG_VALUE_TRUE); @@ -213,8 +213,8 @@ public class AmqpControllerAuthenticationTest { @Test @Description("Tests authentication successfull") public void testSuccessfullAuthentication() { - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1(SHA1)); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1(SHA1)); when(tenantConfigurationManagementMock.getConfigurationValue( eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class))) .thenReturn(CONFIG_VALUE_TRUE); @@ -228,8 +228,8 @@ public class AmqpControllerAuthenticationTest { public void testAuthenticationMessageBadCredantialsWithoutPricipal() { final MessageProperties messageProperties = createMessageProperties(null); - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1(SHA1)); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1(SHA1)); final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, messageProperties); @@ -246,8 +246,8 @@ public class AmqpControllerAuthenticationTest { @Description("Tests authentication message without wrong credential") public void testAuthenticationMessageBadCredantialsWithWrongCredential() { final MessageProperties messageProperties = createMessageProperties(null); - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1(SHA1)); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1(SHA1)); when(tenantConfigurationManagementMock.getConfigurationValue( eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class))) .thenReturn(CONFIG_VALUE_TRUE); @@ -324,8 +324,8 @@ public class AmqpControllerAuthenticationTest { @Description("Tests authentication message successfull") public void successfullMessageAuthenticationWithTenantid() { final MessageProperties messageProperties = createMessageProperties(null); - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(null, TENANT_ID, CONTROLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1(SHA1)); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(null, TENANT_ID, CONTROLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1(SHA1)); when(tenantConfigurationManagementMock.getConfigurationValue( eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class))) .thenReturn(CONFIG_VALUE_TRUE); diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java index 5b1f576ad..9cc315033 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java @@ -53,6 +53,7 @@ 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.SecurityTokenGenerator; +import org.eclipse.hawkbit.tenancy.TenantAware; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -115,6 +116,9 @@ public class AmqpMessageHandlerServiceTest { @Mock private RabbitTemplate rabbitTemplate; + @Mock + private TenantAware tenantAwareMock; + @Captor private ArgumentCaptor> attributesCaptor; @@ -134,7 +138,7 @@ public class AmqpMessageHandlerServiceTest { controllerManagementMock, entityFactoryMock); amqpAuthenticationMessageHandlerService = new AmqpAuthenticationMessageHandler(rabbitTemplate, authenticationManagerMock, artifactManagementMock, downloadIdCache, hostnameResolverMock, - controllerManagementMock); + controllerManagementMock, tenantAwareMock); } @Test @@ -315,8 +319,8 @@ public class AmqpMessageHandlerServiceTest { @Description("Tests that an download request is denied for an artifact which does not exists") public void authenticationRequestDeniedForArtifactWhichDoesNotExists() { final MessageProperties messageProperties = createMessageProperties(null); - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1("12345")); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1("12345")); final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, messageProperties); @@ -334,8 +338,8 @@ public class AmqpMessageHandlerServiceTest { @Description("Tests that an download request is denied for an artifact which is not assigned to the requested target") public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() { final MessageProperties messageProperties = createMessageProperties(null); - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1("12345")); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1("12345")); final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, messageProperties); @@ -358,8 +362,8 @@ public class AmqpMessageHandlerServiceTest { @Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target") public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() throws MalformedURLException { final MessageProperties messageProperties = createMessageProperties(null); - final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, - FileResource.createFileResourceBySha1("12345")); + final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, + TARGET_ID, FileResource.createFileResourceBySha1("12345")); final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, messageProperties); diff --git a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadRestApi.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadRestApi.java index 4a31f78e4..e329b1127 100644 --- a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadRestApi.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDownloadRestApi.java @@ -26,6 +26,8 @@ public interface MgmtDownloadRestApi { /** * Handles the GET request for downloading an artifact. * + * @param tenant + * the download belongs to * @param downloadId * the generated download id * @param response @@ -35,6 +37,7 @@ public interface MgmtDownloadRestApi { */ @RequestMapping(method = RequestMethod.GET, value = MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING) @ResponseBody - ResponseEntity downloadArtifactByDownloadId(@PathVariable("downloadId") String downloadId); + ResponseEntity downloadArtifactByDownloadId(@PathVariable("tenant") String tenant, + @PathVariable("downloadId") String downloadId); } diff --git a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java index f1d0bddf3..648fdc66f 100644 --- a/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java +++ b/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRestConstants.java @@ -46,7 +46,7 @@ public final class MgmtRestConstants { public static final String DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE = "/api/" + API_VERSION + "/downloadserver/"; - public static final String DOWNLOAD_ID_V1_REQUEST_MAPPING = "downloadId/{downloadId}"; + public static final String DOWNLOAD_ID_V1_REQUEST_MAPPING = "/downloadId/{tenant}/{downloadId}"; /** * The base URL mapping for the spring acuator management context path. diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java index 6fcbf1da7..e06cc3b11 100644 --- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java @@ -20,7 +20,6 @@ import org.eclipse.hawkbit.cache.DownloadIdCache; import org.eclipse.hawkbit.cache.DownloadType; import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadRestApi; import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; -import org.eclipse.hawkbit.tenancy.TenantAware; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -54,20 +53,10 @@ public class MgmtDownloadResource implements MgmtDownloadRestApi { @Autowired private RequestResponseContextHolder requestResponseContextHolder; - @Autowired - private TenantAware tenantAware; - - /** - * Handles the GET request for downloading an artifact. - * - * @param downloadId - * the generated download id - * @return {@link ResponseEntity} with status {@link HttpStatus#OK} if - * successful - */ @Override @ResponseBody - public ResponseEntity downloadArtifactByDownloadId(@PathVariable("downloadId") final String downloadId) { + public ResponseEntity downloadArtifactByDownloadId(@PathVariable("tenant") final String tenant, + @PathVariable("downloadId") final String downloadId) { try { final DownloadArtifactCache artifactCache = downloadIdCache.get(downloadId); if (artifactCache == null) { @@ -78,7 +67,7 @@ public class MgmtDownloadResource implements MgmtDownloadRestApi { DbArtifact artifact = null; if (DownloadType.BY_SHA1.equals(artifactCache.getDownloadType())) { - artifact = artifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), artifactCache.getId()); + artifact = artifactRepository.getArtifactBySha1(tenant, artifactCache.getId()); } else { LOGGER.warn("Download Type {} not supported", artifactCache.getDownloadType()); } diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java index 0a1c708bf..fcf24be27 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java @@ -51,22 +51,28 @@ public class MgmtDownloadResourceTest extends AbstractManagementApiIntegrationTe @Test @Description("This test verifies the call of download artifact without a valid download id fails.") public void testNoDownloadIdAvailable() throws Exception { - mvc.perform(get(MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE - + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, downloadIdNotAvailable)) - .andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()); + mvc.perform(get( + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, + tenantAware.getCurrentTenant(), downloadIdNotAvailable)).andDo(MockMvcResultPrinter.print()) + .andExpect(status().isNotFound()); } @Test @Description("This test verifies the call of download artifact works and the download id will be removed.") public void testDownload() throws Exception { - mvc.perform(get(MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE - + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, downloadIdSha1)).andDo(MockMvcResultPrinter.print()) + mvc.perform(get( + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, + tenantAware.getCurrentTenant(), downloadIdSha1)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // because cache is empty - mvc.perform(get(MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE - + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, downloadIdSha1)).andDo(MockMvcResultPrinter.print()) + mvc.perform(get( + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, + tenantAware.getCurrentTenant(), downloadIdSha1)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); }