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

87
hawkbit-security-core/pom.xml Executable file
View File

@@ -0,0 +1,87 @@
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-security-core</artifactId>
<name>hawkBit :: Core Security</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,72 @@
/**
* 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;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
/**
* An {@link ShallowEtagHeaderFilter} with exclusion paths to exclude some paths
* where no ETag header should be generated due that calculating the ETag is an
* expensive operation and the response output need to be copied in memory which
* should be excluded in case of artifact downloads which could be big of size.
*
*
*
*
*/
public class ExcludePathAwareShallowETagFilter extends ShallowEtagHeaderFilter {
private final String[] excludeAntPaths;
private final AntPathMatcher antMatcher;
/**
* @param excludeAntPaths
*/
public ExcludePathAwareShallowETagFilter(final String... excludeAntPaths) {
this.excludeAntPaths = excludeAntPaths;
this.antMatcher = new AntPathMatcher();
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.filter.ShallowEtagHeaderFilter#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 {
final boolean shouldExclude = shouldExclude(request);
if (shouldExclude) {
filterChain.doFilter(request, response);
} else {
super.doFilterInternal(request, response, filterChain);
}
}
private boolean shouldExclude(final HttpServletRequest request) {
for (final String pattern : excludeAntPaths) {
if (antMatcher.match(request.getContextPath() + pattern, request.getRequestURI())) {
// exclude this request from eTag filter
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,31 @@
/**
* 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 org.springframework.security.authentication.AuthenticationProvider;
/**
* Indicates if the SP server runs in multi-tenancy mode. By means e.g. if a
* login screen needs to allow to specifiy the tenant to login.
*
* This can defere e.g. in case if the {@link AuthenticationProvider} allows
* {@link TenantUserPasswordAuthenticationToken} tokens or not.
*
*
*
*/
public interface MultitenancyIndicator {
/**
* @return {@code true} if multi-tenancy is supported, otherwise
* {@code false}.
*/
boolean isMultiTenancySupported();
}

View File

@@ -0,0 +1,98 @@
/**
* 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.List;
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;
/**
*
*
*/
public class PermissionService {
/**
* Checks if the given {@code permission} contains in the. In case no
* {@code context} is available {@code false} will be returned.
*
* @param permission
* the permission to check against the
* @return {@code true} if a is available and contains the given
* {@code permission}, otherwise {@code false}.
* @see SpPermission
*/
public boolean hasPermission(final String permission) {
final SecurityContext context = SecurityContextHolder.getContext();
if (context == null) {
return false;
}
final Authentication authentication = context.getAuthentication();
if (authentication == null) {
return false;
}
for (final GrantedAuthority authority : authentication.getAuthorities()) {
if (authority.getAuthority().equals(permission)) {
return true;
}
}
return false;
}
public List<String> getAllPermission() {
final List<String> permissions = new ArrayList<String>();
final SecurityContext context = SecurityContextHolder.getContext();
if (context == null) {
return permissions;
}
final Authentication authentication = context.getAuthentication();
if (authentication == null) {
return permissions;
}
authentication.getAuthorities().stream().forEach(authority -> permissions.add(authority.getAuthority()));
return permissions;
}
/**
* Checks if at least on permission of the given {@code permissions}
* contains in the . In case no {@code context} is available {@code false}
* will be returned.
*
* @param permissions
* the permissions to check against the
* @return {@code true} if a is available and contains the given
* {@code permission}, otherwise {@code false}.
* @see SpPermission
*/
public boolean hasAtLeastOnePermission(final List<String> permissions) {
final SecurityContext context = SecurityContextHolder.getContext();
if (context != null) {
final Authentication authentication = context.getAuthentication();
if (authentication != null) {
for (final GrantedAuthority authority : authentication.getAuthorities()) {
for (final String permission : permissions) {
if (authority.getAuthority().equals(permission)) {
return true;
}
}
}
}
}
return false;
}
}

View File

@@ -0,0 +1,283 @@
/**
* 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.lang.annotation.Target;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
/**
* <p>
* Software provisioning permissions that are technically available as
* {@link GrantedAuthority} based on the authenticated users identity context.
* </p>
*
* <p>
* The Permissions cover CRUD for two data areas of SP:<br/>
* <br/>
* XX_Target_CRUD which covers the following entities: {@link Target} entities
* including metadata, {@link TargetTag}s, {@link Action}s,
* {@link TargetRegistrationRule}s<br/>
* XX_Repository CRUD which covers: {@link DistributionSet}s,
* {@link SoftwareModule}s, DS Tags<br/>
* </p>
*
*
*
*
*
*/
public final class SpPermission {
/**
* Permission to read the targets from the
* {@link ProvisioningTargetRepository} including their meta information,
* {@link ProvisioningTargetFilter}s and target changing entities (
* {@link DistributionSetApplier} and {@link TargetRegistrationRule}). That
* corresponds in REST API to GET.
*/
public static final String READ_TARGET = "READ_TARGET";
/**
* Permission to read the target security token. The security token is
* security concerned and should be protected. So the combination
* {@link #READ_TARGET} and {@link #READ_TARGET_SEC_TOKEN} is necessary to
* able to read the security token of an target.
*/
public static final String READ_TARGET_SEC_TOKEN = "READ_TARGET_SECURITY_TOKEN";
/**
* Permission to change/edit/update targets in the
* {@link ProvisioningTargetRepository} including their meta information and
* or/relations or {@link DistributionSet} assignment,
* {@link ProvisioningTargetFilter}s and target changing entities (
* {@link DistributionSetApplier} and {@link TargetRegistrationRule}). That
* corresponds in REST API to POST.
*/
public static final String UPDATE_TARGET = "UPDATE_TARGET";
/**
* Permission to add new targets to the {@link ProvisioningTargetRepository}
* including their meta information and or/relations or
* {@link DistributionSet} assignment.That corresponds in REST API to PUT.
*/
public static final String CREATE_TARGET = "CREATE_TARGET";
/**
* Permission to delete targets in the {@link ProvisioningTargetRepository},
* {@link ProvisioningTargetFilter}s and target changing entities (
* {@link DistributionSetApplier} and {@link TargetRegistrationRule}). That
* corresponds in REST API to DELETE.
*/
public static final String DELETE_TARGET = "DELETE_TARGET";
/**
* Permission to read {@link DistributionSet}s and/or {@link OsPackage}s.
* That corresponds in REST API to GET.
*/
public static final String READ_REPOSITORY = "READ_REPOSITORY";
/**
* Permission to edit/update {@link DistributionSet}s including their
* {@link OsPackage} assignment and/or {@link OsPackage}s. That corresponds
* in REST API to POST.
*/
public static final String UPDATE_REPOSITORY = "UPDATE_REPOSITORY";
/**
* Permission to add {@link DistributionSet}s and/or {@link OsPackage}s to
* the repository. That corresponds in REST API to PUT.
*/
public static final String CREATE_REPOSITORY = "CREATE_REPOSITORY";
/**
* Permission to delete {@link DistributionSet}s and/or {@link OsPackage}s
* from the repository. That corresponds in REST API to DELETE.
*/
public static final String DELETE_REPOSITORY = "DELETE_REPOSITORY";
/**
* Permission to monitor the SP system. E.g. retrieving health, monitor
* checks through REST API provided by the spring actuator.
*/
public static final String SYSTEM_MONITOR = "SYSTEM_MONITOR";
/**
* Permission to retrieve diagnosis of the SP system. E.g. retrieving
* metrics, configuration through REST API provided by the spring actuator.
*/
public static final String SYSTEM_DIAG = "SYSTEM_DIAG";
/**
* Permission to administrate the system on a global, i.e. tenant
* independent scale. Thta inlcuds the deletion of tenants.
*/
public static final String SYSTEM_ADMIN = "SYSTEM_ADMIN";
/**
* Permission to download repository artifact of an software module.
*/
public static final String DOWNLOAD_REPOSITORY_ARTIFACT = "DOWNLOAD_REPOSITORY_ARTIFACT";
/**
* Permission to administrate the tenant settings.
*/
public static final String TENANT_CONFIGURATION = "TENANT_CONFIGURATION";
private SpPermission() {
// Constants only
}
/**
* Contains all the spring security evaluation expressions for the
* {@link PreAuthorize} annotation for method security.
* <p/>
* Examples:
* <p/>
* {@code
* hasRole([role]) Returns true if the current principal has the specified role.
* hasAnyRole([role1,role2]) Returns true if the current principal has any of the supplied roles (given as a comma-separated list of strings)
* principal Allows direct access to the principal object representing the current user
* authentication Allows direct access to the current Authentication object obtained from the SecurityContext
* permitAll Always evaluates to true
* denyAll Always evaluates to false
* isAnonymous() Returns true if the current principal is an anonymous user
* isRememberMe() Returns true if the current principal is a remember-me user
* isAuthenticated() Returns true if the user is not anonymous
* isFullyAuthenticated() Returns true if the user is not an anonymous or a remember-me user
* }
*
*
*
*
*/
public static final class SpringEvalExpressions {
/*
* Spring security eval expressions.
*/
private static final String HAS_AUTH_PREFIX = "hasAuthority('";
private static final String HAS_AUTH_SUFFIX = "')";
private static final String HAS_AUTH_AND = " and ";
/**
* The role which contains in the spring security context in case an
* controller is authenticated.
*/
public static final String CONTROLLER_ROLE = "ROLE_CONTROLLER";
/**
* The role which contains in the spring security context in case an
* controller is authenticated but only as anonymous.
*/
public static final String CONTROLLER_ROLE_ANONYMOUS = "ROLE_CONTROLLER_ANONYMOUS";
/**
* The spring security eval expression operator {@code or}.
*/
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 spring
* context contains {@link SpPermission#CREATE_REPOSITORY} and
* {@link SpPermission#CREATE_TARGET}.
*/
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;
private SpringEvalExpressions() {
// utility class
}
}
}

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.im.authentication;
import java.io.Serializable;
import org.springframework.security.authentication.AbstractAuthenticationToken;
/**
* An authentication details object
* {@link AbstractAuthenticationToken#getDetails()} which is stored in the
* spring security authentication token details to transport the principal and
* tenant in the security context session.
*
*
*
*
*/
public class TenantAwareAuthenticationDetails implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private final String tenant;
private final boolean controller;
/**
* @param tenant
* the current tenant
* @param controller
* boolean flag to indicate if this authenticated token is a
* controller authentication. {@code true} in case of
* authenticated controller otherwise {@code false}
*/
public TenantAwareAuthenticationDetails(final String tenant, final boolean controller) {
this.tenant = tenant;
this.controller = controller;
}
/**
* @return the tenant
*/
public String getTenant() {
return tenant;
}
/**
* @return the controller
*/
public boolean isController() {
return controller;
}
}

View File

@@ -0,0 +1,76 @@
/**
* 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.List;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
/**
* The authentication token which transports the username, password and the
* tenant information for authentication.
*
*
*
*
*/
public class TenantUserPasswordAuthenticationToken extends UsernamePasswordAuthenticationToken {
/**
*
*/
private static final long serialVersionUID = 1L;
final Object tenant;
/**
*
* Creating a new {@link TenantUserPasswordAuthenticationToken} as
* {@link #isAuthenticated()} will return {@code false}.
*
* @param tenant
* the tenant to authenticate against
* @param principal
* the principal to authenticate
* @param credentials
* the credentials of the principal
*/
public TenantUserPasswordAuthenticationToken(final Object tenant, final Object principal,
final Object credentials) {
super(principal, credentials);
this.tenant = tenant;
}
/**
* Creating a new {@link TenantUserPasswordAuthenticationToken} as
* {@link #isAuthenticated()} will return {@code true}.
*
* @param tenant
* the tenant to authenticate against
* @param principal
* the principal to authenticate
* @param credentials
* the credentials of the principal
* @param authorities
* the principal's authorities
*/
public TenantUserPasswordAuthenticationToken(final Object tenant, final Object principal, final Object credentials,
final List<GrantedAuthority> authorities) {
super(principal, credentials, authorities);
this.tenant = tenant;
}
/**
* @return the tenant
*/
public Object getTenant() {
return tenant;
}
}

View File

@@ -0,0 +1,63 @@
/**
* 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.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* Filter to integrate into the SP security filter-chain. The filter is called
* in any remote call through HTTP except the SP login screen. E.g. using the SP
* REST-API. To authenticate user e.g. using Basic-Authentication implement the
* {@link #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)}
* method.
*
*
*
*/
public interface UserAuthenticationFilter {
/**
* @see Filter#init(FilterConfig)
*
* @param filterConfig
* the filter config
*/
void init(FilterConfig filterConfig) throws ServletException;
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*
* @param request
* the servlet request
* @param response
* the servlet response
* @param chain
* the filterchain
* @throws IOException
* cannot read from request
* @throws ServletException
* servlet exception
*/
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException;
/**
* @see Filter#destroy()
*/
void destroy();
}

View File

@@ -0,0 +1,163 @@
/**
* 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.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.userdetails.UserDetails;
/**
* A software provisioning user principal definition stored in the
* {@link SecurityContext} which contains the user specific attributes.
*
*
*
*
*/
public class UserPrincipal implements UserDetails, Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private final String username;
private final String firstname;
private final String lastname;
private final String loginname;
private final String tenant;
/**
* @param username
* the user name of the user
* @param firstname
* the first name of the user
* @param lastname
* the last name of the user
* @param loginname
* the login name of user
* @param tenant
* the tenant of the user
*/
public UserPrincipal(final String username, final String firstname, final String lastname, final String loginname,
final String tenant) {
this.username = username;
this.firstname = firstname;
this.lastname = lastname;
this.loginname = loginname;
this.tenant = tenant;
}
/**
* @return the username
*/
@Override
public String getUsername() {
return username;
}
/**
* @return the firstname
*/
public String getFirstname() {
return firstname;
}
/**
* @return the lastname
*/
public String getLastname() {
return lastname;
}
/**
* @return the loginname
*/
public String getLoginname() {
return loginname;
}
/**
* @return the tenant
*/
public String getTenant() {
return tenant;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.core.userdetails.UserDetails#getAuthorities(
* )
*/
@Override
public Collection<SimpleGrantedAuthority> getAuthorities() {
return Collections.emptyList();
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.core.userdetails.UserDetails#getPassword()
*/
@Override
public String getPassword() {
return null;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.userdetails.UserDetails#
* isAccountNonExpired()
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.userdetails.UserDetails#
* isAccountNonLocked()
*/
@Override
public boolean isAccountNonLocked() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.userdetails.UserDetails#
* isCredentialsNonExpired()
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.core.userdetails.UserDetails#isEnabled()
*/
@Override
public boolean isEnabled() {
return true;
}
}

View File

@@ -0,0 +1,193 @@
/**
* 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.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.hawkbit.util.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;
import com.google.common.cache.Cache;
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
*
*
*
*
*/
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 final Pattern ipAdressBlacklist;
private final Cache<String, AtomicInteger> readCountCache = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.SECONDS).build();
private final Cache<String, AtomicInteger> writeCountCache = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.SECONDS).build();
private final Integer maxRead;
private final Integer maxWrite;
private final Pattern whitelist;
private final String forwardHeader;
/**
* Filter constructor including configuration.
*
* @param maxRead
* Maximum number of allowed REST read/GET requests per second
* per client
* @param maxWrite
* Maximum number of allowed REST write/(PUT/POST/etc.) requests
* per second per client
* @param ipDosWhiteListPattern
* {@link Pattern} with with white list of peer IP addresses for
* DOS filter
* @param ipBlackListPattern
* {@link Pattern} with black listed IP addresses
* @param forwardHeader
* the header containing the forwarded IP address e.g.
* {@code x-forwarded-for}
*/
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;
if (ipBlackListPattern != null && !ipBlackListPattern.isEmpty()) {
ipAdressBlacklist = Pattern.compile(ipBlackListPattern);
} else {
ipAdressBlacklist = null;
}
if (ipDosWhiteListPattern != null && !ipDosWhiteListPattern.isEmpty()) {
whitelist = Pattern.compile(ipDosWhiteListPattern);
} else {
whitelist = null;
}
}
/*
* (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 = true;
final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader).getHost();
if (checkIpFails(ip)) {
processChain = handleMissingIpAddress(response);
} else {
processChain = checkAgainstBlacklist(response, ip);
if (processChain && (whitelist == null || !whitelist.matcher(ip).find())) {
// read request
if (HttpMethod.valueOf(request.getMethod()) == HttpMethod.GET) {
processChain = handleReadRequest(response, ip);
}
// write request
else {
processChain = handleWriteRequest(response, ip);
}
}
}
if (processChain) {
filterChain.doFilter(request, response);
}
}
/**
* @return false if the given ip address is on the blacklist and further
* processing of the request if forbidden
*/
private boolean checkAgainstBlacklist(final HttpServletResponse response, final String ip) {
if (ipAdressBlacklist != null && ipAdressBlacklist.matcher(ip).find()) {
LOG_BLACKLIST.info("Blacklisted client ({}) tries to access the server!", ip);
response.setStatus(HttpStatus.FORBIDDEN.value());
return false;
}
return true;
}
private boolean checkIpFails(final String ip) {
return ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip);
}
private 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;
}
private boolean handleWriteRequest(final HttpServletResponse response, final String ip) {
boolean processChain = true;
final AtomicInteger count = writeCountCache.getIfPresent(ip);
if (count == null) {
writeCountCache.put(ip, new AtomicInteger());
} else if (count.getAndIncrement() > maxWrite) {
LOG_DOS.info("Registered DOS attack! Client {} is above configured WRITE request threshold ({})!", ip,
maxWrite);
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
processChain = false;
}
return processChain;
}
private boolean handleReadRequest(final HttpServletResponse response, final String ip) {
boolean processChain = true;
final AtomicInteger count = readCountCache.getIfPresent(ip);
if (count == null) {
readCountCache.put(ip, new AtomicInteger());
} else if (count.getAndIncrement() > maxRead) {
LOG_DOS.info("Registered DOS attack! Client {} is above configured READ request threshold ({})!", ip,
maxRead);
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
processChain = false;
}
return processChain;
}
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.security;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* A {@link TenantAware} implemenation which retrieves the ID of the tenant from
* the {@link SecurityContext#getAuthentication()}
* {@link Authentication#getDetails()} which holds the
* {@link TenantAwareAuthenticationDetails} object.
*
*
*
*
*/
public class SecurityContextTenantAware implements TenantAware {
private static final ThreadLocal<String> TENANT_THREAD_LOCAL = new ThreadLocal<>();
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.tenancy.TenantAware#getCurrentTenantId()
*/
@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();
if (authDetails instanceof TenantAwareAuthenticationDetails) {
return ((TenantAwareAuthenticationDetails) authDetails).getTenant();
}
}
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) {
TENANT_THREAD_LOCAL.set(tenant);
try {
return callable.run();
} finally {
TENANT_THREAD_LOCAL.remove();
}
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* The common properties for security.
*
*
*
*/
@ConfigurationProperties
public class SecurityProperties {
@Value("${hawkbit.server.controller.security.rp.cnHeader:X-Ssl-Client-Cn}")
private String rpCnHeader;
@Value("${hawkbit.server.controller.security.rp.sslIssuerHashHeader:X-Ssl-Issuer-Hash-%d}")
private String rpSslIssuerHashHeader;
@Value("${hawkbit.server.controller.security.rp.trustedIPs:#{null}}")
private List<String> rpTrustedIPs;
@Value("${hawkbit.server.controller.security.authentication.anonymous.enabled:false}")
private Boolean anonymousEnabled;
public String getRpCnHeader() {
return rpCnHeader;
}
public String getRpSslIssuerHashHeader() {
return rpSslIssuerHashHeader;
}
public List<String> getRpTrustedIPs() {
return rpTrustedIPs;
}
public Boolean getAnonymousEnabled() {
return anonymousEnabled;
}
public void setRpCnHeader(final String rpCnHeader) {
this.rpCnHeader = rpCnHeader;
}
public void setRpSslIssuerHashHeader(final String rpSslIssuerHashHeader) {
this.rpSslIssuerHashHeader = rpSslIssuerHashHeader;
}
public void setRpTrustedIPs(final List<String> rpTrustedIPs) {
this.rpTrustedIPs = rpTrustedIPs;
}
public void setAnonymousEnabled(final Boolean anonymousEnabled) {
this.anonymousEnabled = anonymousEnabled;
}
}

View File

@@ -0,0 +1,42 @@
/**
* 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.security.SecureRandom;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.stereotype.Service;
/**
* A security token generator service which can be used to generate security
* tokens for e.g. target or gateway tokens which are valid for authenticates
* against SP.
*
*
*
*
*/
@Service
public class SecurityTokenGenerator {
private static final boolean LETTERS_GENERATION = true;
private static final boolean NUMBER_GENERATION = true;
private static final int TOKEN_LENGTH = 32;
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
/**
* Generates a random secure token of length {@link #TOKEN_LENGTH}
* characters with alphanumeric characters {@code A-Z_a-z_0-9}.
*
* @return a new generated random alphanumeric string.
*/
public String generateToken() {
return RandomStringUtils.random(TOKEN_LENGTH, 0, 0, LETTERS_GENERATION, NUMBER_GENERATION, null, SECURE_RANDOM);
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
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.
*
*
*
*
*
*/
public class SpringSecurityAuditorAware implements AuditorAware<String> {
@Override
public String getCurrentAuditor() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
if (authentication.getPrincipal() != null) {
if (authentication.getPrincipal() instanceof UserDetails) {
return ((UserDetails) authentication.getPrincipal()).getUsername();
}
return authentication.getPrincipal().toString();
}
return null;
}
}

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.util;
import java.lang.annotation.Target;
import java.net.URI;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import com.google.common.net.HttpHeaders;
/**
* A utility which determines the correct IP of a connected {@link Target}. E.g
* from a {@link HttpServletRequest}.
*
*
*
*
*/
public final class IpUtil {
private static final String SCHEME_SEPERATOR = "://";
private static final String HTTP_SCHEME = "http";
private static final String AMPQP_SCHEME = "amqp";
private static final Pattern IPV4_ADDRESS_PATTERN = Pattern
.compile("([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})");
private static final Pattern IPV6_ADDRESS_PATTERN = Pattern.compile("([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}");
private IpUtil() {
}
/**
* 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}
* @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();
}
return createHttpUri(ip);
}
private static String findClientIpAddress(final String s) {
final Matcher matcherv4 = IPV4_ADDRESS_PATTERN.matcher(s);
if (matcherv4.find()) {
return matcherv4.group(0);
}
final Matcher matcherv6 = IPV6_ADDRESS_PATTERN.matcher(s);
if (matcherv6.find()) {
return matcherv6.group(0);
}
return null;
}
/**
* Create a {@link URI} with scheme and host.
*
* @param scheme
* the scheme
* @param host
* the host
* @return the {@link URI}
* @throws IllegalArgumentException
* If the given string not parsable
*/
public static URI createUri(final String scheme, final String host) {
final boolean isIpV6 = host.indexOf(':') >= 0 && host.charAt(0) != '[';
if (isIpV6) {
return URI.create(scheme + SCHEME_SEPERATOR + "[" + host + "]");
}
return URI.create(scheme + SCHEME_SEPERATOR + host);
}
/**
* Create a {@link URI} with amqp scheme and host.
*
* @param host
* the host
* @return the {@link URI}
* @throws IllegalArgumentException
* If the given string not parsable
*/
public static URI createAmqpUri(final String host) {
return createUri(AMPQP_SCHEME, host);
}
/**
* Create a {@link URI} with http scheme and host.
*
* @param host
* the host
* @return the {@link URI}
* @throws IllegalArgumentException
* If the given string not parsable
*/
public static URI createHttpUri(final String host) {
return createUri(HTTP_SCHEME, host);
}
/**
* Check if scheme contains http and uri ist not <code>null</code>.
*
* @param uri
* the uri
* @return true = is http host false = not
*/
public static boolean isHttpUri(final URI uri) {
return uri != null && HTTP_SCHEME.equals(uri.getScheme());
}
/**
* Check if host scheme amqp and uri ist not <code>null</code>.
*
* @param uri
* the uri
* @return true = is http host false = not
*/
public static boolean isAmqpUri(final URI uri) {
return uri != null && AMPQP_SCHEME.equals(uri.getScheme());
}
}

View File

@@ -0,0 +1,105 @@
/**
* 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.util;
import javax.servlet.MultipartConfigElement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
/**
* Bean which contains all informations about the SP software, e.g. like
* version, built time etc. from the environment.
*
*
*
*
*/
@Component
public class SPInfo implements EnvironmentAware {
// package private for testing purposes
static final String UNKNOWN_VERSION = "unknown";
static final String UNKNOWN_CREDENTIAL = "unknown credential";
private Environment environmentData;
@Autowired
private MultipartConfigElement configElement;
/*
* (non-Javadoc)
*
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
* springframework.core.env. Environment)
*/
@Override
public void setEnvironment(final Environment environment) {
this.environmentData = environment;
}
/**
* @return the version in string format, e.g. 1.0.0 or {@code "UNKNOWN"} in
* case the SP version info cannot be determined.
*/
public String getVersion() {
if (environmentData != null) {
return environmentData.getProperty("info.build.version", UNKNOWN_VERSION);
}
return UNKNOWN_VERSION;
}
public String getSupportEmail() {
if (environmentData != null) {
return environmentData.getProperty("hawkbit.server.email.support");
}
return "";
}
public String getRequestAccountEmail() {
if (environmentData != null) {
return environmentData.getProperty("hawkbit.server.email.request.account");
}
return "";
}
public String getDemoTenant() {
if (environmentData != null) {
return environmentData.getProperty("hawkbit.server.demo.tenant");
}
return UNKNOWN_CREDENTIAL;
}
public String getDemoUser() {
if (environmentData != null) {
return environmentData.getProperty("hawkbit.server.demo.user");
}
return UNKNOWN_CREDENTIAL;
}
public String getDemoPassword() {
if (environmentData != null) {
return environmentData.getProperty("hawkbit.server.demo.password");
}
return UNKNOWN_CREDENTIAL;
}
/**
* @return the max file size to upload artifact files in bytes which has
* been configured.
*/
public long getMaxArtifactFileSize() {
return configElement.getMaxFileSize();
}
}

View File

@@ -0,0 +1,86 @@
/**
* 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;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ExcludePathAwareShallowETagFilterTest {
@Mock
private HttpServletRequest servletRequestMock;
@Mock
private HttpServletResponse servletResponseMock;
@Mock
private FilterChain filterChainMock;
@Test
public void excludePathDoesNotCalculateETag() throws ServletException, IOException {
final String knownContextPath = "/bumlux/test";
final String knownUri = knownContextPath + "/exclude/download";
final String antPathExclusion = "/exclude/**";
// mock
when(servletRequestMock.getContextPath()).thenReturn(knownContextPath);
when(servletRequestMock.getRequestURI()).thenReturn(knownUri);
final ExcludePathAwareShallowETagFilter filterUnderTest = new ExcludePathAwareShallowETagFilter(
antPathExclusion);
filterUnderTest.doFilterInternal(servletRequestMock, servletResponseMock, filterChainMock);
// verify no eTag header is set and response has not been changed
assertThat(servletResponseMock.getHeader("ETag")).isNull();
// the servlet response must be the same mock!
verify(filterChainMock, times(1)).doFilter(servletRequestMock, servletResponseMock);
}
@Test
public void pathNotExcludedETagIsCalculated() throws ServletException, IOException {
final String knownContextPath = "/bumlux/test";
final String knownUri = knownContextPath + "/include/download";
final String antPathExclusion = "/exclude/**";
// mock
when(servletRequestMock.getContextPath()).thenReturn(knownContextPath);
when(servletRequestMock.getRequestURI()).thenReturn(knownUri);
final ExcludePathAwareShallowETagFilter filterUnderTest = new ExcludePathAwareShallowETagFilter(
antPathExclusion);
final ArgumentCaptor<HttpServletResponse> responseArgumentCaptor = ArgumentCaptor
.forClass(HttpServletResponse.class);
filterUnderTest.doFilterInternal(servletRequestMock, servletResponseMock, filterChainMock);
// the servlet response must be the same mock!
verify(filterChainMock, times(1)).doFilter(Mockito.eq(servletRequestMock), responseArgumentCaptor.capture());
assertThat(mockingDetails(responseArgumentCaptor.getValue()).isMock()).isFalse();
}
}

View File

@@ -0,0 +1,26 @@
/**
* 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.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import org.junit.Test;
public class SecurityTokenGeneratorTest {
@Test
public void test() throws NoSuchAlgorithmException, UnsupportedEncodingException {
final SecurityTokenGenerator securityTokenGenerator = new SecurityTokenGenerator();
for (int index = 0; index < 1; index++) {
System.out.println(securityTokenGenerator.generateToken());
}
}
}

View File

@@ -0,0 +1,138 @@
/**
* 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.util;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.net.URI;
import javax.servlet.http.HttpServletRequest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import com.google.common.net.HttpHeaders;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@RunWith(MockitoJUnitRunner.class)
@Features("IpUtil Test")
@Stories("Tests the created uris")
public class IpUtilTest {
@Mock
private HttpServletRequest requestMock;
@Test
@Description("Tests create uri from request")
public void getRemoteAddrFromRequestIfForwaredHeaderNotPresent() {
// known values
final URI knownRemoteClientIP = IpUtil.createHttpUri("127.0.0.1");
// mock
when(requestMock.getHeader(HttpHeaders.X_FORWARDED_FOR)).thenReturn(null);
when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost());
// test
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux");
// verify
assertThat(remoteAddr).isEqualTo(knownRemoteClientIP);
verify(requestMock, times(1)).getHeader("bumlux");
verify(requestMock, times(1)).getRemoteAddr();
}
@Test
@Description("Tests create uri from x forward header")
public void getRemoteAddrFromXForwardedForHeader() {
// known values
final URI knownRemoteClientIP = IpUtil.createHttpUri("10.99.99.1");
// mock
when(requestMock.getHeader(HttpHeaders.X_FORWARDED_FOR)).thenReturn(knownRemoteClientIP.getHost());
when(requestMock.getRemoteAddr()).thenReturn(null);
// test
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For");
// verify
assertThat(remoteAddr).isEqualTo(knownRemoteClientIP);
verify(requestMock, times(1)).getHeader(HttpHeaders.X_FORWARDED_FOR);
verify(requestMock, times(0)).getRemoteAddr();
}
@Test
@Description("Tests create http uri ipv4 and ipv6")
public void testCreateHttpUri() {
final String ipv4 = "10.99.99.1";
URI httpUri = IpUtil.createHttpUri(ipv4);
assertHttpUri(ipv4, httpUri);
final String host = "myhost";
httpUri = IpUtil.createHttpUri(host);
assertHttpUri(host, httpUri);
final String ipv6 = "0:0:0:0:0:0:0:1";
httpUri = IpUtil.createHttpUri(ipv6);
assertHttpUri("[" + ipv6 + "]", httpUri);
}
private void assertHttpUri(final String host, final URI httpUri) {
assertTrue(IpUtil.isHttpUri(httpUri));
assertFalse(IpUtil.isAmqpUri(httpUri));
assertEquals(host, httpUri.getHost());
assertEquals("http", httpUri.getScheme());
}
@Test
@Description("Tests create amqp uri ipv4 and ipv6")
public void testCreateAmqpUri() {
final String ipv4 = "10.99.99.1";
URI amqpUri = IpUtil.createAmqpUri(ipv4);
assertAmqpUri(ipv4, amqpUri);
final String host = "myhost";
amqpUri = IpUtil.createAmqpUri(host);
assertAmqpUri(host, amqpUri);
final String ipv6 = "0:0:0:0:0:0:0:1";
amqpUri = IpUtil.createAmqpUri(ipv6);
assertAmqpUri("[" + ipv6 + "]", amqpUri);
}
private void assertAmqpUri(final String host, final URI httpUri) {
assertTrue(IpUtil.isAmqpUri(httpUri));
assertFalse(IpUtil.isHttpUri(httpUri));
assertEquals(host, httpUri.getHost());
assertEquals("amqp", httpUri.getScheme());
}
@Test(expected = IllegalArgumentException.class)
@Description("Tests create invalid uri")
public void testCreateInvalidUri() {
final String host = "10.99.99.1";
final URI testUri = IpUtil.createUri("test", host);
assertFalse(IpUtil.isAmqpUri(testUri));
assertFalse(IpUtil.isHttpUri(testUri));
assertEquals(host, testUri.getHost());
IpUtil.createUri(":/", host);
fail();
}
}