diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java index 24e9667c2..9638377eb 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java @@ -10,7 +10,6 @@ package org.eclipse.hawkbit.autoconfigure.security; import java.io.IOException; import java.net.URI; -import java.util.Collections; import javax.annotation.PostConstruct; 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.DosFilter; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; +import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateAnonymousDownloadFilter; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter; 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.VaadinUrlAuthenticationSuccessHandler; +import com.google.common.collect.Lists; + /** * All configurations related to SP authentication and authorization layer. * @@ -147,6 +149,12 @@ public class SecurityManagedConfiguration { gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true); 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() .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY)).contentTypeOptions() .xssProtection().httpStrictTransportSecurity().and(); @@ -159,15 +167,17 @@ public class SecurityManagedConfiguration { LOG.info( "******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************"); final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter( - "controllerAnonymousFilter", "anonymous", Collections.singletonList( - new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS))); + "controllerAnonymousFilter", "anonymous", + Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), + new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE))); anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource); httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and() .securityContext().disable().anonymous().authenticationFilter(anoymousFilter); } else { httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter) - .addFilter(gatewaySecurityTokenFilter).antMatcher("/*/controller/**").anonymous().disable() - .authorizeRequests().anyRequest().authenticated().and().exceptionHandling() + .addFilter(gatewaySecurityTokenFilter).addFilter(controllerAnonymousDownloadFilter) + .antMatcher("/*/controller/**").anonymous().disable().authorizeRequests().anyRequest() + .authenticated().and().exceptionHandling() .authenticationEntryPoint((request, response, authException) -> response .setStatus(HttpStatus.UNAUTHORIZED.value())) .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java index 3fa7979b9..9d120c17b 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java @@ -19,6 +19,8 @@ import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.security.CoapAnonymousPreAuthenticatedFilter; 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.ControllerPreAuthenticatedSecurityHeaderFilter; import org.eclipse.hawkbit.security.DdiSecurityProperties; @@ -90,6 +92,11 @@ public class AmqpControllerAuthentfication { tenantConfigurationManagement, controllerManagement, tenantAware, systemSecurityContext); filterChain.add(securityTokenFilter); + final ControllerPreAuthenticatedAnonymousDownload anonymousDownloadFilter = new ControllerPreAuthenticatedAnonymousDownload( + tenantConfigurationManagement, tenantAware, systemSecurityContext); + filterChain.add(anonymousDownloadFilter); + + filterChain.add(new ControllerPreAuthenticatedAnonymousFilter(ddiSecruityProperties)); filterChain.add(new CoapAnonymousPreAuthenticatedFilter()); } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java index 71b8f8db8..c5fff29ad 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java @@ -27,9 +27,9 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageType; import org.eclipse.hawkbit.dmf.json.model.ActionUpdateStatus; import org.eclipse.hawkbit.dmf.json.model.Artifact; import org.eclipse.hawkbit.dmf.json.model.ArtifactHash; +import org.eclipse.hawkbit.dmf.json.model.DownloadResponse; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource; -import org.eclipse.hawkbit.dmf.json.model.DownloadResponse; import org.eclipse.hawkbit.eventbus.event.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; @@ -158,8 +158,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService { private Message handleAuthentifiactionMessage(final Message message) { final DownloadResponse authentificationResponse = new DownloadResponse(); final MessageProperties messageProperties = message.getMessageProperties(); - final TenantSecurityToken secruityToken = convertMessage(message, - TenantSecurityToken.class); + final TenantSecurityToken secruityToken = convertMessage(message, TenantSecurityToken.class); final FileResource fileResource = secruityToken.getFileResource(); try { SecurityContextHolder.getContext().setAuthentication(authenticationManager.doAuthenticate(secruityToken)); @@ -221,12 +220,11 @@ public class AmqpMessageHandlerService extends BaseAmqpService { } else if (fileResource.getFilename() != null) { localArtifact = artifactManagement.findLocalArtifactByFilename(fileResource.getFilename()).stream() .findFirst().orElse(null); - } else if (fileResource.getArtifactId() != null) { - final org.eclipse.hawkbit.repository.model.Artifact artifact = artifactManagement - .findArtifact(fileResource.getArtifactId()); - if (artifact instanceof LocalArtifact) { - localArtifact = (LocalArtifact) artifact; - } + } else if (fileResource.getSoftwareModuleFilenameResource() != null) { + localArtifact = artifactManagement + .findByFilenameAndSoftwareModule(fileResource.getSoftwareModuleFilenameResource().getFilename(), + fileResource.getSoftwareModuleFilenameResource().getSoftwareModuleId()) + .stream().findFirst().orElse(null); } return localArtifact; } diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java index d7ab805ed..881260579 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java @@ -26,6 +26,7 @@ import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; 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.SecurityContextTenantAware; import org.eclipse.hawkbit.security.SystemSecurityContext; @@ -80,8 +81,14 @@ public class AmqpControllerAuthenticationTest { final DdiSecurityProperties secruityProperties = mock(DdiSecurityProperties.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(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); tenantConfigurationManagement = mock(TenantConfigurationManagement.class); diff --git a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java index 9e07d3fc4..154ad5158 100644 --- a/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java +++ b/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/TenantSecurityToken.java @@ -103,7 +103,7 @@ public class TenantSecurityToken { @JsonProperty(required = false) private String filename; @JsonProperty(required = false) - private Long artifactId; + private SoftwareModuleFilenameResource softwareModuleFilenameResource; public String getSha1() { return sha1; @@ -121,12 +121,13 @@ public class TenantSecurityToken { this.filename = filename; } - public Long getArtifactId() { - return artifactId; + public SoftwareModuleFilenameResource getSoftwareModuleFilenameResource() { + return softwareModuleFilenameResource; } - public void setArtifactId(final Long artifactId) { - this.artifactId = artifactId; + public void setSoftwareModuleFilenameResource( + final SoftwareModuleFilenameResource softwareModuleFilenameResource) { + this.softwareModuleFilenameResource = softwareModuleFilenameResource; } /** @@ -156,15 +157,19 @@ public class TenantSecurityToken { } /** - * factory method to create a file resource for an artifactId lookup. + * factory method to create a file resource for an softwaremodule + + * filename lookup, because an filename is not globally unique but + * within a softwaremodule. * - * @param artifactId - * the artifactId of the file to obtain + * @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 artifactId(final Long artifactId) { + public static FileResource softwareModuleFilename(final Long softwareModuleId, final String filename) { final FileResource resource = new FileResource(); - resource.artifactId = artifactId; + resource.softwareModuleFilenameResource = new SoftwareModuleFilenameResource(softwareModuleId, filename); return resource; } @@ -172,5 +177,42 @@ public class TenantSecurityToken { 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 final Long softwareModuleId; + @JsonProperty(required = false) + private final 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; + } + } } } diff --git a/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/AbstractHttpControllerAuthenticationFilter.java b/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/AbstractHttpControllerAuthenticationFilter.java index ace5bc834..0e67489ea 100644 --- a/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/AbstractHttpControllerAuthenticationFilter.java +++ b/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/AbstractHttpControllerAuthenticationFilter.java @@ -9,6 +9,8 @@ package org.eclipse.hawkbit.security; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import javax.servlet.FilterChain; @@ -16,6 +18,7 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource; @@ -23,8 +26,11 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.tenancy.TenantAware; import org.slf4j.Logger; 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.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; +import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.util.AntPathMatcher; import com.google.common.collect.Iterators; @@ -80,14 +86,6 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac pathExtractor = new AntPathMatcher(); } - /* - * (non-Javadoc) - * - * @see org.springframework.security.web.authentication.preauth. - * AbstractPreAuthenticatedProcessingFilter - * #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, - * javax.servlet.FilterChain) - */ @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { @@ -113,6 +111,18 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac protected abstract PreAuthenficationFilter createControllerAuthenticationFilter(); + @Override + protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, + final Authentication authResult) { + final Collection 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. * diff --git a/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/HttpControllerPreAuthenticateAnonymousDownloadFilter.java b/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/HttpControllerPreAuthenticateAnonymousDownloadFilter.java new file mode 100644 index 000000000..40fd1e555 --- /dev/null +++ b/hawkbit-http-security/src/main/java/org/eclipse/hawkbit/security/HttpControllerPreAuthenticateAnonymousDownloadFilter.java @@ -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); + } + +} diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java index 122d7b881..145287fbf 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ArtifactManagement.java @@ -404,7 +404,7 @@ public class ArtifactManagement { * if file could not be found in store */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DOWNLOAD_ARTIFACT + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) + + SpringEvalExpressions.HAS_CONTROLLER_DOWNLOAD) public DbArtifact loadLocalArtifactBinary(@NotNull final LocalArtifact artifact) { final DbArtifact result = artifactRepository.getArtifactBySha1(artifact.getGridFsFileName()); if (result == null) { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java index 5d4ab9283..2e222d879 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java @@ -182,6 +182,12 @@ public final class SpPermission { */ 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 * 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 * {@link SpPermission#CONTROLLER_ROLE}. */ - public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" - + CONTROLLER_ROLE + "')"; + public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" + 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 diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousDownload.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousDownload.java new file mode 100644 index 000000000..b4457bfcf --- /dev/null +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousDownload.java @@ -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 getSuccessfulAuthenticationAuthorities() { + return Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE)); + } +} diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousFilter.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousFilter.java new file mode 100644 index 000000000..cf55c47fb --- /dev/null +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousFilter.java @@ -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(); + } + +} diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthTokenSourceTrustAuthenticationProvider.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthTokenSourceTrustAuthenticationProvider.java index ca38404f7..b81b76e5c 100644 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthTokenSourceTrustAuthenticationProvider.java +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthTokenSourceTrustAuthenticationProvider.java @@ -109,6 +109,7 @@ public class PreAuthTokenSourceTrustAuthenticationProvider implements Authentica if (successAuthentication) { final Collection controllerAuthorities = new ArrayList<>(); controllerAuthorities.add(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE)); + controllerAuthorities.add(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE)); final PreAuthenticatedAuthenticationToken successToken = new PreAuthenticatedAuthenticationToken(principal, credentials, controllerAuthorities); successToken.setDetails(tokenDetails); diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthenficationFilter.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthenficationFilter.java index 8981fa9af..5e4aacfa9 100644 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthenficationFilter.java +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/PreAuthenficationFilter.java @@ -8,7 +8,12 @@ */ package org.eclipse.hawkbit.security; +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. @@ -45,4 +50,16 @@ public interface PreAuthenficationFilter { */ 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 getSuccessfulAuthenticationAuthorities() { + return Collections.emptyList(); + }; + }