opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java
@@ -20,7 +20,7 @@ * * CDDL HEADER END * * Copyright 2012 ForgeRock AS * Copyright 2012-2013 ForgeRock AS * */ @@ -168,6 +168,7 @@ * Operation failed. */ static void useAssertionControl(Connection connection) throws ErrorResultException { // --- JCite assertion --- if (isSupported(AssertionRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; @@ -191,6 +192,7 @@ } else { System.err.println("AssertionRequestControl not supported."); } // --- JCite assertion --- } /** @@ -204,6 +206,7 @@ * Operation failed. */ static void useAuthorizationIdentityRequestControl(Connection connection) throws ErrorResultException { // --- JCite authzid --- if (isSupported(AuthorizationIdentityRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); @@ -227,6 +230,7 @@ } else { System.err.println("AuthorizationIdentityRequestControl not supported."); } // --- JCite authzid --- } /** @@ -241,6 +245,7 @@ * Operation failed. */ static void useGetEffectiveRightsRequestControl(Connection connection) throws ErrorResultException { // --- JCite effective rights --- if (isSupported(GetEffectiveRightsRequestControl.OID)) { final String authDN = "uid=kvaughan,ou=People,dc=example,dc=com"; @@ -265,7 +270,8 @@ System.err.println(e.getMessage()); System.exit(e.getCause().getResult().getResultCode().intValue()); } catch (final SearchResultReferenceIOException e) { System.err.println("Got search reference(s): " + e.getReference().getURIs().toString()); System.err.println("Got search reference(s): " + e.getReference() .getURIs().toString()); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); @@ -273,6 +279,7 @@ } else { System.err.println("GetEffectiveRightsRequestControl not supported."); } // --- JCite effective rights --- } /** @@ -287,6 +294,7 @@ * Operation failed. */ static void useManageDsaITRequestControl(Connection connection) throws ErrorResultException { // --- JCite manage DsaIT --- if (isSupported(ManageDsaITRequestControl.OID)) { final String dn = "dc=ref,dc=com"; @@ -312,7 +320,8 @@ System.err.println(e.getMessage()); System.exit(e.getCause().getResult().getResultCode().intValue()); } catch (final SearchResultReferenceIOException e) { System.err.println("Got search reference(s): " + e.getReference().getURIs().toString()); System.err.println("Got search reference(s): " + e.getReference() .getURIs().toString()); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); @@ -320,6 +329,7 @@ } else { System.err.println("ManageDsaITRequestControl not supported."); } // --- JCite manage DsaIT --- } /** @@ -334,6 +344,7 @@ * Operation failed. */ static void useMatchedValuesRequestControl(Connection connection) throws ErrorResultException { // --- JCite matched values --- if (isSupported(MatchedValuesRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final SearchRequest request = @@ -355,6 +366,7 @@ } else { System.err.println("MatchedValuesRequestControl not supported."); } // --- JCite matched values --- } /** @@ -368,6 +380,7 @@ * >Example.ldif</a> content. */ static void usePasswordExpiredResponseControl(Connection connection) { // --- JCite password expired --- if (isSupported(PasswordExpiredResponseControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); @@ -391,6 +404,7 @@ } else { System.err.println("PasswordExpiredResponseControl not supported."); } // --- JCite password expired --- } /** @@ -407,6 +421,7 @@ * Operation failed. */ static void usePasswordExpiringResponseControl(Connection connection) throws ErrorResultException { // --- JCite password expiring --- if (isSupported(PasswordExpiringResponseControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); @@ -427,6 +442,7 @@ } else { System.err.println("PasswordExpiringResponseControl not supported"); } // --- JCite password expiring --- } /** @@ -441,6 +457,7 @@ * >Example.ldif</a> content. */ static void usePasswordPolicyRequestControl(Connection connection) { // --- JCite password policy --- if (isSupported(PasswordPolicyRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); @@ -480,6 +497,7 @@ } else { System.err.println("PasswordPolicyRequestControl not supported"); } // --- JCite password policy --- } /** @@ -494,6 +512,7 @@ * Operation failed. */ static void usePermissiveModifyRequestControl(Connection connection) throws ErrorResultException { // --- JCite permissive modify --- if (isSupported(PermissiveModifyRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; @@ -508,6 +527,7 @@ } else { System.err.println("PermissiveModifyRequestControl not supported"); } // --- JCite permissive modify --- } /** @@ -526,6 +546,7 @@ * Operation failed. */ static void usePersistentSearchRequestControl(Connection connection) throws ErrorResultException { // --- JCite psearch --- if (isSupported(PersistentSearchRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest( @@ -568,11 +589,13 @@ System.err.println(e.getMessage()); System.exit(e.getCause().getResult().getResultCode().intValue()); } catch (final SearchResultReferenceIOException e) { System.err.println("Got search reference(s): " + e.getReference().getURIs().toString()); System.err.println("Got search reference(s): " + e.getReference() .getURIs().toString()); } } else { System.err.println("PersistentSearchRequestControl not supported."); } // --- JCite psearch --- } @@ -587,6 +610,7 @@ * Operation failed. */ static void usePostReadRequestControl(Connection connection) throws ErrorResultException { // --- JCite post read --- if (isSupported(PostReadRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; @@ -616,6 +640,7 @@ } else { System.err.println("PostReadRequestControl not supported"); } // --- JCite post read --- } /** @@ -629,6 +654,7 @@ * Operation failed. */ static void usePreReadRequestControl(Connection connection) throws ErrorResultException { // --- JCite pre read --- if (isSupported(PreReadRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; @@ -658,6 +684,7 @@ } else { System.err.println("PreReadRequestControl not supported"); } // --- JCite pre read --- } /** @@ -671,6 +698,7 @@ * Operation failed. */ static void useProxiedAuthV2RequestControl(Connection connection) throws ErrorResultException { // --- JCite proxied authzv2 --- if (isSupported(ProxiedAuthV2RequestControl.OID)) { final String bindDN = "cn=My App,ou=Apps,dc=example,dc=com"; final String targetDn = "uid=bjensen,ou=People,dc=example,dc=com"; @@ -697,6 +725,7 @@ } else { System.err.println("ProxiedAuthV2RequestControl not supported"); } // --- JCite proxied authzv2 --- } /** @@ -709,7 +738,9 @@ * @throws ErrorResultException * Operation failed. */ static void useServerSideSortRequestControl(Connection connection) throws ErrorResultException { // --- JCite server-side sort --- static void useServerSideSortRequestControl(Connection connection) throws ErrorResultException { if (isSupported(ServerSideSortRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest("ou=People,dc=example,dc=com", @@ -769,6 +800,7 @@ return false; } } // --- JCite server-side sort --- /** * Use the simple paged results mechanism. @@ -781,6 +813,7 @@ * Operation failed. */ static void useSimplePagedResultsControl(Connection connection) throws ErrorResultException { // --- JCite simple paged results --- if (isSupported(SimplePagedResultsControl.OID)) { ByteString cookie = ByteString.empty(); SearchRequest request; @@ -813,6 +846,7 @@ } else { System.err.println("SimplePagedResultsControl not supported"); } // --- JCite simple paged results --- } /** @@ -826,6 +860,7 @@ * Operation failed. */ static void useSubentriesRequestControl(Connection connection) throws ErrorResultException { // --- JCite subentries --- if (isSupported(SubentriesRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest("dc=example,dc=com", @@ -848,7 +883,8 @@ System.err.println(e.getMessage()); System.exit(e.getCause().getResult().getResultCode().intValue()); } catch (final SearchResultReferenceIOException e) { System.err.println("Got search reference(s): " + e.getReference().getURIs().toString()); System.err.println("Got search reference(s): " + e.getReference() .getURIs().toString()); } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); @@ -856,6 +892,7 @@ } else { System.err.println("SubentriesRequestControl not supported"); } // --- JCite subentries --- } /** @@ -869,6 +906,7 @@ * Operation failed. */ static void useSubtreeDeleteRequestControl(Connection connection) throws ErrorResultException { // --- JCite tree delete --- if (isSupported(SubtreeDeleteRequestControl.OID)) { final String dn = "ou=Apps,dc=example,dc=com"; @@ -886,6 +924,7 @@ } else { System.err.println("SubtreeDeleteRequestControl not supported"); } // --- JCite tree delete --- } /** @@ -904,6 +943,7 @@ * Operation failed. */ static void useVirtualListViewRequestControl(Connection connection) throws ErrorResultException { // --- JCite vlv --- if (isSupported(VirtualListViewRequestControl.OID)) { ByteString contextID = ByteString.empty(); @@ -945,8 +985,10 @@ } else { System.err.println("VirtualListViewRequestControl not supported"); } // --- JCite vlv --- } // --- JCite check support --- /** * Controls supported by the LDAP server. */ @@ -960,7 +1002,8 @@ * @throws ErrorResultException * Failed to get list of controls. */ static void checkSupportedControls(Connection connection) throws ErrorResultException { static void checkSupportedControls(Connection connection) throws ErrorResultException { controls = RootDSE.readRootDSE(connection).getSupportedControls(); } @@ -978,6 +1021,7 @@ } return false; } // --- JCite check support --- /** * Constructor not used. opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ExtendedOperations.java
@@ -107,6 +107,7 @@ * Operation failed. */ static void usePasswordModifyExtendedRequest(Connection connection) throws ErrorResultException { // --- JCite password modify --- if (isSupported(PasswordModifyExtendedRequest.OID)) { final String userIdentity = "u:scarter"; final char[] oldPassword = "sprain".toCharArray(); @@ -128,6 +129,7 @@ } else { System.err.println("PasswordModifyExtendedRequest not supported"); } // --- JCite password modify --- } /** @@ -140,6 +142,7 @@ * Operation failed. */ static void useWhoAmIExtendedRequest(Connection connection) throws ErrorResultException { // --- JCite who am I --- if (isSupported(WhoAmIExtendedRequest.OID)) { final String name = "uid=bjensen,ou=People,dc=example,dc=com"; @@ -160,8 +163,10 @@ } else { System.err.println("WhoAmIExtendedRequest not supported"); } // --- JCite who am I --- } // --- JCite check support --- /** * Controls supported by the LDAP server. */ @@ -175,8 +180,10 @@ * @throws ErrorResultException * Failed to get list of extended operations. */ static void checkSupportedExtendedOperations(Connection connection) throws ErrorResultException { extendedOperations = RootDSE.readRootDSE(connection).getSupportedExtendedOperations(); static void checkSupportedExtendedOperations(Connection connection) throws ErrorResultException { extendedOperations = RootDSE.readRootDSE(connection) .getSupportedExtendedOperations(); } /** @@ -193,6 +200,7 @@ } return false; } // --- JCite check support --- /** * Constructor not used. opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/GetADChangeNotifications.java
@@ -84,7 +84,7 @@ final String baseDN = args[4]; // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa772153(v=vs.85).aspx /* --- JCite --- */ // --- JCite --- final SearchScope scope = SearchScope.WHOLE_SUBTREE; final String filter = "(objectclass=*)"; final String[] attributes = { @@ -128,7 +128,7 @@ + ref.getURIs().toString()); } } } /* --- JCite --- */ catch (final ErrorResultException e) { } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); } catch (final ErrorResultIOException e) { @@ -142,6 +142,7 @@ connection.close(); } } // --- JCite --- } private GetADChangeNotifications() { opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/GetInfo.java
@@ -21,7 +21,7 @@ * CDDL HEADER END * * * Copyright 2012 ForgeRock AS * Copyright 2012-2013 ForgeRock AS */ package org.forgerock.opendj.examples; @@ -62,6 +62,7 @@ * Authenticate over LDAP. */ private static void connect() { // --- JCite --- final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; @@ -103,6 +104,7 @@ connection.close(); } } // --- JCite --- } private static void giveUp() { opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Modify.java
@@ -22,7 +22,7 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2011-2012 ForgeRock AS * Portions copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.examples; @@ -86,6 +86,7 @@ } else { ldif = System.in; } // --- JCite --- final LDIFChangeRecordReader reader = new LDIFChangeRecordReader(ldif); // Connect and bind to the server. @@ -124,6 +125,7 @@ // Ignore. } } // --- JCite --- } private Modify() { opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ParseAttributes.java
@@ -20,7 +20,7 @@ * * CDDL HEADER END * * Copyright 2012 ForgeRock AS * Copyright 2012-2013 ForgeRock AS * */ @@ -69,6 +69,7 @@ final String host = args[0]; final int port = Integer.parseInt(args[1]); // --- JCite --- final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { @@ -130,6 +131,7 @@ connection.close(); } } // --- JCite --- } /** opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Proxy.java
@@ -445,6 +445,7 @@ final String proxyPassword = args[3]; // Create load balancer. // --- JCite pools --- final List<ConnectionFactory> factories = new LinkedList<ConnectionFactory>(); final List<ConnectionFactory> bindFactories = new LinkedList<ConnectionFactory>(); for (int i = 4; i < args.length; i += 2) { @@ -453,25 +454,33 @@ factories.add(Connections.newFixedConnectionPool(Connections .newAuthenticatedConnectionFactory(Connections .newHeartBeatConnectionFactory(new LDAPConnectionFactory(remoteAddress, remotePort)), Requests.newSimpleBindRequest(proxyDN, .newHeartBeatConnectionFactory(new LDAPConnectionFactory( remoteAddress, remotePort)), Requests.newSimpleBindRequest(proxyDN, proxyPassword.toCharArray())), Integer.MAX_VALUE)); bindFactories.add(Connections.newFixedConnectionPool(Connections .newHeartBeatConnectionFactory(new LDAPConnectionFactory(remoteAddress, remotePort)), Integer.MAX_VALUE)); } // --- JCite pools --- // --- JCite load balancer --- final RoundRobinLoadBalancingAlgorithm algorithm = new RoundRobinLoadBalancingAlgorithm(factories); final RoundRobinLoadBalancingAlgorithm bindAlgorithm = new RoundRobinLoadBalancingAlgorithm(bindFactories); final ConnectionFactory factory = Connections.newLoadBalancer(algorithm); final ConnectionFactory bindFactory = Connections.newLoadBalancer(bindAlgorithm); // --- JCite load balancer --- // --- JCite backend --- // Create a server connection adapter. final ProxyBackend backend = new ProxyBackend(factory, bindFactory); final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = Connections.newServerConnectionFactory(backend); // --- JCite backend --- // --- JCite listener --- // Create listener. final LDAPListenerOptions options = new LDAPListenerOptions().setBacklog(4096); LDAPListener listener = null; @@ -487,6 +496,7 @@ listener.close(); } } // --- JCite listener --- } private Proxy() { opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SASLAuth.java
@@ -21,7 +21,7 @@ * CDDL HEADER END * * * Copyright 2011-2012 ForgeRock AS * Copyright 2011-2013 ForgeRock AS */ /** @@ -85,6 +85,7 @@ parseArgs(args); Connection connection = null; // --- JCite --- try { final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port, getTrustAllOptions()); @@ -106,6 +107,7 @@ connection.close(); } } // --- JCite --- } /** opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Search.java
@@ -22,7 +22,7 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2011-2012 ForgeRock AS * Portions copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.examples; @@ -97,6 +97,7 @@ return; } // --- JCite --- // Create an LDIF writer which will write the search results to stdout. final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); @@ -114,13 +115,15 @@ while (reader.hasNext()) { if (!reader.isReference()) { final SearchResultEntry entry = reader.readEntry(); writer.writeComment("Search result entry: " + entry.getName().toString()); writer.writeComment("Search result entry: " + entry.getName().toString()); writer.writeEntry(entry); } else { final SearchResultReference ref = reader.readReference(); // Got a continuation reference. writer.writeComment("Search result reference: " + ref.getURIs().toString()); writer.writeComment("Search result reference: " + ref.getURIs().toString()); } } writer.flush(); @@ -141,6 +144,7 @@ connection.close(); } } // --- JCite --- } private Search() { opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SearchAsync.java
@@ -114,6 +114,7 @@ } // --- JCite search result handler --- private static final class SearchResultHandlerImpl implements SearchResultHandler { /** @@ -123,12 +124,15 @@ public synchronized boolean handleEntry(final SearchResultEntry entry) { try { if (entryCount < 10) { WRITER.writeComment("Search result entry: " + entry.getName().toString()); WRITER.writeComment("Search result entry: " + entry.getName().toString()); WRITER.writeEntry(entry); ++entryCount; } else { // Cancel the search. CancelExtendedRequest request = Requests.newCancelExtendedRequest(requestID); connection.extendedRequestAsync(request, null, new CancelResultHandlerImpl()); CancelExtendedRequest request = Requests.newCancelExtendedRequest(requestID); connection.extendedRequestAsync(request, null, new CancelResultHandlerImpl()); return false; } } catch (final IOException e) { @@ -154,9 +158,11 @@ * {@inheritDoc} */ @Override public synchronized boolean handleReference(final SearchResultReference reference) { public synchronized boolean handleReference( final SearchResultReference reference) { try { WRITER.writeComment("Search result reference: " + reference.getURIs().toString()); WRITER.writeComment("Search result reference: " + reference.getURIs().toString()); } catch (final IOException e) { System.err.println(e.getMessage()); resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue(); @@ -176,10 +182,13 @@ } } // --- JCite search result handler --- // --- JCite decl1 --- private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1); private static final CountDownLatch CANCEL_LATCH = new CountDownLatch(1); private static final LDIFEntryWriter WRITER = new LDIFEntryWriter(System.out); // --- JCite decl1 --- private static String userName; private static String password; private static String baseDN; @@ -189,10 +198,14 @@ private static Connection connection = null; private static int resultCode = 0; // --- JCite decl2 --- static int requestID; static int entryCount = 0; // --- JCite decl2 --- private static final class CancelResultHandlerImpl implements ResultHandler<ExtendedResult> { // --- JCite cancel result handler --- private static final class CancelResultHandlerImpl implements ResultHandler<ExtendedResult> { @Override public void handleErrorResult(final ErrorResultException error) { @@ -208,6 +221,7 @@ } } // --- JCite cancel result handler --- /** * Main method. opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SearchBind.java
@@ -20,7 +20,7 @@ * * CDDL HEADER END * * Copyright 2012 ForgeRock AS * Copyright 2012-2013 ForgeRock AS * */ @@ -65,6 +65,7 @@ int port = Integer.parseInt(args[1]); String baseDN = args[2]; // --- JCite --- // Prompt for mail and password. Console c = System.console(); if (c == null) { @@ -97,6 +98,7 @@ connection.close(); } } // --- JCite --- } /** opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ShortLife.java
@@ -20,7 +20,7 @@ * * CDDL HEADER END * * Copyright 2012 ForgeRock AS * Copyright 2012-2013 ForgeRock AS * */ @@ -81,6 +81,7 @@ String adminDN = "uid=kvaughan,ou=people,dc=example,dc=com"; char[] adminPwd = "bribery".toCharArray(); // --- JCite add --- // An entry to add to the directory String entryDN = "cn=Bob,ou=People,dc=example,dc=com"; Entry entry = new LinkedHashMapEntry(entryDN) @@ -104,7 +105,9 @@ writeToConsole(writer, entry); connection.add(entry); System.out.println("...done."); // --- JCite add --- // --- JCite modify --- System.out.println("Updating mail address, adding description..."); Entry old = TreeMapEntry.deepCopyOfEntry(entry); entry = entry.replaceAttribute("mail", "spammer@example.com") @@ -113,18 +116,23 @@ ModifyRequest request = Entries.diffEntries(old, entry); connection.modify(request); System.out.println("...done."); // --- JCite modify --- // --- JCite rename --- System.out.println("Renaming the entry..."); String newDN = "cn=Ted,ou=People,dc=example,dc=com"; entry = entry.setName(newDN); writeToConsole(writer, entry); connection.modifyDN(entryDN, "cn=Ted"); System.out.println("...done."); // --- JCite rename --- // --- JCite delete --- System.out.println("Deleting the entry..."); writeToConsole(writer, entry); connection.delete(newDN); System.out.println("...done."); // --- JCite delete --- } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SimpleAuth.java
@@ -21,7 +21,7 @@ * CDDL HEADER END * * * Copyright 2011-2012 ForgeRock AS * Copyright 2011-2013 ForgeRock AS */ package org.forgerock.opendj.examples; @@ -73,6 +73,7 @@ } } // --- JCite basic auth --- /** * Authenticate over LDAP. */ @@ -94,7 +95,9 @@ } } } // --- JCite basic auth --- // --- JCite trust all --- /** * For StartTLS and SSL the connection factory needs SSL context options. In * the general case, a trust manager in the SSL context serves to check @@ -108,12 +111,15 @@ private static LDAPOptions getTrustAllOptions() throws GeneralSecurityException { LDAPOptions lo = new LDAPOptions(); SSLContext sslContext = new SSLContextBuilder().setTrustManager(TrustManagers.trustAll()).getSSLContext(); new SSLContextBuilder().setTrustManager(TrustManagers.trustAll()) .getSSLContext(); lo.setSSLContext(sslContext); lo.setUseStartTLS(useStartTLS); return lo; } // --- JCite trust all --- // --- JCite trust all connect --- /** * Perform authentication over a secure connection, trusting all server * certificates. @@ -140,6 +146,7 @@ } } } // --- JCite trust all connect --- /** * Authenticate using StartTLS. opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/UpdateGroup.java
@@ -20,7 +20,7 @@ * * CDDL HEADER END * * Copyright 2012 ForgeRock AS * Copyright 2012-2013 ForgeRock AS * */ @@ -99,6 +99,7 @@ final char[] password = "password".toCharArray(); connection.bind(user, password); // --- JCite permissive --- if (controls.contains(PermissiveModifyRequestControl.OID)) { final ModifyRequest request = Requests.newModifyRequest(groupDN) @@ -107,7 +108,9 @@ connection.modify(request); } else { // --- JCite permissive --- // --- JCite without permissive --- System.out.println("Checking whether the entry with DN " + memberDN + " belongs to the group with DN " + groupDN + "..."); @@ -136,6 +139,7 @@ connection.modify(delMember); } } // --- JCite without permissive --- } opendj3/src/main/docbkx/dev-guide/chap-authenticating.xml
@@ -20,7 +20,7 @@ ! ! CCPL HEADER END ! ! Copyright 2011-2012 ForgeRock AS ! Copyright 2011-2013 ForgeRock AS ! --> <chapter xml:id='chap-authenticating' @@ -69,33 +69,8 @@ the directory determines authorization for operations on the connection based on the users identity.</para> <programlisting language="java"> /** * Authenticate over LDAP. */ private static void connect() { final LDAPConnectionFactory factory = new LDAPConnectionFactory( host, port); Connection connection = null; try { connection = factory.getConnection(); connection.bind(bindDN, bindPassword.toCharArray()); System.out.println("Authenticated as " + bindDN + "."); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) connection.close(); } }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SimpleAuth:--- JCite basic auth ---]</programlisting> <para>If the password values do not match, a directory might nevertheless authenticate the client application. The LDAP specifications say that in this @@ -133,19 +108,10 @@ set up a trust manager that trusts all certificates.</para> <para>The following example is an excerpt from the OpenDJ LDAP SDK example, <filename>org.forgerock.opendj.examples.SimpleAuth.java</filename>.</para> <filename>SimpleAuth.java</filename>.</para> <programlisting language="java"> private static LDAPOptions getTrustAllOptions() throws GeneralSecurityException { LDAPOptions lo = new LDAPOptions(); SSLContext sslContext = new SSLContextBuilder() .setTrustManager(TrustManagers.trustAll()).getSSLContext(); lo.setSSLContext(sslContext); lo.setUseStartTLS(useStartTLS); return lo; }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SimpleAuth:--- JCite trust all ---]</programlisting> <para>A more secure and extensive SSL context would include a trust manager using a trust store and trust manager methods to check server certificates. @@ -158,40 +124,8 @@ to the LDAP connection factory, and that you handle the potential security exception involved in setting up the SSL context.</para> <programlisting language="java"> /** * Perform authentication over a secure connection, trusting all server * certificates. */ private static void trustAllConnect() { Connection connection = null; try { final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port, getTrustAllOptions()); connection = factory.getConnection(); connection.bind(bindDN, bindPassword.toCharArray()); System.out.println("Authenticated as " + bindDN + "."); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } catch (final GeneralSecurityException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue()); } finally { if (connection != null) connection.close(); } }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SimpleAuth:--- JCite trust all connect ---]</programlisting> <para>For a complete example in context, see <link xlink:href="http://opendj.forgerock.org/opendj-ldap-sdk-examples/xref/org/forgerock/opendj/examples/SimpleAuth.html" @@ -239,21 +173,11 @@ ID as the authorization ID that identifies the user who performs operations. The SASL PLAIN mechanism itself does not secure the connection, so the example uses StartTLS. The example is provided with the OpenDJ LDAP SDK examples in <filename>org.forgerock.opendj.examples.SASLAuth.java</filename>. The following excerpt shows the core of the bind process.</para> examples in <filename>SASLAuth.java</filename>. The following excerpt shows the core of the bind process.</para> <programlisting language="java"> try { final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port, getTrustAllOptions()); connection = factory.getConnection(); PlainSASLBindRequest request = Requests.newPlainSASLBindRequest(authcid, passwd.toCharArray()) .setAuthorizationID(authzid); connection.bind(request); System.out.println("Authenticated as " + authcid + "."); }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SASLAuth:--- JCite ---]</programlisting> <para>The implementation for <literal>getTrustAllOptions()</literal>, the same as in the example above, sets up Start TLS. When you run this example opendj3/src/main/docbkx/dev-guide/chap-controls.xml
@@ -110,40 +110,8 @@ <para>The following excerpt shows couple of methods to check whether the directory server supports a control.</para> <programlisting language="java"> /** * Controls supported by the LDAP server. */ private static Collection<String> 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; } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite check support ---]</programlisting> </section> <section xml:id="use-assertion-request-control"> @@ -162,28 +130,8 @@ normally. The following excerpt shows, for example, how you might check that no description exists on the entry before adding your description.</para> <programlisting language="java"> if (isSupported(AssertionRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(dn) .addControl(AssertionRequestControl.newControl( true, Filter.valueOf("!(description=*)"))) .addModification(ModificationType.ADD, "description", "Created using LDAP assertion control"); connection.modify(request); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(connection.readEntry(dn, "description")); writer.close(); } catch (final IOException e) { // The writer could not write to System.out. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite assertion ---]</programlisting> <para>OpenDJ directory server supports the LDAP assertion control:</para> @@ -206,28 +154,8 @@ authorization identity established when you bind to the directory server. The following excerpt shows simple use of the controls.</para> <programlisting language="java"> if (isSupported(AuthorizationIdentityRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); System.out.println("Binding as " + dn); final BindRequest request = Requests.newSimpleBindRequest(dn, pwd) .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) { // Failed to decode the response control. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite authzid ---]</programlisting> <para>OpenDJ directory server supports the LDAP Authorization Identity Controls:</para> @@ -256,53 +184,8 @@ xlink:href="http://tools.ietf.org/html/draft-ietf-ldapext-psearch">persistent searches</link> for background information.</para> <programlisting language="java"> if (isSupported(PersistentSearchRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest( "dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(objectclass=inetOrgPerson)", "cn") .addControl(PersistentSearchRequestControl.newControl( true, true, true, // critical,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()); EntryChangeNotificationResponseControl control = entry.getControl( EntryChangeNotificationResponseControl.DECODER, new DecodeOptions()); 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) { // Failed to decode the response control. } catch (final ErrorResultIOException e) { // Request failed due to an IO problem. } catch (final SearchResultReferenceIOException e) { // Read a reference, rather than an entry. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite psearch ---]</programlisting> <para>OpenDJ directory server supports persistent searches and the entry change notification response control. When another application renames @@ -338,36 +221,8 @@ xlink:href="http://tools.ietf.org/html/draft-ietf-ldapext-acl-model">Access Control Model for LDAP</link> for background.</para> <programlisting language="java"> if (isSupported(GetEffectiveRightsRequestControl.OID)) { final String authDN = "uid=kvaughan,ou=People,dc=example,dc=com"; final SearchRequest request = Requests.newSearchRequest( "dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(uid=bjensen)", "cn", "aclRights", "aclRightsInfo") .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) { // Request failed due to an IO problem. } catch (final SearchResultReferenceIOException e) { // Read a reference, rather than an entry. } catch (final IOException e) { // The writer could not write to System.out. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite effective rights ---]</programlisting> <para>OpenDJ SDK currently implements the request control, but not the response control. The results are shown as values of the @@ -449,43 +304,14 @@ Use it when you want to read from or write to reference or special entry.</para> <programlisting language="java"> if (isSupported(ManageDsaITRequestControl.OID)) { final String dn = "dc=ref,dc=com"; final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { System.out.println("Referral without the ManageDsaIT control."); SearchRequest request = Requests.newSearchRequest(dn, SearchScope.SUBORDINATES, "(objectclass=*)", ""); final ConnectionEntryReader reader = connection.search(request); while (reader.hasNext()) { if (reader.isReference()) { final SearchResultReference ref = reader.readReference(); System.out.println("Reference: " + ref.getURIs().toString()); } } System.out.println("Referral with the ManageDsaIT control."); request.addControl(ManageDsaITRequestControl.newControl(true)); final SearchResultEntry entry = connection.searchSingleEntry(request); writer.writeEntry(entry); writer.close(); } catch (final ErrorResultIOException e) { // Request failed due to an IO problem. } catch (final SearchResultReferenceIOException e) { // Read a reference, rather than an entry. } catch (final IOException e) { // The writer could not write to System.out. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite manage DsaIT ---]</programlisting> <para>OpenDJ directory server supports the ManageDsaIT Request Control. To use the example entry create a new base DN, <literal>dc=ref,dc=com</literal> before you import the data:</para> <programlisting>Referral without the ManageDsaIT control. <programlisting language="none">Referral without the ManageDsaIT control. Reference: [ldap:///dc=example,dc=com??sub?] Referral with the ManageDsaIT control. dn: dc=references,dc=ref,dc=com</programlisting> @@ -512,26 +338,8 @@ <literal>Barbara Jensen</literal> and <literal>Babs Jensen</literal>. The following excerpt retrieves only the latter.</para> <programlisting language="java"> if (isSupported(MatchedValuesRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final SearchRequest request = Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, "(objectclass=*)", "cn") .addControl(MatchedValuesRequestControl.newControl( true, "(cn=Babs Jensen)")); final SearchResultEntry entry = connection.searchSingleEntry(request); System.out.println("Reading entry with matched values request."); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(entry); writer.close(); } catch (final IOException e) { // The writer could not write to System.out. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite matched values ---]</programlisting> <para>OpenDJ directory server supports the matched values request control.</para> @@ -560,28 +368,8 @@ because the password has expired. In order to see this, you must configure the directory to expire Barbara Jensen's password.</para> <programlisting language="java"> if (isSupported(PasswordExpiredResponseControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); try { connection.bind(dn, pwd); } catch (final ErrorResultException e) { final Result result = e.getResult(); try { final PasswordExpiredResponseControl control = result.getControl(PasswordExpiredResponseControl.DECODER, new DecodeOptions()); if (!(control == null) && control.hasValue()) { System.out.println("Password expired for " + dn); } } catch (final DecodeException de) { // Failed to decode the response control. } } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite password expired ---]</programlisting> <para>OpenDJ directory server supports the Password Expired Response Control. To obtain the following output from the excerpt, you can change the default @@ -592,7 +380,7 @@ ><citetitle>To Adjust the Default Password Policy</citetitle></link> for an example of how to adjust the maximum password age.</para> <programlisting <programlisting language="none" >Password expired for uid=bjensen,ou=People,dc=example,dc=com</programlisting> </section> @@ -613,25 +401,8 @@ Directories</citetitle></link>, warns your application during a bind that the password used will soon expire.</para> <programlisting language="java"> if (isSupported(PasswordExpiringResponseControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); final BindResult result = connection.bind(dn, pwd); try { final PasswordExpiringResponseControl control = result.getControl(PasswordExpiringResponseControl.DECODER, new DecodeOptions()); if (!(control == null) && control.hasValue()) { System.out.println("Password for " + dn + " expires in " + control.getSecondsUntilExpiration() + " seconds."); } } catch (final DecodeException de) { // Failed to decode the response control. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite password expiring ---]</programlisting> <para>OpenDJ directory server supports the Password Expiring Response Control. To obtain the following output from the excerpt, you can change the default @@ -644,7 +415,7 @@ for an example of how to adjust the maximum password age. Also set a short <literal>password-expiration-warning-interval</literal> value.</para> <programlisting>Password for uid=bjensen,ou=People,dc=example,dc=com <programlisting language="none">Password for uid=bjensen,ou=People,dc=example,dc=com expires in 237 seconds.</programlisting> </section> @@ -667,43 +438,8 @@ handle the response control. The directory server sends the response control on applicable operations to communicate warnings and errors.</para> <programlisting language="java"> if (isSupported(PasswordPolicyRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] pwd = "hifalutin".toCharArray(); try { final BindRequest request = Requests.newSimpleBindRequest(dn, pwd) .addControl(PasswordPolicyRequestControl.newControl(true)); final BindResult result = connection.bind(request); final PasswordPolicyResponseControl control = result.getControl(PasswordPolicyResponseControl.DECODER, new DecodeOptions()); if (!(control == null) && !(control.getWarningType() == null)) { System.out.println("Password policy warning " + control.getWarningType().toString() + ", value " + control.getWarningValue() + " for " + dn); } } catch (final ErrorResultException e) { final Result result = e.getResult(); try { final PasswordPolicyResponseControl control = result.getControl(PasswordPolicyResponseControl.DECODER, new DecodeOptions()); if (!(control == null)) { System.out.println("Password policy error " + control.getErrorType().toString() + " for " + dn); } } catch (final DecodeException de) { // Failed to decode the response control. } } catch (final DecodeException e) { // Failed to decode the response control. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite password policy ---]</programlisting> <para>OpenDJ directory server supports the Password Policy Controls. To obtain the output from the excerpt, you can change the default password policy @@ -717,11 +453,11 @@ <literal>password-expiration-warning-interval</literal> value.</para> <para>For a warning:</para> <programlisting>Password policy warning timeBeforeExpiration, value 237 for <programlisting language="none">Password policy warning timeBeforeExpiration, value 237 for uid=bjensen,ou=People,dc=example,dc=com</programlisting> <para>For an error:</para> <programlisting>Password policy error passwordExpired for <programlisting language="none">Password policy error passwordExpired for uid=bjensen,ou=People,dc=example,dc=com</programlisting> </section> @@ -741,25 +477,13 @@ tries to <literal>add</literal> an attribute that already exists, or to <literal>delete</literal> an attribute that does not exist.</para> <programlisting language="java"> if (isSupported(PermissiveModifyRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(dn) .addControl(PermissiveModifyRequestControl.newControl(true)) .addModification(ModificationType.ADD, "uid", "bjensen"); connection.modify(request); System.out.println("Permissive modify did not complain about " + "attempt to add uid: bjensen to " + dn + "."); } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite permissive modify ---]</programlisting> <para>OpenDJ directory server supports the Permissive Modify Request Control:</para> <programlisting>Permissive modify did not complain about attempt to add <programlisting language="none">Permissive modify did not complain about attempt to add uid: bjensen to uid=bjensen,ou=People,dc=example,dc=com.</programlisting> </section> @@ -796,33 +520,8 @@ describes the post-read controls that let your application get the content of an entry immediately after modifications are applied.</para> <programlisting language="java"> if (isSupported(PostReadRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(dn) .addControl(PostReadRequestControl.newControl(true, "description")) .addModification(ModificationType.REPLACE, "description", "Using the PostReadRequestControl"); final Result result = connection.modify(request); try { final PostReadResponseControl control = result.getControl(PostReadResponseControl.DECODER, new DecodeOptions()); final Entry entry = control.getEntry(); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); writer.writeEntry(entry); writer.close(); } catch (final DecodeException e) { // Failed to decode the response control. } catch (final IOException e) { // The writer could not write to System.out. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite post read ---]</programlisting> <para>OpenDJ directory server supports these controls:</para> @@ -845,33 +544,8 @@ describes the pre-read controls that let your application get the content of an entry immediately before modifications are applied.</para> <programlisting language="java"> if (isSupported(PreReadRequestControl.OID)) { final String dn = "uid=bjensen,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(dn) .addControl(PreReadRequestControl.newControl(true, "mail")) .addModification( ModificationType.REPLACE, "mail", "modified@example.com"); final Result result = connection.modify(request); try { final PreReadResponseControl control = result.getControl(PreReadResponseControl.DECODER, new DecodeOptions()); final Entry entry = control.getEntry(); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); writer.writeEntry(entry); writer.close(); } catch (final DecodeException e) { // Failed to decode the response control. } catch (final IOException e) { // The writer could not write to System.out. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite pre read ---]</programlisting> <para>OpenDJ directory server supports these controls:</para> @@ -897,30 +571,8 @@ application bind with its credentials, and then carry out operations as the users who login to the application.</para> <programlisting language="java"> if (isSupported(ProxiedAuthV2RequestControl.OID)) { final String bindDN = "cn=My App,ou=Apps,dc=example,dc=com"; final String targetDn = "uid=bjensen,ou=People,dc=example,dc=com"; final String authzId = "dn:uid=kvaughan,ou=People,dc=example,dc=com"; final ModifyRequest request = Requests.newModifyRequest(targetDn) .addControl(ProxiedAuthV2RequestControl.newControl(authzId)) .addModification(ModificationType.REPLACE, "description", "Done with proxied authz"); connection.bind(bindDN, "password".toCharArray()); connection.modify(request); final Entry entry = connection.readEntry(targetDn, "description"); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(entry); writer.close(); } catch (final IOException e) { // The writer could not write to System.out. } }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite proxied authzv2 ---]</programlisting> <para>OpenDJ supports proxied authorization, and the example works with the sample data:</para> @@ -953,67 +605,8 @@ reduce load on the server. If not, then you can request a server-side sort.</para> <programlisting language="java"> static void useServerSideSortRequestControl(Connection connection) throws ErrorResultException { if (isSupported(ServerSideSortRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest("ou=People,dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(sn=Jensen)", "cn") .addControl(ServerSideSortRequestControl.newControl( true, new SortKey("cn"))); final SearchResultHandler resultHandler = new MySearchResultHandler(); final Result result = connection.search(request, resultHandler); try { final ServerSideSortResponseControl control = result.getControl(ServerSideSortResponseControl.DECODER, new DecodeOptions()); if (control != null && control.getResult() == ResultCode.SUCCESS) { System.out.println("# Entries are sorted."); } else { System.out.println("# Entries not necessarily sorted"); } } catch (final DecodeException e) { // Failed to decode the response control. } } else { System.out.println("ServerSideSortRequestControl not supported"); } } private static class MySearchResultHandler implements SearchResultHandler { @Override public void handleErrorResult(ErrorResultException error) { // Ignore. } @Override public void handleResult(Result result) { // Ignore. } @Override public boolean handleEntry(SearchResultEntry entry) { final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { writer.writeEntry(entry); writer.flush(); } catch (final IOException e) { // The writer could not write to System.out. } return true; } @Override public boolean handleReference(SearchResultReference reference) { System.out.println("Got a reference: " + reference.toString()); return false; } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite server-side sort ---]</programlisting> <para>OpenDJ directory server supports server-side sorting:</para> @@ -1067,37 +660,8 @@ Manipulation</citetitle></link>, defines a control for simple paging of search results that works with a cookie mechanism.</para> <programlisting language="java"> if (isSupported(SimplePagedResultsControl.OID)) { ByteString cookie = ByteString.empty(); SearchRequest request; final SearchResultHandler resultHandler = new MySearchResultHandler(); Result result; int page = 1; do { System.out.println("# Simple paged results: Page " + page); request = Requests.newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(sn=Jensen)", "cn") .addControl(SimplePagedResultsControl.newControl( true, 3, cookie)); result = connection.search(request, resultHandler); try { SimplePagedResultsControl control = result.getControl(SimplePagedResultsControl.DECODER, new DecodeOptions()); cookie = control.getCookie(); } catch (final DecodeException e) { // Failed to decode the response control. } ++page; } while (cookie.length() != 0); } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite simple paged results ---]</programlisting> <para>OpenDJ directory server supports getting simple paged results:</para> @@ -1152,34 +716,8 @@ are only visible in searches with <literal>SearchScope.BASE_OBJECT</literal>.</para> <programlisting language="java"> if (isSupported(SubentriesRequestControl.OID)) { final SearchRequest request = Requests.newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "cn=*Class of Service", "cn", "subtreeSpecification") .addControl(SubentriesRequestControl.newControl( true, true)); final ConnectionEntryReader reader = connection.search(request); final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); try { while (reader.hasNext()) { if (reader.isEntry()) { final SearchResultEntry entry = reader.readEntry(); writer.writeEntry(entry); } } writer.close(); } catch (final ErrorResultIOException e) { // Request failed due to an IO problem. } catch (final SearchResultReferenceIOException e) { // Read a reference, rather than an entry. } catch (final IOException e) { // The writer could not write to System.out. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite subentries ---]</programlisting> <para>OpenDJ directory server supports the control.</para> @@ -1217,27 +755,12 @@ your application delete an entire branch of entries starting with the entry you target for deletion.</para> <programlisting language="java"> if (isSupported(SubtreeDeleteRequestControl.OID)) { final String dn = "ou=Apps,dc=example,dc=com"; final DeleteRequest request = Requests.newDeleteRequest(dn) .addControl(SubtreeDeleteRequestControl.newControl(true)); final Result result = connection.delete(request); if (result.isSuccess()) { System.out.println("Successfully deleted " + dn + " and all entries below."); } else { System.out.println("Result: " + result.getDiagnosticMessage()); } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite tree delete ---]</programlisting> <para>OpenDJ directory server supports the subtree delete control:</para> <programlisting <programlisting language="none" >Successfully deleted ou=Apps,dc=example,dc=com and all entries below.</programlisting> </section> @@ -1267,46 +790,8 @@ control such that the subset of entries the directory server returns from a search are a window into the full sorted list.</para> <programlisting language="java"> if (isSupported(VirtualListViewRequestControl.OID)) { ByteString contextID = ByteString.empty(); // Add a window of 2 entries on either side of the first sn=Jensen entry. final SearchRequest request = Requests.newSearchRequest("ou=People,dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(sn=*)", "sn", "givenName") .addControl(ServerSideSortRequestControl.newControl( true, new SortKey("sn"))) .addControl( VirtualListViewRequestControl.newAssertionControl( true, ByteString.valueOf("Jensen"), 2, 2, contextID)); final SearchResultHandler resultHandler = new MySearchResultHandler(); final Result result = connection.search(request, resultHandler); try { final ServerSideSortResponseControl sssControl = result.getControl(ServerSideSortResponseControl.DECODER, new DecodeOptions()); if (sssControl != null && sssControl.getResult() == ResultCode.SUCCESS){ System.out.println("# Entries are sorted."); } else { System.out.println("# Entries not necessarily sorted"); } final VirtualListViewResponseControl vlvControl = result.getControl(VirtualListViewResponseControl.DECODER, new DecodeOptions()); System.out.println("# Position in list: " + vlvControl.getTargetPosition() + "/" + vlvControl.getContentCount()); } catch (final DecodeException e) { // Failed to decode the response control. } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Controls:--- JCite vlv ---]</programlisting> <para>OpenDJ directory server supports the virtual list view controls. In order to set up OpenDJ directory server to produce the following output opendj3/src/main/docbkx/dev-guide/chap-extended-ops.xml
@@ -88,41 +88,8 @@ <para>The following excerpt shows code to check for supported extended operations.</para> <programlisting language="java"> /** * Controls supported by the LDAP server. */ private static Collection<String> extendedOperations; /** * Populate the list of supported LDAP extended operation OIDs. * * @param connection * Active connection to the LDAP server. * @throws ErrorResultException * Failed to get list of extended operations. */ static void checkSupportedExtendedOperations(Connection connection) throws ErrorResultException { extendedOperations = RootDSE.readRootDSE(connection) .getSupportedExtendedOperations(); } /** * Check whether an extended operation is supported. Call * {@code checkSupportedExtendedOperations} first. * * @param extendedOperation * Check support for this extended operation, provided by OID. * @return True if the control is supported. */ static boolean isSupported(final String extendedOperation) { if (extendedOperations != null && !extendedOperations.isEmpty()) { return extendedOperations.contains(extendedOperation); } return false; } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.ExtendedOperations:--- JCite check support ---]</programlisting> </section> <section xml:id="use-cancel-extended-operation"> @@ -152,65 +119,17 @@ entries returned from a search if the directory server returns more entries than you want.</para> <programlisting language="java"> private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1); private static final CountDownLatch CANCEL_LATCH = new CountDownLatch(1); private static final LDIFEntryWriter WRITER = new LDIFEntryWriter(System.out); <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SearchAsync:--- JCite decl1 ---]</programlisting> static int requestID; static int entryCount = 0; <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SearchAsync:--- JCite decl2 ---]</programlisting> // The requestID is obtained from the future result of the asynchronous search. // For more context see the example, SearchAsync.java. <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SearchAsync:--- JCite search result handler ---]</programlisting> private static final class SearchResultHandlerImpl implements SearchResultHandler { @Override public synchronized boolean handleEntry(final SearchResultEntry entry) { try { // Cancel the search if it returns too many results. if (entryCount < 10) { WRITER.writeComment("Search result entry: " + entry.getName().toString()); WRITER.writeEntry(entry); ++entryCount; } else { CancelExtendedRequest request = Requests.newCancelExtendedRequest(requestID); connection.extendedRequestAsync( request, null, new CancelResultHandlerImpl()); return false; } } catch (final IOException e) { System.err.println(e.getMessage()); resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue(); COMPLETION_LATCH.countDown(); return false; } return true; } ... } private static final class CancelResultHandlerImpl implements ResultHandler<ExtendedResult> { @Override public void handleErrorResult(final ErrorResultException error) { System.err.println("Cancel request failed with result code: " + error.getResult().getResultCode().intValue()); CANCEL_LATCH.countDown(); } @Override public void handleResult(final ExtendedResult result) { System.err.println("Cancel request succeeded"); CANCEL_LATCH.countDown(); } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SearchAsync:--- JCite cancel result handler ---]</programlisting> <para>OpenDJ directory server supports the cancel operation. If OpenDJ directory server manages to return all entries in @@ -224,7 +143,7 @@ for scope, filter, and attributes respectively, then the example produces something like the following output:</para> <programlisting> <programlisting language="none"> Canceled: Processing on this operation was terminated as a result of receiving a cancel request (message ID 3) # Search result entry: dc=example,dc=org @@ -259,31 +178,12 @@ user passwords that does not depend on the authentication identity, nor on the way passwords are stored.</para> <programlisting language="java"> if (isSupported(PasswordModifyExtendedRequest.OID)) { final String userIdentity = "u:scarter"; final char[] oldPassword = "sprain".toCharArray(); final char[] newPassword = "secret12".toCharArray(); final PasswordModifyExtendedRequest request = Requests.newPasswordModifyExtendedRequest() .setUserIdentity(userIdentity) .setOldPassword(oldPassword) .setNewPassword(newPassword); final PasswordModifyExtendedResult result = connection.extendedRequest(request); if (result.isSuccess()) { System.out.println("Changed password for " + userIdentity); } else { System.err.println(result.getDiagnosticMessage()); } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.ExtendedOperations:--- JCite password modify ---]</programlisting> <para>OpenDJ directory server supports the password modify operation.</para> <programlisting>Changed password for u:scarter</programlisting> <programlisting language="none">Changed password for u:scarter</programlisting> </section> <section xml:id="use-starttls-extended-operation"> @@ -312,30 +212,12 @@ defines an extended operation that lets your application determine the current authorization ID.</para> <programlisting language="java"> if (isSupported(WhoAmIExtendedRequest.OID)) { final String name = "uid=bjensen,ou=People,dc=example,dc=com"; final char[] password = "hifalutin".toCharArray(); final Result result = connection.bind(name, password); if (result.isSuccess()) { final WhoAmIExtendedRequest request = Requests.newWhoAmIExtendedRequest(); final WhoAmIExtendedResult extResult = connection.extendedRequest(request); if (extResult.isSuccess()) { System.out.println("Authz ID: " + extResult.getAuthorizationID()); } } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.ExtendedOperations:--- JCite who am I ---]</programlisting> <para>OpenDJ directory server supports the "Who am I?" operation.</para> <programlisting <programlisting language="none" >Authz ID: dn:uid=bjensen,ou=People,dc=example,dc=com</programlisting> </section> </chapter> opendj3/src/main/docbkx/dev-guide/chap-getting-directory-info.xml
@@ -20,7 +20,7 @@ ! ! CCPL HEADER END ! ! Copyright 2011-2012 ForgeRock AS ! Copyright 2011-2013 ForgeRock AS ! --> <chapter xml:id='chap-getting-directory-info' @@ -64,27 +64,8 @@ get all operational attributes from the root DSE entry as in the following excerpt.</para> <programlisting language="java"> final LDAPConnectionFactory factory = new LDAPConnectionFactory( host, port); Connection connection = null; try { connection = factory.getConnection(); // Perform an anonymous search on the root DSE. final SearchResultEntry entry = connection.searchSingleEntry( "", // DN is "" for root DSE. SearchScope.BASE_OBJECT, // Read only the root DSE. "objectclass=*", // Every object matches this filter. "+"); // Return all operational attributes. final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); writer.writeComment("Root DSE for LDAP server at " + host + ":" + port); if (entry != null) writer.writeEntry(entry); writer.flush(); }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.GetInfo:--- JCite ---]</programlisting> <para>For a complete example in context, see <link xlink:href="http://opendj.forgerock.org/opendj-ldap-sdk-examples/xref/org/forgerock/opendj/examples/GetInfo.html" opendj3/src/main/docbkx/dev-guide/chap-ldif.xml
@@ -20,7 +20,7 @@ ! ! CCPL HEADER END ! ! Copyright 2011-2012 ForgeRock AS ! Copyright 2011-2013 ForgeRock AS ! --> <chapter xml:id='chap-ldif' @@ -180,32 +180,6 @@ directory server.</para> <programlisting language="java" >final LDIFChangeRecordReader reader = new LDIFChangeRecordReader(ldif); final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); connection.bind(userDN, password.toCharArray()); final ConnectionChangeRecordWriter writer = new ConnectionChangeRecordWriter(connection); while (reader.hasNext()) { ChangeRecord changeRecord = reader.readChangeRecord(); writer.writeChangeRecord(changeRecord); } } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } catch (final IOException e) { System.err.println(e.getMessage()); System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); return; } finally { if (connection != null) { connection.close(); } }</programlisting> >[jcp:org.forgerock.opendj.examples.Modify:--- JCite ---]</programlisting> </section> </chapter> opendj3/src/main/docbkx/dev-guide/chap-reading.xml
@@ -108,40 +108,8 @@ <para>The following code excerpt demonstrates how this might be done in a minimal command-line program.</para> <programlisting language="java">// Prompt for mail and password. Console c = System.console(); if (c == null) { System.err.println("No console."); System.exit(1); } String mail = c.readLine("Email address: "); char[] password = c.readPassword("Password: "); // Search using mail address, and then bind with the DN and password. final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); // No explicit bind yet so we remain anonymous for now. SearchResultEntry entry = connection.searchSingleEntry(baseDN, SearchScope.WHOLE_SUBTREE, "(mail=" + mail + ")", "cn"); DN bindDN = entry.getName(); connection.bind(bindDN.toString(), password); String cn = entry.getAttribute("cn").firstValueAsString(); System.out.println("Hello, " + cn + "!"); } catch (final ErrorResultException e) { System.err.println("Failed to bind."); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) { connection.close(); } }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.SearchBind:--- JCite ---]</programlisting> <para>For a complete example in context, see <link xlink:href="http://opendj.forgerock.org/opendj-ldap-sdk-examples/xref/org/forgerock/opendj/examples/SearchBind.html" @@ -362,35 +330,8 @@ <para>You can get a <literal>ConnectionEntryReader</literal>, and iterate over the reader to access individual search results.</para> <programlisting language="java">Connection connection = ...; ConnectionEntryReader reader = connection.search("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, "(objectClass=person)"); try { while (reader.hasNext()) { if (reader.isEntry()) { SearchResultEntry entry = reader.readEntry(); // Handle entry... } else { SearchResultReference ref = reader.readReference(); // Handle continuation reference... } } } catch (IOException e) { // Handle exceptions... } finally { reader.close(); }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Search:--- JCite ---]</programlisting> <para>For a complete example in context, see <link xlink:href="http://opendj.forgerock.org/opendj-ldap-sdk-examples/xref/org/forgerock/opendj/examples/Search.html" @@ -433,38 +374,8 @@ value types. You can use these methods to get attribute values as objects.</para> <programlisting language="java"> // Use Kirsten Vaughan's credentials and her entry. String name = "uid=kvaughan,ou=People,dc=example,dc=com"; char[] password = "bribery".toCharArray(); connection.bind(name, password); // Make sure we have a timestamp to play with. updateEntry(connection, name, "description"); // Read Kirsten's entry. final SearchResultEntry entry = connection.readEntry(name, "cn", "objectClass", "hasSubordinates", "numSubordinates", "isMemberOf", "modifyTimestamp"); // Get the entry DN and some attribute values as objects. DN dn = entry.getName(); Set<String> cn = entry.parseAttribute("cn").asSetOfString(""); Set<AttributeDescription> objectClasses = entry.parseAttribute("objectClass").asSetOfAttributeDescription(); boolean hasChildren = entry.parseAttribute("hasSubordinates").asBoolean(); int numChildren = entry.parseAttribute("numSubordinates").asInteger(0); Set<DN> groups = entry .parseAttribute("isMemberOf") .usingSchema(Schema.getDefaultSchema()).asSetOfDN(); Calendar timestamp = entry .parseAttribute("modifyTimestamp") .asGeneralizedTime().toCalendar(); // Do something with the objects. // ... </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.ParseAttributes:--- JCite ---]</programlisting> <para>For a complete example in context, see <link xlink:href="http://opendj.forgerock.org/opendj-ldap-sdk-examples/xref/org/forgerock/opendj/examples/ParseAttributes.html" opendj3/src/main/docbkx/dev-guide/chap-simple-proxy.xml
@@ -76,15 +76,7 @@ pool of the maximum size you specify.</para> <programlisting language="java" >final List<ConnectionFactory> factories = new LinkedList<~>(); factories.add(Connections.newFixedConnectionPool(Connections .newAuthenticatedConnectionFactory(Connections .newHeartBeatConnectionFactory(new LDAPConnectionFactory( remoteAddress, remotePort)), Requests.newSimpleBindRequest(proxyDN, proxyPassword.toCharArray())), Integer.MAX_VALUE));</programlisting> >[jcp:org.forgerock.opendj.examples.Proxy:--- JCite pools ---]</programlisting> <para>Connections are returned to the pool when you <literal>close()</literal> them. Notice that <literal>Connections</literal> also provides methods to @@ -126,15 +118,7 @@ across directory servers.</para> <programlisting language="java" >final List<ConnectionFactory> factories = new LinkedList<ConnectionFactory>(); // Set up a ConnectionFactory for each directory server in the pool as shown in // the previous example, and then set up a load balancer. final RoundRobinLoadBalancingAlgorithm algorithm = new RoundRobinLoadBalancingAlgorithm(factories); final ConnectionFactory factory = Connections.newLoadBalancer(algorithm);</programlisting> >[jcp:org.forgerock.opendj.examples.Proxy:--- JCite load balancer ---]</programlisting> <para>With multiple pools of directory servers, for example in a deployment across multiple data centers, also use fail over load balancing. Fail over @@ -173,23 +157,8 @@ that deals with the connections, in this case connections back to the directory servers handling client requests.</para> <programlisting language="java"> final LDAPListenerOptions options = new LDAPListenerOptions().setBacklog(4096); LDAPListener listener = null; try { listener = new LDAPListener(localAddress, localPort, connectionHandler, options); System.out.println("Press any key to stop the server..."); System.in.read(); } catch (final IOException e) { System.out.println("Error listening on " + localAddress + ":" + localPort); e.printStackTrace(); } finally { if (listener != null) { listener.close(); } } </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Proxy:--- JCite listener ---]</programlisting> <para>You get a <literal>ServerConnectionFactory</literal> to handle requests coming from clients. The <literal>ServerConnectionFactory</literal> takes a @@ -200,11 +169,8 @@ directory servers and routes the results returned back to client applications.</para> <programlisting language="java"> final ProxyBackend backend = new ProxyBackend(factory, bindFactory); final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = Connections.newServerConnectionFactory(backend); </programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.Proxy:--- JCite backend ---]</programlisting> <para>See the Proxy example code for details about the <literal>ProxyBackend</literal> implementation.</para> opendj3/src/main/docbkx/dev-guide/chap-writing.xml
@@ -137,34 +137,8 @@ <para>The following excerpt demonstrates how to add a simple user entry under <literal>ou=People,dc=example,dc=com</literal>.</para> <programlisting language="java">// An entry to add to the directory Entry entry = new LinkedHashMapEntry("cn=Bob,ou=People,dc=example,dc=com") .addAttribute("cn", "Bob") .addAttribute("objectclass", "top") .addAttribute("objectclass", "person") .addAttribute("objectclass", "organizationalPerson") .addAttribute("objectclass", "inetOrgPerson") .addAttribute("mail", "subgenius@example.com") .addAttribute("sn", "Dobbs"); final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); // Bind as a user who has the right to add entries. connection.bind(adminDN, adminPwd); connection.add(entry); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) { connection.close(); } }</programlisting> <programlisting language="java" >[jcp:org.forgerock.opendj.examples.ShortLife:--- JCite add ---]</programlisting> </section> <section xml:id="modifying-attr-values"> @@ -183,30 +157,7 @@ it can be easy to use in some cases.</para> <programlisting language="java" >final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); // Bind as a user who has the right to modify entries. connection.bind(adminDN, adminPwd); // Here, entry is a user entry with DN cn=Bob,ou=People,dc=example,dc=com. Entry old = TreeMapEntry.deepCopyOfEntry(entry); entry = entry.replaceAttribute("mail", "spammer@example.com") .addAttribute("description", "I see the fnords."); ModifyRequest request = Entries.diffEntries(old, entry); connection.modify(request); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) { connection.close(); } }</programlisting> >[jcp:org.forgerock.opendj.examples.ShortLife:--- JCite modify ---]</programlisting> <para>Especially when working with large entries, a more efficient choice is to construct a <literal>ModifyRequest</literal> without copying the entire @@ -231,26 +182,7 @@ <para>The following excerpt demonstrates how to rename an entry.</para> <programlisting language="java" >final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); // Bind as a user who has the right to rename entries. connection.bind(adminDN, adminPwd); // Here, entryDN contains cn=Bob,ou=People,dc=example,dc=com. // The second argument is the new relative distinguished name. connection.modifyDN(entryDN, "cn=Ted"); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) { connection.close(); } }</programlisting> >[jcp:org.forgerock.opendj.examples.ShortLife:--- JCite rename ---]</programlisting> <para>If you must move rather than rename entries, have a look at the methods for <literal>ModifyDNRequest</literal>. You can get a new request by using @@ -267,24 +199,7 @@ <literal>cn=Ted,ou=People,dc=example,dc=com</literal>.</para> <programlisting language="java" >final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); // Bind as a user who has the right to delete entries. connection.bind(adminDN, adminPwd); connection.delete("cn=Ted,ou=People,dc=example,dc=com"); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) { connection.close(); } }</programlisting> >[jcp:org.forgerock.opendj.examples.ShortLife:--- JCite delete ---]</programlisting> <para>If you must delete an entire branch of entries instead of a single leaf entry, build a <literal>DeleteRequest</literal> that includes the @@ -332,44 +247,7 @@ <example xml:id="update-group-with-permissive-modify"><?dbfo keep-together="auto"?> <title>Updating a Group With Permissive Modify</title> <programlisting language="java" >final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); Collection<String> controls = RootDSE.readRootDSE(connection).getSupportedControls(); final String user = "cn=Directory Manager"; final char[] password = "password".toCharArray(); connection.bind(user, password); if (controls.contains(PermissiveModifyRequestControl.OID)) { final ModifyRequest request = Requests.newModifyRequest(groupDN) .addControl(PermissiveModifyRequestControl.newControl(true)) .addModification(modType, "member", memberDN); connection.modify(request); } else { /* ... */ } String op = (modType == ModificationType.ADD) ? "added to" : "deleted from"; System.out.println("The entry with DN " + memberDN + " has been " + op + " the group with DN " + groupDN + "."); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) { connection.close(); } }</programlisting> >[jcp:org.forgerock.opendj.examples.UpdateGroup:--- JCite permissive ---]</programlisting> </example> <para>If the directory server does not support the Permissive Modify control, @@ -381,68 +259,7 @@ <example xml:id="update-group-with-compare-and-modify"><?dbfo keep-together="auto"?> <title>Updating a Group With Compare & Modify</title> <programlisting language="java" >final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); Connection connection = null; try { connection = factory.getConnection(); Collection<String> controls = RootDSE.readRootDSE(connection).getSupportedControls(); final String user = "cn=Directory Manager"; final char[] password = "password".toCharArray(); connection.bind(user, password); if (controls.contains(PermissiveModifyRequestControl.OID)) { /* ... */ } else { System.out.println("Checking whether the entry with DN " + memberDN + " belongs to the group with DN " + groupDN + "..."); final CompareRequest request = Requests.newCompareRequest(groupDN, "member", memberDN); CompareResult result = connection.compare(request); if (modType == ModificationType.ADD) { if (result.getResultCode() == ResultCode.COMPARE_FALSE) { System.out.println("Member does not yet belong to group." + " Adding it..."); final ModifyRequest addMember = Requests.newModifyRequest(groupDN) .addModification(modType, "member", memberDN); connection.modify(addMember); } } if (modType == ModificationType.DELETE) { if (result.getResultCode() == ResultCode.COMPARE_TRUE) { System.out.println("Member belongs to group." + " Removing it..."); final ModifyRequest delMember = Requests.newModifyRequest(groupDN) .addModification(modType, "member", memberDN); connection.modify(delMember); } } } String op = (modType == ModificationType.ADD) ? "added to" : "deleted from"; System.out.println("The entry with DN " + memberDN + " has been " + op + " the group with DN " + groupDN + "."); } catch (final ErrorResultException e) { System.err.println(e.getMessage()); System.exit(e.getResult().getResultCode().intValue()); return; } finally { if (connection != null) { connection.close(); } }</programlisting> >[jcp:org.forgerock.opendj.examples.UpdateGroup:--- JCite without permissive ---]</programlisting> <para>You can change multiple member values with a single modification. The final argument of this form of the