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:
@@ -21,7 +21,7 @@
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user