Repository navigation
Conversation
…sses (#191) ## Summary #134 replaced `Class.newInstance()` with `ReflectionUtil.newInstance()`, which goes through `MethodHandles.Lookup.findConstructor`. That changed how a connector configuration class with a missing dependency fails: - **before:** `Class.newInstance()` threw `NoClassDefFoundError`. The `catch (Exception)` in `createDefaultAPIConfiguration` let it through, and `LocalConnectorInfoManagerImpl` (`catch (NoClassDefFoundError)`, likewise the OSGi managers) skipped that connector and logged an error; - **now:** `findConstructor` reports the same `NoClassDefFoundError` as `IllegalAccessException: no such constructor`. That is an `Exception`, so it is wrapped in a `ConnectorException` that nobody catches, and the whole bundle scan fails. Found through OpenIdentityPlatform/OpenIDM#259 (bump to openicf 2.1.0-SNAPSHOT): `ScriptedCRESTConfiguration` in `groovy-connector` refers to `httpasyncclient`, which is not on the OpenIDM test classpath, and `ConnectorInfoProviderServiceTest.beforeTest` fails with `LocalManager initialisation failed`; 126 tests of the module are skipped. ``` Caused by: ConnectorException: java.lang.IllegalAccessException: no such constructor: org.forgerock.openicf.connectors.scriptedcrest.ScriptedCRESTConfiguration.<init>()v at LocalConnectorInfoManagerImpl.createDefaultAPIConfiguration(LocalConnectorInfoManagerImpl.java:339) Caused by: java.lang.NoClassDefFoundError: org/apache/http/nio/client/HttpAsyncClient ``` ## Fix `ReflectionUtil.newInstance` rethrows the `LinkageError` cause of the `findConstructor` failure, except for the `NoSuchMethodError` and `IllegalAccessError` that come with a missing or inaccessible constructor (those are still reported as `NoSuchMethodException` / `IllegalAccessException`). This brings back the `Class.newInstance()` behaviour for every caller, including the OSGi info managers. One case stays different: a link failure that is itself an `IllegalAccessError` (a dependency that cannot access its superclass) cannot be told from an inaccessible constructor, so it is still reported as `IllegalAccessException`. `Class.newInstance()` threw the raw `IllegalAccessError`. The managers catch neither, so the scan fails in both cases. ## Test plan - [x] New `ReflectionUtilTests.newInstanceThrowsLinkageErrorOfClassWithMissingDependency`: a class loader that cannot load one dependency, so the class fails to link. Before the fix the test fails with the same `IllegalAccessException: no such constructor` - [x] New `ReflectionUtilTests.newInstanceFailsOnInaccessibleConstructor`: a private constructor seen through `publicLookup()` still fails with `IllegalAccessException`, not with a raw `IllegalAccessError` - [x] New `ReflectionUtilTests.newInstanceFailsOnInaccessibleClass`: a package-private class seen through `publicLookup()`, which `findConstructor` reports without a cause, still fails with `IllegalAccessException`, not with a `NullPointerException` - [x] New `LocalConnectorInfoManagerTests.testSkipsConnectorWithUnlinkableConfiguration`: a bundle with two connectors, the configuration class of one refers to a class missing from the bundle; the scan lists the other connector. Without the fix it fails with the `IllegalAccessException: no such constructor` from OpenIDM#259; without the `catch (NoClassDefFoundError)` in `LocalConnectorInfoManagerImpl` it fails with the `NoClassDefFoundError`. The test closes the bundle class loader before it deletes the temp jar, which Windows cannot delete while it is open - [x] `connector-framework`: 205/205 pass (incl. `newInstanceFailsWithoutNoArgConstructor`, which still gets `NoSuchMethodException`); `connector-framework-internal`: 525 run, 0 failures, 2 skipped (`testConfigurationUpdate` of the remote manager tests) - [x] End to end: with this `connector-framework` installed locally, OpenIDM `openidm-provisioner-openicf` on openicf 2.1.0-SNAPSHOT passes 138/138 (same as on 2.0.4; without the fix `beforeTest` fails)
d2c51b6 to
4a792f3
Compare
|
@maximthomas, a new round since your approval of 4a792f3, in 6772c96:
A full local |
maximthomas
left a comment
There was a problem hiding this comment.
praise: The fix for the bcprov 1.86 failure sits where the failure starts, and the description's claims hold.
CertUtil.generateCertificateguards the C RDN on the one road that both default-certificate callers take (DefaultKeyStoreInitializerand the short overload used bygenerateCert). On the ubuntu-latest JDK 27 leg,openidm-keystorepasses 5/5 on the shipped bcprov 1.86, andopenidm-utilgoes from 156 to 159 tests with the same 5 skipped.- The
SecurityResourceProvider.generateCSRclaim checks out.testActionGenerateCSRsends onlyaliasandCN, so it takes the defaultC=NonethroughX509Principal, andopenidm-securitypasses 18/18 on the same leg.
issue (blocking): A fresh install now generates openidm-localhost without a C RDN, so the subject DN that the guide and OpenDJ's password-sync plugin configure no longer matches it.
openidm-util/src/main/java/org/forgerock/openidm/util/CertUtil.java:106-110, openidm-doc/src/main/asciidoc/integrators-guide/chap-passwords.adoc:439-440, :648
Both default roads pass "None". On a fresh install, openidm-localhost (DefaultKeyStoreInitializer.java:144) used to get CN=localhost, O=OpenIDM Self-Signed Certificate, OU=None, L=None, ST=None, C=None. It now gets the same DN without C. The integrator's guide still gives the old DN as the ds-cfg-certificate-subject-dn default and in the keytool output, and so does OpenDJ's shipped openidm-accountchange-plugin-sample-config:16. The plugin's findCertificateBySubject (OpenidmAccountStatusNotificationHandler.java:363-373) compares with X500Principal.equals. On a miss it throws ConfigException, the handler does not initialise, and no password syncs from OpenDJ. Existing installs keep their stored certificate. A probe on bcprov 1.86 shows that the placeholder can be encoded directly: the certificate builds and converts, and its subject equals new X500Principal(<guide DN>).
import org.bouncycastle.asn1.DERPrintableString;
...
X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
if ("None".equals(country)) {
// "None" is the placeholder the default certificates use. BouncyCastle 1.85+ rejects it as a string
// value for C, so it is encoded directly to keep the subject DN that the integrator's guide and the
// OpenDJ password sync plugin configure
builder.addRDN(BCStyle.C, new DERPrintableString(country));
} else if (country != null) {
builder.addRDN(BCStyle.C, country);
}Javadoc at :85: "the subject's two-letter ISO 3166-1 country code, "None" for the default certificates' placeholder, or {@code null} to omit it". In CertUtilTest, rename both tests to match. testGenerateCertificateOmitsNoneCountry asserts that pair.getKey().getSubjectX500Principal() equals new X500Principal("CN=localhost, O=OpenIDM Self-Signed Certificate, OU=None, L=None, ST=None, C=None"). testGenerateCertificateWithCommonNameOnlyHasNoCountry asserts that C is "None".
Or: keep the C-less DN. Then this PR updates chap-passwords.adoc:439-440 and :648, and the release note says that fresh installs must drop , C=None from the plugin's ds-cfg-certificate-subject-dn; OpenDJ's sample config needs the same change. Neither option was run against DefaultKeyStoreInitializerTest or KeystoreResourceProviderTest, or checked on bcprov versions other than 1.86.
suggestion (non-blocking): No test passes a null country, so nothing pins the country != null half of the guard.
openidm-util/src/main/java/org/forgerock/openidm/util/CertUtil.java:108, openidm-util/src/test/java/org/forgerock/openidm/util/CertUtilTest.java
All three cases pass a non-null country: "None" through both overloads, and "US". Deleting country != null && leaves the suite green (3/3 on a HEAD export). Under that mutant a null country throws an NPE from X500NameBuilder.addRDN, which breaks the Javadoc's "null omits C". BASE threw the same NPE, so this behaviour is new and nothing pins it.
@Test
public void testGenerateCertificateOmitsNullCountry() throws Exception {
final Pair<X509Certificate, PrivateKey> pair = CertUtil.generateCertificate("localhost",
"Example", "IT", "California", null, "San Francisco",
ALGORITHM, KEY_SIZE, SIGNATURE_ALGORITHM, null, null);
assertThat(subjectOf(pair.getKey()).getRDNs(BCStyle.C)).isEmpty();
}Pin: this case passes at the head, fails with the NPE under the mutant, and still holds with the fix above.
…operties (#271) Part of #267 Fixes #269 Fixes #270 ## Problem A managed object property marked as "Nullable" gets a type array: `SchemaUtils.setNullableProperties` in the Admin UI turns its `type` into `[type, "null"]`. For a relationship this is `["relationship", "null"]`, and for a relationship collection `["array", "null"]`. Three places did not read these type arrays: - #267: `ManagedObjectApiDescription.build` read the type of a relationship property, and of the items of a relationship collection, with `asString()`. It failed with `/type: Expecting a java.lang.String`, and the managed object was left out of the API description. `ReverseRelationshipValidator` then fell back to `NA` and skipped the singleton and duplicate-assignment checks. - #269: `SchemaField.initializeType` followed `items` only for the string `"array"`. A Nullable relationship collection became a core field: no relationship provider, its value stored inside the managed object, the reverse property not kept in sync. - #270: the Admin UI finds relationship properties by comparing their type with `"relationship"` and `"array"`. The edit view did not read the value of a Nullable singleton relationship, the relationship widget left Nullable relationships out, and the linked view and the default value editor of a mapping to such a property threw `Unknown editor for schema`. ## Change - `ManagedObjectApiDescription.build` tells a singleton from a collection by `SchemaField.isArray()` of its relationship provider. `replaceRelationshipType` replaces `"relationship"` with `"object"` in a type string or a type array, so `["relationship", "null"]` becomes `["object", "null"]`. The types of a type array stay unique: `["object", "relationship"]` becomes `["object"]`. - `ReverseRelationshipValidator.parseReverseReferenceType` accepts a type array that lists `"array"` or `"object"`. - `SchemaField.initializeType` reads a type array of `"array"` and `"null"` with a typed `items` schema like `"array"`. Without one it stays a core field, as before: no `items`, an `items` schema without `type` such as `{}` or `{"$ref": …}`, a tuple of `items` schemas, an `items` type that is not a string or a list of strings or that lists only `"null"`, or an `items` schema of type `"array"` without a typed `items` schema of its own. A type array that lists another type next to `"array"` is not changed either. - `ResourceDelegate.normalizeRelationshipTypes` reads `["relationship", "null"]` as `"relationship"`, and `["array", "null"]` with relationship items as `"array"`, in the schemas that `ResourceDelegate.getSchema` (with `allSchemas`) and `AdminUtils.findPropertiesList` return. Both work on the copy that `ConfigDelegate.readEntity` returns, so `managed.json` keeps the type arrays. A property that is not an object, such as `null`, is skipped, so it does not stop `getSchema` for every managed object. ## Upgrade note A relationship collection marked as Nullable before this change is a relationship collection again after the upgrade. The values written to it while it was a core field are no longer returned, and the next update of the object does not keep them inside it. The relationships stored before it was marked as Nullable are returned again. See the upgrade note in #269 for how to keep the values. As for any relationship collection, a PATCH `remove` of the whole field without a value, and a `move` or `copy` onto it, now fail with `400 Cannot delete collection`. While the field was a core field they succeeded. A `replace` with `null` is rejected by the PATCH parser, before and after this change. A rollback to a release without this change makes such a field a core field again. The relationships written to it after the upgrade are then no longer returned for the object that holds the field, while a reverse property on the other object that is not Nullable still lists them, and the next update of the object stores the value inside it again. An older copy of `org/forgerock/openidm/ui/common/delegates/ResourceDelegate.js` in `ui/admin/extension` overrides the new file and has no `normalizeRelationshipTypes`. `AdminUtils.findPropertiesList` then fails, and the mapping, assignment, self-service and resource-collection views get no properties. Re-apply such customizations to the new files, as "What You Should Do With Your UI After Updating" in the update guide describes. ## Dependency The OpenAPI transformer still has to describe the type arrays `["object", "null"]` and `["array", "null"]`. That is OpenIdentityPlatform/commons#382, which reaches OpenIDM through OpenDJ#1243, OpenICF#210 and #259. Until then `build` still drops the API description of a managed object with a Nullable relationship, now in the transformer, and `ReverseRelationshipValidator` still falls back to `NA`. This pull request is therefore only part of #267, which #259 closes. The `SchemaField` and Admin UI parts do not depend on it. Once OpenIDM resolves the fixed transformer, `testBuildReplacesRelationshipTypes` also gets rows with `["relationship", "null"]` and with `["array", "null"]` and relationship items, which expect `["object", "null"]` and `isRelationship: true`. Until then no test can tell `build`'s `isArray()` selector from the old type comparison: every type array makes `build` return `null` in the transformer. ## Tests - `openidm-core`: 143 tests, 0 failures. With the old `ReverseRelationshipValidator` and `SchemaField`, exactly the new type-array rows fail. With the `items.get("type").isNotNull()` check of the previous round in `SchemaField.isArraySchema`, exactly the 6 new rows with an unreadable `items` type fail. Without the check for a type besides `"null"` in `hasTypedItems`, exactly the 2 rows `[]` and `["null"]` fail; without its recursion into an `items` schema of type `"array"`, exactly the 2 array-of-arrays rows fail. With `get(0)` instead of `contains` in `hasType`, exactly the 2 rows that list `"null"` first fail. Without the de-duplication in `replaceRelationshipType`, the `["object", "relationship"]` row fails. - `openidm-ui-admin` (with `openidm-ui` and `openidm-ui-common`): eslint clean, 132 QUnit tests, 0 failures; with the old `ResourceDelegate.js` and `AdminUtils.js`, exactly the 3 new tests fail. They compare with `strictEqual`, so a normalization that leaves a one-element array such as `["relationship"]` fails all 3 of them as well. Swapping the two blocks of `normalizeRelationshipTypes`, dropping its `items` guard in the collection branch, or dropping the filter of properties that are not objects, fails the `normalizeRelationshipTypes` test. `openidm-ui-enduser`: 2 tests, 0 failures.
- Import the openicf 2.1.0-SNAPSHOT BOM instead of 2.0.4. - RepoJobStore: drop the unused jobKey local (code scanning #974) and make TriggerComparator static, as it never uses the enclosing instance (#975). - populateAsManagedUser.js: drop the unused propertyMapping (#967). - TemporalConstraintsFormView.js: drop the unused constraint (#966).
bcprov 1.85 rejects a C (2.5.4.6) attribute that is not a two-letter ISO 3166-1 code. CertUtil.generateCertificate added C=None for the default keystore certificates (DefaultKeyStoreInitializer) and for the keystore generateCert action, so both failed with "country code attribute 2.5.4.6 must be exactly 2 characters ... got 4: 'None'". Leave C out when the country is null or the "None" placeholder. Keep RepoJobStore.TriggerComparator non-static: it is protected in an exported package, and code scanning alert 975 repeats 444, dismissed as won't fix in PR 212 for that binary-compatibility reason.
6772c96 to
6fd50d0
Compare
|
@maximthomas, both points are addressed in 6fd50d0; the branch is also rebased on current
On JDK 27 with bcprov 1.86, |
maximthomas
left a comment
There was a problem hiding this comment.
praise: The round-1 subject-DN regression is fixed where it started, and BouncyCastle still checks real country codes.
CertUtil.generateCertificate(CertUtil.java:110-111) writesC=Noneas aDERPrintableString. On bcprov 1.86 this gives the same X500Name bytes that bcprov 1.84's string road wrote at the base, soopenidm-localhostkeeps the DN that OpenDJ password sync looks up.testGenerateCertificateKeepsDefaultSubjectchecks the whole default DN throughX500Principal, andtestGenerateCertificateOmitsNullCountrycovers thecountry != nullbranch.- At this head on bcprov 1.86,
DefaultKeyStoreInitializerTestpasses 2/2,KeystoreResourceProviderTest4/4 andManagedObjectApiDescriptionTest10/10 (with api-descriptor 3.2.2).
## Summary Code scanning: two Trivy findings on the build that no upstream bump covers. #259 handles the ones that come through the OpenICF BOM. | Library | Was → now | Comes from | Alerts | |---|---|---|---| | `xerces:xercesImpl` | 2.9.1 → 2.12.2 | `http-builder` 0.7.1 → `nekohtml` 1.9.16, copied to `lib/` (the `groovy.classpath` in `conf/script.json`) | #941 (CVE-2012-0881), #942 (CVE-2013-4002) | | `at.yawk.lz4:lz4-java` | 1.10.1 → 1.11.4 | `orientdb-core` 3.2.51, embedded in the `openidm-repo-orientdb` bundle | #976 (CVE-2026-106451) | Both versions are managed in the root `dependencyManagement`, next to the MyBatis override, and set through properties. With xercesImpl 2.12.2, `lib/` ships xml-apis 1.4.01 instead of 1.3.04. 1.11.4 is the fixed lz4-java version Trivy reports; even OrientDB 3.2.57 only moves to 1.11.0, so an OrientDB bump alone would not be enough. Maven Enforcer rejects resolved xercesImpl versions below 2.12.2 and lz4-java versions below 1.11.4 across the reactor. The override comments identify when to reassess them, and `legal/THIRDPARTYREADME.txt` reflects the new Xerces and xml-apis versions and their NOTICE copyright years. Only the build scans report #976, so it closes with this PR. The scans of the published 7.1.2 images also report #941 and #942, as well as #979 (lz4 in the 7.1.2 image); those stay open until the next release image is scanned. ## Test plan - [x] `mvn dependency:tree` across the reactor: only `openidm-repo-orientdb` (lz4-java) and `openidm-zip` (xercesImpl, xml-apis) are affected; they now resolve 1.11.4, and 2.12.2 with 1.4.01 - [x] Before the review changes, clean full `mvn -U clean verify` locally on JDK 27: 49/49 modules, no test failures - [x] Before the review changes, `openidm-repo-orientdb` manifest compared against a build with `-Dlz4.version=1.10.1`: only the jar name in `Bundle-ClassPath` and `Embedded-Artifacts` changes; `Import-Package` is identical - [x] Before the review changes, built zip started locally with the default OrientDB repository (`plocal`, embedded server): `OpenIDM ready`, no SEVERE; a managed user created, queried and deleted over REST - [x] Before the review changes, the `lib/` jars of the zip run both http-builder parser paths (the nekohtml `SAXParser` with the xml-resolver `CatalogResolver`, and JAXP `SAXParserFactory`): the same elements and the same `org.apache.xerces.jaxp.SAXParserFactoryImpl` as with xercesImpl 2.9.1 - [x] After the review changes, `mvn -o validate` passed for all 49 modules. Overriding Xerces to 2.9.1 and lz4-java to 1.10.1 separately made Enforcer fail on the corresponding dependency. - [ ] Full build in CI - [ ] Trivy on the build no longer reports #941, #942, #976
Summary
Code scanning triage of the open alerts on
master.Dependencies
openicf2.1.0-SNAPSHOT BOM instead of 2.0.4.The 2.1.0-SNAPSHOT deployed on 2026-10-29 pins OpenDJ 5.2.0 → commons 3.2.2. The build therefore gets jackson 2.18.11, bcprov 1.86 and freemarker 2.3.35, and
xml-connectorembedslib/xercesImpl-2.12.2.jar. This fixes the Trivy findings on the build for #933, #935, #939, #940, #947–#963. Guava 33.7.2 (#1006) follows once OpenIdentityPlatform/OpenDJ#1243 and OpenIdentityPlatform/OpenICF#210 are merged and their snapshots redeployed. Alerts that the image scans also report on the published 7.1.2 images stay open until the next release image is scanned.Default certificates with BouncyCastle 1.85+
bcprov 1.85, the first release with the fixes for CVE-2026-8763 and CVE-2026-13506, checks in
BCStylethat the C (2.5.4.6) attribute is a two-letter ISO 3166-1 code.CertUtil.generateCertificateaddedC=Nonefor the default certificates. Two callers failed withIllegalArgumentException: country code attribute 2.5.4.6 must be exactly 2 characters per ISO 3166-1 / X.520, got 4: 'None':DefaultKeyStoreInitializer, which creates the self-service andopenidm-localhostcertificates when the keystore lacks them (the 4openidm-keystoretest failures in the previous CI run);generateCertaction ofKeystoreResourceProvider, through the shortgenerateCertificateoverload.CertUtilencodes the legacyC=Noneplaceholder directly, preserving the default subject DN used by OpenDJ password sync. Anullcountry omits C; ordinary country codes still go through BouncyCastle's validation.CertUtilTestcovers the full default DN, the short overload, a null country and a real country code.SecurityResourceProvider.generateCSRalso defaults toC=None, but it goes throughX509Principal/X509Name, which bcprov 1.86 does not validate, so it is unchanged here.CodeQL note-level findings
java/local-variable-is-never-readRepoJobStorejobKeylocal.js/unused-local-variablepopulateAsManagedUser.jspropertyMapping.js/unused-local-variableTemporalConstraintsFormView.jsconstraint.Dismissed as won't fix (1):
java/non-static-nested-class(RepoJobStore.TriggerComparator): the same finding as #444, dismissed in Fix CodeQL note-level Java cleanups #212. The class isprotectedin the exportedorg.forgerock.openidm.quartz.impl; making itstaticdrops the outer instance from its constructor descriptor and breaks subclasses compiled against 7.1.2. An earlier revision of this PR made itstatic; that is reverted.Dismissed as false positives (5):
java/sensitive-log(MappedTableHandler,PostgreSQLMappedTableHandler): they log SQL templates that contain only placeholders. This is the same statement as the previously dismissed Admin-Password cannot be changed via self-service ui #10 and Does not work with OpenJDK 11 #12.js/unused-local-variable(router-authz.js): the helpers are called by name from thecustomAuthzexpressions inaccess.js.Test plan
CertUtilTestfailed against bcprov 1.86 before the initial fix, with the same message as CI, and passed after it.mvn -U verifylocally on JDK 27 against openicf 2.1.0-20261029.125007-28: 49/49 modules, no test failures, including the 5openidm-keystoretests andKeystoreResourceProviderTesttestActionGenerateCert/testActionGenerateCSR. The zip ships bcprov 1.86, jackson 2.18.11, freemarker 2.3.35 and the xml-connector snapshot.node --checkon both edited JS filesmvn -o -pl openidm-util,openidm-keystore,openidm-security -am teston JDK 27 with bcprov 1.86: all 12 reactor modules passed, including 5 keystore and 18 security tests. The default-DN tests failed before the fix as expected.