Initial check in accordance with Parallel IP

This commit is contained in:
Kai Zimmermann
2016-01-21 13:18:55 +01:00
parent c5e4f1139f
commit 7497ab61ed
763 changed files with 114508 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
<!--
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
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-security-integration</artifactId>
<name>hawkBit :: Security Integration</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-dmf-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
</dependencies>
</project>

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 org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An abstraction for all controller based security. Check if the tenant
* configuration is enabled.
*
*
*
*/
public abstract class AbstractControllerAuthenticationFilter implements PreAuthenficationFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractControllerAuthenticationFilter.class);
protected final SystemManagement systemManagement;
protected final TenantAware tenantAware;
private final SecurityConfigurationKeyTenantRunner configurationKeyTenantRunner;
protected AbstractControllerAuthenticationFilter(final SystemManagement systemManagement,
final TenantAware tenantAware) {
this.systemManagement = systemManagement;
this.tenantAware = tenantAware;
this.configurationKeyTenantRunner = new SecurityConfigurationKeyTenantRunner();
}
protected abstract TenantConfigurationKey getTenantConfigurationKey();
@Override
public boolean isEnable(final TenantSecruityToken secruityToken) {
return tenantAware.runAsTenant(secruityToken.getTenant(), configurationKeyTenantRunner);
}
@Override
public abstract HeaderAuthentication getPreAuthenticatedPrincipal(TenantSecruityToken secruityToken);
@Override
public abstract HeaderAuthentication getPreAuthenticatedCredentials(TenantSecruityToken secruityToken);
private final class SecurityConfigurationKeyTenantRunner implements TenantAware.TenantRunner<Boolean> {
@Override
public Boolean run() {
LOGGER.trace("retrieving configuration value for configuration key {}", getTenantConfigurationKey());
return systemManagement.getConfigurationValue(getTenantConfigurationKey(), Boolean.class);
}
}
}

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

View File

@@ -0,0 +1,126 @@
/**
* 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.TenantSecruityToken;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
/**
* An pre-authenticated processing filter which extracts (if enabled through
* configuration) the possibility to authenticate a target based on its target
* security-token with the {@code Authorization} HTTP header.
* {@code Example Header: Authorization: TargetToken
* 5d8fSD54fdsFG98DDsa.}
*
*
*
*/
public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractControllerAuthenticationFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(ControllerPreAuthenticateSecurityTokenFilter.class);
private static final String TARGET_SECURITY_TOKEN_AUTH_SCHEME = "TargetToken ";
private static final int OFFSET_TARGET_TOKEN = TARGET_SECURITY_TOKEN_AUTH_SCHEME.length();
private final ControllerManagement controllerManagement;
/**
* Constructor.
*
* @param systemManagement
* the system management service to retrieve configuration
* properties
* @param controllerManagement
* the controller management to retrieve the specific target
* security token to verify
* @param tenantAware
* the tenant aware service to get configuration for the specific
* tenant
*/
public ControllerPreAuthenticateSecurityTokenFilter(final SystemManagement systemManagement,
final ControllerManagement controllerManagement, final TenantAware tenantAware) {
super(systemManagement, tenantAware);
this.controllerManagement = controllerManagement;
}
@Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecruityToken secruityToken) {
final String authHeader = secruityToken.getHeader(TenantSecruityToken.AUTHORIZATION_HEADER);
if ((authHeader != null) && authHeader.startsWith(TARGET_SECURITY_TOKEN_AUTH_SCHEME)) {
LOGGER.debug("found authorization header with scheme {} using target security token for authentication",
TARGET_SECURITY_TOKEN_AUTH_SCHEME);
return new HeaderAuthentication(secruityToken.getControllerId(), authHeader.substring(OFFSET_TARGET_TOKEN));
}
LOGGER.debug(
"security token filter is enabled but requst does not contain either the necessary path variables {} or the authorization header with scheme {}",
secruityToken, TARGET_SECURITY_TOKEN_AUTH_SCHEME);
return null;
}
@Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecruityToken secruityToken) {
final String securityToken = tenantAware.runAsTenant(secruityToken.getTenant(),
new GetSecurityTokenTenantRunner(secruityToken.getTenant(), secruityToken.getControllerId()));
return new HeaderAuthentication(secruityToken.getControllerId(), securityToken);
}
@Override
protected TenantConfigurationKey getTenantConfigurationKey() {
return TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED;
}
private final class GetSecurityTokenTenantRunner implements TenantAware.TenantRunner<String> {
private final String controllerId;
private final String tenant;
private GetSecurityTokenTenantRunner(final String tenant, final String controllerId) {
this.tenant = tenant;
this.controllerId = controllerId;
}
@Override
public String run() {
LOGGER.trace("retrieving security token for controllerId {}", controllerId);
final SecurityContext oldContext = SecurityContextHolder.getContext();
try {
SecurityContextHolder.setContext(getSecurityTokenReadContext());
return controllerManagement.getSecurityTokenByControllerId(controllerId);
} finally {
SecurityContextHolder.setContext(oldContext);
}
}
private SecurityContext getSecurityTokenReadContext() {
final SecurityContextImpl securityContextImpl = new SecurityContextImpl();
securityContextImpl.setAuthentication(getSecurityTokenReadAuthentication());
return securityContextImpl;
}
private Authentication getSecurityTokenReadAuthentication() {
final AnonymousAuthenticationToken anonymousAuthenticationToken = new AnonymousAuthenticationToken(
"anonymous-read-security-token", "anonymous", com.google.common.collect.Lists
.newArrayList(new SimpleGrantedAuthority(SpPermission.READ_TARGET_SEC_TOKEN)));
anonymousAuthenticationToken.setDetails(new TenantAwareAuthenticationDetails(tenant, true));
return anonymousAuthenticationToken;
}
}
}

View File

@@ -0,0 +1,92 @@
/**
* 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.TenantSecruityToken;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An pre-authenticated processing filter which extracts (if enabled through
* configuration) the possibility to authenticate a target based through a
* gateway security token. This is commonly used for targets connected
* indirectly via a gateway. This gateway controls multiple targets under the
* gateway security token which can be set via the {@code TenantSecruityToken}
* header. {@code Example Header: Authorization: GatewayToken
* 5d8fSD54fdsFG98DDsa.}
*
*
*
*/
public class ControllerPreAuthenticatedGatewaySecurityTokenFilter extends AbstractControllerAuthenticationFilter {
private static final Logger LOGGER = LoggerFactory
.getLogger(ControllerPreAuthenticatedGatewaySecurityTokenFilter.class);
private static final String GATEWAY_SECURITY_TOKEN_AUTH_SCHEME = "GatewayToken ";
private static final int OFFSET_GATEWAY_TOKEN = GATEWAY_SECURITY_TOKEN_AUTH_SCHEME.length();
private final GetGatewaySecurityConfigurationKeyTenantRunner gatewaySecurityTokenKeyConfigRunner = new GetGatewaySecurityConfigurationKeyTenantRunner();
/**
* Constructor.
*
* @param systemManagement
* the system management service to retrieve configuration
* properties
* @param tenantAware
* the tenant aware service to get configuration for the specific
* tenant
*/
public ControllerPreAuthenticatedGatewaySecurityTokenFilter(final SystemManagement systemManagement,
final TenantAware tenantAware) {
super(systemManagement, tenantAware);
}
@Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecruityToken secruityToken) {
final String authHeader = secruityToken.getHeader(TenantSecruityToken.AUTHORIZATION_HEADER);
if ((authHeader != null) && authHeader.startsWith(GATEWAY_SECURITY_TOKEN_AUTH_SCHEME)) {
LOGGER.debug("found authorization header with scheme {} using target security token for authentication",
GATEWAY_SECURITY_TOKEN_AUTH_SCHEME);
return new HeaderAuthentication(secruityToken.getControllerId(),
authHeader.substring(OFFSET_GATEWAY_TOKEN));
}
LOGGER.debug(
"security token filter is enabled but request does not contain either the necessary secruity token {} or the authorization header with scheme {}",
secruityToken, GATEWAY_SECURITY_TOKEN_AUTH_SCHEME);
return null;
}
@Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecruityToken secruityToken) {
final String gatewayToken = tenantAware.runAsTenant(secruityToken.getTenant(),
gatewaySecurityTokenKeyConfigRunner);
return new HeaderAuthentication(secruityToken.getControllerId(), gatewayToken);
}
@Override
protected TenantConfigurationKey getTenantConfigurationKey() {
return TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED;
}
private final class GetGatewaySecurityConfigurationKeyTenantRunner implements TenantAware.TenantRunner<String> {
@Override
public String run() {
LOGGER.trace("retrieving configuration value for configuration key {}",
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY);
return systemManagement.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class);
}
}
}

View File

@@ -0,0 +1,149 @@
/**
* 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.TenantSecruityToken;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An pre-authenticated processing filter which extracts the principal from a
* request URI and the credential from a request header in a the
* {@link TenantSecruityToken}.
*
*
*
*/
public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractControllerAuthenticationFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(ControllerPreAuthenticatedSecurityHeaderFilter.class);
private static final Logger LOG_SECURITY_AUTH = LoggerFactory.getLogger("server-security.authentication");
private final GetSecurityAuthorityNameTenantRunner sslIssuerNameConfigTenantRunner = new GetSecurityAuthorityNameTenantRunner();
// Example Headers with Cert Information
// Clientip: 217.24.201.180
// X-Forwarded-Proto: https
// X-Ssl-Client-Cn: my.name
// X-Ssl-Client-Dn:
// CN=my.name,CN=O,CN=R,CN=DE,CN=BOSCH,CN=pki,DC=bosch,DC=com
// X-Ssl-Client-Hash: 7f:87:cb:b5:9c:e0:c5:0a:1a:a6:57:69:0f:ca:0a:95
// X-Ssl-Client-Notafter: Dec 18 08:02:45 2017 GMT
// X-Ssl-Client-Notbefore: Dec 18 07:32:45 2014 GMT
// X-Ssl-Client-Verify: ok
// X-Ssl-Issuer: CN=Bosch-CA1-DE,CN=PKI,DC=Bosch,DC=com
// X-Ssl-Issuer-Dn-1: CN=Bosch-CA-DE,CN=PKI,DC=Bosch,DC=com
// X-Ssl-Issuer-Hash-1: ae:11:f5:6a:0a:e8:74:50:81:0e:0c:37:ec:c5:22:fc
private final String caCommonNameHeader;
// the X-Ssl-Issuer-Hash basic header header which contains the x509
// fingerprint hash, this
// header exists multiple in the request for all trusted chain.
private final String sslIssuerHashBasicHeader;
/**
* Constructor.
*
* @param caCommonNameHeader
* the http-header which holds the common-name of the certificate
* @param caAuthorityNameHeader
* the http-header which holds the ca-authority name of the
* certificate
* @param systemManagement
* the system management service to retrieve configuration
* properties to check if the header authentication is enabled
* for this tenant
* @param tenantAware
* the tenant aware service to get configuration for the specific
* tenant
*/
public ControllerPreAuthenticatedSecurityHeaderFilter(final String caCommonNameHeader,
final String caAuthorityNameHeader, final SystemManagement systemManagement,
final TenantAware tenantAware) {
super(systemManagement, tenantAware);
this.caCommonNameHeader = caCommonNameHeader;
this.sslIssuerHashBasicHeader = caAuthorityNameHeader;
}
@Override
public HeaderAuthentication getPreAuthenticatedPrincipal(final TenantSecruityToken secruityToken) {
// retrieve the common name header and the authority name header from
// the http request and
// combine them together
final String commonNameValue = secruityToken.getHeader(caCommonNameHeader);
final String knownSslIssuerConfigurationValue = tenantAware.runAsTenant(secruityToken.getTenant(),
sslIssuerNameConfigTenantRunner);
final String sslIssuerHashValue = getIssuerHashHeader(secruityToken, knownSslIssuerConfigurationValue);
if (commonNameValue != null && LOGGER.isTraceEnabled()) {
LOGGER.trace("Found commonNameHeader {}={}, using as credentials", caCommonNameHeader, commonNameValue);
}
if (sslIssuerHashValue != null && LOGGER.isTraceEnabled()) {
LOGGER.trace("Found sslIssuerHash ****, using as credentials for tenant {}", secruityToken.getTenant());
}
if (commonNameValue != null && sslIssuerHashValue != null) {
return new HeaderAuthentication(commonNameValue, sslIssuerHashValue);
}
return null;
}
@Override
public HeaderAuthentication getPreAuthenticatedCredentials(final TenantSecruityToken secruityToken) {
final String authorityNameConfigurationValue = tenantAware.runAsTenant(secruityToken.getTenant(),
sslIssuerNameConfigTenantRunner);
String controllerId = secruityToken.getControllerId();
// in case of legacy download artifact, the controller ID is not in the
// URL path, so then
// we just use the common name header
if (controllerId == null || "anonymous".equals(controllerId)) {
controllerId = secruityToken.getHeader(caCommonNameHeader);
}
return new HeaderAuthentication(controllerId, authorityNameConfigurationValue);
}
/**
* Iterates over the {@link #sslIssuerHashBasicHeader} basic header
* {@code X-Ssl-Issuer-Hash-%d} and try to finds the same hash as known.
* It's ok if we find the the hash in any the trusted CA chain to accept
* this request for this tenant.
*/
private String getIssuerHashHeader(final TenantSecruityToken secruityToken, final String knownIssuerHash) {
// iterate over the headers until we get a null header.
int iHeader = 1;
String foundHash = null;
while ((foundHash = secruityToken.getHeader(String.format(sslIssuerHashBasicHeader, iHeader))) != null) {
if (foundHash.equals(knownIssuerHash)) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Found matching ssl issuer hash at position {}", iHeader);
}
return foundHash;
}
iHeader++;
}
LOG_SECURITY_AUTH.debug(
"Certifacte request but no matching hash found in headers {} for common name {} in request",
sslIssuerHashBasicHeader, secruityToken.getHeader(caCommonNameHeader));
return null;
}
@Override
protected TenantConfigurationKey getTenantConfigurationKey() {
return TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
}
private final class GetSecurityAuthorityNameTenantRunner implements TenantAware.TenantRunner<String> {
@Override
public String run() {
return systemManagement.getConfigurationValue(
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class);
}
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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;
/**
* The authentication principal and credentials object which holds the
* controller-id and the authority name from the http-headers as principal or
* from the http-url and tenant configuration for the credentials.
*
*
*
*/
public final class HeaderAuthentication {
private final String controllerId;
private final String headerAuth;
HeaderAuthentication(final String controllerId, final String headerAuth) {
this.controllerId = controllerId;
this.headerAuth = headerAuth;
}
@Override
public int hashCode() {// NOSONAR - as this is generated
final int prime = 31;
int result = 1;
result = prime * result + ((controllerId == null) ? 0 : controllerId.hashCode());
result = prime * result + ((headerAuth == null) ? 0 : headerAuth.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {// NOSONAR - as this is generated
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final HeaderAuthentication other = (HeaderAuthentication) obj;
if (controllerId == null) {
if (other.controllerId != null) {
return false;
}
} else if (!controllerId.equals(other.controllerId)) {
return false;
}
if (headerAuth == null) {
if (other.headerAuth != null) {
return false;
}
} else if (!headerAuth.equals(other.headerAuth)) {
return false;
}
return true;
}
@Override
public String toString() {
// only the controller ID because the principal is stored as string for
// audit information
// etc.
return controllerId;
}
}

View File

@@ -0,0 +1,158 @@
/**
* 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.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
/**
* An spring authentication provider which supportes authentication tokens of
* type {@link PreAuthenticatedAuthenticationToken} created by the
* {@link ControllerPreAuthenticatedSecurityHeaderFilter}.
*
* Addtionally to the authentication token providing the principal and the
* credentials which must be match, this authentication provider can also check
* the remote IP address of the request.
*
* E.g. The request path is /controller/v1/{controllerId} then the controllerId
* in the path is the principal. The credentials are the extracted information
* from e.g. a certificate provided by an reverse proxy. Due this request is
* only allowed from a specific source address this authentication manager can
* also check the remote IP address of the request.
*
*
*
*/
public class PreAuthTokenSourceTrustAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(PreAuthenticatedAuthenticationToken.class);
private final List<String> authorizedSourceIps;
/**
* Creates a new PreAuthTokenSourceTrustAuthenticationProvider without
* source IPs, which disables the source IP check.
*/
public PreAuthTokenSourceTrustAuthenticationProvider() {
authorizedSourceIps = null;
}
/**
* Creates a new PreAuthTokenSourceTrustAuthenticationProvider with given
* source IP addresses which are trusted and should be checked against the
* request remote IP address.
*
* @param authorizedSourceIps
* a list of IP addresses.
*/
public PreAuthTokenSourceTrustAuthenticationProvider(final List<String> authorizedSourceIps) {
this.authorizedSourceIps = authorizedSourceIps;
}
/**
* Creates a new PreAuthTokenSourceTrustAuthenticationProvider with given
* source IP addresses which are trusted and should be checked against the
* request remote IP address.
*
* @param authorizedSourceIps
* a list of IP addresses.
*/
public PreAuthTokenSourceTrustAuthenticationProvider(final String... authorizedSourceIps) {
this.authorizedSourceIps = new ArrayList<>();
for (final String ip : authorizedSourceIps) {
this.authorizedSourceIps.add(ip);
}
}
@Override
public Authentication authenticate(final Authentication authentication) {
if (!supports(authentication.getClass())) {
return null;
}
boolean successAuthentication = false;
final PreAuthenticatedAuthenticationToken token = (PreAuthenticatedAuthenticationToken) authentication;
final Object credentials = token.getCredentials();
final Object principal = token.getPrincipal();
final Object tokenDetails = token.getDetails();
if (principal == null) {
throw new BadCredentialsException("The provided principal and credentials are not match");
}
// check if principal equals credentials because we want to check if
// e.g. controllerId
// containing in the URL equals the controllerId in the special header
// set by the reverse
// proxy which extracted the CN from the certificate
if (principal.equals(credentials)) {
successAuthentication = checkSourceIPAddressIfNeccessary(tokenDetails);
}
if (successAuthentication) {
final Collection<GrantedAuthority> controllerAuthorities = new ArrayList<>();
controllerAuthorities.add(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE));
final PreAuthenticatedAuthenticationToken successToken = new PreAuthenticatedAuthenticationToken(principal,
credentials, controllerAuthorities);
successToken.setDetails(tokenDetails);
return successToken;
}
throw new BadCredentialsException("The provided principal and credentials are not match");
}
private boolean checkSourceIPAddressIfNeccessary(final Object tokenDetails) {
boolean success = authorizedSourceIps == null;
String remoteAddress = null;
// controllerIds in URL path and request header are the same but is the
// request coming
// from a trustful source, like the reverse proxy.
if (authorizedSourceIps != null) {
if (!(tokenDetails instanceof TenantAwareWebAuthenticationDetails)) {
// is not of type WebAuthenticationDetails, then we cannot
// determine the remote address!
LOGGER.error(
"Cannot determine the controller remote-ip-address based on the given authentication token - {} , token details are not TenantAwareWebAuthenticationDetails! ",
tokenDetails);
success = false;
} else {
remoteAddress = ((TenantAwareWebAuthenticationDetails) tokenDetails).getRemoteAddress();
if (authorizedSourceIps.contains(remoteAddress)) {
// source ip matches the given pattern -> authenticated
success = true;
}
}
}
if (!success) {
throw new InsufficientAuthenticationException("The remote source IP address " + remoteAddress
+ " is not in the list of trusted IP addresses " + authorizedSourceIps);
}
// no trusted IP check, because no authorizedSourceIPs configuration
return true;
}
@Override
public boolean supports(final Class<?> authentication) {
return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
}
}

View File

@@ -0,0 +1,48 @@
/**
* 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.TenantSecruityToken;
/**
* Interface for Pre Authenfication.
*
*
*
*/
public interface PreAuthenficationFilter {
/**
* Check if the filter is enabled.
*
* @param secruityToken
* the secruity info
* @return <true> is enabled <false> diabled
*/
boolean isEnable(TenantSecruityToken secruityToken);
/**
* Extract the principal information from the current secruityToken.
*
* @param secruityToken
* the secruityToken
* @return the extracted tenant and controller id
*/
HeaderAuthentication getPreAuthenticatedPrincipal(TenantSecruityToken secruityToken);
/**
* Extract the principal credentials from the current secruityToken.
*
* @param secruityToken
* the secruityToken
* @return the extracted tenant and controller id
*/
HeaderAuthentication getPreAuthenticatedCredentials(TenantSecruityToken secruityToken);
}

View File

@@ -0,0 +1,51 @@
/**
* 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 javax.servlet.http.HttpServletRequest;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
/**
* Extends the {@link TenantAwareAuthenticationDetails} to web information to
* retrieve also e.g. the remoteAddress of the {@link HttpServletRequest} when
* authenticating the requested controller e.g. based on the security header and
* trusted IP address we need the remote address of the http request to verify
* the e.g. the reverse proxy is trusted and allowed to set the header.
*
*
*
*/
public class TenantAwareWebAuthenticationDetails extends TenantAwareAuthenticationDetails {
private static final long serialVersionUID = 1L;
private final String remoteAddress;
/**
* @param tenant
* the current tenant
* @param remoteAddress
* the remote address of this web request
* @param controller
* {@code true} indicates this is an controller HTTP request
* otherwise {@code false}.
*/
public TenantAwareWebAuthenticationDetails(final String tenant, final String remoteAddress,
final boolean controller) {
super(tenant, controller);
this.remoteAddress = remoteAddress;
}
/**
* @return the remoteAddress
*/
public String getRemoteAddress() {
return remoteAddress;
}
}