fixes #9427 regex pattern is now pre-compiled

This commit is contained in:
Alexander Schwartz 2022-01-07 09:38:51 +01:00 committed by Hynek Mlnařík
parent 9d5355b7ad
commit 9b18688ce2
2 changed files with 52 additions and 5 deletions

View file

@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -35,10 +36,10 @@ import java.util.stream.Stream;
* <p/> * <p/>
* For example, * For example,
* <p/> * <p/>
* for operator {@link ModelCriteriaBuilder.Operator.EQ} we concatenate left operand and right operand with equal sign: * for operator {@link ModelCriteriaBuilder.Operator#EQ} we concatenate left operand and right operand with equal sign:
* {@code fieldName = :parameterName} * {@code fieldName = :parameterName}
* <p/> * <p/>
* however, for operator {@link ModelCriteriaBuilder.Operator.EXISTS} we add following: * however, for operator {@link ModelCriteriaBuilder.Operator#EXISTS} we add following:
* <p/> * <p/>
* {@code fieldName IS NOT NULL AND fieldName IS NOT EMPTY"}. * {@code fieldName IS NOT NULL AND fieldName IS NOT EMPTY"}.
* *
@ -46,7 +47,7 @@ import java.util.stream.Stream;
* corresponding value is then saved into {@code Map<String, Object>} that is passed to each {@link ExpressionCombinator}. * corresponding value is then saved into {@code Map<String, Object>} that is passed to each {@link ExpressionCombinator}.
*/ */
public class IckleQueryOperators { public class IckleQueryOperators {
private static final String UNWANTED_CHARACTERS_REGEX = "[^a-zA-Z\\d]"; private static final Pattern UNWANTED_CHARACTERS_REGEX = Pattern.compile("[^a-zA-Z\\d]");
public static final String C = "c"; public static final String C = "c";
private static final Map<ModelCriteriaBuilder.Operator, String> OPERATOR_TO_STRING = new HashMap<>(); private static final Map<ModelCriteriaBuilder.Operator, String> OPERATOR_TO_STRING = new HashMap<>();
private static final Map<ModelCriteriaBuilder.Operator, ExpressionCombinator> OPERATOR_TO_EXPRESSION_COMBINATORS = new HashMap<>(); private static final Map<ModelCriteriaBuilder.Operator, ExpressionCombinator> OPERATOR_TO_EXPRESSION_COMBINATORS = new HashMap<>();
@ -123,14 +124,18 @@ public class IckleQueryOperators {
} }
private static String removeForbiddenCharactersFromNamedParameter(String name) { private static String removeForbiddenCharactersFromNamedParameter(String name) {
return name.replaceAll(UNWANTED_CHARACTERS_REGEX, ""); return UNWANTED_CHARACTERS_REGEX.matcher(name).replaceAll( "");
} }
/** /**
* Maps {@code namePrefix} to next available parameter name. For example, if {@code namePrefix == "id"} * Maps {@code namePrefix} to next available parameter name. For example, if {@code namePrefix == "id"}
* and {@code existingNames} set already contains {@code id0} and {@code id1} it returns {@code id2}. * and {@code existingNames} set already contains {@code id0} and {@code id1} it returns {@code id2}.
* Any character that is not an alphanumeric will be stripped, so that it works for prefixes like
* {@code "attributes.name"} as well.
* *
* This method is used for computing available names for name query parameters * This method is used for computing available names for name query parameters.
* Instead of creating generic named parameters that would be hard to debug and read by humans, it creates readable
* named parameters from the prefix.
* *
* @param existingNames set of parameter names that are already used in this Ickle query * @param existingNames set of parameter names that are already used in this Ickle query
* @param namePrefix name of the parameter * @param namePrefix name of the parameter

View file

@ -0,0 +1,42 @@
package org.keycloak.models.map.storage.hotRod;
import org.hamcrest.Matchers;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
import static org.hamcrest.MatcherAssert.assertThat;
public class IckleQueryOperatorsTest {
@Test
public void testFindAvailableNamedParamSimple() {
Set<String> existingNames = new HashSet<>();
String param = IckleQueryOperators.findAvailableNamedParam(existingNames, "clientId");
assertThat("should create the first ID", param, Matchers.equalTo("clientId0"));
}
@Test
public void testFindAvailableNamedParamAlreadyExists() {
Set<String> existingNames = new HashSet<>();
existingNames.add("clientId0");
String param = IckleQueryOperators.findAvailableNamedParam(existingNames, "clientId");
assertThat("should create the next ID as clientId0 is already taken", param, Matchers.equalTo("clientId1"));
}
@Test
public void testFindAvailableNamedParamIllegalCharacterInPrefix() {
Set<String> existingNames = new HashSet<>();
existingNames.add("clientid0");
String param = IckleQueryOperators.findAvailableNamedParam(existingNames, "client.id");
assertThat("should remove non-characters and non-numbers from the ID", param, Matchers.equalTo("clientid1"));
}
}