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;