Initial check in accordance with Parallel IP
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
193
hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java
Executable file
193
hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java
Executable 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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
149
hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java
Executable file
149
hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java
Executable 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());
|
||||
}
|
||||
}
|
||||
105
hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/SPInfo.java
Executable file
105
hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/SPInfo.java
Executable 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
138
hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java
Executable file
138
hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java
Executable 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();
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user