Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ 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
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.51.0] - 2026-10-26

### Changed
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.pointblue.dirxml</groupId>
<artifactId>dirxml-dev</artifactId>
<version>0.51.0</version>
<version>0.52.0</version>
<packaging>jar</packaging>

<name>DirXML Dev</name>
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/pointblue/dirxml/dev/deploy/Vault.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
45 changes: 45 additions & 0 deletions src/test/java/com/pointblue/dirxml/dev/deploy/VaultOpenTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
}
Loading