/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2012 ForgeRock AS
*
*/
package org.forgerock.opendj.examples;
import java.io.IOException;
import java.util.Collection;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.DecodeOptions;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.ErrorResultIOException;
import org.forgerock.opendj.ldap.Filter;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.RootDSE;
import org.forgerock.opendj.ldap.SearchResultReferenceIOException;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.controls.AssertionRequestControl;
import org.forgerock.opendj.ldap.controls.AuthorizationIdentityRequestControl;
import org.forgerock.opendj.ldap.controls.AuthorizationIdentityResponseControl;
import org.forgerock.opendj.ldap.controls.EntryChangeNotificationResponseControl;
import org.forgerock.opendj.ldap.controls.GetEffectiveRightsRequestControl;
import org.forgerock.opendj.ldap.controls.PersistentSearchChangeType;
import org.forgerock.opendj.ldap.controls.PersistentSearchRequestControl;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldif.ConnectionEntryReader;
import org.forgerock.opendj.ldif.LDIFEntryWriter;
/**
* This command-line client demonstrates use of LDAP controls. The client takes
* as arguments the host and port for the directory server, and expects to find
* the entries and access control instructions as defined in Example.ldif.
*
* This client connects as cn=Directory Manager with password
* password. Not a best practice; in real code use application
* specific credentials to connect, and ensure that your application has access
* to use the LDAP controls needed.
*/
public final class Controls {
/**
* Connect to the server, and then try to use some LDAP controls.
*
* @param args
* The command line arguments: host, port
*/
public static void main(final String[] args) {
if (args.length != 2) {
System.err.println("Usage: host port");
System.err.println("For example: localhost 1389");
System.exit(1);
}
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port);
Connection connection = null;
try {
connection = factory.getConnection();
checkSupportedControls(connection);
final String user = "cn=Directory Manager";
final char[] password = "password".toCharArray();
connection.bind(user, password);
// Uncomment one of the methods:
//useAssertionControl(connection);
useAuthorizationIdentityRequestControl(connection);
// For the EntryChangeNotificationResponseControl see
// usePersistentSearchRequestControl()
//useGetEffectiveRightsRequestControl(connection);
//usePersistentSearchRequestControl(connection);
// TODO: The rest of the supported controls
} catch (final ErrorResultException e) {
System.err.println(e.getMessage());
System.exit(e.getResult().getResultCode().intValue());
return;
} finally {
if (connection != null) {
connection.close();
}
}
}
/**
* Use the LDAP assertion control to perform a trivial modification.
*
* @param connection
* Active connection to LDAP server containing Example.ldif content.
* @throws ErrorResultException
* Operation failed.
*/
static void useAssertionControl(Connection connection) throws ErrorResultException {
if (isSupported(AssertionRequestControl.OID)) {
// Modify Babs Jensen's description if her entry does not have
// a description, yet.
final String dn = "uid=bjensen,ou=People,dc=example,dc=com";
ModifyRequest request = Requests.newModifyRequest(dn);
request.addControl(AssertionRequestControl.newControl(true, Filter
.valueOf("!(description=*)")));
request.addModification(ModificationType.ADD, "description",
"Created with the help of the LDAP assertion control");
connection.modify(request);
LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
try {
writer.writeEntry(connection.readEntry(dn, "description"));
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
}
/**
* Use the LDAP Authorization Identity Controls to get the authorization ID.
*
* @param connection
* Active connection to LDAP server containing Example.ldif content.
* @throws ErrorResultException
* Operation failed.
*/
static void useAuthorizationIdentityRequestControl(Connection connection) throws ErrorResultException {
if (isSupported(AuthorizationIdentityRequestControl.OID)) {
final String name = "uid=bjensen,ou=People,dc=example,dc=com";
final char[] password = "hifalutin".toCharArray();
System.out.println("Binding as " + name);
BindRequest request = Requests.newSimpleBindRequest(name, password);
request.addControl(AuthorizationIdentityRequestControl.newControl(true));
final BindResult result = connection.bind(request);
try {
final AuthorizationIdentityResponseControl control =
result.getControl(AuthorizationIdentityResponseControl.DECODER,
new DecodeOptions());
System.out.println("Authorization ID returned: "
+ control.getAuthorizationID());
} catch (final DecodeException e) {
e.printStackTrace();
}
}
}
/**
* Use the GetEffectiveRights Request Control to determine what sort of
* access a user has to particular attributes on an entry.
*
* @param connection
* Active connection to LDAP server containing Example.ldif content.
* @throws ErrorResultException
* Operation failed.
*/
static void useGetEffectiveRightsRequestControl(Connection connection)
throws ErrorResultException {
if (isSupported(GetEffectiveRightsRequestControl.OID)) {
final String authDN = "uid=kvaughan,ou=People,dc=example,dc=com";
SearchRequest request =
Requests.newSearchRequest(
"dc=example,dc=com", SearchScope.WHOLE_SUBTREE,
"(uid=bjensen)", "cn", "aclRights", "aclRightsInfo");
request.addControl(
GetEffectiveRightsRequestControl.newControl(true, authDN, "cn"));
final ConnectionEntryReader reader = connection.search(request);
final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
try {
while (reader.hasNext()) {
if (!reader.isReference()) {
final SearchResultEntry entry = reader.readEntry();
writer.writeEntry(entry);
}
}
writer.close();
} catch (final ErrorResultIOException e) {
e.printStackTrace();
} catch (final SearchResultReferenceIOException e) {
e.printStackTrace();
} catch (final IOException e) {
e.printStackTrace();
}
}
}
/**
* Use the LDAP PersistentSearchRequestControl to set up a persistent
* search. Also use the Entry Change Notification Response Control to get
* details about why an entry was returned for a persistent search.
*
* After you set this up, use another application to make changes to user
* entries under dc=example,dc=com.
*
* @param connection
* Active connection to LDAP server containing Example.ldif content.
* @throws ErrorResultException
* Operation failed.
*/
static void usePersistentSearchRequestControl(Connection connection) throws ErrorResultException {
if (isSupported(PersistentSearchRequestControl.OID)) {
SearchRequest request =
Requests.newSearchRequest(
"dc=example,dc=com",
SearchScope.WHOLE_SUBTREE,
"(objectclass=inetOrgPerson)",
"cn");
request.addControl(PersistentSearchRequestControl.newControl(
true, true, true, // isCritical, changesOnly, returnECs
PersistentSearchChangeType.ADD,
PersistentSearchChangeType.DELETE,
PersistentSearchChangeType.MODIFY,
PersistentSearchChangeType.MODIFY_DN));
final ConnectionEntryReader reader = connection.search(request);
try {
while (reader.hasNext()) {
if (!reader.isReference()) {
final SearchResultEntry entry = reader.readEntry();
System.out.println("Entry changed: " + entry.getName().toString());
final EntryChangeNotificationResponseControl control =
entry.getControl(
EntryChangeNotificationResponseControl.DECODER,
new DecodeOptions());
final PersistentSearchChangeType type = control.getChangeType();
System.out.println("Change type: " + type.toString());
if (type.equals(PersistentSearchChangeType.MODIFY_DN)) {
System.out.println("Previous DN: "
+ control.getPreviousName().toString());
}
System.out.println("Change number: " + control.getChangeNumber());
System.out.println(); // Add a blank line.
}
}
} catch (final DecodeException e) {
e.printStackTrace();
} catch (final ErrorResultIOException e) {
e.printStackTrace();
} catch (final SearchResultReferenceIOException e) {
e.printStackTrace();
}
}
}
/**
* Controls supported by the LDAP server.
*/
private static Collection controls;
/**
* Populate the list of supported LDAP control OIDs.
*
* @param connection
* Active connection to the LDAP server.
* @throws ErrorResultException
* Failed to get list of controls.
*/
static void checkSupportedControls(Connection connection) throws ErrorResultException {
controls = RootDSE.readRootDSE(connection).getSupportedControls();
}
/**
* Check whether a control is supported. Call {@code checkSupportedControls}
* first.
*
* @param control
* Check support for this control, provided by OID.
* @return True if the control is supported.
*/
static boolean isSupported(final String control) {
if (controls != null && !controls.isEmpty()) {
return controls.contains(control);
}
return false;
}
/**
* Constructor not used.
*/
private Controls() {
// Not used.
}
}