diff --git a/mycore-base/pom.xml b/mycore-base/pom.xml
index 899cdb17a2..22f3105b59 100644
--- a/mycore-base/pom.xml
+++ b/mycore-base/pom.xml
@@ -466,6 +466,11 @@
junit-jupiter-api
test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
org.junit.vintage
junit-vintage-engine
diff --git a/mycore-base/src/main/java/org/mycore/datamodel/classifications2/MCRCategoryID.java b/mycore-base/src/main/java/org/mycore/datamodel/classifications2/MCRCategoryID.java
index 5bfce35d35..67094278be 100644
--- a/mycore-base/src/main/java/org/mycore/datamodel/classifications2/MCRCategoryID.java
+++ b/mycore-base/src/main/java/org/mycore/datamodel/classifications2/MCRCategoryID.java
@@ -21,7 +21,6 @@
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Locale;
-import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.mycore.common.MCRException;
@@ -40,7 +39,7 @@
/**
* The composite identifier of a MCRCategory. If rootID == ID
the
* associated MCRCategory instance is a root category (a classification).
- *
+ *
* @author Thomas Scheffler (yagee)
* @since 2.0
*/
@@ -88,19 +87,20 @@ public static MCRCategoryID rootID(String rootID) {
/**
* @param categoryId must be in format classificationId:categoryId
* @return the {@link MCRCategoryID} if any
+ * @throws IllegalArgumentException if the given categoryId is invalid
*/
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public static MCRCategoryID fromString(String categoryId) {
- StringTokenizer tok = new StringTokenizer(categoryId, ":");
- String rootId = tok.nextToken();
- if (!tok.hasMoreTokens()) {
- return rootID(rootId);
- }
- String categId = tok.nextToken();
- if (tok.hasMoreTokens()) {
- throw new IllegalArgumentException("CategoryId is ambiguous: " + categoryId);
+ String[] parts = categoryId.split(":");
+ try {
+ return switch (parts.length) {
+ case 1 -> rootID(parts[0]);
+ case 2 -> new MCRCategoryID(parts[0], parts[1]);
+ default -> throw new IllegalArgumentException("CategoryId is ambiguous: " + categoryId);
+ };
+ } catch (MCRException e) {
+ throw new IllegalArgumentException("Invalid category ID: " + categoryId, e);
}
- return new MCRCategoryID(rootId, categId);
}
@Transient
@@ -110,7 +110,7 @@ public boolean isRootID() {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#hashCode()
*/
@Override
@@ -124,7 +124,7 @@ public int hashCode() {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -220,7 +220,7 @@ private void setRootID(String rootID) {
}
if (rootID.length() > ROOT_ID_LENGTH) {
throw new MCRException(String.format(Locale.ENGLISH,
- "classification ID ''%s'' is more than %d chracters long: %d", rootID, ROOT_ID_LENGTH,
+ "classification ID ''%s'' is more than %d characters long: %d", rootID, ROOT_ID_LENGTH,
rootID.length()));
}
this.rootID = rootID.intern();
@@ -228,7 +228,7 @@ private void setRootID(String rootID) {
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#toString()
*/
@Override
diff --git a/mycore-base/src/test/java/org/mycore/datamodel/classifications2/MCRCategoryIDTest.java b/mycore-base/src/test/java/org/mycore/datamodel/classifications2/MCRCategoryIDTest.java
index ba6b53ba6c..08466c62eb 100644
--- a/mycore-base/src/test/java/org/mycore/datamodel/classifications2/MCRCategoryIDTest.java
+++ b/mycore-base/src/test/java/org/mycore/datamodel/classifications2/MCRCategoryIDTest.java
@@ -19,16 +19,19 @@
package org.mycore.datamodel.classifications2;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
-import org.junit.Test;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import org.mycore.common.MCRException;
-import org.mycore.common.MCRTestCase;
/**
* @author Thomas Scheffler (yagee)
*
*/
-public class MCRCategoryIDTest extends MCRTestCase {
+public class MCRCategoryIDTest {
private static final String invalidID = "identifier:.sub";
private static final String validRootID = "rootID";
@@ -56,23 +59,36 @@ public void testRootID() {
assertEquals("RootIds do not match", validRootID, MCRCategoryID.rootID(validRootID).getRootID());
}
- @Test(expected = MCRException.class)
+ @Test
public void testInvalidRootID() {
- new MCRCategoryID(invalidID, validCategID);
+ assertThrows(MCRException.class, () -> new MCRCategoryID(invalidID, validCategID));
}
- @Test(expected = MCRException.class)
+ @Test
public void testInvalidCategID() {
- new MCRCategoryID(validRootID, invalidID);
+ assertThrows(MCRException.class, () -> new MCRCategoryID(validRootID, invalidID));
}
- @Test(expected = MCRException.class)
+ @Test
public void testLongCategID() {
- new MCRCategoryID(validRootID, toLongCategID);
+ assertThrows(MCRException.class, () -> new MCRCategoryID(validRootID, toLongCategID));
}
- @Test(expected = MCRException.class)
+ @Test
public void testLongRootID() {
- new MCRCategoryID(toLongRootID, validCategID);
+ assertThrows(MCRException.class, () -> new MCRCategoryID(toLongRootID, validCategID));
}
+
+ /**
+ * @see MCR-3302
+ */
+ @ParameterizedTest
+ @Tag("MCR-3302")
+ @ValueSource(strings = {
+ "", "foo:bar:baz", ":bar", ":bar:", ":bar:baz", "foo::bar", "foo::bar::", "foo::bar::baz", "::bar", "::bar::baz"
+ })
+ public void testInvalidEdgeCases(String invalidCategoryId) {
+ assertThrows(IllegalArgumentException.class, () -> MCRCategoryID.fromString(invalidCategoryId));
+ }
+
}
diff --git a/mycore-mods/src/main/java/org/mycore/mods/classification/MCRClassificationMappingEventHandler.java b/mycore-mods/src/main/java/org/mycore/mods/classification/MCRClassificationMappingEventHandler.java
index 4a96289d95..ce59443180 100644
--- a/mycore-mods/src/main/java/org/mycore/mods/classification/MCRClassificationMappingEventHandler.java
+++ b/mycore-mods/src/main/java/org/mycore/mods/classification/MCRClassificationMappingEventHandler.java
@@ -96,8 +96,8 @@ private static List> getXMappings(MCRCat
final MCRCategoryDAO dao = MCRCategoryDAOFactory.getInstance();
String label = labelOptional.get().getText();
return Stream.of(label.split("\\s"))
- .map(categIdString -> categIdString.split(":"))
- .map(categIdArr -> new MCRCategoryID(categIdArr[0], categIdArr[1]))
+ .map(MCRCategoryID::fromString)
+ .filter(id -> !id.isRootID())
.filter(dao::exist)
.map(mappingTarget -> new AbstractMap.SimpleEntry<>(category.getId(), mappingTarget))
.collect(Collectors.toList());
diff --git a/mycore-solr/src/main/java/org/mycore/solr/search/MCRQLSearchServlet.java b/mycore-solr/src/main/java/org/mycore/solr/search/MCRQLSearchServlet.java
index c1ece38efb..5de8d8c2ca 100644
--- a/mycore-solr/src/main/java/org/mycore/solr/search/MCRQLSearchServlet.java
+++ b/mycore-solr/src/main/java/org/mycore/solr/search/MCRQLSearchServlet.java
@@ -26,6 +26,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.util.ClientUtils;
import org.jdom2.Document;
import org.jdom2.output.XMLOutputter;
import org.mycore.common.config.MCRConfiguration2;
@@ -60,7 +61,13 @@ public void doGetPost(MCRServletJob job) throws IOException, ServletException {
HttpServletRequest request = job.getRequest();
HttpServletResponse response = job.getResponse();
String searchString = getReqParameter(request, "search", null);
+ if (searchString != null) {
+ searchString = ClientUtils.escapeQueryChars(searchString);
+ }
String queryString = getReqParameter(request, "query", null);
+ if (queryString != null) {
+ queryString = ClientUtils.escapeQueryChars(queryString);
+ }
Document input = (Document) request.getAttribute("MCRXEditorSubmission");
MCRQuery query;