From 1e52ab608029b2b27b9c80fffe5e3ee40569833e Mon Sep 17 00:00:00 2001 From: Jerry Combs Date: Mon, 26 Oct 2026 08:55:09 -0500 Subject: [PATCH 1/2] Vault.open over a caller's extended-operation connection Vault.open(DirContext, LDAPConnection) takes an engine connection the caller has already connected and bound; whatever the caller set on it, such as RFC 4370 proxied authorization as default controls, applies to every engine request. Directory Console needs it for Identity Manager under single sign-on, where it now reaches Vault's private field instead. The vault closes that connection; the directory connection stays the caller's. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 8 ++++ .../pointblue/dirxml/dev/deploy/Vault.java | 25 +++++++++++ .../dirxml/dev/deploy/VaultOpenTest.java | 45 +++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 863e047..61585e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html) ## [Unreleased] +### Added + +- **`Vault.open(DirContext, LDAPConnection)`:** a vault over an extended-operation connection the + caller has already connected and bound. Whatever the caller set on it applies to every engine + request, such as RFC 4370 proxied authorization, so a service account's connection acts for one + person; Directory Console uses it for Identity Manager under single sign-on. The engine keeps the + last identity it was given on a connection, so such a connection belongs to that one person. + ## [0.50.0] - 2026-10-22 ### Changed diff --git a/src/main/java/com/pointblue/dirxml/dev/deploy/Vault.java b/src/main/java/com/pointblue/dirxml/dev/deploy/Vault.java index bc2269a..485c690 100644 --- a/src/main/java/com/pointblue/dirxml/dev/deploy/Vault.java +++ b/src/main/java/com/pointblue/dirxml/dev/deploy/Vault.java @@ -209,6 +209,31 @@ public static Vault open(DirContext ldap, String host, int port, javax.net.ssl.S return v; } + /** + * A vault over two connections the caller already holds: {@code ldap}, used as is and left open by + * {@link #close}, and {@code ops}, the extended-operation connection, already connected and bound by + * the caller and closed by {@link #close}. Whatever the caller set on {@code ops} applies to every + * engine request: for example default controls, such as RFC 4370 proxied authorization so a service + * account's connection acts for one person (Directory Console's single sign-on). Such a connection + * belongs to that one person: the engine keeps the last identity it was given on a connection. + */ + public static Vault open(DirContext ldap, LDAPConnection ops) { + if (ldap == null || ops == null) { + throw new IllegalArgumentException("open needs the directory connection and the extended-operation connection"); + } + if (!ops.isConnected()) { + throw new IllegalArgumentException("the extended-operation connection is not connected"); + } + Config c = new Config(); + String host = ops.getHost(); + c.url = "ldaps://" + (host != null && host.contains(":") && !host.startsWith("[") ? "[" + host + "]" : host) + ":" + ops.getPort(); + c.bindDn = ops.getAuthenticationDN(); + Vault v = new Vault(c, ldap); + v.ownsLdap = false; + v.ops = ops; + return v; + } + @Override public void close() { if (ownsLdap) { diff --git a/src/test/java/com/pointblue/dirxml/dev/deploy/VaultOpenTest.java b/src/test/java/com/pointblue/dirxml/dev/deploy/VaultOpenTest.java index 0e9f603..e25a817 100644 --- a/src/test/java/com/pointblue/dirxml/dev/deploy/VaultOpenTest.java +++ b/src/test/java/com/pointblue/dirxml/dev/deploy/VaultOpenTest.java @@ -35,4 +35,49 @@ public void aFailedBindNamesTheServerAndLeavesTheCallersConnectionAlone() throws assertFalse("the password never appears in the message", e.getMessage().contains("never-sent")); assertFalse("the caller's connection is not closed", closed.get()); } + + @Test + public void aCallersEngineConnectionIsUsedAsGivenAndClosedWithTheVault() { + AtomicBoolean ldapClosed = new AtomicBoolean(); + DirContext lent = (DirContext) Proxy.newProxyInstance(DirContext.class.getClassLoader(), new Class[] {DirContext.class}, + (proxy, method, args) -> { + if (method.getName().equals("close")) { + ldapClosed.set(true); + } + return null; + }); + AtomicBoolean opsClosed = new AtomicBoolean(); + com.novell.ldap.LDAPConnection ops = new com.novell.ldap.LDAPConnection() { + @Override + public boolean isConnected() { + return true; + } + + @Override + public String getHost() { + return "edir1.acme.example"; + } + + @Override + public int getPort() { + return 636; + } + + @Override + public void disconnect() { + opsClosed.set(true); + } + }; + Vault v = Vault.open(lent, ops); + v.close(); + assertTrue("the engine connection is the vault's to close", opsClosed.get()); + assertFalse("the caller's directory connection is not closed", ldapClosed.get()); + } + + @Test + public void anEngineConnectionMustBeConnected() { + DirContext lent = (DirContext) Proxy.newProxyInstance(DirContext.class.getClassLoader(), new Class[] {DirContext.class}, (p, m, a) -> null); + assertThrows(IllegalArgumentException.class, () -> Vault.open(lent, new com.novell.ldap.LDAPConnection())); + assertThrows(IllegalArgumentException.class, () -> Vault.open(null, new com.novell.ldap.LDAPConnection())); + } } From 377e1a45acc25a13c2331221d441a34802214f2d Mon Sep 17 00:00:00 2001 From: Jerry Combs Date: Mon, 26 Oct 2026 09:08:20 -0500 Subject: [PATCH 2/2] 0.52.0 Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 ++ pom.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae0972d..dc06efa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html) ## [Unreleased] +## [0.52.0] - 2026-10-26 + ### Added - **`Vault.open(DirContext, LDAPConnection)`:** a vault over an extended-operation connection the diff --git a/pom.xml b/pom.xml index 9ac1333..cb1fb87 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.pointblue.dirxml dirxml-dev - 0.51.0 + 0.52.0 jar DirXML Dev