diff --git a/hawkbit-security-core/pom.xml b/hawkbit-security-core/pom.xml index 1c0ee6898..dc38069d6 100644 --- a/hawkbit-security-core/pom.xml +++ b/hawkbit-security-core/pom.xml @@ -9,64 +9,64 @@ SPDX-License-Identifier: EPL-2.0 --> - - 4.0.0 - - org.eclipse.hawkbit - hawkbit-parent - ${revision} - - hawkbit-security-core - hawkBit :: Core Security + + 4.0.0 + + org.eclipse.hawkbit + hawkbit-parent + ${revision} + + hawkbit-security-core + hawkBit :: Core Security - - - org.eclipse.hawkbit - hawkbit-core - ${project.version} - - - jakarta.servlet - jakarta.servlet-api - provided - - - org.slf4j - slf4j-api - - - org.springframework.data - spring-data-commons - - - org.springframework.security - spring-security-core - - - org.springframework.boot - spring-boot-starter-oauth2-resource-server - - - org.springframework.boot - spring-boot-starter-oauth2-client - - - org.springframework.boot - spring-boot - + + + org.eclipse.hawkbit + hawkbit-core + ${project.version} + + + jakarta.servlet + jakarta.servlet-api + provided + + + org.slf4j + slf4j-api + + + org.springframework.data + spring-data-commons + + + org.springframework.security + spring-security-core + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + org.springframework.boot + spring-boot + - - - org.springframework.boot - spring-boot-starter-test - test - - - io.qameta.allure - allure-junit5 - test - - + + + org.springframework.boot + spring-boot-starter-test + test + + + io.qameta.allure + allure-junit5 + test + + \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java index 3e016d74d..7fee17bea 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java @@ -22,12 +22,12 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; @NoArgsConstructor(access = lombok.AccessLevel.PRIVATE) public final class PermissionUtils { - /** - * Returns all authorities. - * - * @return a list of {@link GrantedAuthority} - */ - public static List createAllAuthorityList() { - return SpPermission.getAllAuthorities().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); - } + /** + * Returns all authorities. + * + * @return a list of {@link GrantedAuthority} + */ + public static List createAllAuthorityList() { + return SpPermission.getAllAuthorities().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); + } } \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java index cb66ab38f..ed80da771 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java @@ -146,6 +146,7 @@ public final class SpPermission { /** * Return all permission. + * * @return all permissions */ public static List getAllAuthorities() { @@ -189,6 +190,7 @@ public final class SpPermission { */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public static final class SpringEvalExpressions { + /* * Spring security eval expressions. */ @@ -197,37 +199,21 @@ public final class SpPermission { public static final String HAS_AUTH_PREFIX = "hasAuthority" + BRACKET_OPEN + "'"; public static final String HAS_AUTH_SUFFIX = "'" + BRACKET_CLOSE; public 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 contained in the spring security context in case that a - * controller is authenticated, but only as 'anonymous'. - */ - public static final String CONTROLLER_ROLE_ANONYMOUS = "ROLE_CONTROLLER_ANONYMOUS"; - /** * The role which contains the spring security context in case the * system is executing code which is necessary to be privileged. */ public static final String SYSTEM_ROLE = "ROLE_SYSTEM_CODE"; - /** * The spring security eval expression operator {@code or}. */ public static final String HAS_AUTH_OR = " or "; - /** * Spring security eval hasAnyRole expression to check if the spring * context contains system code role * {@link SpringEvalExpressions#SYSTEM_ROLE}. */ public static final String IS_SYSTEM_CODE = HAS_AUTH_PREFIX + SYSTEM_ROLE + HAS_AUTH_SUFFIX; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#UPDATE_TARGET} or @@ -235,7 +221,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_UPDATE_TARGET = HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#SYSTEM_ADMIN} or @@ -243,7 +228,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_SYSTEM_ADMIN = HAS_AUTH_PREFIX + SYSTEM_ADMIN + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_TARGET} or @@ -251,7 +235,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_READ_TARGET = HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_TARGET_SEC_TOKEN} or @@ -259,7 +242,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_READ_TARGET_SEC_TOKEN = HAS_AUTH_PREFIX + READ_TARGET_SEC_TOKEN + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#CREATE_TARGET} or @@ -267,7 +249,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_CREATE_TARGET = HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#DELETE_TARGET} or @@ -275,7 +256,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_DELETE_TARGET = HAS_AUTH_PREFIX + DELETE_TARGET + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_REPOSITORY} and @@ -284,7 +264,6 @@ public final class SpPermission { public static final String HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX + READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#CREATE_REPOSITORY} or @@ -292,7 +271,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_CREATE_REPOSITORY = HAS_AUTH_PREFIX + CREATE_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#DELETE_REPOSITORY} or @@ -300,7 +278,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_DELETE_REPOSITORY = HAS_AUTH_PREFIX + DELETE_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_REPOSITORY} or @@ -308,7 +285,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_READ_REPOSITORY = HAS_AUTH_PREFIX + READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#UPDATE_REPOSITORY} or @@ -316,7 +292,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_UPDATE_REPOSITORY = HAS_AUTH_PREFIX + UPDATE_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_REPOSITORY} and @@ -325,7 +300,6 @@ public final class SpPermission { public static final String HAS_AUTH_READ_REPOSITORY_AND_UPDATE_REPOSITORY = BRACKET_OPEN + HAS_AUTH_PREFIX + READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_REPOSITORY + HAS_AUTH_SUFFIX + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_REPOSITORY} and @@ -334,7 +308,6 @@ public final class SpPermission { public static final String HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX + READ_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#DOWNLOAD_REPOSITORY_ARTIFACT} or @@ -342,15 +315,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_DOWNLOAD_ARTIFACT = HAS_AUTH_PREFIX + DOWNLOAD_REPOSITORY_ARTIFACT + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - - /** - * Spring security eval hasAnyRole expression to check if the spring - * context contains the anonymous role or the controller specific role - * {@link SpringEvalExpressions#CONTROLLER_ROLE}. - */ - public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" + CONTROLLER_ROLE - + "')"; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#CREATE_REPOSITORY} and @@ -359,7 +323,6 @@ public final class SpPermission { public static final String HAS_AUTH_CREATE_REPOSITORY_AND_CREATE_TARGET = BRACKET_OPEN + HAS_AUTH_PREFIX + CREATE_REPOSITORY + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + CREATE_TARGET + HAS_AUTH_SUFFIX + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_ROLLOUT} or @@ -367,7 +330,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_READ = HAS_AUTH_PREFIX + READ_ROLLOUT + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_ROLLOUT} and @@ -376,7 +338,6 @@ public final class SpPermission { public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_READ_AND_TARGET_READ = BRACKET_OPEN + HAS_AUTH_PREFIX + READ_ROLLOUT + HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + BRACKET_CLOSE + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#CREATE_ROLLOUT} or @@ -384,7 +345,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE = HAS_AUTH_PREFIX + CREATE_ROLLOUT + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#HANDLE_ROLLOUT} or @@ -392,7 +352,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_HANDLE = HAS_AUTH_PREFIX + HANDLE_ROLLOUT + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#APPROVE_ROLLOUT} or @@ -400,7 +359,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_APPROVE = HAS_AUTH_PREFIX + APPROVE_ROLLOUT + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#UPDATE_ROLLOUT} or @@ -408,7 +366,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_UPDATE = HAS_AUTH_PREFIX + UPDATE_ROLLOUT + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#DELETE_ROLLOUT} or @@ -416,7 +373,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_DELETE = HAS_AUTH_PREFIX + DELETE_ROLLOUT + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#READ_TENANT_CONFIGURATION} or @@ -424,7 +380,6 @@ public final class SpPermission { */ public static final String HAS_AUTH_TENANT_CONFIGURATION_READ = HAS_AUTH_PREFIX + READ_TENANT_CONFIGURATION + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - /** * Spring security eval hasAuthority expression to check if spring * context contains {@link SpPermission#TENANT_CONFIGURATION} or @@ -432,7 +387,23 @@ public final class SpPermission { */ public static final String HAS_AUTH_TENANT_CONFIGURATION = HAS_AUTH_PREFIX + TENANT_CONFIGURATION + HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE; - + /** + * 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 contained in the spring security context in case that a + * controller is authenticated, but only as 'anonymous'. + */ + public static final String CONTROLLER_ROLE_ANONYMOUS = "ROLE_CONTROLLER_ANONYMOUS"; + /** + * Spring security eval hasAnyRole expression to check if the spring + * context contains the anonymous role or the controller specific role + * {@link SpringEvalExpressions#CONTROLLER_ROLE}. + */ + public static final String IS_CONTROLLER = "hasAnyRole('" + CONTROLLER_ROLE_ANONYMOUS + "', '" + CONTROLLER_ROLE + + "')"; /** * Spring security eval hasAuthority expression to check if spring * context contains {@link #IS_CONTROLLER} or diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java index ac119de1f..ae4061069 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java @@ -20,53 +20,48 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public final class SpRole { + public static final String TARGET_ADMIN = "ROLE_TARGET_ADMIN"; + public static final String REPOSITORY_ADMIN = "ROLE_REPOSITORY_ADMIN"; + public static final String ROLLOUT_ADMIN = "ROLE_ROLLOUT_ADMIN"; + public static final String TENANT_ADMIN = "ROLE_TENANT_ADMIN"; private static final String IMPLIES = " > "; private static final String LINE_BREAK = "\n"; - - public static final String TARGET_ADMIN = "ROLE_TARGET_ADMIN"; public static final String TARGET_ADMIN_HIERARCHY = TARGET_ADMIN + IMPLIES + SpPermission.READ_TARGET + LINE_BREAK + - TARGET_ADMIN + IMPLIES + SpPermission.READ_TARGET_SEC_TOKEN + LINE_BREAK + - TARGET_ADMIN + IMPLIES + SpPermission.UPDATE_TARGET + LINE_BREAK + - TARGET_ADMIN + IMPLIES + SpPermission.CREATE_TARGET + LINE_BREAK + - TARGET_ADMIN + IMPLIES + SpPermission.DELETE_TARGET + LINE_BREAK; - - public static final String REPOSITORY_ADMIN = "ROLE_REPOSITORY_ADMIN"; + TARGET_ADMIN + IMPLIES + SpPermission.READ_TARGET_SEC_TOKEN + LINE_BREAK + + TARGET_ADMIN + IMPLIES + SpPermission.UPDATE_TARGET + LINE_BREAK + + TARGET_ADMIN + IMPLIES + SpPermission.CREATE_TARGET + LINE_BREAK + + TARGET_ADMIN + IMPLIES + SpPermission.DELETE_TARGET + LINE_BREAK; public static final String REPOSITORY_ADMIN_HIERARCHY = REPOSITORY_ADMIN + IMPLIES + SpPermission.READ_REPOSITORY + LINE_BREAK + - REPOSITORY_ADMIN + IMPLIES + SpPermission.UPDATE_REPOSITORY + LINE_BREAK + - REPOSITORY_ADMIN + IMPLIES + SpPermission.CREATE_REPOSITORY + LINE_BREAK + - REPOSITORY_ADMIN + IMPLIES + SpPermission.DELETE_REPOSITORY + LINE_BREAK + - REPOSITORY_ADMIN + IMPLIES + SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT + LINE_BREAK; - - public static final String ROLLOUT_ADMIN = "ROLE_ROLLOUT_ADMIN"; + REPOSITORY_ADMIN + IMPLIES + SpPermission.UPDATE_REPOSITORY + LINE_BREAK + + REPOSITORY_ADMIN + IMPLIES + SpPermission.CREATE_REPOSITORY + LINE_BREAK + + REPOSITORY_ADMIN + IMPLIES + SpPermission.DELETE_REPOSITORY + LINE_BREAK + + REPOSITORY_ADMIN + IMPLIES + SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT + LINE_BREAK; public static final String ROLLOUT_ADMIN_HIERARCHY = ROLLOUT_ADMIN + IMPLIES + SpPermission.READ_ROLLOUT + LINE_BREAK + - ROLLOUT_ADMIN + IMPLIES + SpPermission.CREATE_ROLLOUT + LINE_BREAK + - ROLLOUT_ADMIN + IMPLIES + SpPermission.UPDATE_ROLLOUT + LINE_BREAK + - ROLLOUT_ADMIN + IMPLIES + SpPermission.DELETE_ROLLOUT + LINE_BREAK + - ROLLOUT_ADMIN + IMPLIES + SpPermission.HANDLE_ROLLOUT + LINE_BREAK + - ROLLOUT_ADMIN + IMPLIES + SpPermission.APPROVE_ROLLOUT + LINE_BREAK; - + ROLLOUT_ADMIN + IMPLIES + SpPermission.CREATE_ROLLOUT + LINE_BREAK + + ROLLOUT_ADMIN + IMPLIES + SpPermission.UPDATE_ROLLOUT + LINE_BREAK + + ROLLOUT_ADMIN + IMPLIES + SpPermission.DELETE_ROLLOUT + LINE_BREAK + + ROLLOUT_ADMIN + IMPLIES + SpPermission.HANDLE_ROLLOUT + LINE_BREAK + + ROLLOUT_ADMIN + IMPLIES + SpPermission.APPROVE_ROLLOUT + LINE_BREAK; public static final String TENANT_CONFIGURATION_HIERARCHY = SpPermission.TENANT_CONFIGURATION + IMPLIES + SpPermission.READ_TENANT_CONFIGURATION + LINE_BREAK + SpPermission.TENANT_CONFIGURATION + IMPLIES + SpPermission.READ_GATEWAY_SEC_TOKEN + LINE_BREAK; - - public static final String TENANT_ADMIN = "ROLE_TENANT_ADMIN"; public static final String TENANT_ADMIN_HIERARCHY = TENANT_ADMIN + IMPLIES + TARGET_ADMIN + LINE_BREAK + - TENANT_ADMIN + IMPLIES + REPOSITORY_ADMIN + LINE_BREAK + - TENANT_ADMIN + IMPLIES + ROLLOUT_ADMIN + LINE_BREAK + - TENANT_ADMIN + IMPLIES + SpPermission.TENANT_CONFIGURATION + LINE_BREAK; + TENANT_ADMIN + IMPLIES + REPOSITORY_ADMIN + LINE_BREAK + + TENANT_ADMIN + IMPLIES + ROLLOUT_ADMIN + LINE_BREAK + + TENANT_ADMIN + IMPLIES + SpPermission.TENANT_CONFIGURATION + LINE_BREAK; public static final String SYSTEM_ADMIN_HIERARCHY = SpPermission.SYSTEM_ADMIN + IMPLIES + TENANT_ADMIN + LINE_BREAK; public static String DEFAULT_ROLE_HIERARCHY = TARGET_ADMIN_HIERARCHY + - REPOSITORY_ADMIN_HIERARCHY + - ROLLOUT_ADMIN_HIERARCHY + - TENANT_CONFIGURATION_HIERARCHY + - TENANT_ADMIN_HIERARCHY + - SYSTEM_ADMIN_HIERARCHY; + REPOSITORY_ADMIN_HIERARCHY + + ROLLOUT_ADMIN_HIERARCHY + + TENANT_CONFIGURATION_HIERARCHY + + TENANT_ADMIN_HIERARCHY + + SYSTEM_ADMIN_HIERARCHY; } \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java index 5c2b5dbd6..0ba7b8967 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/StaticAuthenticationProvider.java @@ -9,6 +9,14 @@ */ package org.eclipse.hawkbit.im.authentication; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.function.Supplier; +import java.util.regex.Pattern; + import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; @@ -21,14 +29,6 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.util.ObjectUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.function.Supplier; -import java.util.regex.Pattern; - /** * Authentication provider for configured via spring application properties users. * The users could be tenant scoped or global. @@ -128,7 +128,7 @@ public class StaticAuthenticationProvider extends DaoAuthenticationProvider { private static User clone(final User user) { if (user instanceof TenantAwareUser) { return new TenantAwareUser(user.getUsername(), user.getPassword(), user.getAuthorities(), - ((TenantAwareUser)user).getTenant()); + ((TenantAwareUser) user).getTenant()); } else { return new User(user.getUsername(), user.getPassword(), user.getAuthorities()); } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantAwareAuthenticationDetails.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantAwareAuthenticationDetails.java index 0c9a11b2e..92d8a76f1 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantAwareAuthenticationDetails.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantAwareAuthenticationDetails.java @@ -31,12 +31,10 @@ public class TenantAwareAuthenticationDetails implements Serializable { 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} + * @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; diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantAwareUser.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantAwareUser.java index 8ccf22833..cd4f5068f 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantAwareUser.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantAwareUser.java @@ -56,6 +56,11 @@ public class TenantAwareUser extends User { this(username, "***", null, tenant); } + @Override + public boolean isEnabled() { + return true; + } + @Override public boolean isAccountNonExpired() { return true; @@ -70,9 +75,4 @@ public class TenantAwareUser extends User { public boolean isCredentialsNonExpired() { return true; } - - @Override - public boolean isEnabled() { - return true; - } } \ No newline at end of file diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantUserPasswordAuthenticationToken.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantUserPasswordAuthenticationToken.java index 19cbe6733..f5c4a189e 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantUserPasswordAuthenticationToken.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/TenantUserPasswordAuthenticationToken.java @@ -17,26 +17,21 @@ 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; // Exception squid:S1948 - no need to be Serializable @SuppressWarnings({ "squid:S1948" }) final Object tenant; + private static final long serialVersionUID = 1L; /** - * * 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 + * @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) { @@ -48,14 +43,10 @@ public class TenantUserPasswordAuthenticationToken extends UsernamePasswordAuthe * 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 + * @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 authorities) { @@ -70,14 +61,6 @@ public class TenantUserPasswordAuthenticationToken extends UsernamePasswordAuthe return tenant; } - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((tenant == null) ? 0 : tenant.hashCode()); - return result; - } - @Override public boolean equals(final Object obj) { if (this == obj) { @@ -100,4 +83,12 @@ public class TenantUserPasswordAuthenticationToken extends UsernamePasswordAuthe return true; } + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((tenant == null) ? 0 : tenant.hashCode()); + return result; + } + } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java index 10744c0ce..7794441b1 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java @@ -15,7 +15,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; - import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -74,10 +73,10 @@ public class DdiSecurityProperties { /** * Target token authentication. Tokens are defined per target. - * */ @Data public static class Targettoken { + /** * Set to true to enable target token authentication. */ diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java index 7266f2a53..4813d63a2 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java @@ -104,6 +104,8 @@ public class HawkbitSecurityProperties { @Data public static class Dos { + private final Filter filter = new Filter(); + private final Filter uiFilter = new Filter(); /** * Maximum number of status updates that the controller can report for * an action (0 to disable). @@ -176,9 +178,6 @@ public class HawkbitSecurityProperties { */ private int maxDistributionSetTypesPerTargetType = 50; - private final Filter filter = new Filter(); - private final Filter uiFilter = new Filter(); - /** * Configuration for hawkBits DOS prevention filter. This is usually an * infrastructure topic (e.g. Web Application Firewall (WAF)) but might diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java index 2e6e5fc9f..540cd897b 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/InMemoryUserAuthoritiesResolver.java @@ -26,7 +26,7 @@ public class InMemoryUserAuthoritiesResolver implements UserAuthoritiesResolver /** * Constructs the resolver based on the given authority lookup map. - * + * * @param usernamesToAuthorities The authority map to read from. Must not be null. */ public InMemoryUserAuthoritiesResolver(final Map> usernamesToAuthorities) { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java index 1d239da6e..2083979d8 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/MdcHandler.java @@ -9,10 +9,15 @@ */ package org.eclipse.hawkbit.security; +import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.Callable; + import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; + import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; @@ -25,10 +30,6 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.web.filter.OncePerRequestFilter; -import java.io.IOException; -import java.util.Objects; -import java.util.concurrent.Callable; - @NoArgsConstructor(access = AccessLevel.PRIVATE) public class MdcHandler { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java index 6860dd169..28b5b63b9 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java @@ -9,8 +9,6 @@ */ package org.eclipse.hawkbit.security; -import org.springframework.security.core.context.SecurityContext; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -19,6 +17,8 @@ import java.io.ObjectOutputStream; import java.util.Base64; import java.util.Objects; +import org.springframework.security.core.context.SecurityContext; + public interface SecurityContextSerializer { /** @@ -57,7 +57,8 @@ public interface SecurityContextSerializer { */ class Nop implements SecurityContextSerializer { - private Nop() {} + private Nop() { + } @Override public String serialize(final SecurityContext securityContext) { @@ -75,13 +76,14 @@ public interface SecurityContextSerializer { */ class JavaSerialization implements SecurityContextSerializer { - private JavaSerialization() {} + private JavaSerialization() { + } @Override public String serialize(final SecurityContext securityContext) { Objects.requireNonNull(securityContext); try (final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final ObjectOutputStream oos = new ObjectOutputStream(baos)) { + final ObjectOutputStream oos = new ObjectOutputStream(baos)) { oos.writeObject(securityContext); oos.flush(); return Base64.getEncoder().encodeToString(baos.toByteArray()); @@ -94,7 +96,7 @@ public interface SecurityContextSerializer { public SecurityContext deserialize(String securityContextString) { Objects.requireNonNull(securityContextString); try (final ByteArrayInputStream bais = new ByteArrayInputStream(Base64.getDecoder().decode(securityContextString)); - final ObjectInputStream ois = new ObjectInputStream(bais)) { + final ObjectInputStream ois = new ObjectInputStream(bais)) { return (SecurityContext) ois.readObject(); } catch (final IOException | ClassNotFoundException e) { throw new RuntimeException(e); diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java index aea434a2c..6fa537fb1 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java @@ -54,9 +54,8 @@ public class SecurityContextTenantAware implements ContextAware { * Creates the {@link SecurityContextTenantAware} based on the given * {@link UserAuthoritiesResolver}. * - * @param authoritiesResolver - * Resolver to retrieve the authorities for a given user. Must - * not be null.. + * @param authoritiesResolver Resolver to retrieve the authorities for a given user. Must + * not be null.. */ public SecurityContextTenantAware(final UserAuthoritiesResolver authoritiesResolver) { this.authoritiesResolver = authoritiesResolver; @@ -66,11 +65,12 @@ public class SecurityContextTenantAware implements ContextAware { /** * Creates the {@link SecurityContextTenantAware} based on the given * {@link UserAuthoritiesResolver}. - * + * * @param authoritiesResolver Resolver to retrieve the authorities for a given user. Must not be null. - * @param securityContextSerializer Serializer that is used to serialize / deserialize {@link SecurityContext}s. + * @param securityContextSerializer Serializer that is used to serialize / deserialize {@link SecurityContext}s. */ - public SecurityContextTenantAware(final UserAuthoritiesResolver authoritiesResolver, @Nullable final SecurityContextSerializer securityContextSerializer) { + public SecurityContextTenantAware(final UserAuthoritiesResolver authoritiesResolver, + @Nullable final SecurityContextSerializer securityContextSerializer) { this.authoritiesResolver = authoritiesResolver; this.securityContextSerializer = securityContextSerializer == null ? SecurityContextSerializer.NOP : securityContextSerializer; } @@ -104,11 +104,6 @@ public class SecurityContextTenantAware implements ContextAware { return null; } - @Override - public Optional getCurrentContext() { - return Optional.ofNullable(SecurityContextHolder.getContext()).map(securityContextSerializer::serialize); - } - @Override public T runAsTenant(final String tenant, final TenantRunner tenantRunner) { return runInContext(buildUserSecurityContext(tenant, SYSTEM_USER, SYSTEM_AUTHORITIES), tenantRunner::run); @@ -125,6 +120,11 @@ public class SecurityContextTenantAware implements ContextAware { return runInContext(buildUserSecurityContext(tenant, username, authorities), tenantRunner::run); } + @Override + public Optional getCurrentContext() { + return Optional.ofNullable(SecurityContextHolder.getContext()).map(securityContextSerializer::serialize); + } + @Override public R runInContext(final String serializedContext, final Function function, final T t) { Objects.requireNonNull(serializedContext); @@ -153,7 +153,7 @@ public class SecurityContextTenantAware implements ContextAware { final SecurityContext currentContext = SecurityContextHolder.getContext(); SystemSecurityContext.setSystemContext(currentContext); try { - return MdcHandler.getInstance().callWithAuthRE(tenantRunner::run); + return MdcHandler.getInstance().callWithAuthRE(tenantRunner::run); } finally { SecurityContextHolder.setContext(currentContext); } @@ -188,6 +188,11 @@ public class SecurityContextTenantAware implements ContextAware { tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false); } + @Override + public int hashCode() { + return delegate != null ? delegate.hashCode() : -1; + } + @Override public boolean equals(final Object another) { if (another instanceof Authentication anotherAuthentication) { @@ -204,11 +209,6 @@ public class SecurityContextTenantAware implements ContextAware { return delegate != null ? delegate.toString() : null; } - @Override - public int hashCode() { - return delegate != null ? delegate.hashCode() : -1; - } - @Override public String getName() { return delegate != null ? delegate.getName() : null; diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java index 600480163..1bb0e23a9 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityTokenGenerator.java @@ -26,7 +26,7 @@ public class SecurityTokenGenerator { /** * Generates a random secure token of {@link #TOKEN_LENGTH} bytes length as * hexadecimal string. - * + * * @return a new generated random alphanumeric string. */ public String generateToken() { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java index 0f5d52f24..9795c2858 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java @@ -29,6 +29,19 @@ public class SpringSecurityAuditorAware implements AuditorAware { // So this thread local variable provides option to override explicitly the auditor. private static final ThreadLocal AUDITOR_OVERRIDE = new ThreadLocal<>(); + // Always shall be followed by {@link #clearAuditorOverride} + public static void setAuditorOverride(final String auditor) { + if (auditor == null) { + AUDITOR_OVERRIDE.remove(); + } else { + AUDITOR_OVERRIDE.set(auditor); + } + } + + public static void clearAuditorOverride() { + AUDITOR_OVERRIDE.remove(); + } + @Override public Optional getCurrentAuditor() { if (AUDITOR_OVERRIDE.get() != null) { @@ -44,19 +57,6 @@ public class SpringSecurityAuditorAware implements AuditorAware { return Optional.ofNullable(getCurrentAuditor(authentication)); } - // Always shall be followed by {@link #clearAuditorOverride} - public static void setAuditorOverride(final String auditor) { - if (auditor == null) { - AUDITOR_OVERRIDE.remove(); - } else { - AUDITOR_OVERRIDE.set(auditor); - } - } - - public static void clearAuditorOverride() { - AUDITOR_OVERRIDE.remove(); - } - protected String getCurrentAuditor(final Authentication authentication) { if (authentication.getPrincipal() instanceof UserDetails) { return ((UserDetails) authentication.getPrincipal()).getUsername(); diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java index 9628a5a11..ae0e0568f 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java @@ -19,8 +19,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; -import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.authentication.AnonymousAuthenticationToken; @@ -43,7 +43,7 @@ public class SystemSecurityContext { /** * Autowired constructor. - * + * * @param tenantAware the tenant aware bean to retrieve the current tenant */ public SystemSecurityContext(final TenantAware tenantAware) { @@ -68,13 +68,13 @@ public class SystemSecurityContext { * context e.g. if the current security context does not contain the * necessary permission it's necessary to execute code as system code to * execute necessary methods and functionality. - * + * * The security context will be switched to the system code and back after * the callable is called. - * + * * The system code is executed for a current tenant by using the * {@link TenantAware#getCurrentTenant()}. - * + * * @param callable the callable to call within the system security context * @return the return value of the {@link Callable#call()} method. */ @@ -91,13 +91,13 @@ public class SystemSecurityContext { * context e.g. if the current security context does not contain the * necessary permission it's necessary to execute code as system code to * execute necessary methods and functionality. - * + * * The security context will be switched to the system code and back after * the callable is called. - * + * * The system code is executed for a specific given tenant by using the * {@link TenantAware}. - * + * * @param callable the callable to call within the system security context * @param tenant the tenant to act as system code * @return the return value of the {@link Callable#call()} method. @@ -122,10 +122,10 @@ public class SystemSecurityContext { * Runs a given {@link Callable} within a system security context, which has * the provided {@link GrantedAuthority}s to successfully run the * {@link Callable}. - * + * * The security context will be switched to the a new * {@link SecurityContext} and back after the callable is called. - * + * * @param tenant under which the {@link Callable#call()} must be executed. * @param callable to call within the security context * @return the return value of the {@link Callable#call()} method. diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java index 535f0a72e..b9921a45f 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java @@ -39,18 +39,17 @@ public final class IpUtil { .compile("([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})(:[0-9]{1,5})?"); private static final Pattern IPV6_ADDRESS_PATTERN = Pattern.compile("([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}"); // v6 address with [] amd (optionally) port - private static final Pattern IPV6_ADDRESS_WITH_PORT_PATTERN = Pattern.compile("\\[(?
([0-9a-f]{1,4}:){7}([0-9a-f]){1,4})](:[0-9]{1,5})?"); + private static final Pattern IPV6_ADDRESS_WITH_PORT_PATTERN = Pattern.compile( + "\\[(?
([0-9a-f]{1,4}:){7}([0-9a-f]){1,4})](:[0-9]{1,5})?"); /** * Retrieves the string based IP address from a given * {@link HttpServletRequest} by either the configured {@link HawkbitSecurityProperties.Clients#getRemoteIpHeader()} * (by default X-Forwarded-For) or by the {@link HttpServletRequest#getRemoteAddr()} method. * - * @param request - * the {@link HttpServletRequest} to determine the IP address - * where this request has been sent from - * @param securityProperties - * hawkBit security properties. + * @param request the {@link HttpServletRequest} to determine the IP address + * where this request has been sent from + * @param securityProperties hawkBit security properties. * @return the {@link URI} based IP address from the client which sent the * request */ @@ -65,12 +64,10 @@ public final class IpUtil { * Retrieves the string based IP address from a given {@link HttpServletRequest} by either the * forward header or by the {@link HttpServletRequest#getRemoteAddr()} method. * - * @param request - * the {@link HttpServletRequest} to determine the IP address - * where this request has been sent from - * @param forwardHeader - * the header name containing the IP address e.g. forwarded by a - * proxy {@code x-forwarded-for} + * @param 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 */ @@ -78,6 +75,76 @@ public final class IpUtil { return getClientIpFromRequest(request, forwardHeader, true); } + /** + * 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.indexOf('.') == -1 && host.charAt(0) != '['; + if (isIpV6) { + return URI.create(scheme + SCHEME_SEPARATOR + "[" + host + "]"); + } + return URI.create(scheme + SCHEME_SEPARATOR + host); + } + + /** + * Create a {@link URI} with amqp scheme and host. + * + * @param host the host + * @param exchange the exchange will store in the path + * @return the {@link URI} + * @throws IllegalArgumentException If the given string not parse able + */ + public static URI createAmqpUri(final String host, final String exchange) { + return createUri(AMQP_SCHEME, host).resolve("/" + exchange); + } + + /** + * 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 null. + * + * @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 null. + * + * @param uri the uri + * @return true = is http host false = not + */ + public static boolean isAmqpUri(final URI uri) { + return uri != null && AMQP_SCHEME.equals(uri.getScheme()); + } + + /** + * Check if the IP address of that {@link URI} is known, i.e. not an AQMP + * exchange in DMF case and not HIDDEN_IP in DDI case. + * + * @param uri the uri + * @return true if IP address is actually known by the server + */ + public static boolean isIpAddresKnown(final URI uri) { + return uri != null && !(AMQP_SCHEME.equals(uri.getScheme()) || HIDDEN_IP.equals(uri.getHost())); + } + private static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader, final boolean trackRemoteIp) { String ip; @@ -113,85 +180,4 @@ public final class IpUtil { 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.indexOf('.') == -1 && host.charAt(0) != '['; - if (isIpV6) { - return URI.create(scheme + SCHEME_SEPARATOR + "[" + host + "]"); - } - return URI.create(scheme + SCHEME_SEPARATOR + host); - } - - /** - * Create a {@link URI} with amqp scheme and host. - * - * @param host - * the host - * @param exchange - * the exchange will store in the path - * @return the {@link URI} - * @throws IllegalArgumentException - * If the given string not parse able - */ - public static URI createAmqpUri(final String host, final String exchange) { - return createUri(AMQP_SCHEME, host).resolve("/" + exchange); - } - - /** - * 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 null. - * - * @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 null. - * - * @param uri - * the uri - * @return true = is http host false = not - */ - public static boolean isAmqpUri(final URI uri) { - return uri != null && AMQP_SCHEME.equals(uri.getScheme()); - } - - /** - * Check if the IP address of that {@link URI} is known, i.e. not an AQMP - * exchange in DMF case and not HIDDEN_IP in DDI case. - * - * @param uri - * the uri - * @return true if IP address is actually known by the server - */ - public static boolean isIpAddresKnown(final URI uri) { - return uri != null && !(AMQP_SCHEME.equals(uri.getScheme()) || HIDDEN_IP.equals(uri.getHost())); - } - } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java index 2fee20d4e..861b63ba4 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/UrlUtils.java @@ -9,16 +9,16 @@ */ package org.eclipse.hawkbit.util; +import java.nio.charset.StandardCharsets; + import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.springframework.web.util.UriUtils; -import java.nio.charset.StandardCharsets; - @NoArgsConstructor(access = AccessLevel.PRIVATE) public class UrlUtils { - public static String decodeUriValue(String value) { - return UriUtils.decode(value, StandardCharsets.UTF_8); - } + public static String decodeUriValue(String value) { + return UriUtils.decode(value, StandardCharsets.UTF_8); + } } \ No newline at end of file diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java index 0caff6a43..69a95f2ff 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java +++ b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/SpPermissionTest.java @@ -16,13 +16,12 @@ import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; -import org.junit.jupiter.api.Test; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.util.ReflectionUtils; - import io.qameta.allure.Description; import io.qameta.allure.Feature; import io.qameta.allure.Story; +import org.junit.jupiter.api.Test; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.util.ReflectionUtils; /** * Test {@link SpPermission}. @@ -31,17 +30,17 @@ import io.qameta.allure.Story; @Story("Permission Test") public final class SpPermissionTest { - @Test - @Description("Verify the get permission function") - public void testGetPermissions() { - final int allPermission = 20; - final Collection allAuthorities = SpPermission.getAllAuthorities(); - final List allAuthoritiesList = PermissionUtils.createAllAuthorityList(); - assertThat(allAuthorities).hasSize(allPermission); - assertThat(allAuthoritiesList).hasSize(allPermission); - assertThat(allAuthoritiesList.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) - .containsAll(allAuthorities); - } + @Test + @Description("Verify the get permission function") + public void testGetPermissions() { + final int allPermission = 20; + final Collection allAuthorities = SpPermission.getAllAuthorities(); + final List allAuthoritiesList = PermissionUtils.createAllAuthorityList(); + assertThat(allAuthorities).hasSize(allPermission); + assertThat(allAuthoritiesList).hasSize(allPermission); + assertThat(allAuthoritiesList.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + .containsAll(allAuthorities); + } @Test @Description("Try to double check if all permissions works as expected") diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java index 70059ffbd..4162007d3 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java +++ b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java @@ -19,12 +19,11 @@ import java.net.URI; import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.security.HawkbitSecurityProperties.Clients; - import io.qameta.allure.Description; import io.qameta.allure.Feature; import io.qameta.allure.Story; +import org.eclipse.hawkbit.security.HawkbitSecurityProperties; +import org.eclipse.hawkbit.security.HawkbitSecurityProperties.Clients; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -116,21 +115,6 @@ public class IpUtilTest { checkHostInfoResolution("[0:0:0:0:0:0:0:1]:4233", "[0:0:0:0:0:0:0:1]", false); } - private void checkHostInfoResolution(final String hostInfo, final String expectedHost, final boolean remoteAddress) { - reset(requestMock); - when(remoteAddress ? requestMock.getRemoteAddr() : requestMock.getHeader(KNOWN_REQUEST_HEADER)).thenReturn(hostInfo); - - final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, KNOWN_REQUEST_HEADER); - - // verify - assertThat(remoteAddr.getHost()).as("The remote address should be as the known client IP address") - .isEqualTo(expectedHost); - verify(requestMock, times(1)).getHeader(KNOWN_REQUEST_HEADER); - if (remoteAddress) { - verify(requestMock, times(1)).getRemoteAddr(); - } - } - @Test @Description("Tests create http uri ipv4 and ipv6") public void testCreateHttpUri() { @@ -147,13 +131,6 @@ public class IpUtilTest { assertHttpUri("[" + ipv6 + "]", httpUri); } - private void assertHttpUri(final String host, final URI httpUri) { - assertThat(IpUtil.isHttpUri(httpUri)).as("The given URI has an http scheme").isTrue(); - assertThat(IpUtil.isAmqpUri(httpUri)).as("The given URI is not an AMQP scheme").isFalse(); - assertThat(host).as("The URI hosts matches the given host").isEqualTo(httpUri.getHost()); - assertThat(httpUri.getScheme()).as("The given URI scheme is http").isEqualTo("http"); - } - @Test @Description("Tests create amqp uri ipv4 and ipv6") public void testCreateAmqpUri() { @@ -181,15 +158,6 @@ public class IpUtilTest { assertAmqpUri(ipv6Braces, amqpUri); } - private void assertAmqpUri(final String host, final URI amqpUri) { - - assertThat(IpUtil.isAmqpUri(amqpUri)).as("The given URI is an AMQP scheme").isTrue(); - assertThat(IpUtil.isHttpUri(amqpUri)).as("The given URI is not an HTTP scheme").isFalse(); - assertThat(amqpUri.getHost()).as("The given host matches the URI host").isEqualTo(host); - assertThat(amqpUri.getScheme()).as("The given URI has an AMQP scheme").isEqualTo("amqp"); - assertThat(amqpUri.getRawPath()).as("The given URI has an AMQP path").isEqualTo("/path"); - } - @Test @Description("Tests create invalid uri") public void testCreateInvalidUri() { @@ -208,4 +176,35 @@ public class IpUtilTest { // expected } } + + private void checkHostInfoResolution(final String hostInfo, final String expectedHost, final boolean remoteAddress) { + reset(requestMock); + when(remoteAddress ? requestMock.getRemoteAddr() : requestMock.getHeader(KNOWN_REQUEST_HEADER)).thenReturn(hostInfo); + + final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, KNOWN_REQUEST_HEADER); + + // verify + assertThat(remoteAddr.getHost()).as("The remote address should be as the known client IP address") + .isEqualTo(expectedHost); + verify(requestMock, times(1)).getHeader(KNOWN_REQUEST_HEADER); + if (remoteAddress) { + verify(requestMock, times(1)).getRemoteAddr(); + } + } + + private void assertHttpUri(final String host, final URI httpUri) { + assertThat(IpUtil.isHttpUri(httpUri)).as("The given URI has an http scheme").isTrue(); + assertThat(IpUtil.isAmqpUri(httpUri)).as("The given URI is not an AMQP scheme").isFalse(); + assertThat(host).as("The URI hosts matches the given host").isEqualTo(httpUri.getHost()); + assertThat(httpUri.getScheme()).as("The given URI scheme is http").isEqualTo("http"); + } + + private void assertAmqpUri(final String host, final URI amqpUri) { + + assertThat(IpUtil.isAmqpUri(amqpUri)).as("The given URI is an AMQP scheme").isTrue(); + assertThat(IpUtil.isHttpUri(amqpUri)).as("The given URI is not an HTTP scheme").isFalse(); + assertThat(amqpUri.getHost()).as("The given host matches the URI host").isEqualTo(host); + assertThat(amqpUri.getScheme()).as("The given URI has an AMQP scheme").isEqualTo("amqp"); + assertThat(amqpUri.getRawPath()).as("The given URI has an AMQP path").isEqualTo("/path"); + } }