Merge branch 'master' into Feature_Improve_Code_Quality

Conflicts:
	hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java
	hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java
	hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java
	hawkbit-repository/src/main/java/org/eclipse/hawkbit/eventbus/CacheFieldEntityListener.java
	hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java


Signed-off-by: Michael Hirsch <michael.hirsch@bosch-si.com>
This commit is contained in:
Michael Hirsch
2016-07-25 10:08:24 +02:00
805 changed files with 31882 additions and 22829 deletions

View File

@@ -21,7 +21,7 @@
<dependencies>
<dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-core</artifactId>
<version>${project.version}</version>

View File

@@ -17,7 +17,7 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
/**
*
* Service to check permissions.
*
*/
public class PermissionService {

View File

@@ -0,0 +1,55 @@
/**
* 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.im.authentication;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
/**
* Utility method for creation of <tt>GrantedAuthority</tt> collections etc.
*/
public final class PermissionUtils {
private PermissionUtils() {
}
/**
* Create {@link GrantedAuthority} by a special role.
*
* @param roles
* the roles
* @return a list of {@link GrantedAuthority}
*/
public static List<GrantedAuthority> createAuthorityList(final Collection<String> roles) {
final List<GrantedAuthority> authorities = new ArrayList<>(roles.size());
for (final String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
// add spring security ROLE authority which is indicated by the
// `ROLE_` prefix
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}
return authorities;
}
/**
* Returns all authorities.
*
* @return a list of {@link GrantedAuthority}
*/
public static List<GrantedAuthority> createAllAuthorityList() {
return createAuthorityList(SpPermission.getAllAuthorities());
}
}

View File

@@ -9,7 +9,16 @@
package org.eclipse.hawkbit.im.authentication;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
@@ -35,6 +44,8 @@ import org.springframework.security.core.GrantedAuthority;
*/
public final class SpPermission {
private static final Logger LOGGER = LoggerFactory.getLogger(SpPermission.class);
/**
* Permission to read the targets from the
* {@link ProvisioningTargetRepository} including their meta information,
@@ -139,6 +150,53 @@ public final class SpPermission {
// Constants only
}
/**
* Return all permission.
*
* @return all permission
*/
public static Collection<String> getAllAuthorities() {
return getAllAuthorities(Collections.emptyList());
}
/**
* Return all permission.
*
* @param exclusionRoles
* roles which will excluded
* @return all permissions
*/
public static Collection<String> getAllAuthorities(final String... exclusionRoles) {
return getAllAuthorities(Arrays.asList(exclusionRoles));
}
/**
* Return all permission.
*
* @param exclusionRoles
* roles which will excluded
* @return all permissions
*/
public static Collection<String> getAllAuthorities(final Collection<String> exclusionRoles) {
final List<String> allPermissions = new ArrayList<>();
final Field[] declaredFields = SpPermission.class.getDeclaredFields();
for (final Field field : declaredFields) {
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) {
field.setAccessible(true);
try {
final String role = (String) field.get(null);
if (!(exclusionRoles.contains(role))) {
allPermissions.add(role);
}
} catch (final IllegalAccessException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
return allPermissions;
}
/**
* Contains all the spring security evaluation expressions for the
* {@link PreAuthorize} annotation for method security.
@@ -166,8 +224,10 @@ public final class SpPermission {
/*
* Spring security eval expressions.
*/
private static final String HAS_AUTH_PREFIX = "hasAuthority('";
private static final String HAS_AUTH_SUFFIX = "')";
private static final String BRACKET_OPEN = "(";
private static final String BRACKET_CLOSE = ")";
private static final String HAS_AUTH_PREFIX = "hasAuthority" + BRACKET_OPEN + "'";
private static final String HAS_AUTH_SUFFIX = "'" + BRACKET_CLOSE;
private static final String HAS_AUTH_AND = " and ";
/**
@@ -199,99 +259,6 @@ public final class SpPermission {
*/
public static final String HAS_AUTH_OR = " or ";
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#UPDATE_TARGET}.
*/
public static final String HAS_AUTH_UPDATE_TARGET = HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#SYSTEM_ADMIN}.
*/
public static final String HAS_AUTH_SYSTEM_ADMIN = HAS_AUTH_PREFIX + SYSTEM_ADMIN + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#READ_TARGET}.
*/
public static final String HAS_AUTH_READ_TARGET = HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#CREATE_TARGET}.
*/
public static final String HAS_AUTH_CREATE_TARGET = HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#DELETE_TARGET}.
*/
public static final String HAS_AUTH_DELETE_TARGET = HAS_AUTH_PREFIX + DELETE_TARGET + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#READ_REPOSITORY} and
* {@link SpPermission#UPDATE_TARGET}.
*/
public static final String HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET = HAS_AUTH_PREFIX + READ_REPOSITORY
+ HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#CREATE_REPOSITORY}.
*/
public static final String HAS_AUTH_CREATE_REPOSITORY = HAS_AUTH_PREFIX + CREATE_REPOSITORY + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#DELETE_REPOSITORY}.
*/
public static final String HAS_AUTH_DELETE_REPOSITORY = HAS_AUTH_PREFIX + DELETE_REPOSITORY + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#READ_REPOSITORY}.
*/
public static final String HAS_AUTH_READ_REPOSITORY = HAS_AUTH_PREFIX + READ_REPOSITORY + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#UPDATE_REPOSITORY}.
*/
public static final String HAS_AUTH_UPDATE_REPOSITORY = HAS_AUTH_PREFIX + UPDATE_REPOSITORY + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#READ_REPOSITORY} and
* {@link SpPermission#READ_TARGET}.
*/
public static final String HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET = HAS_AUTH_PREFIX + READ_REPOSITORY
+ HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#DOWNLOAD_REPOSITORY_ARTIFACT}.
*/
public static final String HAS_AUTH_DOWNLOAD_ARTIFACT = HAS_AUTH_PREFIX + DOWNLOAD_REPOSITORY_ARTIFACT
+ HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAnyRole expression to check if the spring
* 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
+ "')";
/**
* 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
* context contains system code role
@@ -301,33 +268,168 @@ public final class SpPermission {
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#CREATE_REPOSITORY} and
* {@link SpPermission#CREATE_TARGET}.
* context contains {@link SpPermission#UPDATE_TARGET} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_CREATE_REPOSITORY_AND_CREATE_TARGET = HAS_AUTH_PREFIX + CREATE_REPOSITORY
+ HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_UPDATE_TARGET = HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#ROLLOUT_MANAGEMENT}
* context contains {@link SpPermission#SYSTEM_ADMIN} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_SYSTEM_ADMIN = HAS_AUTH_PREFIX + SYSTEM_ADMIN + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#READ_TARGET} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_READ_TARGET = HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + HAS_AUTH_OR
+ IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#CREATE_TARGET} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_CREATE_TARGET = HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#DELETE_TARGET} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_DELETE_TARGET = HAS_AUTH_PREFIX + DELETE_TARGET + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#READ_REPOSITORY} and
* {@link SpPermission#UPDATE_TARGET} or {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX
+ READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX
+ BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#CREATE_REPOSITORY} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_CREATE_REPOSITORY = HAS_AUTH_PREFIX + CREATE_REPOSITORY + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#DELETE_REPOSITORY} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_DELETE_REPOSITORY = HAS_AUTH_PREFIX + DELETE_REPOSITORY + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#READ_REPOSITORY} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_READ_REPOSITORY = HAS_AUTH_PREFIX + READ_REPOSITORY + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#UPDATE_REPOSITORY} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_UPDATE_REPOSITORY = HAS_AUTH_PREFIX + UPDATE_REPOSITORY + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#READ_REPOSITORY} and
* {@link SpPermission#READ_TARGET} or {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX
+ READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX
+ BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#DOWNLOAD_REPOSITORY_ARTIFACT} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_DOWNLOAD_ARTIFACT = HAS_AUTH_PREFIX + DOWNLOAD_REPOSITORY_ARTIFACT
+ HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAnyRole expression to check if the spring
* context contains the anoynmous role or the controller specific role
* {@link SpringEvalExpressions#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 SpringEvalExpressions#CONTROLLER_DOWNLOAD_ROLE}
*/
public static final String HAS_CONTROLLER_DOWNLOAD = HAS_AUTH_PREFIX + CONTROLLER_DOWNLOAD_ROLE
+ HAS_AUTH_SUFFIX;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#CREATE_REPOSITORY} and
* {@link SpPermission#CREATE_TARGET} or {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_CREATE_REPOSITORY_AND_CREATE_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX
+ CREATE_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX
+ BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#ROLLOUT_MANAGEMENT} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_READ = HAS_AUTH_PREFIX + ROLLOUT_MANAGEMENT
+ HAS_AUTH_SUFFIX;
+ HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#ROLLOUT_MANAGEMENT} and
* {@link SpPermission#UPDATE_TARGET}.
* {@link SpPermission#READ_TARGET} or {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE = HAS_AUTH_PREFIX + ROLLOUT_MANAGEMENT
+ HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX;
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ = BRACKET_OPEN + HAS_AUTH_PREFIX
+ ROLLOUT_MANAGEMENT + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX
+ BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#TENANT_CONFIGURATION}
* context contains {@link SpPermission#ROLLOUT_MANAGEMENT} and
* {@link SpPermission#UPDATE_TARGET} or {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE = BRACKET_OPEN + HAS_AUTH_PREFIX
+ ROLLOUT_MANAGEMENT + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET
+ HAS_AUTH_SUFFIX + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#TENANT_CONFIGURATION} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_TENANT_CONFIGURATION = HAS_AUTH_PREFIX + TENANT_CONFIGURATION
+ HAS_AUTH_SUFFIX;
+ HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE;
/**
* Spring security eval hasAuthority expression to check if spring
* context contains {@link SpPermission#SYSTEM_MONITOR} or
* {@link #IS_SYSTEM_CODE}.
*/
public static final String HAS_AUTH_SYSTEM_MONITOR = HAS_AUTH_PREFIX + SYSTEM_MONITOR + HAS_AUTH_SUFFIX
+ HAS_AUTH_OR + IS_SYSTEM_CODE;
private SpringEvalExpressions() {
// utility class

View File

@@ -8,8 +8,10 @@
*/
package org.eclipse.hawkbit.security;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.hawkbit.security.SecurityConstants.SECURITY_LOG_PREFIX;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
@@ -31,25 +33,21 @@ import com.google.common.cache.CacheBuilder;
/**
* Filter for protection against denial of service attacks. It reduces the
* maximum number of request per seconds which can be separately configured for
* read (GET) and write (PUT/POST/DELETE) requests. requests
*
*
*
*
* read (GET) and write (PUT/POST/DELETE) requests.
*/
public class DosFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(DosFilter.class);
private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos");
private static final Logger LOG_BLACKLIST = LoggerFactory.getLogger("server-security.blacklist");
private static final Logger LOG_DOS = LoggerFactory.getLogger(SECURITY_LOG_PREFIX + ".dos");
private static final Logger LOG_BLACKLIST = LoggerFactory.getLogger(SECURITY_LOG_PREFIX + ".blacklist");
private final Pattern ipAdressBlacklist;
private final Cache<String, AtomicInteger> readCountCache = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.SECONDS).build();
private final Cache<String, AtomicInteger> readCountCache = CacheBuilder.newBuilder().expireAfterAccess(1, SECONDS)
.build();
private final Cache<String, AtomicInteger> writeCountCache = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.SECONDS).build();
private final Cache<String, AtomicInteger> writeCountCache = CacheBuilder.newBuilder().expireAfterAccess(1, SECONDS)
.build();
private final Integer maxRead;
private final Integer maxWrite;
@@ -78,7 +76,7 @@ public class DosFilter extends OncePerRequestFilter {
*/
public DosFilter(final Integer maxRead, final Integer maxWrite, final String ipDosWhiteListPattern,
final String ipBlackListPattern, final String forwardHeader) {
super();
this.maxRead = maxRead;
this.maxWrite = maxWrite;
this.forwardHeader = forwardHeader;
@@ -96,21 +94,13 @@ public class DosFilter extends OncePerRequestFilter {
}
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(
* javax.servlet.http. HttpServletRequest,
* javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
*/
@Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
final FilterChain filterChain) throws ServletException, IOException {
boolean processChain;
final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader).getHost();
final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader, true).getHost();
if (checkIpFails(ip)) {
processChain = handleMissingIpAddress(response);
} else {
@@ -152,11 +142,9 @@ public class DosFilter extends OncePerRequestFilter {
}
private static boolean handleMissingIpAddress(final HttpServletResponse response) {
boolean processChain;
LOG.error("Failed to get peer IP adress");
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
processChain = false;
return processChain;
return false;
}
private boolean handleWriteRequest(final HttpServletResponse response, final String ip) {

View File

@@ -82,10 +82,16 @@ public class HawkbitSecurityProperties {
private String blacklist = "";
/**
* Name of the http header from which the remote ip is extracted.
* Name of the http header from which the remote ip is extracted for DDI
* connected clients.
*/
private String remoteIpHeader = "X-Forwarded-For";
/**
* Set to <code>true</code> if DDI clients remote IP should be stored.
*/
private boolean trackRemoteIp = true;
public String getBlacklist() {
return blacklist;
}
@@ -101,6 +107,14 @@ public class HawkbitSecurityProperties {
public void setRemoteIpHeader(final String remoteIpHeader) {
this.remoteIpHeader = remoteIpHeader;
}
public boolean isTrackRemoteIp() {
return trackRemoteIp;
}
public void setTrackRemoteIp(final boolean trackRemoteIp) {
this.trackRemoteIp = trackRemoteIp;
}
}
/**

View File

@@ -0,0 +1,24 @@
/**
* 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;
/**
* Constants related to security.
*/
public final class SecurityConstants {
/**
* Logger prefix used for security logging.
*/
public static final String SECURITY_LOG_PREFIX = "server-security";
private SecurityConstants() {
}
}

View File

@@ -8,13 +8,16 @@
*/
package org.eclipse.hawkbit.security;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Collection;
import java.util.Collections;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
/**
* A {@link TenantAware} implemenation which retrieves the ID of the tenant from
@@ -22,15 +25,9 @@ import org.springframework.security.core.context.SecurityContextHolder;
* {@link Authentication#getDetails()} which holds the
* {@link TenantAwareAuthenticationDetails} object.
*
*
*
*
*/
public class SecurityContextTenantAware implements TenantAware {
private static final ThreadLocal<String> TENANT_THREAD_LOCAL = new ThreadLocal<>();
private static final ThreadLocal<AtomicInteger> RUN_AS_DEPTH = new ThreadLocal<>();
/*
* (non-Javadoc)
*
@@ -38,9 +35,6 @@ public class SecurityContextTenantAware implements TenantAware {
*/
@Override
public String getCurrentTenant() {
if (TENANT_THREAD_LOCAL.get() != null) {
return TENANT_THREAD_LOCAL.get();
}
final SecurityContext context = SecurityContextHolder.getContext();
if (context.getAuthentication() != null) {
final Object authDetails = context.getAuthentication().getDetails();
@@ -51,29 +45,96 @@ public class SecurityContextTenantAware implements TenantAware {
return null;
}
/*
* (non-Javadoc)
*
* @see hawkbit.server.tenancy.TenantAware#runAsTenant(java.lang.String,
* java.util.concurrent.Callable)
*/
@Override
public <T> T runAsTenant(final String tenant, final TenantRunner<T> callable) {
AtomicInteger runAsDepth = RUN_AS_DEPTH.get();
if (runAsDepth == null) {
runAsDepth = new AtomicInteger(1);
RUN_AS_DEPTH.set(runAsDepth);
} else {
runAsDepth.incrementAndGet();
}
TENANT_THREAD_LOCAL.set(tenant);
final SecurityContext originalContext = SecurityContextHolder.getContext();
try {
SecurityContextHolder.setContext(buildSecurityContext(tenant));
return callable.run();
} finally {
if (runAsDepth.decrementAndGet() <= 0) {
RUN_AS_DEPTH.remove();
TENANT_THREAD_LOCAL.remove();
SecurityContextHolder.setContext(originalContext);
}
}
private SecurityContext buildSecurityContext(final String tenant) {
final SecurityContextImpl securityContext = new SecurityContextImpl();
securityContext.setAuthentication(
new AuthenticationDelegate(SecurityContextHolder.getContext().getAuthentication(), tenant));
return securityContext;
}
/**
* An {@link Authentication} implementation to delegate to an existing
* {@link Authentication} object except setting the details specifically for
* a specific tenant.
*/
private class AuthenticationDelegate implements Authentication {
private static final long serialVersionUID = 1L;
private final Authentication delegate;
private final TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails;
private AuthenticationDelegate(final Authentication delegate, final String tenant) {
this.delegate = delegate;
tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false);
}
@Override
public boolean equals(final Object another) {
if (delegate != null) {
return delegate.equals(another);
} else if (another == null) {
return true;
}
return false;
}
@Override
public String toString() {
return (delegate != null) ? delegate.toString() : null;
}
@Override
public int hashCode() {
return (delegate != null) ? delegate.hashCode() : -1;
}
@Override
public String getName() {
return (delegate != null) ? delegate.getName() : null;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return (delegate != null) ? delegate.getAuthorities() : Collections.emptyList();
}
@Override
public Object getCredentials() {
return (delegate != null) ? delegate.getCredentials() : null;
}
@Override
public Object getDetails() {
return tenantAwareAuthenticationDetails;
}
@Override
public Object getPrincipal() {
return (delegate != null) ? delegate.getPrincipal() : null;
}
@Override
public boolean isAuthenticated() {
return (delegate != null) ? delegate.isAuthenticated() : true;
}
@Override
public void setAuthenticated(final boolean isAuthenticated) {
if (delegate == null) {
return;
}
delegate.setAuthenticated(isAuthenticated);
}
}
}

View File

@@ -14,12 +14,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
/**
* Auditor class that allows {@link BaseEntity}s to insert currenlt logged in
* user for repository changes.
*
*
*
*
* Auditor class that allows BaseEntitys to insert current logged in user for
* repository changes.
*
*/
public class SpringSecurityAuditorAware implements AuditorAware<String> {
@@ -29,16 +25,21 @@ public class SpringSecurityAuditorAware implements AuditorAware<String> {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
if (isAuthenticationInvalid(authentication)) {
return null;
}
if (authentication.getPrincipal() != null) {
if (authentication.getPrincipal() instanceof UserDetails) {
return ((UserDetails) authentication.getPrincipal()).getUsername();
}
return authentication.getPrincipal().toString();
return getCurrentAuditor(authentication);
}
private String getCurrentAuditor(final Authentication authentication) {
if (authentication.getPrincipal() instanceof UserDetails) {
return ((UserDetails) authentication.getPrincipal()).getUsername();
}
return null;
return authentication.getPrincipal().toString();
}
private static boolean isAuthenticationInvalid(final Authentication authentication) {
return authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() == null;
}
}

View File

@@ -34,7 +34,7 @@ import com.google.common.base.Throwables;
@Service
public class SystemSecurityContext {
private static final Logger LOGGER = LoggerFactory.getLogger(SystemSecurityContext.class);
private static final Logger logger = LoggerFactory.getLogger(SystemSecurityContext.class);
private final TenantAware tenantAware;
@@ -60,27 +60,55 @@ public class SystemSecurityContext {
* The security context will be switched to the system code and back after
* the callable is called.
*
* The system code is executed for a current tenant by using the
* {@link TenantAware#getCurrentTenant()}.
*
* @param callable
* the callable to call within the system security context
* @return the return value of the {@link Callable#call()} method.
*/
// Exception squid:S2221 - Callable declares Exception
@SuppressWarnings("squid:S2221")
public <T> T runAsSystem(final Callable<T> callable) {
return runAsSystemAsTenant(callable, tenantAware.getCurrentTenant());
}
/**
* Runs a given {@link Callable} within a system security context, which is
* permitted to call secured system code. Often the system needs to call
* secured methods by it's own without relying on the current security
* context e.g. if the current security context does not contain the
* necessary permission it's necessary to execute code as system code to
* execute necessary methods and functionality.
*
* The security context will be switched to the system code and back after
* the callable is called.
*
* The system code is executed for a specific given tenant by using the
* {@link TenantAware}.
*
* @param callable
* the callable to call within the system security context
* @param tenant
* the tenant to act as system code
* @return the return value of the {@link Callable#call()} method.
*/
public <T> T runAsSystemAsTenant(final Callable<T> callable, final String tenant) {
final SecurityContext oldContext = SecurityContextHolder.getContext();
try {
LOGGER.debug("entering system code execution");
return tenantAware.runAsTenant(tenantAware.getCurrentTenant(), () -> {
logger.debug("entering system code execution");
return tenantAware.runAsTenant(tenant, () -> {
try {
setSystemContext();
setSystemContext(SecurityContextHolder.getContext());
return callable.call();
// The callable API throws a Exception and not a specific
} catch (@SuppressWarnings("squid:S2221") final Exception e) {
} catch (final Exception e) {
throw Throwables.propagate(e);
}
});
} finally {
SecurityContextHolder.setContext(oldContext);
LOGGER.debug("leaving system code execution");
logger.debug("leaving system code execution");
}
}
@@ -92,20 +120,30 @@ public class SystemSecurityContext {
return SecurityContextHolder.getContext().getAuthentication() instanceof SystemCodeAuthentication;
}
private static void setSystemContext() {
private static void setSystemContext(final SecurityContext oldContext) {
final Authentication oldAuthentication = oldContext.getAuthentication();
final SecurityContextImpl securityContextImpl = new SecurityContextImpl();
securityContextImpl.setAuthentication(new SystemCodeAuthentication());
securityContextImpl.setAuthentication(new SystemCodeAuthentication(oldAuthentication));
SecurityContextHolder.setContext(securityContextImpl);
}
/**
* Authentication with the system role.
* An implementation of the Spring's {@link Authentication} object which is
* used within a system security code block and wraps the original
* authentication object. The wrapped object contains the necessary
* {@link SpringEvalExpressions#SYSTEM_ROLE} which is allowed to execute all
* secured methods.
*/
public static class SystemCodeAuthentication implements Authentication {
private static final long serialVersionUID = 1L;
private static final List<SimpleGrantedAuthority> AUTHORITIES = Collections
.singletonList(new SimpleGrantedAuthority(SpringEvalExpressions.SYSTEM_ROLE));
private final Authentication oldAuthentication;
private SystemCodeAuthentication(final Authentication oldAuthentication) {
this.oldAuthentication = oldAuthentication;
}
@Override
public String getName() {
@@ -119,17 +157,17 @@ public class SystemSecurityContext {
@Override
public Object getCredentials() {
return null;
return oldAuthentication != null ? oldAuthentication.getCredentials() : null;
}
@Override
public Object getDetails() {
return null;
return oldAuthentication != null ? oldAuthentication.getDetails() : null;
}
@Override
public Object getPrincipal() {
return null;
return oldAuthentication != null ? oldAuthentication.getPrincipal() : null;
}
@Override

View File

@@ -15,6 +15,8 @@ import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import com.google.common.net.HttpHeaders;
/**
@@ -24,6 +26,7 @@ import com.google.common.net.HttpHeaders;
*/
public final class IpUtil {
private static final String HIDDEN_IP = "***";
private static final String SCHEME_SEPERATOR = "://";
private static final String HTTP_SCHEME = "http";
private static final String AMPQP_SCHEME = "amqp";
@@ -45,17 +48,49 @@ public final class IpUtil {
* @param request
* the {@link HttpServletRequest} to determine the IP address
* where this request has been sent from
* @param forwardHeader
* the header name containing the IP address e.g. forwarded by a
* proxy {@code x-forwarded-for}
* @param securityProperties
* hawkBit security properties.
* @return the {@link URI} based IP address from the client which sent the
* request
*/
public static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader) {
String ip = request.getHeader(forwardHeader);
if (ip == null || (ip = findClientIpAddress(ip)) == null) {
ip = request.getRemoteAddr();
public static URI getClientIpFromRequest(final HttpServletRequest request,
final HawkbitSecurityProperties securityProperties) {
return getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader(),
securityProperties.getClients().isTrackRemoteIp());
}
/**
* Retrieves the string based IP address from a given
* {@link HttpServletRequest} by either the
* {@link HttpHeaders#X_FORWARDED_FOR} or by the
* {@link HttpServletRequest#getRemoteAddr()} methods.
*
* @param request
* the {@link HttpServletRequest} to determine the IP address
* where this request has been sent from
* @param forwardHeader
* the header name containing the IP address e.g. forwarded by a
* proxy {@code x-forwarded-for}
*
* @param trackRemoteIp
* to <code>true</code> if remote IP should be tracked.
* @return the {@link URI} based IP address from the client which sent the
* request
*/
public static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader,
final boolean trackRemoteIp) {
String ip;
if (trackRemoteIp) {
ip = request.getHeader(forwardHeader);
if (ip == null || (ip = findClientIpAddress(ip)) == null) {
ip = request.getRemoteAddr();
}
} else {
ip = HIDDEN_IP;
}
return createHttpUri(ip);
}
@@ -144,4 +179,17 @@ public final class IpUtil {
public static boolean isAmqpUri(final URI uri) {
return uri != null && AMPQP_SCHEME.equals(uri.getScheme());
}
/**
* Check if the IP address of that {@link URI} is known, i.e. not an AQMP
* exchange in DMF case and not HIDDEN_IP in DDI case.
*
* @param uri
* the uri
* @return <code>true</code> if IP address is actually known by the server
*/
public static boolean isIpAddresKnown(final URI uri) {
return uri != null && !(AMPQP_SCHEME.equals(uri.getScheme()) || HIDDEN_IP.equals(uri.getHost()));
}
}

View File

@@ -0,0 +1,56 @@
/**
* 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.im.authentication;
import static org.fest.assertions.api.Assertions.assertThat;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import org.springframework.context.annotation.Description;
import org.springframework.security.core.GrantedAuthority;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test {@link SpPermission}.
*/
@Features("Unit Tests - Security")
@Stories("Permission Test")
public final class PermissionTest {
@Test
@Description("Verify the get permission function")
public void testGetPermissions() {
final int allPermission = 15;
final int permissionWithoutSystem = allPermission - 3;
final Collection<String> allAuthorities = SpPermission.getAllAuthorities();
final List<GrantedAuthority> allAuthoritiesList = PermissionUtils.createAllAuthorityList();
assertThat(allAuthorities).hasSize(allPermission);
// times 2 because we add also all authorities as prefix 'ROLE_';
assertThat(allAuthoritiesList).hasSize(allPermission * 2);
assertThat(allAuthoritiesList.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
.containsAll(allAuthorities);
final Collection<String> authoritiesWithoutSystem = SpPermission.getAllAuthorities(SpPermission.SYSTEM_ADMIN,
SpPermission.SYSTEM_DIAG, SpPermission.SYSTEM_MONITOR);
final List<GrantedAuthority> authoritiesListWithoutSystem = PermissionUtils.createAuthorityList(SpPermission
.getAllAuthorities(SpPermission.SYSTEM_ADMIN, SpPermission.SYSTEM_DIAG, SpPermission.SYSTEM_MONITOR));
assertThat(authoritiesWithoutSystem).hasSize(permissionWithoutSystem);
// times 2 because we add also all authorities as prefix 'ROLE_';
assertThat(authoritiesListWithoutSystem).hasSize(permissionWithoutSystem * 2);
assertThat(authoritiesListWithoutSystem.stream().map(authority -> authority.getAuthority())
.collect(Collectors.toList())).containsAll(authoritiesWithoutSystem);
}
}

View File

@@ -50,7 +50,7 @@ public class IpUtilTest {
when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost());
// test
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux");
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux", true);
// verify
assertThat(remoteAddr).as("The remote address should be as the known client IP address")
@@ -59,6 +59,25 @@ public class IpUtilTest {
verify(requestMock, times(1)).getRemoteAddr();
}
@Test
@Description("Tests create uri from request with masked IP when IP tracking is disabled")
public void maskRemoteAddrIfDisabled() {
// known values
final URI knownRemoteClientIP = IpUtil.createHttpUri("***");
// mock
when(requestMock.getHeader(HttpHeaders.X_FORWARDED_FOR)).thenReturn(null);
when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost());
// test
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux", false);
// verify
assertThat(remoteAddr).as("The remote address should be as the known client IP address")
.isEqualTo(knownRemoteClientIP);
verify(requestMock, times(0)).getHeader("bumlux");
verify(requestMock, times(0)).getRemoteAddr();
}
@Test
@Description("Tests create uri from x forward header")
public void getRemoteAddrFromXForwardedForHeader() {
@@ -69,7 +88,7 @@ public class IpUtilTest {
when(requestMock.getRemoteAddr()).thenReturn(null);
// test
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For");
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For", true);
// verify
assertThat(remoteAddr).as("The remote address should be as the known client IP address")