Fix case sensitiveness of limited DS complete search support (#2774)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-10-24 10:58:47 +03:00
committed by GitHub
parent 7ce88cb335
commit dc8211c64b
5 changed files with 24 additions and 15 deletions

View File

@@ -49,6 +49,7 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility; import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement.Update; import org.eclipse.hawkbit.repository.DistributionSetManagement.Update;
import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.Create; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement.Create;
import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
@@ -1329,16 +1330,22 @@ class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegrationTe
@Test @Test
void filterDistributionSetComplete() throws Exception { void filterDistributionSetComplete() throws Exception {
final int amount = 10; final int amount = 10;
testdataFactory.createDistributionSets(amount); final List<String> dsIds = testdataFactory.createDistributionSets(amount).stream()
.map(Identifiable::getId).map(String::valueOf).toList();
distributionSetManagement distributionSetManagement
.create(DistributionSetManagement.Create.builder() .create(DistributionSetManagement.Create.builder()
.type(distributionSetTypeManagement.findByKey("os").orElseThrow()) .type(distributionSetTypeManagement.findByKey("os").orElseThrow())
.name("incomplete").version("2") .name("incomplete").version("2")
.build()); .build());
final String rsqlFindLikeDs1OrDs2 = "complete==" + Boolean.TRUE; mvc.perform(get("/rest/v1/distributionsets?q=complete==true"))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("size", equalTo(10)))
.andExpect(jsonPath("total", equalTo(10)));
mvc.perform(get("/rest/v1/distributionsets?q=" + rsqlFindLikeDs1OrDs2)) // and more complex (case insensitive) query
mvc.perform(get("/rest/v1/distributionsets?q=complete==true;valid==true;id=IN=(" + String.join(",", dsIds) + ")"))
.andDo(MockMvcResultPrinter.print()) .andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(jsonPath("size", equalTo(10))) .andExpect(jsonPath("size", equalTo(10)))

View File

@@ -146,6 +146,10 @@ public class QLSupport implements ApplicationListener<ContextRefreshedEvent> {
this.virtualPropertyResolver = virtualPropertyResolver; this.virtualPropertyResolver = virtualPropertyResolver;
} }
public Node parse(final String query) {
return parse(query, null);
}
public <A extends Enum<A> & QueryField> Node parse(final String query, final Class<A> queryFieldType) { public <A extends Enum<A> & QueryField> Node parse(final String query, final Class<A> queryFieldType) {
return parser.parse(ignoreCase || caseInsensitiveDB ? query.toLowerCase() : query, queryFieldType); return parser.parse(ignoreCase || caseInsensitiveDB ? query.toLowerCase() : query, queryFieldType);
} }

View File

@@ -50,7 +50,6 @@ import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository; import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParser;
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -116,7 +115,7 @@ public class JpaDistributionSetManagement
public Page<JpaDistributionSet> findByRsql(final String rsql, final Pageable pageable) { public Page<JpaDistributionSet> findByRsql(final String rsql, final Pageable pageable) {
if (rsql != null && rsql.toLowerCase().contains(COMPLETE)) { if (rsql != null && rsql.toLowerCase().contains(COMPLETE)) {
// limited support for 'complete' - could be removed in future // limited support for 'complete' - could be removed in future
final Node node = RsqlParser.parse(rsql); final Node node = QLSupport.getInstance().parse(rsql);
final Specification<JpaDistributionSet> notDeleted = (root, query, cb) -> cb.equal(root.get(DELETED), false); final Specification<JpaDistributionSet> notDeleted = (root, query, cb) -> cb.equal(root.get(DELETED), false);
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>(); final List<Specification<JpaDistributionSet>> specList = new ArrayList<>();
specList.add(notDeleted); specList.add(notDeleted);

View File

@@ -9,6 +9,9 @@
*/ */
package org.eclipse.hawkbit.ui.simple.security; package org.eclipse.hawkbit.ui.simple.security;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import com.vaadin.flow.spring.security.VaadinAwareSecurityContextHolderStrategyConfiguration; import com.vaadin.flow.spring.security.VaadinAwareSecurityContextHolderStrategyConfiguration;
import com.vaadin.flow.spring.security.VaadinSecurityConfigurer; import com.vaadin.flow.spring.security.VaadinSecurityConfigurer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -27,11 +30,8 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
@EnableWebSecurity @EnableWebSecurity
@Configuration @Configuration
@@ -41,11 +41,6 @@ import org.springframework.security.web.access.intercept.AuthorizationFilter;
public class SecurityConfiguration { public class SecurityConfiguration {
private Customizer<OAuth2LoginConfigurer<HttpSecurity>> oAuth2LoginConfigurerCustomizer; private Customizer<OAuth2LoginConfigurer<HttpSecurity>> oAuth2LoginConfigurerCustomizer;
@Autowired
private UserDetailsSetter userDetailsSetter;
@Autowired(required = false)
private InMemoryClientRegistrationRepository clientRegistrationRepository;
@Autowired(required = false) @Autowired(required = false)
public void setOAuth2LoginConfigurerCustomizer( public void setOAuth2LoginConfigurerCustomizer(
@@ -66,7 +61,10 @@ public class SecurityConfiguration {
} }
@Bean @Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { SecurityFilterChain securityFilterChain(
final HttpSecurity http,
final UserDetailsSetter userDetailsSetter,
@Autowired(required = false) InMemoryClientRegistrationRepository clientRegistrationRepository) throws Exception {
http.authorizeHttpRequests(authorize -> authorize.requestMatchers("/images/*.png").permitAll()); http.authorizeHttpRequests(authorize -> authorize.requestMatchers("/images/*.png").permitAll());
http.addFilterAfter(userDetailsSetter, AuthorizationFilter.class); http.addFilterAfter(userDetailsSetter, AuthorizationFilter.class);
return http.with(VaadinSecurityConfigurer.vaadin(), configurer -> { return http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {

View File

@@ -40,6 +40,7 @@ class UserDetailsSetter extends OncePerRequestFilter {
private final SecurityContextHolderStrategy securityContextHolderStrategy; private final SecurityContextHolderStrategy securityContextHolderStrategy;
private final GrantedAuthoritiesService grantedAuthoritiesService; private final GrantedAuthoritiesService grantedAuthoritiesService;
@SuppressWarnings("java:S1066") // java:S1066 - readability preferred
@Override @Override
protected void doFilterInternal(@NotNull final HttpServletRequest request, @NotNull final HttpServletResponse response, protected void doFilterInternal(@NotNull final HttpServletRequest request, @NotNull final HttpServletResponse response,
@NotNull final FilterChain filterChain) @NotNull final FilterChain filterChain)