From 8bdcc519854765d9a578aaf2c0e0ca7701c25043 Mon Sep 17 00:00:00 2001 From: Avgustin Marinov Date: Fri, 19 Sep 2025 15:47:20 +0300 Subject: [PATCH] Add actions contxt management (#2680) * based on TARGET permissions - action is accessible iff it its target is accessible * add some more (id) serch fields * (backward incompatible) software module search supports now search by name (type.name) and the old search by type (indead by type key) is now with type.key Signed-off-by: Avgustin Marinov --- .../jpa/acm/DefaultAccessController.java | 4 +- .../DefaultAccessControllerConfiguration.java | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessController.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessController.java index 53c3d745a..51a545a00 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessController.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessController.java @@ -64,12 +64,12 @@ public class DefaultAccessController & RsqlQueryField, T> impl return Optional.empty(); } - return Optional.ofNullable(getScopes(operation)) // if get scopes returns null, no scopes return no spec - all entities are accessible + return Optional.ofNullable(getScopes(operation)) // if "get scopes" returns null, no scopes return no spec - all entities are accessible .map(scopes -> // to RSQL scopes.size() == 1 ? scopes.get(0) // single scope : "(" + String.join(") or (", scopes) + ")") // join multiple scopes with 'or' - union - .map(scope -> RsqlUtility.getInstance().buildRsqlSpecification(scope, rsqlQueryFieldType)); + .map(rsql -> RsqlUtility.getInstance().buildRsqlSpecification(rsql, rsqlQueryFieldType)); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessControllerConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessControllerConfiguration.java index e1f29b687..5f636bb45 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessControllerConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/acm/DefaultAccessControllerConfiguration.java @@ -9,13 +9,19 @@ */ package org.eclipse.hawkbit.repository.jpa.acm; +import java.util.List; + +import lombok.Getter; import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.repository.DistributionSetFields; import org.eclipse.hawkbit.repository.DistributionSetTypeFields; +import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.SoftwareModuleFields; import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; +import org.eclipse.hawkbit.repository.TagFields; import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetTypeFields; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; @@ -36,6 +42,13 @@ public class DefaultAccessControllerConfiguration { return new DefaultAccessController<>(TargetFields.class, SpPermission.TARGET); } + // after adding support for internal action field search support it add matchIfMissing = true + @Bean + @ConditionalOnProperty(name = "hawkbit.acm.access-controller.action.enabled", havingValue = "true", matchIfMissing = false) + AccessController actionAccessController() { + return new DefaultAccessController<>(ActionFieldsInternal.class, SpPermission.TARGET); + } + @Bean @ConditionalOnProperty(name = "hawkbit.acm.access-controller.target-type.enabled", havingValue = "true") AccessController targetTypeAccessController() { @@ -65,4 +78,46 @@ public class DefaultAccessControllerConfiguration { AccessController distributionSetTypeAccessController() { return new DefaultAccessController<>(DistributionSetTypeFields.class, SpPermission.DISTRIBUTION_SET_TYPE); } + + // contains the same fields as TargetFields, but with "target." prefix for JPA queries in order to be applied to JpaAction repository + @Getter + public enum ActionFieldsInternal implements RsqlQueryField { + + ID("controllerId"), + NAME("name"), + DESCRIPTION("description"), + CREATEDAT("createdAt"), + CREATEDBY("createdBy"), + LASTMODIFIEDAT("lastModifiedAt"), + LASTMODIFIEDBY("lastModifiedBy"), + CONTROLLERID("controllerId"), + UPDATESTATUS("updateStatus"), + IPADDRESS("address"), + ATTRIBUTE("controllerAttributes"), + GROUP("group"), + ASSIGNEDDS("assignedDistributionSet", + DistributionSetFields.NAME.getJpaEntityFieldName(), DistributionSetFields.VERSION.getJpaEntityFieldName()), + INSTALLEDDS("installedDistributionSet", + DistributionSetFields.NAME.getJpaEntityFieldName(), DistributionSetFields.VERSION.getJpaEntityFieldName()), + TAG("tags", TagFields.NAME.getJpaEntityFieldName()), + LASTCONTROLLERREQUESTAT("lastTargetQuery"), + METADATA("metadata"), + TARGETTYPE("targetType", + TargetTypeFields.ID.getJpaEntityFieldName(), + TargetTypeFields.KEY.getJpaEntityFieldName(), + TargetTypeFields.NAME.getJpaEntityFieldName()); + + private final String jpaEntityFieldName; + private final List subEntityAttributes; + + ActionFieldsInternal(final String jpaEntityFieldName, final String... subEntityAttributes) { + this.jpaEntityFieldName = "target." + jpaEntityFieldName; + this.subEntityAttributes = List.of(subEntityAttributes); + } + + @Override + public boolean isMap() { + return this == ATTRIBUTE || this == METADATA; + } + } }