Merge pull request #120 from bsinno/Download_server_supports_download_through_HTTP_and_HTTPs

DDI supports actifact download through http and anonyomous
This commit is contained in:
Michael Hirsch
2016-04-06 08:12:53 +02:00
52 changed files with 1043 additions and 477 deletions

View File

@@ -10,7 +10,6 @@ package org.eclipse.hawkbit.autoconfigure.security;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.Collections;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.servlet.Filter; import javax.servlet.Filter;
@@ -35,6 +34,7 @@ import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSo
import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.DosFilter; import org.eclipse.hawkbit.security.DosFilter;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateAnonymousDownloadFilter;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter;
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedSecurityHeaderFilter; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedSecurityHeaderFilter;
@@ -83,6 +83,8 @@ import org.vaadin.spring.security.web.VaadinRedirectStrategy;
import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler; import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler;
import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler; import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler;
import com.google.common.collect.Lists;
/** /**
* All configurations related to SP authentication and authorization layer. * All configurations related to SP authentication and authorization layer.
* *
@@ -147,6 +149,12 @@ public class SecurityManagedConfiguration {
gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true); gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource); gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
final HttpControllerPreAuthenticateAnonymousDownloadFilter controllerAnonymousDownloadFilter = new HttpControllerPreAuthenticateAnonymousDownloadFilter(
tenantConfigurationManagement, tenantAware, systemSecurityContext);
controllerAnonymousDownloadFilter.setAuthenticationManager(authenticationManager());
controllerAnonymousDownloadFilter.setCheckForPrincipalChanges(true);
controllerAnonymousDownloadFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
HttpSecurity httpSec = http.csrf().disable().headers() HttpSecurity httpSec = http.csrf().disable().headers()
.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY)).contentTypeOptions() .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY)).contentTypeOptions()
.xssProtection().httpStrictTransportSecurity().and(); .xssProtection().httpStrictTransportSecurity().and();
@@ -159,15 +167,17 @@ public class SecurityManagedConfiguration {
LOG.info( LOG.info(
"******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************"); "******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************");
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter( final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter(
"controllerAnonymousFilter", "anonymous", Collections.singletonList( "controllerAnonymousFilter", "anonymous",
new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS))); Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS),
new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE)));
anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource); anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and() httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and()
.securityContext().disable().anonymous().authenticationFilter(anoymousFilter); .securityContext().disable().anonymous().authenticationFilter(anoymousFilter);
} else { } else {
httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter) httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
.addFilter(gatewaySecurityTokenFilter).antMatcher("/*/controller/**").anonymous().disable() .addFilter(gatewaySecurityTokenFilter).addFilter(controllerAnonymousDownloadFilter)
.authorizeRequests().anyRequest().authenticated().and().exceptionHandling() .antMatcher("/*/controller/**").anonymous().disable().authorizeRequests().anyRequest()
.authenticated().and().exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> response .authenticationEntryPoint((request, response, authException) -> response
.setStatus(HttpStatus.UNAUTHORIZED.value())) .setStatus(HttpStatus.UNAUTHORIZED.value()))
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

View File

@@ -0,0 +1,37 @@
/**
* 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.api;
/**
* Interface declaration of the {@link ArtifactUrlHandler} which generates the
* URLs to specific artifacts.
*
*/
@FunctionalInterface
public interface ArtifactUrlHandler {
/**
* Returns a generated download URL for a given artifact parameters for a
* specific protocol.
*
* @param controllerId
* the authenticated controller id
* @param softwareModuleId
* the softwareModuleId belonging to the artifact
* @param filename
* the filename of the artifact
* @param sha1Hash
* the sha1Hash of the artifact
* @param protocol
* the protocol the URL should be generated
* @return an URL for the given artifact parameters in a given protocol
*/
String getUrl(String controllerId, final Long softwareModuleId, final String filename, final String sha1Hash,
final UrlProtocol protocol);
}

View File

@@ -6,13 +6,13 @@
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
*/ */
package org.eclipse.hawkbit.util; package org.eclipse.hawkbit.api;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* * Artifact handler properties class for holding all supported protocols with
* * host, ip, port and download pattern.
*/ */
@ConfigurationProperties("hawkbit.artifact.url") @ConfigurationProperties("hawkbit.artifact.url")
public class ArtifactUrlHandlerProperties { public class ArtifactUrlHandlerProperties {
@@ -23,23 +23,14 @@ public class ArtifactUrlHandlerProperties {
private final Https https = new Https(); private final Https https = new Https();
private final Coap coap = new Coap(); private final Coap coap = new Coap();
/**
* @return the http
*/
public Http getHttp() { public Http getHttp() {
return http; return http;
} }
/**
* @return the https
*/
public Https getHttps() { public Https getHttps() {
return https; return https;
} }
/**
* @return the coap
*/
public Coap getCoap() { public Coap getCoap() {
return coap; return coap;
} }
@@ -66,9 +57,6 @@ public class ArtifactUrlHandlerProperties {
/** /**
* Interface for declaring common properties through all supported protocols * Interface for declaring common properties through all supported protocols
* pattern. * pattern.
*
*
*
*/ */
public interface ProtocolProperties { public interface ProtocolProperties {
/** /**
@@ -94,9 +82,6 @@ public class ArtifactUrlHandlerProperties {
/** /**
* Object to hold the properties for the HTTP protocol. * Object to hold the properties for the HTTP protocol.
*
*
*
*/ */
public static class Http implements ProtocolProperties { public static class Http implements ProtocolProperties {
private String hostname = LOCALHOST; private String hostname = LOCALHOST;
@@ -108,66 +93,38 @@ public class ArtifactUrlHandlerProperties {
*/ */
private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}";
/**
* @return the hostname
*/
@Override @Override
public String getHostname() { public String getHostname() {
return hostname; return hostname;
} }
/**
* @param hostname
* the hostname to set
*/
public void setHostname(final String hostname) { public void setHostname(final String hostname) {
this.hostname = hostname; this.hostname = hostname;
} }
/**
* @return the ip
*/
@Override @Override
public String getIp() { public String getIp() {
return ip; return ip;
} }
/**
* @param ip
* the ip to set
*/
public void setIp(final String ip) { public void setIp(final String ip) {
this.ip = ip; this.ip = ip;
} }
/**
* @return the urlPattern
*/
@Override @Override
public String getPattern() { public String getPattern() {
return pattern; return pattern;
} }
/**
* @param urlPattern
* the urlPattern to set
*/
public void setPattern(final String urlPattern) { public void setPattern(final String urlPattern) {
this.pattern = urlPattern; this.pattern = urlPattern;
} }
/**
* @return the port
*/
@Override @Override
public String getPort() { public String getPort() {
return port; return port;
} }
/**
* @param port
* the port to set
*/
public void setPort(final String port) { public void setPort(final String port) {
this.port = port; this.port = port;
} }
@@ -175,9 +132,6 @@ public class ArtifactUrlHandlerProperties {
/** /**
* Object to hold the properties for the HTTP protocol. * Object to hold the properties for the HTTP protocol.
*
*
*
*/ */
public static class Https implements ProtocolProperties { public static class Https implements ProtocolProperties {
private String hostname = LOCALHOST; private String hostname = LOCALHOST;
@@ -189,66 +143,38 @@ public class ArtifactUrlHandlerProperties {
*/ */
private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; private String pattern = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{targetId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}";
/**
* @return the hostname
*/
@Override @Override
public String getHostname() { public String getHostname() {
return hostname; return hostname;
} }
/**
* @param hostname
* the hostname to set
*/
public void setHostname(final String hostname) { public void setHostname(final String hostname) {
this.hostname = hostname; this.hostname = hostname;
} }
/**
* @return the ip
*/
@Override @Override
public String getIp() { public String getIp() {
return ip; return ip;
} }
/**
* @param ip
* the ip to set
*/
public void setIp(final String ip) { public void setIp(final String ip) {
this.ip = ip; this.ip = ip;
} }
/**
* @return the urlPattern
*/
@Override @Override
public String getPattern() { public String getPattern() {
return pattern; return pattern;
} }
/**
* @param urlPattern
* the urlPattern to set
*/
public void setPattern(final String urlPattern) { public void setPattern(final String urlPattern) {
this.pattern = urlPattern; this.pattern = urlPattern;
} }
/**
* @return the port
*/
@Override @Override
public String getPort() { public String getPort() {
return port; return port;
} }
/**
* @param port
* the port to set
*/
public void setPort(final String port) { public void setPort(final String port) {
this.port = port; this.port = port;
} }
@@ -256,9 +182,6 @@ public class ArtifactUrlHandlerProperties {
/** /**
* Object to hold the properties for the HTTP protocol. * Object to hold the properties for the HTTP protocol.
*
*
*
*/ */
public static class Coap implements ProtocolProperties { public static class Coap implements ProtocolProperties {
private String hostname = LOCALHOST; private String hostname = LOCALHOST;
@@ -270,68 +193,41 @@ public class ArtifactUrlHandlerProperties {
*/ */
private String pattern = "{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}"; private String pattern = "{protocol}://{ip}:{port}/fw/{tenant}/{targetId}/sha1/{artifactSHA1}";
/**
* @return the hostname
*/
@Override @Override
public String getHostname() { public String getHostname() {
return hostname; return hostname;
} }
/**
* @param hostname
* the hostname to set
*/
public void setHostname(final String hostname) { public void setHostname(final String hostname) {
this.hostname = hostname; this.hostname = hostname;
} }
/**
* @return the ip
*/
@Override @Override
public String getIp() { public String getIp() {
return ip; return ip;
} }
/**
* @param ip
* the ip to set
*/
public void setIp(final String ip) { public void setIp(final String ip) {
this.ip = ip; this.ip = ip;
} }
/**
* @return the urlPattern
*/
@Override @Override
public String getPattern() { public String getPattern() {
return pattern; return pattern;
} }
/**
* @param urlPattern
* the urlPattern to set
*/
public void setPattern(final String urlPattern) { public void setPattern(final String urlPattern) {
this.pattern = urlPattern; this.pattern = urlPattern;
} }
/**
* @return the port
*/
@Override @Override
public String getPort() { public String getPort() {
return port; return port;
} }
/**
* @param port
* the port to set
*/
public void setPort(final String port) { public void setPort(final String port) {
this.port = port; this.port = port;
} }
} }
} }

View File

@@ -6,17 +6,15 @@
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
*/ */
package org.eclipse.hawkbit.util; package org.eclipse.hawkbit.api;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import org.eclipse.hawkbit.dmf.json.model.Artifact; import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties.ProtocolProperties;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.util.ArtifactUrlHandlerProperties.ProtocolProperties;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -24,8 +22,8 @@ import org.springframework.stereotype.Component;
import com.google.common.base.Strings; import com.google.common.base.Strings;
/** /**
* * Implementation for ArtifactUrlHandler for creating urls to download resource
* * based on pattern.
*/ */
@Component @Component
@EnableConfigurationProperties(ArtifactUrlHandlerProperties.class) @EnableConfigurationProperties(ArtifactUrlHandlerProperties.class)
@@ -48,7 +46,9 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
private TenantAware tenantAware; private TenantAware tenantAware;
@Override @Override
public String getUrl(final String targetId, final LocalArtifact artifact, final Artifact.UrlProtocol protocol) { public String getUrl(final String targetId, final Long softwareModuleId, final String filename,
final String sha1Hash, final UrlProtocol protocol) {
final String protocolString = protocol.name().toLowerCase(); final String protocolString = protocol.name().toLowerCase();
final ProtocolProperties properties = urlHandlerProperties.getProperties(protocolString); final ProtocolProperties properties = urlHandlerProperties.getProperties(protocolString);
if (properties == null || properties.getPattern() == null) { if (properties == null || properties.getPattern() == null) {
@@ -56,8 +56,8 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
} }
String urlPattern = properties.getPattern(); String urlPattern = properties.getPattern();
final Set<Entry<String, String>> entrySet = getReplaceMap(targetId, artifact, protocolString, properties) final Set<Entry<String, String>> entrySet = getReplaceMap(targetId, softwareModuleId, filename, sha1Hash,
.entrySet(); protocolString, properties).entrySet();
for (final Entry<String, String> entry : entrySet) { for (final Entry<String, String> entry : entrySet) {
if (entry.getKey().equals(PORT_PLACEHOLDER)) { if (entry.getKey().equals(PORT_PLACEHOLDER)) {
urlPattern = urlPattern.replace(":{" + entry.getKey() + "}", urlPattern = urlPattern.replace(":{" + entry.getKey() + "}",
@@ -69,18 +69,18 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
return urlPattern; return urlPattern;
} }
private Map<String, String> getReplaceMap(final String targetId, final LocalArtifact artifact, private Map<String, String> getReplaceMap(final String targetId, final Long softwareModuleId, final String filename,
final String protocol, final ProtocolProperties properties) { final String sha1Hash, final String protocol, final ProtocolProperties properties) {
final Map<String, String> replaceMap = new HashMap<>(); final Map<String, String> replaceMap = new HashMap<>();
replaceMap.put(IP_PLACEHOLDER, properties.getIp()); replaceMap.put(IP_PLACEHOLDER, properties.getIp());
replaceMap.put(HOSTNAME_PLACEHOLDER, properties.getHostname()); replaceMap.put(HOSTNAME_PLACEHOLDER, properties.getHostname());
replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER, artifact.getFilename()); replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER, filename);
replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, artifact.getSha1Hash()); replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, sha1Hash);
replaceMap.put(PROTOCOL_PLACEHOLDER, protocol); replaceMap.put(PROTOCOL_PLACEHOLDER, protocol);
replaceMap.put(PORT_PLACEHOLDER, properties.getPort()); replaceMap.put(PORT_PLACEHOLDER, properties.getPort());
replaceMap.put(TENANT_PLACEHOLDER, tenantAware.getCurrentTenant()); replaceMap.put(TENANT_PLACEHOLDER, tenantAware.getCurrentTenant());
replaceMap.put(TARGET_ID_PLACEHOLDER, targetId); replaceMap.put(TARGET_ID_PLACEHOLDER, targetId);
replaceMap.put(SOFTWARE_MODULE_ID_PLACDEHOLDER, String.valueOf(artifact.getSoftwareModule().getId())); replaceMap.put(SOFTWARE_MODULE_ID_PLACDEHOLDER, String.valueOf(softwareModuleId));
return replaceMap; return replaceMap;
} }

View File

@@ -0,0 +1,16 @@
/**
* 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.api;
/**
* Represented the supported protocols for artifact url's.
*/
public enum UrlProtocol {
COAP, HTTP, HTTPS
}

View File

@@ -30,40 +30,60 @@ public enum TenantConfigurationKey {
/** /**
* boolean value {@code true} {@code false}. * boolean value {@code true} {@code false}.
*/ */
AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled", "hawkbit.server.ddi.security.authentication.header.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled",
"hawkbit.server.ddi.security.authentication.header.enabled", Boolean.class, Boolean.FALSE.toString(),
TenantConfigurationBooleanValidator.class),
/** /**
* *
*/ */
AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority", "hawkbit.server.ddi.security.authentication.header.authority", String.class, Boolean.FALSE.toString(), TenantConfigurationStringValidator.class), AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority",
"hawkbit.server.ddi.security.authentication.header.authority", String.class, Boolean.FALSE.toString(),
TenantConfigurationStringValidator.class),
/** /**
* boolean value {@code true} {@code false}. * boolean value {@code true} {@code false}.
*/ */
AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled", "hawkbit.server.ddi.security.authentication.targettoken.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled",
"hawkbit.server.ddi.security.authentication.targettoken.enabled", Boolean.class, Boolean.FALSE.toString(),
TenantConfigurationBooleanValidator.class),
/** /**
* boolean value {@code true} {@code false}. * boolean value {@code true} {@code false}.
*/ */
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled", "hawkbit.server.ddi.security.authentication.gatewaytoken.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled",
"hawkbit.server.ddi.security.authentication.gatewaytoken.enabled", Boolean.class, Boolean.FALSE.toString(),
TenantConfigurationBooleanValidator.class),
/** /**
* string value which holds the name of the security token key. * string value which holds the name of the security token key.
*/ */
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name", "hawkbit.server.ddi.security.authentication.gatewaytoken.name", String.class, null, TenantConfigurationStringValidator.class), AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name",
"hawkbit.server.ddi.security.authentication.gatewaytoken.name", String.class, null,
TenantConfigurationStringValidator.class),
/** /**
* string value which holds the actual security-key of the gateway security * string value which holds the actual security-key of the gateway security
* token. * token.
*/ */
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key", "hawkbit.server.ddi.security.authentication.gatewaytoken.key", String.class, null, TenantConfigurationStringValidator.class), AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key",
"hawkbit.server.ddi.security.authentication.gatewaytoken.key", String.class, null,
TenantConfigurationStringValidator.class),
/** /**
* string value which holds the polling time interval in the format HH:mm:ss * string value which holds the polling time interval in the format HH:mm:ss
*/ */
POLLING_TIME_INTERVAL("pollingTime", "hawkbit.controller.pollingTime", String.class, null, TenantConfigurationPollingDurationValidator.class), POLLING_TIME_INTERVAL("pollingTime", "hawkbit.controller.pollingTime", String.class, null,
TenantConfigurationPollingDurationValidator.class),
/** /**
* string value which holds the polling time interval in the format HH:mm:ss * string value which holds the polling time interval in the format HH:mm:ss
*/ */
POLLING_OVERDUE_TIME_INTERVAL("pollingOverdueTime", "hawkbit.controller.pollingOverdueTime", String.class, null, TenantConfigurationPollingDurationValidator.class); POLLING_OVERDUE_TIME_INTERVAL("pollingOverdueTime", "hawkbit.controller.pollingOverdueTime", String.class, null,
TenantConfigurationPollingDurationValidator.class),
/**
* boolean value {@code true} {@code false}.
*/
ANONYMOUS_DOWNLOAD_MODE_ENABLED("anonymous.download.enabled", "hawkbit.server.download.anonymous.enabled",
Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class);
private final String keyName; private final String keyName;
private final String defaultKeyName; private final String defaultKeyName;

View File

@@ -25,6 +25,11 @@
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository</artifactId> <artifactId>hawkbit-repository</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-core</artifactId>
<version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>

View File

@@ -13,12 +13,14 @@ import java.util.List;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.security.CoapAnonymousPreAuthenticatedFilter; import org.eclipse.hawkbit.security.CoapAnonymousPreAuthenticatedFilter;
import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter; import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter;
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousDownload;
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedAnonymousFilter;
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedGatewaySecurityTokenFilter; import org.eclipse.hawkbit.security.ControllerPreAuthenticatedGatewaySecurityTokenFilter;
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedSecurityHeaderFilter; import org.eclipse.hawkbit.security.ControllerPreAuthenticatedSecurityHeaderFilter;
import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.DdiSecurityProperties;
@@ -90,6 +92,11 @@ public class AmqpControllerAuthentfication {
tenantConfigurationManagement, controllerManagement, tenantAware, systemSecurityContext); tenantConfigurationManagement, controllerManagement, tenantAware, systemSecurityContext);
filterChain.add(securityTokenFilter); filterChain.add(securityTokenFilter);
final ControllerPreAuthenticatedAnonymousDownload anonymousDownloadFilter = new ControllerPreAuthenticatedAnonymousDownload(
tenantConfigurationManagement, tenantAware, systemSecurityContext);
filterChain.add(anonymousDownloadFilter);
filterChain.add(new ControllerPreAuthenticatedAnonymousFilter(ddiSecruityProperties));
filterChain.add(new CoapAnonymousPreAuthenticatedFilter()); filterChain.add(new CoapAnonymousPreAuthenticatedFilter());
} }
@@ -100,7 +107,7 @@ public class AmqpControllerAuthentfication {
* the authentication request object * the authentication request object
* @return the authentfication object * @return the authentfication object
*/ */
public Authentication doAuthenticate(final TenantSecruityToken secruityToken) { public Authentication doAuthenticate(final TenantSecurityToken secruityToken) {
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(null, null); PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(null, null);
for (final PreAuthenficationFilter filter : filterChain) { for (final PreAuthenficationFilter filter : filterChain) {
final PreAuthenticatedAuthenticationToken authenticationRest = createAuthentication(filter, secruityToken); final PreAuthenticatedAuthenticationToken authenticationRest = createAuthentication(filter, secruityToken);
@@ -115,7 +122,7 @@ public class AmqpControllerAuthentfication {
} }
private static PreAuthenticatedAuthenticationToken createAuthentication(final PreAuthenficationFilter filter, private static PreAuthenticatedAuthenticationToken createAuthentication(final PreAuthenficationFilter filter,
final TenantSecruityToken secruityToken) { final TenantSecurityToken secruityToken) {
if (!filter.isEnable(secruityToken)) { if (!filter.isEnable(secruityToken)) {
return null; return null;

View File

@@ -14,6 +14,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.api.UrlProtocol;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType; import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
@@ -25,7 +27,6 @@ import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent; import org.eclipse.hawkbit.eventbus.event.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.util.ArtifactUrlHandler;
import org.eclipse.hawkbit.util.IpUtil; import org.eclipse.hawkbit.util.IpUtil;
import org.springframework.amqp.core.Message; import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.core.MessageProperties;
@@ -152,12 +153,16 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private Artifact convertArtifact(final String targetId, final LocalArtifact localArtifact) { private Artifact convertArtifact(final String targetId, final LocalArtifact localArtifact) {
final Artifact artifact = new Artifact(); final Artifact artifact = new Artifact();
artifact.getUrls().put(Artifact.UrlProtocol.COAP, artifact.getUrls().put(Artifact.UrlProtocol.COAP,
artifactUrlHandler.getUrl(targetId, localArtifact, Artifact.UrlProtocol.COAP)); artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.COAP));
artifact.getUrls().put(Artifact.UrlProtocol.HTTP, artifact.getUrls().put(Artifact.UrlProtocol.HTTP,
artifactUrlHandler.getUrl(targetId, localArtifact, Artifact.UrlProtocol.HTTP)); artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTP));
artifact.getUrls().put(Artifact.UrlProtocol.HTTPS, artifact.getUrls().put(Artifact.UrlProtocol.HTTPS,
artifactUrlHandler.getUrl(targetId, localArtifact, Artifact.UrlProtocol.HTTPS)); artifactUrlHandler.getUrl(targetId, localArtifact.getSoftwareModule().getId(),
localArtifact.getFilename(), localArtifact.getSha1Hash(), UrlProtocol.HTTPS));
artifact.setFilename(localArtifact.getFilename()); artifact.setFilename(localArtifact.getFilename());
artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), null)); artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), null));

View File

@@ -28,7 +28,8 @@ import org.eclipse.hawkbit.dmf.json.model.ActionUpdateStatus;
import org.eclipse.hawkbit.dmf.json.model.Artifact; import org.eclipse.hawkbit.dmf.json.model.Artifact;
import org.eclipse.hawkbit.dmf.json.model.ArtifactHash; import org.eclipse.hawkbit.dmf.json.model.ArtifactHash;
import org.eclipse.hawkbit.dmf.json.model.DownloadResponse; import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
@@ -157,25 +158,28 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
private Message handleAuthentifiactionMessage(final Message message) { private Message handleAuthentifiactionMessage(final Message message) {
final DownloadResponse authentificationResponse = new DownloadResponse(); final DownloadResponse authentificationResponse = new DownloadResponse();
final MessageProperties messageProperties = message.getMessageProperties(); final MessageProperties messageProperties = message.getMessageProperties();
final TenantSecruityToken secruityToken = convertMessage(message, TenantSecruityToken.class); final TenantSecurityToken secruityToken = convertMessage(message, TenantSecurityToken.class);
final String sha1 = secruityToken.getSha1(); final FileResource fileResource = secruityToken.getFileResource();
try { try {
SecurityContextHolder.getContext().setAuthentication(authenticationManager.doAuthenticate(secruityToken)); SecurityContextHolder.getContext().setAuthentication(authenticationManager.doAuthenticate(secruityToken));
final LocalArtifact localArtifact = artifactManagement
.findFirstLocalArtifactsBySHA1(secruityToken.getSha1()); final LocalArtifact localArtifact = findLocalArtifactByFileResource(fileResource);
if (localArtifact == null) { if (localArtifact == null) {
throw new EntityNotFoundException(); throw new EntityNotFoundException();
} }
// check action for this download purposes, the method will throw an // check action for this download purposes, the method will throw an
// EntityNotFoundException in case the controller is not allowed to // EntityNotFoundException in case the controller is not allowed to
// download this file // download this file because it's not assigned to an action and not
// because it's not assigned to an action and not assigned to this // assigned to this controller. Otherwise no controllerId is set =
// controller. // anonymous download
final Action action = controllerManagement.getActionForDownloadByTargetAndSoftwareModule( if (secruityToken.getControllerId() != null) {
secruityToken.getControllerId(), localArtifact.getSoftwareModule()); final Action action = controllerManagement.getActionForDownloadByTargetAndSoftwareModule(
LOG.info("Found action for download authentication request action: {}, sha1: {}", action, secruityToken.getControllerId(), localArtifact.getSoftwareModule());
secruityToken.getSha1()); LOG.info("Found action for download authentication request action: {}, resource: {}", action,
secruityToken.getFileResource());
}
final Artifact artifact = convertDbArtifact(artifactManagement.loadLocalArtifactBinary(localArtifact)); final Artifact artifact = convertDbArtifact(artifactManagement.loadLocalArtifactBinary(localArtifact));
if (artifact == null) { if (artifact == null) {
@@ -183,7 +187,9 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
} }
authentificationResponse.setArtifact(artifact); authentificationResponse.setArtifact(artifact);
final String downloadId = UUID.randomUUID().toString(); final String downloadId = UUID.randomUUID().toString();
final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1, sha1); // SHA1 key is set, download by SHA1
final DownloadArtifactCache downloadCache = new DownloadArtifactCache(DownloadType.BY_SHA1,
localArtifact.getSha1Hash());
cache.put(downloadId, downloadCache); cache.put(downloadId, downloadCache);
authentificationResponse authentificationResponse
.setDownloadUrl(UriComponentsBuilder.fromUri(hostnameResolver.resolveHostname().toURI()) .setDownloadUrl(UriComponentsBuilder.fromUri(hostnameResolver.resolveHostname().toURI())
@@ -198,7 +204,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
authentificationResponse.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); authentificationResponse.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
authentificationResponse.setMessage("Building download URI failed"); authentificationResponse.setMessage("Building download URI failed");
} catch (final EntityNotFoundException e) { } catch (final EntityNotFoundException e) {
final String errorMessage = "Artifact with sha1 " + sha1 + "not found "; final String errorMessage = "Artifact for resource " + fileResource + "not found ";
LOG.warn(errorMessage, e); LOG.warn(errorMessage, e);
authentificationResponse.setResponseCode(HttpStatus.NOT_FOUND.value()); authentificationResponse.setResponseCode(HttpStatus.NOT_FOUND.value());
authentificationResponse.setMessage(errorMessage); authentificationResponse.setMessage(errorMessage);
@@ -207,6 +213,21 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
return getMessageConverter().toMessage(authentificationResponse, messageProperties); return getMessageConverter().toMessage(authentificationResponse, messageProperties);
} }
private LocalArtifact findLocalArtifactByFileResource(final FileResource fileResource) {
if (fileResource.getSha1() != null) {
return artifactManagement.findFirstLocalArtifactsBySHA1(fileResource.getSha1());
} else if (fileResource.getFilename() != null) {
return artifactManagement.findLocalArtifactByFilename(fileResource.getFilename()).stream().findFirst()
.orElse(null);
} else if (fileResource.getSoftwareModuleFilenameResource() != null) {
return artifactManagement
.findByFilenameAndSoftwareModule(fileResource.getSoftwareModuleFilenameResource().getFilename(),
fileResource.getSoftwareModuleFilenameResource().getSoftwareModuleId())
.stream().findFirst().orElse(null);
}
return null;
}
private static Artifact convertDbArtifact(final DbArtifact dbArtifact) { private static Artifact convertDbArtifact(final DbArtifact dbArtifact) {
final Artifact artifact = new Artifact(); final Artifact artifact = new Artifact();
artifact.setSize(dbArtifact.getSize()); artifact.setSize(dbArtifact.getSize());

View File

@@ -1,35 +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.util;
import org.eclipse.hawkbit.dmf.json.model.Artifact;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
/**
* Interface declaration of the {@link ArtifactUrlHandler} which generates the
* URLs to specific artifacts.
*
*/
@FunctionalInterface
public interface ArtifactUrlHandler {
/**
* Returns a generated URL for a given artifact for a specific protocol.
*
* @param controllerId
* the authentifacted controller id
* @param localArtifact
* the artifact to retrieve a URL to
* @param protocol
* the protocol the URL should be generated
* @return an URL for the given artifact in a given protocol
*/
String getUrl(String controllerId, LocalArtifact localArtifact, final Artifact.UrlProtocol protocol);
}

View File

@@ -19,12 +19,14 @@ import static org.mockito.Mockito.when;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType; import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DownloadResponse; import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication.Anonymous;
import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp; import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp;
import org.eclipse.hawkbit.security.SecurityContextTenantAware; import org.eclipse.hawkbit.security.SecurityContextTenantAware;
import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.security.SystemSecurityContext;
@@ -79,8 +81,14 @@ public class AmqpControllerAuthenticationTest {
final DdiSecurityProperties secruityProperties = mock(DdiSecurityProperties.class); final DdiSecurityProperties secruityProperties = mock(DdiSecurityProperties.class);
final Rp rp = mock(Rp.class); final Rp rp = mock(Rp.class);
final org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication ddiAuthentication = mock(
org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication.class);
final Anonymous anonymous = mock(Anonymous.class);
when(secruityProperties.getRp()).thenReturn(rp); when(secruityProperties.getRp()).thenReturn(rp);
when(rp.getSslIssuerHashHeader()).thenReturn("X-Ssl-Issuer-Hash-%d"); when(rp.getSslIssuerHashHeader()).thenReturn("X-Ssl-Issuer-Hash-%d");
when(secruityProperties.getAuthentication()).thenReturn(ddiAuthentication);
when(ddiAuthentication.getAnonymous()).thenReturn(anonymous);
when(anonymous.isEnabled()).thenReturn(false);
authenticationManager.setSecruityProperties(secruityProperties); authenticationManager.setSecruityProperties(secruityProperties);
tenantConfigurationManagement = mock(TenantConfigurationManagement.class); tenantConfigurationManagement = mock(TenantConfigurationManagement.class);
@@ -105,7 +113,8 @@ public class AmqpControllerAuthenticationTest {
@Test @Test
@Description("Tests authentication manager without principal") @Description("Tests authentication manager without principal")
public void testAuthenticationeBadCredantialsWithoutPricipal() { public void testAuthenticationeBadCredantialsWithoutPricipal() {
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
try { try {
authenticationManager.doAuthenticate(securityToken); authenticationManager.doAuthenticate(securityToken);
fail("BadCredentialsException was excepeted since principal was missing"); fail("BadCredentialsException was excepeted since principal was missing");
@@ -118,11 +127,12 @@ public class AmqpControllerAuthenticationTest {
@Test @Test
@Description("Tests authentication manager without wrong credential") @Description("Tests authentication manager without wrong credential")
public void testAuthenticationBadCredantialsWithWrongCredential() { public void testAuthenticationBadCredantialsWithWrongCredential() {
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
when(tenantConfigurationManagement.getConfigurationValue( when(tenantConfigurationManagement.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class))) eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE); .thenReturn(CONFIG_VALUE_TRUE);
securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID); securityToken.getHeaders().put(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID);
try { try {
authenticationManager.doAuthenticate(securityToken); authenticationManager.doAuthenticate(securityToken);
fail("BadCredentialsException was excepeted due to wrong credential"); fail("BadCredentialsException was excepeted due to wrong credential");
@@ -135,11 +145,12 @@ public class AmqpControllerAuthenticationTest {
@Test @Test
@Description("Tests authentication successfull") @Description("Tests authentication successfull")
public void testSuccessfullAuthentication() { public void testSuccessfullAuthentication() {
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
when(tenantConfigurationManagement.getConfigurationValue( when(tenantConfigurationManagement.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class))) eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE); .thenReturn(CONFIG_VALUE_TRUE);
securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLLER_ID); securityToken.getHeaders().put(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLLER_ID);
final Authentication authentication = authenticationManager.doAuthenticate(securityToken); final Authentication authentication = authenticationManager.doAuthenticate(securityToken);
assertThat(authentication).isNotNull(); assertThat(authentication).isNotNull();
} }
@@ -149,7 +160,8 @@ public class AmqpControllerAuthenticationTest {
public void testAuthenticationMessageBadCredantialsWithoutPricipal() { public void testAuthenticationMessageBadCredantialsWithoutPricipal() {
final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION);
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties); messageProperties);
@@ -167,11 +179,12 @@ public class AmqpControllerAuthenticationTest {
@Description("Tests authentication message without wrong credential") @Description("Tests authentication message without wrong credential")
public void testAuthenticationMessageBadCredantialsWithWrongCredential() { public void testAuthenticationMessageBadCredantialsWithWrongCredential() {
final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION);
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
when(tenantConfigurationManagement.getConfigurationValue( when(tenantConfigurationManagement.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class))) eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE); .thenReturn(CONFIG_VALUE_TRUE);
securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID); securityToken.getHeaders().put(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID);
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties); messageProperties);
@@ -189,11 +202,12 @@ public class AmqpControllerAuthenticationTest {
@Description("Tests authentication message successfull") @Description("Tests authentication message successfull")
public void testSuccessfullMessageAuthentication() { public void testSuccessfullMessageAuthentication() {
final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION);
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, CONTROLLLER_ID,
FileResource.sha1("12345"));
when(tenantConfigurationManagement.getConfigurationValue( when(tenantConfigurationManagement.getConfigurationValue(
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class))) eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
.thenReturn(CONFIG_VALUE_TRUE); .thenReturn(CONFIG_VALUE_TRUE);
securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLLER_ID); securityToken.getHeaders().put(TenantSecurityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLLER_ID);
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties); messageProperties);

View File

@@ -13,6 +13,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
@@ -25,6 +26,7 @@ import java.util.List;
import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.TestDataUtil;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
@@ -36,7 +38,6 @@ import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.util.ArtifactUrlHandler;
import org.eclipse.hawkbit.util.IpUtil; import org.eclipse.hawkbit.util.IpUtil;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@@ -77,7 +78,8 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTestWit
amqpMessageDispatcherService.setAmqpSenderService(senderService); amqpMessageDispatcherService.setAmqpSenderService(senderService);
final ArtifactUrlHandler artifactUrlHandlerMock = Mockito.mock(ArtifactUrlHandler.class); final ArtifactUrlHandler artifactUrlHandlerMock = Mockito.mock(ArtifactUrlHandler.class);
when(artifactUrlHandlerMock.getUrl(anyString(), any(), anyObject())).thenReturn("http://mockurl"); when(artifactUrlHandlerMock.getUrl(anyString(), anyLong(), anyString(), anyString(), anyObject()))
.thenReturn("http://mockurl");
amqpMessageDispatcherService.setArtifactUrlHandler(artifactUrlHandlerMock); amqpMessageDispatcherService.setArtifactUrlHandler(artifactUrlHandlerMock);

View File

@@ -34,7 +34,8 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.ActionStatus; import org.eclipse.hawkbit.dmf.json.model.ActionStatus;
import org.eclipse.hawkbit.dmf.json.model.ActionUpdateStatus; import org.eclipse.hawkbit.dmf.json.model.ActionUpdateStatus;
import org.eclipse.hawkbit.dmf.json.model.DownloadResponse; import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
@@ -263,7 +264,7 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is denied for an artifact which does not exists") @Description("Tests that an download request is denied for an artifact which does not exists")
public void authenticationRequestDeniedForArtifactWhichDoesNotExists() { public void authenticationRequestDeniedForArtifactWhichDoesNotExists() {
final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION);
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, "123", "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.sha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties); messageProperties);
@@ -282,7 +283,7 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is denied for an artifact which is not assigned to the requested target") @Description("Tests that an download request is denied for an artifact which is not assigned to the requested target")
public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() { public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() {
final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION);
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, "123", "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.sha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties); messageProperties);
@@ -306,7 +307,7 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target") @Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target")
public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() throws MalformedURLException { public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() throws MalformedURLException {
final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION); final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION);
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, "123", "12345"); final TenantSecurityToken securityToken = new TenantSecurityToken(TENANT, "123", FileResource.sha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
messageProperties); messageProperties);

View File

@@ -15,7 +15,8 @@ import org.eclipse.hawkbit.AmqpTestConfiguration;
import org.eclipse.hawkbit.RepositoryApplicationConfiguration; import org.eclipse.hawkbit.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.TestConfiguration; import org.eclipse.hawkbit.TestConfiguration;
import org.eclipse.hawkbit.TestDataUtil; import org.eclipse.hawkbit.TestDataUtil;
import org.eclipse.hawkbit.dmf.json.model.Artifact; import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.api.UrlProtocol;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -30,8 +31,7 @@ import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories; import ru.yandex.qatools.allure.annotations.Stories;
/** /**
* * Tests for creating urls to download artifacts.
*
*/ */
@Features("Component Tests - Artifact URL Handler") @Features("Component Tests - Artifact URL Handler")
@Stories("Test to generate the artifact download URL") @Stories("Test to generate the artifact download URL")
@@ -45,6 +45,9 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest
private TenantAware tenantAware; private TenantAware tenantAware;
private LocalArtifact localArtifact; private LocalArtifact localArtifact;
private final String controllerId = "Test"; private final String controllerId = "Test";
private String fileName;
private Long softwareModuleId;
private String sha1Hash;
@Before @Before
public void setup() { public void setup() {
@@ -53,12 +56,18 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest
final SoftwareModule module = dsA.getModules().iterator().next(); final SoftwareModule module = dsA.getModules().iterator().next();
localArtifact = (LocalArtifact) TestDataUtil.generateArtifacts(artifactManagement, module.getId()).stream() localArtifact = (LocalArtifact) TestDataUtil.generateArtifacts(artifactManagement, module.getId()).stream()
.findAny().get(); .findAny().get();
softwareModuleId = localArtifact.getSoftwareModule().getId();
fileName = localArtifact.getFilename();
sha1Hash = localArtifact.getSha1Hash();
} }
@Test @Test
@Description("Tests the generation of http download url.") @Description("Tests the generation of http download url.")
public void testHttpUrl() { public void testHttpUrl() {
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.HTTP);
final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash,
UrlProtocol.HTTP);
assertEquals("http is build incorrect", assertEquals("http is build incorrect",
"http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId "http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId
+ "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/" + "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/"
@@ -69,7 +78,8 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest
@Test @Test
@Description("Tests the generation of https download url.") @Description("Tests the generation of https download url.")
public void testHttpsUrl() { public void testHttpsUrl() {
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.HTTPS); final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash,
UrlProtocol.HTTPS);
assertEquals("https is build incorrect", assertEquals("https is build incorrect",
"https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId "https://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/" + controllerId
+ "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/" + "/softwaremodules/" + localArtifact.getSoftwareModule().getId() + "/artifacts/"
@@ -80,7 +90,8 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest
@Test @Test
@Description("Tests the generation of coap download url.") @Description("Tests the generation of coap download url.")
public void testCoapUrl() { public void testCoapUrl() {
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.COAP); final String url = urlHandlerProperties.getUrl(controllerId, softwareModuleId, fileName, sha1Hash,
UrlProtocol.COAP);
assertEquals("coap is build incorrect", "coap://127.0.0.1:5683/fw/" + tenantAware.getCurrentTenant() + "/" assertEquals("coap is build incorrect", "coap://127.0.0.1:5683/fw/" + tenantAware.getCurrentTenant() + "/"
+ controllerId + "/sha1/" + localArtifact.getSha1Hash(), url); + controllerId + "/sha1/" + localArtifact.getSha1Hash(), url);

View File

@@ -1,94 +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.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 TenantSecruityToken {
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String COAP_AUTHORIZATION_HEADER = "Coap-Authorization";
public static final String COAP_TOKEN_VALUE = "CoapToken";
@JsonProperty
private final String tenant;
@JsonProperty
private final String controllerId;
@JsonProperty(required = false)
private Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@JsonProperty(required = false)
private final String sha1;
/**
* Constructor.
*
* @param tenant
* the tenant for the security token
* @param controllerId
* the ID of the controller for the security token
* @param sha1
* the sha1 of authentication
*/
@JsonCreator
public TenantSecruityToken(@JsonProperty("tenant") final String tenant,
@JsonProperty("controllerId") final String controllerId, @JsonProperty("sha1") final String sha1) {
this.tenant = tenant;
this.controllerId = controllerId;
this.sha1 = sha1;
}
public String getTenant() {
return tenant;
}
public String getControllerId() {
return controllerId;
}
public Map<String, String> getHeaders() {
return headers;
}
public String getSha1() {
return sha1;
}
/**
* Gets a header value.
*
* @param name
* of header
* @return the value
*/
public String getHeader(final String name) {
return headers.get(name);
}
public void setHeaders(final Map<String, String> headers) {
this.headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
this.headers.putAll(headers);
}
}

View File

@@ -0,0 +1,226 @@
/**
* 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.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 TenantSecurityToken {
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String COAP_AUTHORIZATION_HEADER = "Coap-Authorization";
public static final String COAP_TOKEN_VALUE = "CoapToken";
@JsonProperty
private final String tenant;
@JsonProperty
private final String controllerId;
@JsonProperty(required = false)
private Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@JsonProperty(required = false)
private final 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
*/
@JsonCreator
public TenantSecurityToken(@JsonProperty("tenant") final String tenant,
@JsonProperty("controllerId") final String controllerId,
@JsonProperty("fileResource") final FileResource fileResource) {
this.tenant = tenant;
this.controllerId = controllerId;
this.fileResource = fileResource;
}
public String getTenant() {
return tenant;
}
public String getControllerId() {
return controllerId;
}
public Map<String, String> getHeaders() {
return headers;
}
public FileResource getFileResource() {
return fileResource;
}
/**
* Gets a header value.
*
* @param name
* of header
* @return the value
*/
public String getHeader(final String name) {
return headers.get(name);
}
public void setHeaders(final Map<String, String> headers) {
this.headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
this.headers.putAll(headers);
}
/**
* 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 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;
}
/**
* 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 sha1(final String sha1) {
final FileResource resource = new FileResource();
resource.sha1 = sha1;
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 filename(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 + ", 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;
}
}
}
}

View File

@@ -9,6 +9,8 @@
package org.eclipse.hawkbit.security; package org.eclipse.hawkbit.security;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
@@ -16,14 +18,19 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAware;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
import com.google.common.collect.Iterators; import com.google.common.collect.Iterators;
@@ -79,14 +86,6 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
pathExtractor = new AntPathMatcher(); pathExtractor = new AntPathMatcher();
} }
/*
* (non-Javadoc)
*
* @see org.springframework.security.web.authentication.preauth.
* AbstractPreAuthenticatedProcessingFilter
* #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse,
* javax.servlet.FilterChain)
*/
@Override @Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException { throws IOException, ServletException {
@@ -96,7 +95,7 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
return; return;
} }
final TenantSecruityToken secruityToken = createTenantSecruityTokenVariables((HttpServletRequest) request); final TenantSecurityToken secruityToken = createTenantSecruityTokenVariables((HttpServletRequest) request);
if (secruityToken == null) { if (secruityToken == null) {
chain.doFilter(request, response); chain.doFilter(request, response);
return; return;
@@ -112,6 +111,18 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
protected abstract PreAuthenficationFilter createControllerAuthenticationFilter(); protected abstract PreAuthenficationFilter createControllerAuthenticationFilter();
@Override
protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response,
final Authentication authResult) {
final Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.addAll(authResult.getAuthorities());
authorities.addAll(abstractControllerAuthenticationFilter.getSuccessfulAuthenticationAuthorities());
final PreAuthenticatedAuthenticationToken authTokenWithGrantedAuthorities = new PreAuthenticatedAuthenticationToken(
authResult.getPrincipal(), authResult.getCredentials(), authorities);
authTokenWithGrantedAuthorities.setDetails(authResult.getDetails());
super.successfulAuthentication(request, response, authTokenWithGrantedAuthorities);
}
/** /**
* Extracts tenant and controllerId from the request URI as path variables. * Extracts tenant and controllerId from the request URI as path variables.
* *
@@ -121,7 +132,7 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
* request does not match the pattern and no variables could be * request does not match the pattern and no variables could be
* extracted * extracted
*/ */
protected TenantSecruityToken createTenantSecruityTokenVariables(final HttpServletRequest request) { protected TenantSecurityToken createTenantSecruityTokenVariables(final HttpServletRequest request) {
final String requestURI = request.getRequestURI(); final String requestURI = request.getRequestURI();
if (pathExtractor.match(request.getContextPath() + CONTROLLER_REQUEST_ANT_PATTERN, requestURI)) { if (pathExtractor.match(request.getContextPath() + CONTROLLER_REQUEST_ANT_PATTERN, requestURI)) {
@@ -153,9 +164,9 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
} }
} }
private TenantSecruityToken createTenantSecruityTokenVariables(final HttpServletRequest request, private TenantSecurityToken createTenantSecruityTokenVariables(final HttpServletRequest request,
final String tenant, final String controllerId) { final String tenant, final String controllerId) {
final TenantSecruityToken secruityToken = new TenantSecruityToken(tenant, controllerId, ""); final TenantSecurityToken secruityToken = new TenantSecurityToken(tenant, controllerId, FileResource.sha1(""));
final UnmodifiableIterator<String> forEnumeration = Iterators.forEnumeration(request.getHeaderNames()); final UnmodifiableIterator<String> forEnumeration = Iterators.forEnumeration(request.getHeaderNames());
forEnumeration.forEachRemaining(header -> secruityToken.getHeaders().put(header, request.getHeader(header))); forEnumeration.forEachRemaining(header -> secruityToken.getHeaders().put(header, request.getHeader(header)));
return secruityToken; return secruityToken;
@@ -163,7 +174,7 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
@Override @Override
protected Object getPreAuthenticatedPrincipal(final HttpServletRequest request) { protected Object getPreAuthenticatedPrincipal(final HttpServletRequest request) {
final TenantSecruityToken secruityToken = createTenantSecruityTokenVariables(request); final TenantSecurityToken secruityToken = createTenantSecruityTokenVariables(request);
if (secruityToken == null) { if (secruityToken == null) {
return null; return null;
} }
@@ -172,7 +183,7 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
@Override @Override
protected Object getPreAuthenticatedCredentials(final HttpServletRequest request) { protected Object getPreAuthenticatedCredentials(final HttpServletRequest request) {
final TenantSecruityToken secruityToken = createTenantSecruityTokenVariables(request); final TenantSecurityToken secruityToken = createTenantSecruityTokenVariables(request);
if (secruityToken == null) { if (secruityToken == null) {
return null; return null;
} }

View File

@@ -0,0 +1,47 @@
/**
* 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.security;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.TenantAware;
/**
* An pre-authenticated processing filter which add the
* {@link SpringEvalExpressions#CONTROLLER_DOWNLOAD_ROLE_ANONYMOUS} to the
* security context in case the anonymous download is allowed through
* configuration.
*/
public class HttpControllerPreAuthenticateAnonymousDownloadFilter extends AbstractHttpControllerAuthenticationFilter {
/**
* Constructor.
*
* @param tenantConfigurationManagement
* the system management service to retrieve configuration
* properties
* @param tenantAware
* the tenant aware service to get configuration for the specific
* tenant
* @param systemSecurityContext
* the system security context
*/
public HttpControllerPreAuthenticateAnonymousDownloadFilter(
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
final SystemSecurityContext systemSecurityContext) {
super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
}
@Override
protected PreAuthenficationFilter createControllerAuthenticationFilter() {
return new ControllerPreAuthenticatedAnonymousDownload(tenantConfigurationManagement, tenantAware,
systemSecurityContext);
}
}

View File

@@ -321,7 +321,8 @@ public class ArtifactManagement {
} }
boolean artifactIsOnlyUsedByOneSoftwareModule = true; boolean artifactIsOnlyUsedByOneSoftwareModule = true;
for (LocalArtifact lArtifact : localArtifactRepository.findByGridFsFileName(existing.getGridFsFileName())) { for (final LocalArtifact lArtifact : localArtifactRepository
.findByGridFsFileName(existing.getGridFsFileName())) {
if (!lArtifact.getSoftwareModule().isDeleted() if (!lArtifact.getSoftwareModule().isDeleted()
&& lArtifact.getSoftwareModule().getId() != existing.getSoftwareModule().getId()) { && lArtifact.getSoftwareModule().getId() != existing.getSoftwareModule().getId()) {
artifactIsOnlyUsedByOneSoftwareModule = false; artifactIsOnlyUsedByOneSoftwareModule = false;
@@ -403,7 +404,7 @@ public class ArtifactManagement {
* if file could not be found in store * if file could not be found in store
*/ */
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DOWNLOAD_ARTIFACT + SpringEvalExpressions.HAS_AUTH_OR @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DOWNLOAD_ARTIFACT + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.IS_CONTROLLER) + SpringEvalExpressions.HAS_CONTROLLER_DOWNLOAD)
public DbArtifact loadLocalArtifactBinary(@NotNull final LocalArtifact artifact) { public DbArtifact loadLocalArtifactBinary(@NotNull final LocalArtifact artifact) {
final DbArtifact result = artifactRepository.getArtifactBySha1(artifact.getGridFsFileName()); final DbArtifact result = artifactRepository.getArtifactBySha1(artifact.getGridFsFileName());
if (result == null) { if (result == null) {

View File

@@ -25,6 +25,11 @@
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository</artifactId> <artifactId>hawkbit-repository</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-core</artifactId>
<version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.hawkbit</groupId> <groupId>org.eclipse.hawkbit</groupId>

View File

@@ -18,6 +18,8 @@ import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.api.UrlProtocol;
import org.eclipse.hawkbit.controller.model.Artifact; import org.eclipse.hawkbit.controller.model.Artifact;
import org.eclipse.hawkbit.controller.model.Chunk; import org.eclipse.hawkbit.controller.model.Chunk;
import org.eclipse.hawkbit.controller.model.Config; import org.eclipse.hawkbit.controller.model.Config;
@@ -29,27 +31,29 @@ import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactHash; import org.eclipse.hawkbit.rest.resource.model.artifact.ArtifactHash;
import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.Link;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
/** /**
* Utility class for the Controller API. * Utility class for the Controller API.
*
*
*
*
*/ */
public final class DataConversionHelper { public final class DataConversionHelper {
@Autowired
ArtifactUrlHandler artifactUrlHandler;
// utility class, private constructor. // utility class, private constructor.
private DataConversionHelper() { private DataConversionHelper() {
} }
static List<Chunk> createChunks(final String targetid, final Action uAction, final TenantAware tenantAware) { static List<Chunk> createChunks(final String targetid, final Action uAction,
return uAction.getDistributionSet() final ArtifactUrlHandler artifactUrlHandler) {
.getModules().stream().map(module -> new Chunk(mapChunkLegacyKeys(module.getType().getKey()), return uAction.getDistributionSet().getModules().stream()
module.getVersion(), module.getName(), createArtifacts(targetid, module, tenantAware))) .map(module -> new Chunk(mapChunkLegacyKeys(module.getType().getKey()), module.getVersion(),
module.getName(), createArtifacts(targetid, module, artifactUrlHandler)))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@@ -72,23 +76,25 @@ public final class DataConversionHelper {
* of the target * of the target
* @param module * @param module
* the software module * the software module
* @param tenantAware
* of the tenant
* @return a list of artifacts or a empty list. Cannot be <null>. * @return a list of artifacts or a empty list. Cannot be <null>.
*/ */
public static List<Artifact> createArtifacts(final String targetid, public static List<Artifact> createArtifacts(final String targetid,
final org.eclipse.hawkbit.repository.model.SoftwareModule module, final TenantAware tenantAware) { final org.eclipse.hawkbit.repository.model.SoftwareModule module,
final ArtifactUrlHandler artifactUrlHandler) {
final List<Artifact> files = new ArrayList<>(); final List<Artifact> files = new ArrayList<>();
module.getLocalArtifacts().forEach(artifact -> { module.getLocalArtifacts().forEach(artifact -> {
final Artifact file = new Artifact(); final Artifact file = new Artifact();
file.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash())); file.setHashes(new ArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash()));
file.setFilename(artifact.getFilename()); file.setFilename(artifact.getFilename());
file.setSize(artifact.getSize()); file.setSize(artifact.getSize());
final String linkHttp = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(),
file.add(linkTo(methodOn(RootController.class, tenantAware.getCurrentTenant()).downloadArtifact(targetid, artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTP);
artifact.getSoftwareModule().getId(), artifact.getFilename(), null, null)).withRel("download")); final String linkHttps = artifactUrlHandler.getUrl(targetid, artifact.getSoftwareModule().getId(),
file.add(linkTo(methodOn(RootController.class, tenantAware.getCurrentTenant()).downloadArtifactMd5(targetid, artifact.getFilename(), artifact.getSha1Hash(), UrlProtocol.HTTPS);
artifact.getSoftwareModule().getId(), artifact.getFilename(), null, null)).withRel("md5sum")); file.add(new Link(linkHttps).withRel("download"));
file.add(new Link(linkHttps + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum"));
file.add(new Link(linkHttp).withRel("download-http"));
file.add(new Link(linkHttp + ControllerConstants.ARTIFACT_MD5_DWNL_SUFFIX).withRel("md5sum-http"));
files.add(file); files.add(file);
}); });

View File

@@ -15,6 +15,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact; import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.cache.CacheWriteNotify; import org.eclipse.hawkbit.cache.CacheWriteNotify;
import org.eclipse.hawkbit.controller.model.ActionFeedback; import org.eclipse.hawkbit.controller.model.ActionFeedback;
@@ -84,11 +85,14 @@ public class RootController {
@Autowired @Autowired
private CacheWriteNotify cacheWriteNotify; private CacheWriteNotify cacheWriteNotify;
@Autowired
private HawkbitSecurityProperties securityProperties;
@Autowired @Autowired
private TenantAware tenantAware; private TenantAware tenantAware;
@Autowired @Autowired
private HawkbitSecurityProperties securityProperties; private ArtifactUrlHandler artifactUrlHandler;
/** /**
* Returns all artifacts of a given software module and target. * Returns all artifacts of a given software module and target.
@@ -114,7 +118,7 @@ public class RootController {
} }
return new ResponseEntity<>(DataConversionHelper.createArtifacts(targetid, softwareModule, tenantAware), return new ResponseEntity<>(DataConversionHelper.createArtifacts(targetid, softwareModule, artifactUrlHandler),
HttpStatus.OK); HttpStatus.OK);
} }
@@ -303,7 +307,7 @@ public class RootController {
if (!action.isCancelingOrCanceled()) { if (!action.isCancelingOrCanceled()) {
final List<Chunk> chunks = DataConversionHelper.createChunks(targetid, action, tenantAware); final List<Chunk> chunks = DataConversionHelper.createChunks(targetid, action, artifactUrlHandler);
final HandlingType handlingType = action.isForce() ? HandlingType.FORCED : HandlingType.ATTEMPT; final HandlingType handlingType = action.isForce() ? HandlingType.FORCED : HandlingType.ATTEMPT;

View File

@@ -170,15 +170,27 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB {
jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1",
equalTo(artifact.getSha1Hash()))) equalTo(artifact.getSha1Hash())))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1"))) + "/artifacts/test1")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href",
equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.MD5SUM")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.MD5SUM"))) + "/artifacts/test1.MD5SUM")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].size", equalTo(5 * 1024))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].size", equalTo(5 * 1024)))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].filename", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].filename",
equalTo("test1.signature"))) equalTo("test1.signature")))
@@ -188,11 +200,21 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB {
jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1",
equalTo(artifactSignature.getSha1Hash()))) equalTo(artifactSignature.getSha1Hash())))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature"))) + "/artifacts/test1.signature")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href",
equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature.MD5SUM")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
@@ -293,12 +315,12 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB {
jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1",
equalTo(artifact.getSha1Hash()))) equalTo(artifact.getSha1Hash())))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1"))) + "/artifacts/test1")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.MD5SUM"))) + "/artifacts/test1.MD5SUM")))
@@ -311,11 +333,21 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB {
jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1",
equalTo(artifactSignature.getSha1Hash()))) equalTo(artifactSignature.getSha1Hash())))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature"))) + "/artifacts/test1.signature")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href",
equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature.MD5SUM")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
@@ -409,15 +441,25 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB {
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].filename", equalTo("test1"))) .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].filename", equalTo("test1")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.md5", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.md5",
equalTo(artifact.getMd5Hash()))) equalTo(artifact.getMd5Hash())))
.andExpect( .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1",
jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0].hashes.sha1", equalTo(artifact.getSha1Hash())))
equalTo(artifact.getSha1Hash())))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1"))) + "/artifacts/test1")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum.href",
equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.MD5SUM")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.download-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[0]._links.md5sum-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
@@ -431,15 +473,27 @@ public class DeploymentBaseTest extends AbstractIntegrationTestWithMongoDB {
jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1", jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1].hashes.sha1",
equalTo(artifactSignature.getSha1Hash()))) equalTo(artifactSignature.getSha1Hash())))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature"))) + "/artifacts/test1.signature")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href", .andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum.href",
equalTo("https://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature.MD5SUM")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.download-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==os)][0].artifacts[1]._links.md5sum-http.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant() equalTo("http://localhost/" + tenantAware.getCurrentTenant()
+ "/controller/v1/4712/softwaremodules/" + "/controller/v1/4712/softwaremodules/"
+ findDistributionSetByAction.findFirstModuleByType(osType).getId() + findDistributionSetByAction.findFirstModuleByType(osType).getId()
+ "/artifacts/test1.signature.MD5SUM"))) + "/artifacts/test1.signature.MD5SUM")))
.andExpect(jsonPath("$deployment.chunks[?(@.part==bApp)][0].version", .andExpect(jsonPath("$deployment.chunks[?(@.part==bApp)][0].version",
equalTo(ds.findFirstModuleByType(appType).getVersion()))) equalTo(ds.findFirstModuleByType(appType).getVersion())))
.andExpect(jsonPath("$deployment.chunks[?(@.part==bApp)][0].name", .andExpect(jsonPath("$deployment.chunks[?(@.part==bApp)][0].name",

View File

@@ -182,6 +182,12 @@ public final class SpPermission {
*/ */
public static final String CONTROLLER_ROLE_ANONYMOUS = "ROLE_CONTROLLER_ANONYMOUS"; public static final String CONTROLLER_ROLE_ANONYMOUS = "ROLE_CONTROLLER_ANONYMOUS";
/**
* The role which contains in the spring security context in case an
* controller is authenticated to download artifacts.
*/
public static final String CONTROLLER_DOWNLOAD_ROLE = "ROLE_CONTROLLER_DOWNLOAD";
/** /**
* The role which contains the spring security context in case the * The role which contains the spring security context in case the
* system is executing code which is necessary to be privileged. * system is executing code which is necessary to be privileged.
@@ -275,8 +281,16 @@ public final class SpPermission {
* context contains the anoynmous role or the controller specific role * context contains the anoynmous role or the controller specific role
* {@link SpPermission#CONTROLLER_ROLE}. * {@link SpPermission#CONTROLLER_ROLE}.
*/ */
public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" + CONTROLLER_ROLE
+ CONTROLLER_ROLE + "')"; + "')";
/**
* Spring security eval hasAuthority expression to check if the spring
* context contains the role to allow controllers to download specific
* role {@link SpPermission#CONTROLLER_DOWNLOAD_ROLE}.
*/
public static final String HAS_CONTROLLER_DOWNLOAD = HAS_AUTH_PREFIX + CONTROLLER_DOWNLOAD_ROLE
+ HAS_AUTH_SUFFIX;
/** /**
* Spring security eval hasAnyRole expression to check if the spring * Spring security eval hasAnyRole expression to check if the spring

View File

@@ -35,7 +35,32 @@
<groupId>org.springframework.security</groupId> <groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId> <artifactId>spring-security-web</artifactId>
</dependency> </dependency>
<!-- TEST -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -8,7 +8,7 @@
*/ */
package org.eclipse.hawkbit.security; package org.eclipse.hawkbit.security;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
@@ -42,15 +42,15 @@ public abstract class AbstractControllerAuthenticationFilter implements PreAuthe
protected abstract TenantConfigurationKey getTenantConfigurationKey(); protected abstract TenantConfigurationKey getTenantConfigurationKey();
@Override @Override
public boolean isEnable(final TenantSecruityToken secruityToken) { public boolean isEnable(final TenantSecurityToken secruityToken) {
return tenantAware.runAsTenant(secruityToken.getTenant(), configurationKeyTenantRunner); return tenantAware.runAsTenant(secruityToken.getTenant(), configurationKeyTenantRunner);
} }
@Override @Override
public abstract HeaderAuthentication getPreAuthenticatedPrincipal(TenantSecruityToken secruityToken); public abstract HeaderAuthentication getPreAuthenticatedPrincipal(TenantSecurityToken secruityToken);
@Override @Override
public abstract HeaderAuthentication getPreAuthenticatedCredentials(TenantSecruityToken secruityToken); public abstract HeaderAuthentication getPreAuthenticatedCredentials(TenantSecurityToken secruityToken);
private final class SecurityConfigurationKeyTenantRunner implements TenantAware.TenantRunner<Boolean> { private final class SecurityConfigurationKeyTenantRunner implements TenantAware.TenantRunner<Boolean> {
@Override @Override

View File

@@ -8,7 +8,7 @@
*/ */
package org.eclipse.hawkbit.security; package org.eclipse.hawkbit.security;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
/** /**
* A Filter for device which download via coap. * A Filter for device which download via coap.
@@ -19,19 +19,19 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
public class CoapAnonymousPreAuthenticatedFilter implements PreAuthenficationFilter { public class CoapAnonymousPreAuthenticatedFilter implements PreAuthenficationFilter {
@Override @Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecruityToken secruityToken) { public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecurityToken secruityToken) {
return new HeaderAuthentication(secruityToken.getControllerId(), TenantSecruityToken.COAP_TOKEN_VALUE); return new HeaderAuthentication(secruityToken.getControllerId(), TenantSecurityToken.COAP_TOKEN_VALUE);
} }
@Override @Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecruityToken secruityToken) { public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecurityToken secruityToken) {
return new HeaderAuthentication(secruityToken.getControllerId(), TenantSecruityToken.COAP_TOKEN_VALUE); return new HeaderAuthentication(secruityToken.getControllerId(), TenantSecurityToken.COAP_TOKEN_VALUE);
} }
@Override @Override
public boolean isEnable(final TenantSecruityToken secruityToken) { public boolean isEnable(final TenantSecurityToken secruityToken) {
final String authHeader = secruityToken.getHeader(TenantSecruityToken.COAP_AUTHORIZATION_HEADER); final String authHeader = secruityToken.getHeader(TenantSecurityToken.COAP_AUTHORIZATION_HEADER);
return TenantSecruityToken.COAP_TOKEN_VALUE.equals(authHeader); return TenantSecurityToken.COAP_TOKEN_VALUE.equals(authHeader);
} }
} }

View File

@@ -8,7 +8,7 @@
*/ */
package org.eclipse.hawkbit.security; package org.eclipse.hawkbit.security;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.ControllerManagement;
@@ -67,8 +67,8 @@ public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractContro
} }
@Override @Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecruityToken secruityToken) { public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecurityToken secruityToken) {
final String authHeader = secruityToken.getHeader(TenantSecruityToken.AUTHORIZATION_HEADER); final String authHeader = secruityToken.getHeader(TenantSecurityToken.AUTHORIZATION_HEADER);
if ((authHeader != null) && authHeader.startsWith(TARGET_SECURITY_TOKEN_AUTH_SCHEME)) { if ((authHeader != null) && authHeader.startsWith(TARGET_SECURITY_TOKEN_AUTH_SCHEME)) {
LOGGER.debug("found authorization header with scheme {} using target security token for authentication", LOGGER.debug("found authorization header with scheme {} using target security token for authentication",
TARGET_SECURITY_TOKEN_AUTH_SCHEME); TARGET_SECURITY_TOKEN_AUTH_SCHEME);
@@ -81,7 +81,7 @@ public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractContro
} }
@Override @Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecruityToken secruityToken) { public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecurityToken secruityToken) {
final String securityToken = tenantAware.runAsTenant(secruityToken.getTenant(), final String securityToken = tenantAware.runAsTenant(secruityToken.getTenant(),
new GetSecurityTokenTenantRunner(secruityToken.getTenant(), secruityToken.getControllerId())); new GetSecurityTokenTenantRunner(secruityToken.getTenant(), secruityToken.getControllerId()));
return new HeaderAuthentication(secruityToken.getControllerId(), securityToken); return new HeaderAuthentication(secruityToken.getControllerId(), securityToken);

View File

@@ -0,0 +1,69 @@
/**
* 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.security;
import java.util.Collection;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import com.google.common.collect.Lists;
/**
* An pre-authenticated processing filter which add the
* {@link SpringEvalExpressions#CONTROLLER_DOWNLOAD_ROLE_ANONYMOUS} to the
* security context in case the anonymous download is allowed through
* configuration.
*/
public class ControllerPreAuthenticatedAnonymousDownload extends AbstractControllerAuthenticationFilter {
/**
* Constructor.
*
* @param tenantConfigurationManagement
* the tenant management service to retrieve configuration
* properties
* @param tenantAware
* the tenant aware service to get configuration for the specific
* tenant
* @param systemSecurityContext
* the system security context to get access to tenant
* configuration
*/
public ControllerPreAuthenticatedAnonymousDownload(
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
final SystemSecurityContext systemSecurityContext) {
super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
}
@Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecurityToken secruityToken) {
return new HeaderAuthentication(secruityToken.getControllerId(), secruityToken.getControllerId());
}
@Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecurityToken secruityToken) {
return new HeaderAuthentication(secruityToken.getControllerId(), secruityToken.getControllerId());
}
@Override
protected TenantConfigurationKey getTenantConfigurationKey() {
return TenantConfigurationKey.ANONYMOUS_DOWNLOAD_MODE_ENABLED;
}
@Override
public Collection<GrantedAuthority> getSuccessfulAuthenticationAuthorities() {
return Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE));
}
}

View File

@@ -0,0 +1,47 @@
/**
* 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.security;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
/**
* An anonymous controller filter which is only enabled in case of anonymous
* access is granted. This should only be for development purposes.
*
* @see DdiSecurityProperties
*/
public class ControllerPreAuthenticatedAnonymousFilter implements PreAuthenficationFilter {
private final DdiSecurityProperties ddiSecurityConfiguration;
/**
* @param ddiSecurityConfiguration
* the security configuration which holds the configuration if
* anonymous is enabled or not
*/
public ControllerPreAuthenticatedAnonymousFilter(final DdiSecurityProperties ddiSecurityConfiguration) {
this.ddiSecurityConfiguration = ddiSecurityConfiguration;
}
@Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecurityToken secruityToken) {
return new HeaderAuthentication(secruityToken.getControllerId(), secruityToken.getControllerId());
}
@Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecurityToken secruityToken) {
return new HeaderAuthentication(secruityToken.getControllerId(), secruityToken.getControllerId());
}
@Override
public boolean isEnable(final TenantSecurityToken secruityToken) {
return ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled();
}
}

View File

@@ -8,7 +8,7 @@
*/ */
package org.eclipse.hawkbit.security; package org.eclipse.hawkbit.security;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
@@ -56,8 +56,8 @@ public class ControllerPreAuthenticatedGatewaySecurityTokenFilter extends Abstra
} }
@Override @Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecruityToken secruityToken) { public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecurityToken secruityToken) {
final String authHeader = secruityToken.getHeader(TenantSecruityToken.AUTHORIZATION_HEADER); final String authHeader = secruityToken.getHeader(TenantSecurityToken.AUTHORIZATION_HEADER);
if ((authHeader != null) && authHeader.startsWith(GATEWAY_SECURITY_TOKEN_AUTH_SCHEME)) { if ((authHeader != null) && authHeader.startsWith(GATEWAY_SECURITY_TOKEN_AUTH_SCHEME)) {
LOGGER.debug("found authorization header with scheme {} using target security token for authentication", LOGGER.debug("found authorization header with scheme {} using target security token for authentication",
GATEWAY_SECURITY_TOKEN_AUTH_SCHEME); GATEWAY_SECURITY_TOKEN_AUTH_SCHEME);
@@ -71,7 +71,7 @@ public class ControllerPreAuthenticatedGatewaySecurityTokenFilter extends Abstra
} }
@Override @Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecruityToken secruityToken) { public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecurityToken secruityToken) {
final String gatewayToken = tenantAware.runAsTenant(secruityToken.getTenant(), final String gatewayToken = tenantAware.runAsTenant(secruityToken.getTenant(),
gatewaySecurityTokenKeyConfigRunner); gatewaySecurityTokenKeyConfigRunner);
return new HeaderAuthentication(secruityToken.getControllerId(), gatewayToken); return new HeaderAuthentication(secruityToken.getControllerId(), gatewayToken);

View File

@@ -8,7 +8,7 @@
*/ */
package org.eclipse.hawkbit.security; package org.eclipse.hawkbit.security;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
@@ -18,7 +18,7 @@ import org.slf4j.LoggerFactory;
/** /**
* An pre-authenticated processing filter which extracts the principal from a * An pre-authenticated processing filter which extracts the principal from a
* request URI and the credential from a request header in a the * request URI and the credential from a request header in a the
* {@link TenantSecruityToken}. * {@link TenantSecurityToken}.
* *
* *
* *
@@ -75,7 +75,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont
} }
@Override @Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecruityToken secruityToken) { public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecurityToken secruityToken) {
// retrieve the common name header and the authority name header from // retrieve the common name header and the authority name header from
// the http request and // the http request and
// combine them together // combine them together
@@ -97,7 +97,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont
} }
@Override @Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecruityToken secruityToken) { public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecurityToken secruityToken) {
final String authorityNameConfigurationValue = tenantAware.runAsTenant(secruityToken.getTenant(), final String authorityNameConfigurationValue = tenantAware.runAsTenant(secruityToken.getTenant(),
sslIssuerNameConfigTenantRunner); sslIssuerNameConfigTenantRunner);
String controllerId = secruityToken.getControllerId(); String controllerId = secruityToken.getControllerId();
@@ -117,7 +117,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont
* It's ok if we find the the hash in any the trusted CA chain to accept * It's ok if we find the the hash in any the trusted CA chain to accept
* this request for this tenant. * this request for this tenant.
*/ */
private String getIssuerHashHeader(final TenantSecruityToken secruityToken, final String knownIssuerHash) { private String getIssuerHashHeader(final TenantSecurityToken secruityToken, final String knownIssuerHash) {
// iterate over the headers until we get a null header. // iterate over the headers until we get a null header.
int iHeader = 1; int iHeader = 1;
String foundHash; String foundHash;

View File

@@ -109,6 +109,7 @@ public class PreAuthTokenSourceTrustAuthenticationProvider implements Authentica
if (successAuthentication) { if (successAuthentication) {
final Collection<GrantedAuthority> controllerAuthorities = new ArrayList<>(); final Collection<GrantedAuthority> controllerAuthorities = new ArrayList<>();
controllerAuthorities.add(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE)); controllerAuthorities.add(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE));
controllerAuthorities.add(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE));
final PreAuthenticatedAuthenticationToken successToken = new PreAuthenticatedAuthenticationToken(principal, final PreAuthenticatedAuthenticationToken successToken = new PreAuthenticatedAuthenticationToken(principal,
credentials, controllerAuthorities); credentials, controllerAuthorities);
successToken.setDetails(tokenDetails); successToken.setDetails(tokenDetails);

View File

@@ -8,7 +8,12 @@
*/ */
package org.eclipse.hawkbit.security; package org.eclipse.hawkbit.security;
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken; import java.util.Collection;
import java.util.Collections;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
/** /**
* Interface for Pre Authenfication. * Interface for Pre Authenfication.
@@ -25,7 +30,7 @@ public interface PreAuthenficationFilter {
* the secruity info * the secruity info
* @return <true> is enabled <false> diabled * @return <true> is enabled <false> diabled
*/ */
boolean isEnable(TenantSecruityToken secruityToken); boolean isEnable(TenantSecurityToken secruityToken);
/** /**
* Extract the principal information from the current secruityToken. * Extract the principal information from the current secruityToken.
@@ -34,7 +39,7 @@ public interface PreAuthenficationFilter {
* the secruityToken * the secruityToken
* @return the extracted tenant and controller id * @return the extracted tenant and controller id
*/ */
HeaderAuthentication getPreAuthenticatedPrincipal(TenantSecruityToken secruityToken); HeaderAuthentication getPreAuthenticatedPrincipal(TenantSecurityToken secruityToken);
/** /**
* Extract the principal credentials from the current secruityToken. * Extract the principal credentials from the current secruityToken.
@@ -43,6 +48,18 @@ public interface PreAuthenficationFilter {
* the secruityToken * the secruityToken
* @return the extracted tenant and controller id * @return the extracted tenant and controller id
*/ */
HeaderAuthentication getPreAuthenticatedCredentials(TenantSecruityToken secruityToken); HeaderAuthentication getPreAuthenticatedCredentials(TenantSecurityToken secruityToken);
/**
* Allows to add additional authorities to the successful authenticated
* token.
*
* @return the authorities granted to the principal, or an empty collection
* if the token has not been authenticated. Never null.
* @see Authentication#getAuthorities()
*/
default Collection<GrantedAuthority> getSuccessfulAuthenticationAuthorities() {
return Collections.emptyList();
};
} }

View File

@@ -0,0 +1,61 @@
/**
* 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.security;
import static org.fest.assertions.Assertions.assertThat;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* @author Michael Hirsch
*
*/
@Features("Unit Tests - Security")
@Stories("Exclude path aware shallow ETag filter")
@RunWith(MockitoJUnitRunner.class)
public class ControllerPreAuthenticatedAnonymousDownloadTest {
private ControllerPreAuthenticatedAnonymousDownload underTest;
@Mock
private TenantConfigurationManagement tenantConfigurationManagementMock;
@Mock
private TenantAware tenantAwareMock;
@Before
public void before() {
underTest = new ControllerPreAuthenticatedAnonymousDownload(tenantConfigurationManagementMock, tenantAwareMock,
new SystemSecurityContext(tenantAwareMock));
}
@Test
public void useCorrectTenantConfiguationKey() {
assertThat(underTest.getTenantConfigurationKey()).as("Should be using the correct tenant configuration key")
.isEqualTo(underTest.getTenantConfigurationKey());
}
@Test
public void successfulAuthenticationAdditionalAuthoritiesForDownload() {
assertThat(underTest.getSuccessfulAuthenticationAuthorities())
.as("Additional authorities should be containing the download anonymous role")
.contains(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE));
}
}

View File

@@ -30,9 +30,6 @@ import com.vaadin.ui.VerticalLayout;
/** /**
* View to configure the authentication mode. * View to configure the authentication mode.
*
*
*
*/ */
@SpringComponent @SpringComponent
@ViewScope @ViewScope

View File

@@ -14,8 +14,8 @@ import java.util.List;
import com.vaadin.ui.CustomComponent; import com.vaadin.ui.CustomComponent;
/** /**
* base class for all configuration views. This class implements the logic for * Base class for all configuration views. This class implements the logic for
* the handling of the * the handling of the configurations in a consistent way.
* *
*/ */
public abstract class BaseConfigurationView extends CustomComponent implements ConfigurationGroup { public abstract class BaseConfigurationView extends CustomComponent implements ConfigurationGroup {

View File

@@ -11,9 +11,8 @@ package org.eclipse.hawkbit.ui.tenantconfiguration;
import com.vaadin.ui.Component; import com.vaadin.ui.Component;
/** /**
* * Interface that all system configurations have to implement to save and undo
* * their customized changes.
*
*/ */
public interface ConfigurationGroup extends Component, ConfigurationItem { public interface ConfigurationGroup extends Component, ConfigurationItem {

View File

@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.ui.tenantconfiguration;
import java.io.Serializable; import java.io.Serializable;
/** /**
* represents an configurationItem, which can be modified by the user * Represents an configurationItem, which can be modified by the user
*/ */
public interface ConfigurationItem { public interface ConfigurationItem {

View File

@@ -33,9 +33,6 @@ import com.vaadin.ui.VerticalLayout;
/** /**
* Default DistributionSet Panel. * Default DistributionSet Panel.
*
*
*
*/ */
@SpringComponent @SpringComponent
@ViewScope @ViewScope

View File

@@ -0,0 +1,119 @@
/**
* 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.ui.tenantconfiguration;
import javax.annotation.PostConstruct;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.utils.I18N;
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions;
import org.springframework.beans.factory.annotation.Autowired;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.ViewScope;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
/**
* View to enable anonymous download.
*/
@SpringComponent
@ViewScope
public class DownloadAnonymousConfigurationView extends BaseConfigurationView
implements ConfigurationItem.ConfigurationItemChangeListener {
private static final String DIST_CHECKBOX_STYLE = "dist-checkbox-style";
private static final long serialVersionUID = 1L;
@Autowired
private I18N i18n;
@Autowired
private transient TenantConfigurationManagement tenantConfigurationManagement;
boolean anonymousDownloadEnabled;
private CheckBox downloadAnonymousCheckBox;
/**
* Initialize Default Download Anonymous layout.
*/
@PostConstruct
public void init() {
final TenantConfigurationValue<Boolean> value = tenantConfigurationManagement
.getConfigurationValue(TenantConfigurationKey.ANONYMOUS_DOWNLOAD_MODE_ENABLED, Boolean.class);
anonymousDownloadEnabled = value.getValue();
final Panel rootPanel = new Panel();
rootPanel.setSizeFull();
rootPanel.addStyleName("config-panel");
final VerticalLayout vLayout = new VerticalLayout();
vLayout.setMargin(true);
vLayout.setSizeFull();
final Label headerDisSetType = new Label(i18n.get("enonymous.download.title"));
headerDisSetType.addStyleName("config-panel-header");
vLayout.addComponent(headerDisSetType);
final GridLayout gridLayout = new GridLayout(2, 1);
gridLayout.setSpacing(true);
gridLayout.setImmediate(true);
gridLayout.setColumnExpandRatio(1, 1.0F);
gridLayout.setSizeFull();
downloadAnonymousCheckBox = SPUIComponentProvider.getCheckBox("", DIST_CHECKBOX_STYLE, null, false, "");
downloadAnonymousCheckBox.setValue(anonymousDownloadEnabled);
downloadAnonymousCheckBox.addValueChangeListener(event -> configurationHasChanged());
downloadAnonymousCheckBox.setId(SPUIComponetIdProvider.SYSTEM_CONFIGURATION_ANONYMOUS_DOWNLOAD_CHECKBOX);
gridLayout.addComponent(downloadAnonymousCheckBox);
final Label configurationLabel = SPUIComponentProvider.getLabel(i18n.get("enonymous.download.label"),
SPUILabelDefinitions.SP_LABEL_SIMPLE);
gridLayout.addComponent(configurationLabel);
gridLayout.setComponentAlignment(configurationLabel, Alignment.MIDDLE_LEFT);
vLayout.addComponent(gridLayout);
rootPanel.setContent(vLayout);
setCompositionRoot(rootPanel);
}
@Override
public void configurationHasChanged() {
anonymousDownloadEnabled = downloadAnonymousCheckBox.getValue();
notifyConfigurationChanged();
}
@Override
public void save() {
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.ANONYMOUS_DOWNLOAD_MODE_ENABLED,
downloadAnonymousCheckBox.getValue());
}
@Override
public void undo() {
final TenantConfigurationValue<Boolean> value = tenantConfigurationManagement
.getConfigurationValue(TenantConfigurationKey.ANONYMOUS_DOWNLOAD_MODE_ENABLED, Boolean.class);
anonymousDownloadEnabled = value.getValue();
downloadAnonymousCheckBox.setValue(anonymousDownloadEnabled);
}
}

View File

@@ -29,8 +29,6 @@ import com.vaadin.ui.VerticalLayout;
/** /**
* View to configure the polling interval and the overdue time. * View to configure the polling interval and the overdue time.
*
*
*/ */
@SpringComponent @SpringComponent
@ViewScope @ViewScope

View File

@@ -38,9 +38,6 @@ import com.vaadin.ui.VerticalLayout;
/** /**
* Main UI for the system configuration view. * Main UI for the system configuration view.
*
*
*
*/ */
@SpringView(name = TenantConfigurationDashboardView.VIEW_NAME, ui = HawkbitUI.class) @SpringView(name = TenantConfigurationDashboardView.VIEW_NAME, ui = HawkbitUI.class)
@ViewScope @ViewScope
@@ -58,6 +55,9 @@ public class TenantConfigurationDashboardView extends CustomComponent implements
@Autowired @Autowired
private PollingConfigurationView pollingConfigurationView; private PollingConfigurationView pollingConfigurationView;
@Autowired
private DownloadAnonymousConfigurationView downloadAnonymousConfigurationView;
@Autowired @Autowired
private I18N i18n; private I18N i18n;
@@ -73,13 +73,14 @@ public class TenantConfigurationDashboardView extends CustomComponent implements
private final List<ConfigurationGroup> configurationViews = new ArrayList<>(); private final List<ConfigurationGroup> configurationViews = new ArrayList<>();
/** /**
* init method adds all Configuration Views to the list of Views. * Init method adds all Configuration Views to the list of Views.
*/ */
@PostConstruct @PostConstruct
public void init() { public void init() {
configurationViews.add(defaultDistributionSetTypeLayout); configurationViews.add(defaultDistributionSetTypeLayout);
configurationViews.add(authenticationConfigurationView); configurationViews.add(authenticationConfigurationView);
configurationViews.add(pollingConfigurationView); configurationViews.add(pollingConfigurationView);
configurationViews.add(downloadAnonymousConfigurationView);
} }
@Override @Override
@@ -154,13 +155,6 @@ public class TenantConfigurationDashboardView extends CustomComponent implements
undoConfigurationBtn.setEnabled(false); undoConfigurationBtn.setEnabled(false);
} }
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.ui.tenantconfiguration.ConfigurationGroup.
* ConfigurationGroupChangeListener #configurationChanged()
*/
@Override @Override
public void configurationHasChanged() { public void configurationHasChanged() {
saveConfigurationBtn.setEnabled(true); saveConfigurationBtn.setEnabled(true);

View File

@@ -21,9 +21,6 @@ import com.vaadin.server.Resource;
/** /**
* Menu item for system configuration view. * Menu item for system configuration view.
*
*
*
*/ */
@Component @Component
@Order(700) @Order(700)

View File

@@ -26,16 +26,13 @@ import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme; import com.vaadin.ui.themes.ValoTheme;
/** /**
* * This class represents the UI item for the certificate authenticated by an
* * reverse proxy in the authentication configuration view.
*/ */
@SpringComponent @SpringComponent
@ViewScope @ViewScope
public class CertificateAuthenticationConfigurationItem extends AbstractAuthenticationTenantConfigurationItem { public class CertificateAuthenticationConfigurationItem extends AbstractAuthenticationTenantConfigurationItem {
/**
*
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Autowired @Autowired
@@ -59,7 +56,7 @@ public class CertificateAuthenticationConfigurationItem extends AbstractAuthenti
} }
/** /**
* init mehotd called by spring. * Init mehotd called by spring.
*/ */
@PostConstruct @PostConstruct
public void init() { public void init() {
@@ -94,12 +91,6 @@ public class CertificateAuthenticationConfigurationItem extends AbstractAuthenti
} }
} }
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.ui.tenantconfiguration.
* TenantConfigurationItem# configEnable()
*/
@Override @Override
public void configEnable() { public void configEnable() {
if (!configurationEnabled) { if (!configurationEnabled) {
@@ -110,12 +101,6 @@ public class CertificateAuthenticationConfigurationItem extends AbstractAuthenti
setDetailVisible(true); setDetailVisible(true);
} }
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.ui.tenantconfiguration.
* TenantConfigurationItem# configDisable()
*/
@Override @Override
public void configDisable() { public void configDisable() {
if (configurationEnabled) { if (configurationEnabled) {
@@ -125,11 +110,6 @@ public class CertificateAuthenticationConfigurationItem extends AbstractAuthenti
setDetailVisible(false); setDetailVisible(false);
} }
/*
* (non-Javadoc)
*
* @see hawkbit.server.ui.tenantconfiguration.TenantConfigurationItem#save()
*/
@Override @Override
public void save() { public void save() {
if (configurationEnabledChange) { if (configurationEnabledChange) {
@@ -142,11 +122,6 @@ public class CertificateAuthenticationConfigurationItem extends AbstractAuthenti
} }
} }
/*
* (non-Javadoc)
*
* @see hawkbit.server.ui.tenantconfiguration.TenantConfigurationItem#undo()
*/
@Override @Override
public void undo() { public void undo() {
configurationEnabledChange = false; configurationEnabledChange = false;

View File

@@ -30,16 +30,13 @@ import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme; import com.vaadin.ui.themes.ValoTheme;
/** /**
* * This class represents the UI item for the gateway security token section in
* * the authentication configuration view.
*/ */
@SpringComponent @SpringComponent
@ViewScope @ViewScope
public class GatewaySecurityTokenAuthenticationConfigurationItem extends AbstractAuthenticationTenantConfigurationItem { public class GatewaySecurityTokenAuthenticationConfigurationItem extends AbstractAuthenticationTenantConfigurationItem {
/**
*
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Autowired @Autowired
@@ -70,7 +67,7 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac
} }
/** /**
* init mehotd called by spring. * Init mehotd called by spring.
*/ */
@PostConstruct @PostConstruct
public void init() { public void init() {
@@ -135,12 +132,6 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac
notifyConfigurationChanged(); notifyConfigurationChanged();
} }
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.ui.tenantconfiguration.
* TenantConfigurationItem# configEnable()
*/
@Override @Override
public void configEnable() { public void configEnable() {
if (!configurationEnabled) { if (!configurationEnabled) {

View File

@@ -19,17 +19,13 @@ import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.ViewScope; import com.vaadin.spring.annotation.ViewScope;
/** /**
* * This class represents the UI item for the target security token section in
* * the authentication configuration view.
*
*/ */
@SpringComponent @SpringComponent
@ViewScope @ViewScope
public class TargetSecurityTokenAuthenticationConfigurationItem extends AbstractAuthenticationTenantConfigurationItem { public class TargetSecurityTokenAuthenticationConfigurationItem extends AbstractAuthenticationTenantConfigurationItem {
/**
*
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Autowired @Autowired
@@ -49,7 +45,7 @@ public class TargetSecurityTokenAuthenticationConfigurationItem extends Abstract
} }
/** /**
* init mehotd called by spring. * Init mehotd called by spring.
*/ */
@PostConstruct @PostConstruct
public void init() { public void init() {
@@ -57,12 +53,6 @@ public class TargetSecurityTokenAuthenticationConfigurationItem extends Abstract
configurationEnabled = isConfigEnabled(); configurationEnabled = isConfigEnabled();
} }
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.ui.tenantconfiguration.
* TenantConfigurationItem# configEnable()
*/
@Override @Override
public void configEnable() { public void configEnable() {
if (!configurationEnabled) { if (!configurationEnabled) {
@@ -71,12 +61,6 @@ public class TargetSecurityTokenAuthenticationConfigurationItem extends Abstract
configurationEnabled = true; configurationEnabled = true;
} }
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.ui.tenantconfiguration.
* TenantConfigurationItem# configDisable()
*/
@Override @Override
public void configDisable() { public void configDisable() {
if (configurationEnabled) { if (configurationEnabled) {

View File

@@ -501,6 +501,11 @@ public final class SPUIComponetIdProvider {
*/ */
public static final String SYSTEM_CONFIGURATION_CANCEL = "system.configuration.cancel"; public static final String SYSTEM_CONFIGURATION_CANCEL = "system.configuration.cancel";
/**
* Id of the anonymous download checkbox.
*/
public static final String SYSTEM_CONFIGURATION_ANONYMOUS_DOWNLOAD_CHECKBOX = "system.configuration.anonymous.download.checkbox";
/** /**
* Id of maximize/minimize icon of table - Software module table. * Id of maximize/minimize icon of table - Software module table.
*/ */
@@ -827,7 +832,7 @@ public final class SPUIComponetIdProvider {
* Rollout status label id. * Rollout status label id.
*/ */
public static final String ROLLOUT_STATUS_LABEL_ID = "rollout.status.id"; public static final String ROLLOUT_STATUS_LABEL_ID = "rollout.status.id";
/** /**
* Rollout group status label id. * Rollout group status label id.
*/ */
@@ -867,12 +872,12 @@ public final class SPUIComponetIdProvider {
* Rollout group targets count message label. * Rollout group targets count message label.
*/ */
public static final String ROLLOUT_GROUP_TARGET_LABEL = "rollout.group.target.label"; public static final String ROLLOUT_GROUP_TARGET_LABEL = "rollout.group.target.label";
/** /**
* Action confirmation popup id. * Action confirmation popup id.
*/ */
public static final String CONFIRMATION_POPUP_ID = "action.confirmation.popup.id"; public static final String CONFIRMATION_POPUP_ID = "action.confirmation.popup.id";
/** /**
* Validation status icon . * Validation status icon .
*/ */

View File

@@ -401,6 +401,8 @@ configuration.polling.title=Polling Configuration
configuration.polling.time=Polling Time configuration.polling.time=Polling Time
configuration.polling.overduetime=Polling Overdue Time configuration.polling.overduetime=Polling Overdue Time
configuration.polling.custom.value=use a custom value configuration.polling.custom.value=use a custom value
enonymous.download.title=Anonymous download
enonymous.download.label=Allow anonymous download. If you enable this option the download server will accept anonymous download requests.
#Calendar #Calendar
calendar.year=year calendar.year=year

View File

@@ -389,6 +389,8 @@ configuration.defaultdistributionset.select.label=Wahl des default Distribution
configuration.savebutton.tooltip=Konfigurationen speichern configuration.savebutton.tooltip=Konfigurationen speichern
configuration.cancellbutton.tooltip=Konfigurationen zur<75>cksetzen configuration.cancellbutton.tooltip=Konfigurationen zur<75>cksetzen
configuration.authentication.title=Authentifikationseinstellungen configuration.authentication.title=Authentifikationseinstellungen
enonymous.download.title=Anonymes herunterladen
enonymous.download.label=Erlaube anonymes herunterladen. When diese option aktivert ist, wird der download server anonyme download anfragen erlauben.
#Calendar #Calendar
calendar.year=Jahr calendar.year=Jahr
calendar.years=Jahre calendar.years=Jahre

View File

@@ -383,6 +383,8 @@ configuration.authentication.title=Authentication Configuration
controller.polling.title=Polling Configuration controller.polling.title=Polling Configuration
controller.polling.time=Polling Time controller.polling.time=Polling Time
controller.polling.overduetime=Polling Overdue Time controller.polling.overduetime=Polling Overdue Time
enonymous.download.title=Anonymous download
enonymous.download.label=Allow anonymous download. If you enable this option the download server will accept anonymous download requests.
#Calendar #Calendar
calendar.year=year calendar.year=year