From c16b408790aa564b089fe4496455ef9428cd05b1 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Sat, 19 Sep 2026 12:29:22 +0300 Subject: [PATCH] Close out the remaining small note-tier CodeQL categories - GuardedString now overrides toString() so it never inherits Object's default (fixes call-to-object-tostring at its two call sites in one place instead of patching each site). - AttributeTypeUtil.createInstantiatedObject wraps its numeric parsing in the same try/catch -> ConnectorException pattern used elsewhere (uncaught-number-format-exception), and switches from deprecated boxed constructors to the static parse methods. - Remove the dead ContractTestFactory inner class and its now-unused imports. - Mechanical fixes: StringUtil/XSDAnnotationParser empty-string checks, PrettyStringBuilder's Map iteration via entrySet(), a shadowed local in LdapInternalSearch, a javadoc @param typo/gap in MultiOpTests, and a missing space in a log message in ActiveDirectoryChangeLogSyncStrategy. --- .../contract/test/ContractITCase.java | 15 +---- .../contract/test/MultiOpTests.java | 4 +- .../common/PrettyStringBuilder.java | 9 +-- .../identityconnectors/common/StringUtil.java | 2 +- .../common/security/GuardedString.java | 9 +++ .../common/security/GuardedStringTests.java | 9 +++ .../ldap/search/LdapInternalSearch.java | 5 +- .../ActiveDirectoryChangeLogSyncStrategy.java | 4 +- .../xml/util/AttributeTypeUtil.java | 57 +++++++++++++++---- .../xml/xsdparser/XSDAnnotationParser.java | 2 +- .../xml/util/AttributeTypeUtilTests.java | 52 +++++++++++++++++ 11 files changed, 133 insertions(+), 35 deletions(-) create mode 100644 OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTests.java diff --git a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ContractITCase.java b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ContractITCase.java index 398cef04..a69f064c 100644 --- a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ContractITCase.java +++ b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ContractITCase.java @@ -20,6 +20,8 @@ * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" + * + * Portions Copyrighted 2026 3A Systems LLC. */ package org.identityconnectors.contract.test; @@ -32,12 +34,9 @@ import org.identityconnectors.common.StringUtil; import org.identityconnectors.contract.data.DataProvider; -import org.identityconnectors.framework.api.ConnectorFacade; -import org.identityconnectors.framework.common.objects.Schema; import org.testng.IObjectFactory; import org.testng.ITestContext; import org.testng.annotations.Factory; -import org.testng.internal.ObjectFactoryImpl; import com.google.inject.Guice; import com.google.inject.Injector; @@ -111,14 +110,4 @@ public Injector getInjector(ITestContext context) { public DataProvider getDataProvider(ITestContext context) { return ConnectorHelper.createDataProvider(); } - - private static class ContractTestFactory { - - private ConnectorFacade connectorFacade = null; - - private Schema schema = null; - - private IObjectFactory objectFactory = new ObjectFactoryImpl(); - - } } diff --git a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/MultiOpTests.java b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/MultiOpTests.java index dabb83b7..d948209a 100644 --- a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/MultiOpTests.java +++ b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/MultiOpTests.java @@ -21,6 +21,7 @@ * ==================== * * Portions Copyrighted 2012 ForgeRock AS + * Portions Copyrighted 2026 3A Systems LLC. * */ package org.identityconnectors.contract.test; @@ -576,11 +577,12 @@ public void testPasswordChangeIntervalPredAttribute(ObjectClass objectClass) { /** * Method to check the attrName's attribute contract * + * @param objectClass object class under test * @param attrName attribute to be checked * @param createValue value used for create * @param updateValue value used for update * @param type expected type of the value - * @param addPassword, add password to attributes in the update + * @param addPassword add password to attributes in the update */ private void checkOpAttribute(ObjectClass objectClass, String attrName, Object createValue, Object updateValue, Class type, boolean addPassword) { final int iteration = 0; diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/PrettyStringBuilder.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/PrettyStringBuilder.java index 4477f8c5..252a8e1c 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/PrettyStringBuilder.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/PrettyStringBuilder.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2015 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems LLC. */ package org.identityconnectors.common; @@ -96,13 +97,13 @@ protected String toPrettyString(final Object obj) { s.append(')'); } else if (obj instanceof Map) { final Map map = (Map) obj; - final Iterator it = map.keySet().iterator(); + final Iterator it = map.entrySet().iterator(); int i = 0; s.append('{'); while ((it.hasNext() && (i++ < maxArrayLen))) { - final Object key = it.next(); - s.append(key).append(':'); - s.append(toPrettyString(map.get(key))); + final Map.Entry entry = (Map.Entry) it.next(); + s.append(entry.getKey()).append(':'); + s.append(toPrettyString(entry.getValue())); if (it.hasNext()) { s.append(","); } diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/StringUtil.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/StringUtil.java index d1702373..ea73ee0e 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/StringUtil.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/StringUtil.java @@ -285,7 +285,7 @@ public static int indexOf(final String src, final char[] ch, final int idx) { * @return true if the string is empty else false. */ public static boolean isEmpty(final String val) { - return (val == null) ? true : "".equals(val) ? true : false; + return (val == null) ? true : val.isEmpty(); } /** diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/GuardedString.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/GuardedString.java index 8589d7e0..118d0c48 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/GuardedString.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/GuardedString.java @@ -291,4 +291,13 @@ public boolean equals(Object o) { public int hashCode() { return base64SHA1Hash.hashCode(); } + + /** + * Never prints the clear text; the default {@link Object#toString()} would not either, + * but its output is just a class name and hash code, not useful for logging. + */ + @Override + public String toString() { + return "GuardedString(...)"; + } } diff --git a/OpenICF-java-framework/connector-framework/src/test/java/org/identityconnectors/common/security/GuardedStringTests.java b/OpenICF-java-framework/connector-framework/src/test/java/org/identityconnectors/common/security/GuardedStringTests.java index af7061a3..17e0d526 100644 --- a/OpenICF-java-framework/connector-framework/src/test/java/org/identityconnectors/common/security/GuardedStringTests.java +++ b/OpenICF-java-framework/connector-framework/src/test/java/org/identityconnectors/common/security/GuardedStringTests.java @@ -19,6 +19,8 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * + * Portions Copyrighted 2026 3A Systems LLC. */ package org.identityconnectors.common.security; @@ -121,6 +123,13 @@ public void testDispose() { } } + @Test + public void testToStringNeverExposesTheClearText() { + GuardedString str = new GuardedString("secret".toCharArray()); + assertFalse(str.toString().contains("secret"), + "toString() must never leak the clear text"); + } + @Test public void testUnicode() { diff --git a/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/search/LdapInternalSearch.java b/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/search/LdapInternalSearch.java index c2a26f1b..6757669d 100644 --- a/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/search/LdapInternalSearch.java +++ b/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/search/LdapInternalSearch.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * "Portions Copyrighted 2014 ForgeRock AS" + * Portions Copyrighted 2026 3A Systems LLC. */ package org.identityconnectors.ldap.search; @@ -59,9 +60,9 @@ public LdapInternalSearch(LdapConnection conn, String filter, List baseD } public void execute(LdapSearchResultsHandler handler) { - String filter = blankAsAllObjects(this.filter); + String effectiveFilter = blankAsAllObjects(this.filter); try { - strategy.doSearch(conn.getInitialContext(), baseDNs, filter, controls, handler); + strategy.doSearch(conn.getInitialContext(), baseDNs, effectiveFilter, controls, handler); } catch (IOException e) { throw new ConnectorException(e); } catch (PartialResultException e) { diff --git a/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/sync/activedirectory/ActiveDirectoryChangeLogSyncStrategy.java b/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/sync/activedirectory/ActiveDirectoryChangeLogSyncStrategy.java index b9b6ccdd..6c9bd7f2 100644 --- a/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/sync/activedirectory/ActiveDirectoryChangeLogSyncStrategy.java +++ b/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/sync/activedirectory/ActiveDirectoryChangeLogSyncStrategy.java @@ -20,6 +20,8 @@ * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" + * + * Portions Copyrighted 2026 3A Systems LLC. */ package org.identityconnectors.ldap.sync.activedirectory; @@ -321,7 +323,7 @@ private String gethighestCommittedUSN() { Attributes attrs = conn.getInitialContext().getAttributes("", new String[]{HCU_CHANGED_ATTR}); hcUSN = getStringAttrValue(attrs, HCU_CHANGED_ATTR); if (hcUSN == null) { - String error = "Unable to read the highestCommittedUSN attribute" + String error = "Unable to read the highestCommittedUSN attribute " + "from the rootDSE of Active Directory "; throw new ConnectorException(error); } diff --git a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java index b6bc1296..8ec95a69 100644 --- a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java +++ b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java @@ -22,6 +22,8 @@ * "Portions Copyrighted 2010 [name of copyright owner]" * * $Id$ + * + * Portions Copyrighted 2026 3A Systems LLC. */ package org.forgerock.openicf.connectors.xml.util; @@ -44,47 +46,46 @@ public class AttributeTypeUtil { public static Object createInstantiatedObject(String attrValue, String javaclass) { if (javaclass.equals(XmlHandlerUtil.STRING)) { - String s = new String(attrValue); - return s; + return attrValue; } else if (javaclass.equals(XmlHandlerUtil.INT_PRIMITIVE)) { - int i = new Integer(attrValue); + int i = parseInt(attrValue); return i; } else if (javaclass.equals(XmlHandlerUtil.INTEGER)) { - Integer i = new Integer(attrValue); + Integer i = parseInt(attrValue); return i; } else if (javaclass.equals(XmlHandlerUtil.LONG)) { - Long l = new Long(attrValue); + Long l = parseLong(attrValue); return l; } else if (javaclass.equals(XmlHandlerUtil.LONG_PRIMITIVE)) { - long l = new Long(attrValue); + long l = parseLong(attrValue); return l; } else if (javaclass.equals(XmlHandlerUtil.BOOLEAN)) { - Boolean b = new Boolean(attrValue); + Boolean b = Boolean.valueOf(attrValue); return b; } else if (javaclass.equals(XmlHandlerUtil.BOOLEAN_PRIMITIVE)) { - boolean b = new Boolean(attrValue); + boolean b = Boolean.parseBoolean(attrValue); return b; } else if (javaclass.equals(XmlHandlerUtil.DOUBLE)) { - Double d = new Double(attrValue); + Double d = parseDouble(attrValue); return d; } else if (javaclass.equals(XmlHandlerUtil.DOUBLE_PRIMITIVE)) { - double d = new Double(attrValue); + double d = parseDouble(attrValue); return d; } else if (javaclass.equals(XmlHandlerUtil.FLOAT)) { - Float f = new Float(attrValue); + Float f = parseFloat(attrValue); return f; } else if (javaclass.equals(XmlHandlerUtil.FLOAT_PRIMITIVE)) { - float f = new Float(attrValue); + float f = parseFloat(attrValue); return f; } else if (javaclass.equals(XmlHandlerUtil.CHARACTER)) { @@ -120,6 +121,38 @@ else if (javaclass.equals(XmlHandlerUtil.BYTE_ARRAY)) { } } + private static int parseInt(String attrValue) { + try { + return Integer.parseInt(attrValue); + } catch (NumberFormatException e) { + throw new ConnectorException("Malformed int value in the XML: '" + attrValue + "'", e); + } + } + + private static long parseLong(String attrValue) { + try { + return Long.parseLong(attrValue); + } catch (NumberFormatException e) { + throw new ConnectorException("Malformed long value in the XML: '" + attrValue + "'", e); + } + } + + private static double parseDouble(String attrValue) { + try { + return Double.parseDouble(attrValue); + } catch (NumberFormatException e) { + throw new ConnectorException("Malformed double value in the XML: '" + attrValue + "'", e); + } + } + + private static float parseFloat(String attrValue) { + try { + return Float.parseFloat(attrValue); + } catch (NumberFormatException e) { + throw new ConnectorException("Malformed float value in the XML: '" + attrValue + "'", e); + } + } + public static List findAttributeValue(Attribute attr, AttributeInfo attrInfo) { Class javaClass = attrInfo.getType(); diff --git a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/xsdparser/XSDAnnotationParser.java b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/xsdparser/XSDAnnotationParser.java index e7e0661f..70c29342 100644 --- a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/xsdparser/XSDAnnotationParser.java +++ b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/xsdparser/XSDAnnotationParser.java @@ -71,7 +71,7 @@ public void characters(char[] chars, int start, int length) throws SAXException if(parse){ StringBuilder sb = new StringBuilder(); sb.append(chars, start, length); - if(!sb.toString().replace(" ", "").trim().equals("")){ + if(!sb.toString().replace(" ", "").trim().isEmpty()){ String stringToAppend = addValue + " " + sb.toString().trim(); stringBuilder.append(stringToAppend); stringBuilder.append("\n"); diff --git a/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTests.java b/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTests.java new file mode 100644 index 00000000..7b1fc891 --- /dev/null +++ b/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTests.java @@ -0,0 +1,52 @@ +/* + * The contents of this file are subject to the terms of the Common Development and + * Distribution License (the License). You may not use this file except in compliance with the + * License. + * + * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the + * specific language governing permission and limitations under the License. + * + * When distributing Covered Software, include this CDDL Header Notice in each file and include + * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL + * Header, with the fields enclosed by brackets [] replaced by your own identifying + * information: "Portions copyright [year] [name of copyright owner]". + * + * Copyright 2026 3A Systems, LLC. + */ +package org.forgerock.openicf.connectors.xml.util; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import org.identityconnectors.framework.common.exceptions.ConnectorException; +import org.testng.annotations.Test; + +public class AttributeTypeUtilTests { + + @Test + public void testValidNumericValuesAreParsed() { + assertEquals(AttributeTypeUtil.createInstantiatedObject("42", XmlHandlerUtil.INT_PRIMITIVE), 42); + assertEquals(AttributeTypeUtil.createInstantiatedObject("42", XmlHandlerUtil.INTEGER), Integer.valueOf(42)); + assertEquals(AttributeTypeUtil.createInstantiatedObject("42", XmlHandlerUtil.LONG), Long.valueOf(42L)); + assertEquals(AttributeTypeUtil.createInstantiatedObject("42", XmlHandlerUtil.LONG_PRIMITIVE), 42L); + assertEquals(AttributeTypeUtil.createInstantiatedObject("4.2", XmlHandlerUtil.DOUBLE), Double.valueOf(4.2)); + assertEquals(AttributeTypeUtil.createInstantiatedObject("4.2", XmlHandlerUtil.DOUBLE_PRIMITIVE), 4.2); + assertEquals(AttributeTypeUtil.createInstantiatedObject("4.2", XmlHandlerUtil.FLOAT), Float.valueOf(4.2f)); + assertEquals(AttributeTypeUtil.createInstantiatedObject("4.2", XmlHandlerUtil.FLOAT_PRIMITIVE), 4.2f); + } + + @Test + public void testMalformedNumericValueThrowsConnectorExceptionNotNumberFormatException() { + String[] javaClasses = { XmlHandlerUtil.INT_PRIMITIVE, XmlHandlerUtil.INTEGER, XmlHandlerUtil.LONG, + XmlHandlerUtil.LONG_PRIMITIVE, XmlHandlerUtil.DOUBLE, XmlHandlerUtil.DOUBLE_PRIMITIVE, + XmlHandlerUtil.FLOAT, XmlHandlerUtil.FLOAT_PRIMITIVE }; + for (String javaClass : javaClasses) { + try { + AttributeTypeUtil.createInstantiatedObject("not-a-number", javaClass); + fail("expected ConnectorException for javaClass " + javaClass); + } catch (ConnectorException e) { + // expected: the raw NumberFormatException must be wrapped, not propagated + } + } + } +}