diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java index d14660ed2..52d0afd14 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.stream.Collectors; import org.eclipse.hawkbit.ContextAware; +import org.eclipse.hawkbit.im.authentication.SpRole; import org.eclipse.hawkbit.im.authentication.TenantAwareUserProperties; import org.eclipse.hawkbit.im.authentication.TenantAwareUserProperties.User; import org.eclipse.hawkbit.im.authentication.PermissionService; @@ -36,6 +37,10 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.AuditorAware; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; +import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.security.web.authentication.logout.LogoutHandler; @@ -164,4 +169,20 @@ public class SecurityAutoConfiguration { return simpleUrlLogoutSuccessHandler; } -} + @Bean + @ConditionalOnMissingBean + static RoleHierarchy roleHierarchy() { + final RoleHierarchyImpl hierarchy = new RoleHierarchyImpl(); + hierarchy.setHierarchy(SpRole.DEFAULT_ROLE_HIERARCHY); + return hierarchy; + } + + // and, if using method security also add + @Bean + @ConditionalOnMissingBean + static MethodSecurityExpressionHandler methodSecurityExpressionHandler(final RoleHierarchy roleHierarchy) { + final DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); + expressionHandler.setRoleHierarchy(roleHierarchy); + return expressionHandler; + } +} \ No newline at end of file diff --git a/hawkbit-runtime/hawkbit-mgmt-server/src/main/resources/application.properties b/hawkbit-runtime/hawkbit-mgmt-server/src/main/resources/application.properties index 8b8d4c87a..2cbed77b9 100644 --- a/hawkbit-runtime/hawkbit-mgmt-server/src/main/resources/application.properties +++ b/hawkbit-runtime/hawkbit-mgmt-server/src/main/resources/application.properties @@ -36,7 +36,7 @@ spring.rabbitmq.port=5672 # Define own (my_user) users instead together default "admin" (system-wide) user: #hawkbit.security.user.my_user.password={noop}isAwesome! -#hawkbit.security.user.my_user.permissions=ALL +#hawkbit.security.user.my_user.roles=TENANT_ADMIN #hawkbit.security.user.my_user.tenant=DEFAULT # Enable CORS and specify the allowed origins: diff --git a/hawkbit-runtime/hawkbit-update-server/src/main/resources/application.properties b/hawkbit-runtime/hawkbit-update-server/src/main/resources/application.properties index 52aeaad99..c9a99e1b5 100644 --- a/hawkbit-runtime/hawkbit-update-server/src/main/resources/application.properties +++ b/hawkbit-runtime/hawkbit-update-server/src/main/resources/application.properties @@ -37,7 +37,7 @@ spring.rabbitmq.port=5672 # Define own (my_user) users instead together default "admin" (system-wide) user: #hawkbit.security.user.my_user.password={noop}isAwesome! -#hawkbit.security.user.my_user.permissions=ALL +#hawkbit.security.user.my_user.roles=TENANT_ADMIN #hawkbit.security.user.my_user.tenant=DEFAULT # Enable CORS and specify the allowed origins: 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 new file mode 100644 index 000000000..f0c226992 --- /dev/null +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpRole.java @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.hawkbit.im.authentication; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * Software provisioning roles that implies set of permissions and reflects high-level roles. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@Slf4j +public final class SpRole { + + 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"; + 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"; + 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; + + 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; + + 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_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 9eea73b1f..c0262a49b 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 @@ -102,13 +102,8 @@ public class StaticAuthenticationProvider extends DaoAuthenticationProvider { grantedAuthorityList.add(new SimpleGrantedAuthority("ROLE_" + role)); } } - // Allows ALL as a shorthand for all permissions - if (userPermissions.size() == 1 && "ALL".equals(userPermissions.get(0))) { - grantedAuthorityList.addAll(PermissionUtils.createAllAuthorityList()); - } else { - for (final String permission : userPermissions) { - grantedAuthorityList.add(new SimpleGrantedAuthority(permission)); - } + for (final String permission : userPermissions) { + grantedAuthorityList.add(new SimpleGrantedAuthority(permission)); } return grantedAuthorityList;