001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2010 Sun Microsystems, Inc.
025 *      Portions copyright 2012-2015 ForgeRock AS.
026 */
027
028package org.forgerock.opendj.ldap;
029
030import java.util.LinkedList;
031import java.util.List;
032import java.util.concurrent.TimeUnit;
033
034import javax.net.ssl.SSLContext;
035
036import org.forgerock.util.Reject;
037
038/**
039 * Common options for LDAP client connections.
040 * <p>
041 * For example you set LDAP options when you want to use StartTLS.
042 *
043 * <pre>
044 * LDAPOptions options = new LDAPOptions();
045 * SSLContext sslContext =
046 *         new SSLContextBuilder().setTrustManager(...).getSSLContext();
047 * options.setSSLContext(sslContext);
048 * options.setUseStartTLS(true);
049 *
050 * String host = ...;
051 * int port = ...;
052 * LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port, options);
053 * Connection connection = factory.getConnection();
054 * // Connection uses StartTLS...
055 * </pre>
056 */
057public final class LDAPOptions extends CommonLDAPOptions<LDAPOptions> {
058    /** Default values for options taken from Java properties. */
059    private static final long DEFAULT_TIMEOUT;
060    private static final long DEFAULT_CONNECT_TIMEOUT;
061    static {
062        DEFAULT_TIMEOUT = getIntProperty("org.forgerock.opendj.io.timeout", 0);
063        DEFAULT_CONNECT_TIMEOUT = getIntProperty("org.forgerock.opendj.io.connectTimeout", 5000);
064    }
065
066    private SSLContext sslContext;
067    private boolean useStartTLS;
068    private long timeoutInMillis = DEFAULT_TIMEOUT;
069    private long connectTimeoutInMillis = DEFAULT_CONNECT_TIMEOUT;
070    private final List<String> enabledCipherSuites = new LinkedList<>();
071    private final List<String> enabledProtocols = new LinkedList<>();
072
073    /**
074     * Creates a new set of connection options with default settings. SSL will
075     * not be enabled, and a default set of decode options will be used.
076     */
077    public LDAPOptions() {
078        super();
079    }
080
081    /**
082     * Creates a new set of connection options having the same initial set of
083     * options as the provided set of connection options.
084     *
085     * @param options
086     *            The set of connection options to be copied.
087     */
088    public LDAPOptions(final LDAPOptions options) {
089        super(options);
090        this.sslContext = options.sslContext;
091        this.timeoutInMillis = options.timeoutInMillis;
092        this.useStartTLS = options.useStartTLS;
093        this.enabledCipherSuites.addAll(options.getEnabledCipherSuites());
094        this.enabledProtocols.addAll(options.getEnabledProtocols());
095        this.connectTimeoutInMillis = options.connectTimeoutInMillis;
096    }
097
098    /**
099     * Adds the cipher suites enabled for secure connections with the Directory
100     * Server.
101     * <p>
102     * The suites must be supported by the SSLContext specified in
103     * {@link #setSSLContext(SSLContext)}. Following a successful call to this
104     * method, only the suites listed in the protocols parameter are enabled for
105     * use.
106     *
107     * @param suites
108     *            Names of all the suites to enable.
109     * @return A reference to this set of options.
110     */
111    public LDAPOptions addEnabledCipherSuite(final String... suites) {
112        for (final String suite : suites) {
113            enabledCipherSuites.add(Reject.checkNotNull(suite));
114        }
115        return this;
116    }
117
118    /**
119     * Adds the protocol versions enabled for secure connections with the
120     * Directory Server.
121     * <p>
122     * The protocols must be supported by the SSLContext specified in
123     * {@link #setSSLContext(SSLContext)}. Following a successful call to this
124     * method, only the protocols listed in the protocols parameter are enabled
125     * for use.
126     *
127     * @param protocols
128     *            Names of all the protocols to enable.
129     * @return A reference to this set of options.
130     */
131    public LDAPOptions addEnabledProtocol(final String... protocols) {
132        for (final String protocol : protocols) {
133            enabledProtocols.add(Reject.checkNotNull(protocol));
134        }
135        return this;
136    }
137
138    /**
139     * Returns the connect timeout in the specified unit. If a connection is not
140     * established within the timeout period, then a
141     * {@link TimeoutResultException} error result will be returned. A timeout
142     * setting of 0 causes the OS connect timeout to be used.
143     * <p>
144     * The default operation timeout is 10 seconds and may be configured using
145     * the {@code org.forgerock.opendj.io.connectTimeout} property.
146     *
147     * @param unit
148     *            The time unit.
149     * @return The connect timeout, which may be 0 if there is no connect
150     *         timeout.
151     */
152    public long getConnectTimeout(final TimeUnit unit) {
153        return unit.convert(connectTimeoutInMillis, TimeUnit.MILLISECONDS);
154    }
155
156    /**
157     * Returns the names of the protocol versions which are currently enabled
158     * for secure connections with the Directory Server.
159     *
160     * @return An array of protocols or empty set if the default protocols are
161     *         to be used.
162     */
163    public List<String> getEnabledCipherSuites() {
164        return enabledCipherSuites;
165    }
166
167    /**
168     * Returns the names of the protocol versions which are currently enabled
169     * for secure connections with the Directory Server.
170     *
171     * @return An array of protocols or empty set if the default protocols are
172     *         to be used.
173     */
174    public List<String> getEnabledProtocols() {
175        return enabledProtocols;
176    }
177
178    /**
179     * Returns the SSL context which will be used when initiating connections
180     * with the Directory Server.
181     * <p>
182     * By default no SSL context will be used, indicating that connections will
183     * not be secured. If a non-{@code null} SSL context is returned then
184     * connections will be secured using either SSL or StartTLS depending on
185     * {@link #useStartTLS()}.
186     *
187     * @return The SSL context which will be used when initiating secure
188     *         connections with the Directory Server, which may be {@code null}
189     *         indicating that connections will not be secured.
190     */
191    public SSLContext getSSLContext() {
192        return sslContext;
193    }
194
195    /**
196     * Returns the operation timeout in the specified unit. If a response is not
197     * received from the Directory Server within the timeout period, then the
198     * operation will be abandoned and a {@link TimeoutResultException} error
199     * result returned. A timeout setting of 0 disables operation timeout
200     * limits.
201     * <p>
202     * The default operation timeout is 0 (no timeout) and may be configured
203     * using the {@code org.forgerock.opendj.io.timeout} property.
204     *
205     * @param unit
206     *            The time unit.
207     * @return The operation timeout, which may be 0 if there is no operation
208     *         timeout.
209     */
210    public long getTimeout(final TimeUnit unit) {
211        return unit.convert(timeoutInMillis, TimeUnit.MILLISECONDS);
212    }
213
214    /**
215     * Sets the connect timeout. If a connection is not established within the
216     * timeout period, then a {@link TimeoutResultException} error result will
217     * be returned. A timeout setting of 0 causes the OS connect timeout to be
218     * used.
219     * <p>
220     * The default operation timeout is 10 seconds and may be configured using
221     * the {@code org.forgerock.opendj.io.connectTimeout} property.
222     *
223     * @param timeout
224     *            The connect timeout, which may be 0 if there is no connect
225     *            timeout.
226     * @param unit
227     *            The time unit.
228     * @return A reference to this set of options.
229     */
230    public LDAPOptions setConnectTimeout(final long timeout, final TimeUnit unit) {
231        this.connectTimeoutInMillis = unit.toMillis(timeout);
232        return this;
233    }
234
235    /**
236     * Sets the SSL context which will be used when initiating connections with
237     * the Directory Server.
238     * <p>
239     * By default no SSL context will be used, indicating that connections will
240     * not be secured. If a non-{@code null} SSL context is returned then
241     * connections will be secured using either SSL or StartTLS depending on
242     * {@link #useStartTLS()}.
243     *
244     * @param sslContext
245     *            The SSL context which will be used when initiating secure
246     *            connections with the Directory Server, which may be
247     *            {@code null} indicating that connections will not be secured.
248     * @return A reference to this set of options.
249     */
250    public LDAPOptions setSSLContext(final SSLContext sslContext) {
251        this.sslContext = sslContext;
252        return this;
253    }
254
255    /**
256     * Sets the operation timeout. If a response is not received from the
257     * Directory Server within the timeout period, then the operation will be
258     * abandoned and a {@link TimeoutResultException} error result returned. A
259     * timeout setting of 0 disables operation timeout limits.
260     * <p>
261     * The default operation timeout is 0 (no timeout) and may be configured
262     * using the {@code org.forgerock.opendj.io.timeout} property.
263     *
264     * @param timeout
265     *            The operation timeout, which may be 0 if there is no operation
266     *            timeout.
267     * @param unit
268     *            The time unit.
269     * @return A reference to this set of options.
270     */
271    public LDAPOptions setTimeout(final long timeout, final TimeUnit unit) {
272        this.timeoutInMillis = unit.toMillis(timeout);
273        return this;
274    }
275
276    /**
277     * Specifies whether or not SSL or StartTLS should be used for securing
278     * connections when an SSL context is specified.
279     * <p>
280     * By default SSL will be used in preference to StartTLS.
281     *
282     * @param useStartTLS
283     *            {@code true} if StartTLS should be used for securing
284     *            connections when an SSL context is specified, otherwise
285     *            {@code false} indicating that SSL should be used.
286     * @return A reference to this set of options.
287     */
288    public LDAPOptions setUseStartTLS(final boolean useStartTLS) {
289        this.useStartTLS = useStartTLS;
290        return this;
291    }
292
293    /**
294     * Indicates whether or not SSL or StartTLS should be used for securing
295     * connections when an SSL context is specified.
296     * <p>
297     * By default SSL will be used in preference to StartTLS.
298     *
299     * @return {@code true} if StartTLS should be used for securing connections
300     *         when an SSL context is specified, otherwise {@code false}
301     *         indicating that SSL should be used.
302     */
303    public boolean useStartTLS() {
304        return useStartTLS;
305    }
306
307    @Override
308    LDAPOptions getThis() {
309        return this;
310    }
311}