0
# Controls and Extensions
1
2
Standard LDAP controls and extended operations for advanced directory functionality including paged results, server-side sorting, persistent search, and password management.
3
4
## Capabilities
5
6
### Standard LDAP Controls
7
8
#### Paged Results Controls
9
10
```java { .api }
11
/**
12
* Control for retrieving search results in pages
13
*/
14
public class PagedResultsRequestControl extends Control {
15
public PagedResultsRequestControl(int pageSize);
16
public PagedResultsRequestControl(int pageSize, ASN1OctetString cookie);
17
18
public int getSize();
19
public ASN1OctetString getCookie();
20
}
21
22
/**
23
* Response control for paged results
24
*/
25
public class SimplePagedResultsControl extends Control {
26
public int getSize();
27
public ASN1OctetString getCookie();
28
public boolean moreResultsToReturn();
29
30
public static SimplePagedResultsControl get(LDAPResult result);
31
}
32
```
33
34
#### Server-Side Sort Controls
35
36
```java { .api }
37
/**
38
* Control for server-side sorting of search results
39
*/
40
public class ServerSideSortRequestControl extends Control {
41
public ServerSideSortRequestControl(SortKey... sortKeys);
42
public ServerSideSortRequestControl(List<SortKey> sortKeys);
43
44
public List<SortKey> getSortKeys();
45
}
46
47
/**
48
* Sort key specification
49
*/
50
public class SortKey implements Serializable {
51
public SortKey(String attributeName);
52
public SortKey(String attributeName, boolean reverseOrder);
53
public SortKey(String attributeName, String matchingRuleID, boolean reverseOrder);
54
55
public String getAttributeName();
56
public String getMatchingRuleID();
57
public boolean reverseOrder();
58
}
59
60
/**
61
* Response control for server-side sort status
62
*/
63
public class ServerSideSortResponseControl extends Control {
64
public ResultCode getResultCode();
65
public String getAttributeName();
66
}
67
```
68
69
#### Authorization Controls
70
71
```java { .api }
72
/**
73
* Control for proxied authorization (version 1)
74
*/
75
public class ProxiedAuthorizationV1RequestControl extends Control {
76
public ProxiedAuthorizationV1RequestControl(String proxyDN);
77
78
public String getProxyDN();
79
}
80
81
/**
82
* Control for proxied authorization (version 2)
83
*/
84
public class ProxiedAuthorizationV2RequestControl extends Control {
85
public ProxiedAuthorizationV2RequestControl(String authorizationID);
86
87
public String getAuthorizationID();
88
}
89
90
/**
91
* Control for requesting authorization identity
92
*/
93
public class AuthorizationIdentityRequestControl extends Control {
94
public AuthorizationIdentityRequestControl();
95
}
96
97
/**
98
* Response control containing authorization identity
99
*/
100
public class AuthorizationIdentityResponseControl extends Control {
101
public String getAuthorizationID();
102
}
103
```
104
105
### Extended Operations
106
107
#### Password Management
108
109
```java { .api }
110
/**
111
* Extended operation for password modification
112
*/
113
public class PasswordModifyExtendedRequest extends ExtendedRequest {
114
public PasswordModifyExtendedRequest();
115
public PasswordModifyExtendedRequest(String userIdentity, String oldPassword, String newPassword);
116
117
public String getUserIdentity();
118
public String getOldPassword();
119
public String getNewPassword();
120
}
121
122
/**
123
* Result for password modify operation
124
*/
125
public class PasswordModifyExtendedResult extends ExtendedResult {
126
public String getGeneratedPassword();
127
}
128
```
129
130
#### Identity Operations
131
132
```java { .api }
133
/**
134
* Extended operation to determine current identity
135
*/
136
public class WhoAmIExtendedRequest extends ExtendedRequest {
137
public WhoAmIExtendedRequest();
138
}
139
140
/**
141
* Result containing current authorization identity
142
*/
143
public class WhoAmIExtendedResult extends ExtendedResult {
144
public String getAuthorizationID();
145
}
146
```
147
148
#### Transaction Support
149
150
```java { .api }
151
/**
152
* Extended operation to start a transaction
153
*/
154
public class StartTransactionExtendedRequest extends ExtendedRequest {
155
public StartTransactionExtendedRequest();
156
}
157
158
/**
159
* Result for start transaction operation
160
*/
161
public class StartTransactionExtendedResult extends ExtendedResult {
162
public ASN1OctetString getTransactionID();
163
}
164
165
/**
166
* Extended operation to end a transaction
167
*/
168
public class EndTransactionExtendedRequest extends ExtendedRequest {
169
public EndTransactionExtendedRequest(ASN1OctetString transactionID, boolean commit);
170
171
public ASN1OctetString getTransactionID();
172
public boolean commit();
173
}
174
```
175
176
#### SSL/TLS Support
177
178
```java { .api }
179
/**
180
* Extended operation to start TLS encryption
181
*/
182
public class StartTLSExtendedRequest extends ExtendedRequest {
183
public StartTLSExtendedRequest();
184
public StartTLSExtendedRequest(SSLContext sslContext);
185
public StartTLSExtendedRequest(SSLSocketFactory socketFactory);
186
}
187
```
188
189
## Usage Examples
190
191
### Paged Search Results
192
193
```java
194
import com.unboundid.ldap.sdk.*;
195
import com.unboundid.ldap.sdk.controls.*;
196
197
LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);
198
199
try {
200
connection.bind("cn=admin,dc=example,dc=com", "password");
201
202
SearchRequest searchRequest = new SearchRequest(
203
"dc=example,dc=com",
204
SearchScope.SUB,
205
"(objectClass=inetOrgPerson)",
206
"cn", "mail"
207
);
208
209
int pageSize = 10;
210
ASN1OctetString cookie = null;
211
212
do {
213
searchRequest.setControls(new PagedResultsRequestControl(pageSize, cookie));
214
SearchResult result = connection.search(searchRequest);
215
216
System.out.println("Page with " + result.getEntryCount() + " entries:");
217
for (SearchResultEntry entry : result.getSearchEntries()) {
218
System.out.println(" " + entry.getAttributeValue("cn"));
219
}
220
221
SimplePagedResultsControl responseControl =
222
SimplePagedResultsControl.get(result);
223
cookie = (responseControl != null) ? responseControl.getCookie() : null;
224
225
} while ((cookie != null) && (cookie.getValueLength() > 0));
226
227
} finally {
228
connection.close();
229
}
230
```
231
232
### Server-Side Sorting
233
234
```java
235
import com.unboundid.ldap.sdk.*;
236
import com.unboundid.ldap.sdk.controls.*;
237
238
LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);
239
240
try {
241
connection.bind("cn=admin,dc=example,dc=com", "password");
242
243
SearchRequest searchRequest = new SearchRequest(
244
"dc=example,dc=com",
245
SearchScope.SUB,
246
"(objectClass=inetOrgPerson)",
247
"cn", "sn", "mail", "department"
248
);
249
250
// Sort by department, then by surname
251
SortKey[] sortKeys = {
252
new SortKey("department"),
253
new SortKey("sn")
254
};
255
256
searchRequest.addControl(new ServerSideSortRequestControl(sortKeys));
257
258
SearchResult result = connection.search(searchRequest);
259
260
// Check if sorting was successful
261
ServerSideSortResponseControl sortResponse =
262
result.getResponseControl(ServerSideSortResponseControl.class);
263
264
if (sortResponse != null && sortResponse.getResultCode() == ResultCode.SUCCESS) {
265
System.out.println("Results sorted successfully");
266
}
267
268
// Results are now sorted by department, then surname
269
for (SearchResultEntry entry : result.getSearchEntries()) {
270
System.out.println(entry.getAttributeValue("department") +
271
" - " + entry.getAttributeValue("sn") +
272
", " + entry.getAttributeValue("cn"));
273
}
274
275
} finally {
276
connection.close();
277
}
278
```
279
280
### Password Modification
281
282
```java
283
import com.unboundid.ldap.sdk.*;
284
import com.unboundid.ldap.sdk.extensions.*;
285
286
LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);
287
288
try {
289
connection.bind("cn=admin,dc=example,dc=com", "password");
290
291
// Change password for specific user
292
PasswordModifyExtendedRequest passwordRequest = new PasswordModifyExtendedRequest(
293
"cn=john.doe,ou=people,dc=example,dc=com", // user identity
294
"oldPassword", // old password
295
"newSecurePassword123" // new password
296
);
297
298
PasswordModifyExtendedResult passwordResult =
299
(PasswordModifyExtendedResult) connection.processExtendedOperation(passwordRequest);
300
301
if (passwordResult.getResultCode() == ResultCode.SUCCESS) {
302
System.out.println("Password changed successfully");
303
} else {
304
System.err.println("Password change failed: " + passwordResult.getDiagnosticMessage());
305
}
306
307
// Generate new password (let server generate)
308
PasswordModifyExtendedRequest generateRequest = new PasswordModifyExtendedRequest(
309
"cn=jane.smith,ou=people,dc=example,dc=com",
310
"currentPassword",
311
null // null = let server generate new password
312
);
313
314
PasswordModifyExtendedResult generateResult =
315
(PasswordModifyExtendedResult) connection.processExtendedOperation(generateRequest);
316
317
if (generateResult.getResultCode() == ResultCode.SUCCESS) {
318
System.out.println("Generated password: " + generateResult.getGeneratedPassword());
319
}
320
321
} finally {
322
connection.close();
323
}
324
```
325
326
### Authorization Identity
327
328
```java
329
import com.unboundid.ldap.sdk.*;
330
import com.unboundid.ldap.sdk.extensions.*;
331
import com.unboundid.ldap.sdk.controls.*;
332
333
LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);
334
335
try {
336
connection.bind("cn=admin,dc=example,dc=com", "password");
337
338
// Determine current authorization identity
339
WhoAmIExtendedRequest whoAmIRequest = new WhoAmIExtendedRequest();
340
WhoAmIExtendedResult whoAmIResult =
341
(WhoAmIExtendedResult) connection.processExtendedOperation(whoAmIRequest);
342
343
if (whoAmIResult.getResultCode() == ResultCode.SUCCESS) {
344
System.out.println("Current identity: " + whoAmIResult.getAuthorizationID());
345
}
346
347
// Perform operation with proxied authorization
348
SearchRequest searchRequest = new SearchRequest(
349
"dc=example,dc=com",
350
SearchScope.ONE,
351
"(objectClass=*)",
352
"1.1" // no attributes, just check access
353
);
354
355
// Act as different user
356
searchRequest.addControl(new ProxiedAuthorizationV2RequestControl(
357
"dn:cn=readonly,ou=service,dc=example,dc=com"
358
));
359
360
// Request authorization identity in response
361
searchRequest.addControl(new AuthorizationIdentityRequestControl());
362
363
SearchResult result = connection.search(searchRequest);
364
365
// Check what identity was actually used
366
AuthorizationIdentityResponseControl authzResponse =
367
result.getResponseControl(AuthorizationIdentityResponseControl.class);
368
369
if (authzResponse != null) {
370
System.out.println("Operation performed as: " + authzResponse.getAuthorizationID());
371
}
372
373
} finally {
374
connection.close();
375
}
376
```
377
378
### Transaction Operations
379
380
```java
381
import com.unboundid.ldap.sdk.*;
382
import com.unboundid.ldap.sdk.extensions.*;
383
import com.unboundid.ldap.sdk.controls.*;
384
385
LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);
386
387
try {
388
connection.bind("cn=admin,dc=example,dc=com", "password");
389
390
// Start transaction
391
StartTransactionExtendedRequest startTxnRequest = new StartTransactionExtendedRequest();
392
StartTransactionExtendedResult startTxnResult =
393
(StartTransactionExtendedResult) connection.processExtendedOperation(startTxnRequest);
394
395
if (startTxnResult.getResultCode() != ResultCode.SUCCESS) {
396
throw new LDAPException(startTxnResult.getResultCode(), "Failed to start transaction");
397
}
398
399
ASN1OctetString transactionID = startTxnResult.getTransactionID();
400
System.out.println("Transaction started");
401
402
try {
403
// Create transaction control
404
TransactionSpecificationRequestControl txnControl =
405
new TransactionSpecificationRequestControl(transactionID);
406
407
// Perform operations within transaction
408
AddRequest addRequest1 = new AddRequest(
409
"cn=user1,ou=people,dc=example,dc=com",
410
new Attribute("objectClass", "inetOrgPerson"),
411
new Attribute("cn", "user1"),
412
new Attribute("sn", "User")
413
);
414
addRequest1.addControl(txnControl);
415
416
AddRequest addRequest2 = new AddRequest(
417
"cn=user2,ou=people,dc=example,dc=com",
418
new Attribute("objectClass", "inetOrgPerson"),
419
new Attribute("cn", "user2"),
420
new Attribute("sn", "User")
421
);
422
addRequest2.addControl(txnControl);
423
424
// Execute operations (won't be committed until transaction ends)
425
connection.add(addRequest1);
426
connection.add(addRequest2);
427
428
System.out.println("Operations queued in transaction");
429
430
// Commit transaction
431
EndTransactionExtendedRequest commitRequest =
432
new EndTransactionExtendedRequest(transactionID, true);
433
434
ExtendedResult commitResult = connection.processExtendedOperation(commitRequest);
435
436
if (commitResult.getResultCode() == ResultCode.SUCCESS) {
437
System.out.println("Transaction committed successfully");
438
} else {
439
System.err.println("Transaction commit failed: " + commitResult.getDiagnosticMessage());
440
}
441
442
} catch (LDAPException e) {
443
// Rollback transaction on error
444
System.err.println("Error in transaction: " + e.getMessage());
445
446
EndTransactionExtendedRequest rollbackRequest =
447
new EndTransactionExtendedRequest(transactionID, false);
448
449
connection.processExtendedOperation(rollbackRequest);
450
System.out.println("Transaction rolled back");
451
}
452
453
} finally {
454
connection.close();
455
}
456
```
457
458
### Start TLS
459
460
```java
461
import com.unboundid.ldap.sdk.*;
462
import com.unboundid.ldap.sdk.extensions.*;
463
import com.unboundid.util.ssl.*;
464
465
// Start with plain connection
466
LDAPConnection connection = new LDAPConnection("ldap.example.com", 389);
467
468
try {
469
// Create SSL context
470
SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
471
472
// Start TLS to upgrade connection to SSL
473
StartTLSExtendedRequest startTLSRequest =
474
new StartTLSExtendedRequest(sslUtil.createSSLContext());
475
476
ExtendedResult startTLSResult = connection.processExtendedOperation(startTLSRequest);
477
478
if (startTLSResult.getResultCode() == ResultCode.SUCCESS) {
479
System.out.println("TLS started successfully");
480
System.out.println("Connection is now encrypted");
481
482
// Now authenticate over the encrypted connection
483
connection.bind("cn=admin,dc=example,dc=com", "password");
484
485
// Perform operations over encrypted connection
486
SearchResult result = connection.search("dc=example,dc=com", SearchScope.BASE, "(objectClass=*)");
487
System.out.println("Secure search completed");
488
489
} else {
490
System.err.println("Start TLS failed: " + startTLSResult.getDiagnosticMessage());
491
}
492
493
} catch (Exception e) {
494
System.err.println("TLS operation failed: " + e.getMessage());
495
} finally {
496
connection.close();
497
}
498
```