Make download url for DMF tenant aware. (#542)

* Make download url for DMF tenant aware.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix test.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
Kai Zimmermann
2017-06-16 13:01:12 +02:00
committed by GitHub
parent 8d17d21259
commit 6f81e3f251
8 changed files with 60 additions and 64 deletions

View File

@@ -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);

View File

@@ -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);
}
/**

View File

@@ -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);

View File

@@ -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<Map<String, String>> 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);

View File

@@ -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<Void> downloadArtifactByDownloadId(@PathVariable("downloadId") String downloadId);
ResponseEntity<Void> downloadArtifactByDownloadId(@PathVariable("tenant") String tenant,
@PathVariable("downloadId") String downloadId);
}

View File

@@ -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.

View File

@@ -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<Void> downloadArtifactByDownloadId(@PathVariable("downloadId") final String downloadId) {
public ResponseEntity<Void> 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());
}

View File

@@ -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());
}