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,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;
}
}