View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.common.lib;
20  
21  import java.io.Serializable;
22  import java.time.Duration;
23  import java.util.List;
24  import java.util.stream.Collectors;
25  import java.util.stream.Stream;
26  
27  public abstract class AbstractLDAPConf implements Serializable {
28  
29      private static final long serialVersionUID = 3705514707899419599L;
30  
31      /**
32       * The ldap type used to handle specific ops.
33       */
34      public enum LdapType {
35  
36          /**
37           * Generic ldap type (OpenLDAP, 389ds, etc).
38           */
39          GENERIC,
40          /**
41           * Active directory.
42           */
43          AD,
44          /**
45           * FreeIPA directory.
46           */
47          FreeIPA,
48          /**
49           * EDirectory.
50           */
51          EDirectory
52  
53      }
54  
55      /**
56       * The ldap connection pool passivator.
57       */
58      public enum LdapConnectionPoolPassivator {
59  
60          /**
61           * No passivator.
62           */
63          NONE,
64          /**
65           * Bind passivator.
66           */
67          BIND
68  
69      }
70  
71      public enum LdapConnectionStrategy {
72  
73          /**
74           * First ldap used until it fails.
75           */
76          ACTIVE_PASSIVE,
77          /**
78           * Navigate the ldap url list for new connections and circle back.
79           */
80          ROUND_ROBIN,
81          /**
82           * Randomly pick a url.
83           */
84          RANDOM,
85          /**
86           * ldap urls based on DNS SRV records.
87           */
88          DNS_SRV
89  
90      }
91  
92      /**
93       * Describe hostname verification strategies.
94       */
95      public enum LdapHostnameVerifier {
96          /**
97           * Default option, forcing verification.
98           */
99          DEFAULT,
100         /**
101          * Skip hostname verification and allow all.
102          */
103         ANY
104 
105     }
106 
107     /**
108      * Describe trust manager strategies.
109      */
110     public enum LdapTrustManager {
111         /**
112          * Loads the trust managers from the default {@link javax.net.ssl.TrustManagerFactory} and delegates to those.
113          */
114         DEFAULT,
115         /**
116          * Trusts any client or server.
117          */
118         ANY
119 
120     }
121 
122     /**
123      * User filter to use for searching.
124      * Syntax is {@code cn={user}} or {@code cn={0}}.
125      *
126      * You may also provide an external groovy script in the syntax of {@code file:/path/to/GroovyScript.groovy}
127      * to fully build the final filter template dynamically.
128      */
129     private String searchFilter;
130 
131     /**
132      * Whether subtree searching is allowed.
133      */
134     private boolean subtreeSearch = true;
135 
136     /**
137      * Request that the server return results in batches of a
138      * specific size. See <a href="http://www.ietf.org/rfc/rfc2696.txt">RFC 2696</a>. This control is often
139      * used to work around server result size limits.
140      * A negative/zero value disables paged requests.
141      */
142     private int pageSize;
143 
144     /**
145      * Base DN to use.
146      * There may be scenarios where different parts of a single LDAP tree could be considered as base-dns. Rather than
147      * duplicating the LDAP configuration block for each individual base-dn, each entry can be specified
148      * and joined together using a special delimiter character. The user DN is retrieved using the combination of all
149      * base-dn and DN resolvers in the order defined. DN resolution should fail if multiple DNs are found. Otherwise the
150      * first DN found is returned.
151      * Usual syntax is: {@code subtreeA,dc=example,dc=net|subtreeC,dc=example,dc=net}.
152      */
153     private String baseDn;
154 
155     private String ldapUrl;
156 
157     /**
158      * LDAP type.
159      */
160     private LdapType ldapType = LdapType.GENERIC;
161 
162     /**
163      * The bind DN to use when connecting to LDAP.
164      * LDAP connection configuration injected into the LDAP connection pool
165      * can be initialized with the following parameters:
166      * <ul>
167      * <li>{@code bindDn/bindCredential} provided - Use the provided credentials
168      * to bind when initializing connections.</li>
169      * <li>{@code bindDn/bindCredential} set to {@code *} - Use a fast-bind
170      * strategy to initialize the pool.</li>
171      * <li>{@code bindDn/bindCredential} set to blank - Skip connection
172      * initializing; perform operations anonymously.</li>
173      * <li>SASL mechanism provided - Use the given SASL mechanism
174      * to bind when initializing connections. </li>
175      * </ul>
176      */
177     private String bindDn;
178 
179     /**
180      * The bind credential to use when connecting to LDAP.
181      */
182     private String bindCredential;
183 
184     /**
185      * Whether to use a pooled connection factory in components.
186      */
187     private boolean disablePooling;
188 
189     /**
190      * Minimum LDAP connection pool size.
191      * Size the pool should be initialized to and pruned to
192      */
193     private int minPoolSize = 3;
194 
195     /**
196      * Maximum LDAP connection pool size which the pool can use to grow.
197      */
198     private int maxPoolSize = 10;
199 
200     /**
201      * You may receive unexpected LDAP failures, when CAS is configured to authenticate
202      * using {@code DIRECT} or {@code AUTHENTICATED} types and LDAP is locked down to not allow anonymous
203      * binds/searches.
204      * Every second attempt with a given LDAP connection from the pool would fail if it was on
205      * the same connection as a failed login attempt, and the regular connection validator would
206      * similarly fail. When a connection is returned back to a pool,
207      * it still may contain the principal and credentials from the previous attempt.
208      * Before the next bind attempt using that connection, the validator tries to
209      * validate the connection again but fails because it’s no longer trying with the
210      * configured bind credentials but with whatever user DN was used in the previous step.
211      * Given the validation failure, the connection is closed and CAS would deny
212      * access by default. Passivators attempt to reconnect
213      * to LDAP with the configured bind credentials, effectively resetting the connection
214      * to what it should be after each bind request.
215      * Furthermore if you are seeing errors in the logs that resemble
216      * a 'Operation exception encountered, reopening connection' type of message, this
217      * usually is an indication that the connection pool’s validation timeout
218      * established and created by CAS is greater than the timeout configured
219      * in the LDAP server, or more likely, in the load balancer in front of
220      * the LDAP servers. You can adjust the LDAP server session’s timeout
221      * for connections, or you can teach CAS to use a validity period that
222      * is equal or less than the LDAP server session’s timeout.
223      * Accepted values are:
224      * <ul>
225      * <li>{@code NONE}: No passivation takes place.</li>
226      * <li>{@code BIND}: The default behavior which passivates a connection by performing a
227      * bind operation on it. This option requires the availability of bind credentials when establishing connections to
228      * LDAP.</li>
229      * </ul>
230      */
231     private LdapConnectionPoolPassivator poolPassivator = LdapConnectionPoolPassivator.BIND;
232 
233     /**
234      * Hostname verification options.
235      */
236     private LdapHostnameVerifier hostnameVerifier = LdapHostnameVerifier.DEFAULT;
237 
238     /**
239      * Trust Manager options.
240      * Trust managers are responsible for managing the trust material that is used when making LDAP trust decisions,
241      * and for deciding whether credentials presented by a peer should be accepted.
242      */
243     private LdapTrustManager trustManager;
244 
245     /**
246      * Whether connections should be validated when loaned out from the pool.
247      */
248     private boolean validateOnCheckout = true;
249 
250     /**
251      * Whether connections should be validated periodically when the pool is idle.
252      */
253     private boolean validatePeriodically = true;
254 
255     /**
256      * Period at which validation operations may time out.
257      */
258     private Duration validateTimeout = Duration.parse("PT5S");
259 
260     /**
261      * Period at which pool should be validated.
262      */
263     private Duration validatePeriod = Duration.parse("PT5M");
264 
265     /**
266      * Attempt to populate the connection pool early on startup
267      * and fail quickly if something goes wrong.
268      */
269     private boolean failFast = true;
270 
271     /**
272      * Removes connections from the pool based on how long they have been idle in the available queue.
273      * Prunes connections that have been idle for more than the indicated amount.
274      */
275     private Duration idleTime = Duration.parse("PT10M");
276 
277     /**
278      * Removes connections from the pool based on how long they have been idle in the available queue.
279      * Run the pruning process at the indicated interval.
280      */
281     private Duration prunePeriod = Duration.parse("PT2H");
282 
283     /**
284      * The length of time the pool will block.
285      * By default the pool will block indefinitely and there is no guarantee that
286      * waiting threads will be serviced in the order in which they made their request.
287      * This option should be used with a blocking connection pool when you need to control the exact
288      * number of connections that can be created
289      */
290     private Duration blockWaitTime = Duration.parse("PT3S");
291 
292     /**
293      * If multiple URLs are provided as the ldapURL this describes how each URL will be processed.
294      * <ul>
295      * <li>{@code ACTIVE_PASSIVE} First LDAP will be used for every request unless it fails and then the next shall be
296      * used.</li>
297      * <li>{@code ROUND_ROBIN} For each new connection the next url in the list will be used.</li>
298      * <li>{@code RANDOM} For each new connection a random LDAP url will be selected.</li>
299      * <li>{@code DNS_SRV} LDAP urls based on DNS SRV records of the configured/given LDAP url will be used. </li>
300      * </ul>
301      */
302     private LdapConnectionStrategy connectionStrategy;
303 
304     /**
305      * Whether TLS should be used and enabled when establishing the connection.
306      */
307     private boolean useStartTls;
308 
309     /**
310      * Sets the maximum amount of time that connects will block.
311      */
312     private Duration connectTimeout = Duration.parse("PT5S");
313 
314     /**
315      * Duration of time to wait for responses.
316      */
317     private Duration responseTimeout = Duration.parse("PT5S");
318 
319     /**
320      * Whether search/query results are allowed to match on multiple DNs,
321      * or whether a single unique DN is expected for the result.
322      */
323     private boolean allowMultipleDns;
324 
325     /**
326      * Set if multiple Entries are allowed.
327      */
328     private boolean allowMultipleEntries;
329 
330     /**
331      * Set if search referrals should be followed.
332      */
333     private boolean followReferrals = true;
334 
335     /**
336      * Indicate the collection of attributes that are to be tagged and processed as binary
337      * attributes by the underlying search resolver.
338      */
339     private List<String> binaryAttributes = Stream.of("objectGUID", "objectSid").collect(Collectors.toList());
340 
341     public String getSearchFilter() {
342         return searchFilter;
343     }
344 
345     public void setSearchFilter(final String searchFilter) {
346         this.searchFilter = searchFilter;
347     }
348 
349     public int getPageSize() {
350         return pageSize;
351     }
352 
353     public void setPageSize(final int pageSize) {
354         this.pageSize = pageSize;
355     }
356 
357     public boolean isSubtreeSearch() {
358         return subtreeSearch;
359     }
360 
361     public void setSubtreeSearch(final boolean subtreeSearch) {
362         this.subtreeSearch = subtreeSearch;
363     }
364 
365     public LdapType getLdapType() {
366         return ldapType;
367     }
368 
369     public void setLdapType(final LdapType ldapType) {
370         this.ldapType = ldapType;
371     }
372 
373     public String getLdapUrl() {
374         return ldapUrl;
375     }
376 
377     public void setLdapUrl(final String ldapUrl) {
378         this.ldapUrl = ldapUrl;
379     }
380 
381     public String getBindDn() {
382         return bindDn;
383     }
384 
385     public void setBindDn(final String bindDn) {
386         this.bindDn = bindDn;
387     }
388 
389     public String getBindCredential() {
390         return bindCredential;
391     }
392 
393     public void setBindCredential(final String bindCredential) {
394         this.bindCredential = bindCredential;
395     }
396 
397     public String getBaseDn() {
398         return baseDn;
399     }
400 
401     public void setBaseDn(final String baseDn) {
402         this.baseDn = baseDn;
403     }
404 
405     public boolean isDisablePooling() {
406         return disablePooling;
407     }
408 
409     public void setDisablePooling(final boolean disablePooling) {
410         this.disablePooling = disablePooling;
411     }
412 
413     public int getMinPoolSize() {
414         return minPoolSize;
415     }
416 
417     public void setMinPoolSize(final int minPoolSize) {
418         this.minPoolSize = minPoolSize;
419     }
420 
421     public int getMaxPoolSize() {
422         return maxPoolSize;
423     }
424 
425     public void setMaxPoolSize(final int maxPoolSize) {
426         this.maxPoolSize = maxPoolSize;
427     }
428 
429     public LdapConnectionPoolPassivator getPoolPassivator() {
430         return poolPassivator;
431     }
432 
433     public void setPoolPassivator(final LdapConnectionPoolPassivator poolPassivator) {
434         this.poolPassivator = poolPassivator;
435     }
436 
437     public LdapHostnameVerifier getHostnameVerifier() {
438         return hostnameVerifier;
439     }
440 
441     public void setHostnameVerifier(final LdapHostnameVerifier hostnameVerifier) {
442         this.hostnameVerifier = hostnameVerifier;
443     }
444 
445     public LdapTrustManager getTrustManager() {
446         return trustManager;
447     }
448 
449     public void setTrustManager(final LdapTrustManager trustManager) {
450         this.trustManager = trustManager;
451     }
452 
453     public boolean isValidateOnCheckout() {
454         return validateOnCheckout;
455     }
456 
457     public void setValidateOnCheckout(final boolean validateOnCheckout) {
458         this.validateOnCheckout = validateOnCheckout;
459     }
460 
461     public boolean isValidatePeriodically() {
462         return validatePeriodically;
463     }
464 
465     public void setValidatePeriodically(final boolean validatePeriodically) {
466         this.validatePeriodically = validatePeriodically;
467     }
468 
469     public Duration getValidateTimeout() {
470         return validateTimeout;
471     }
472 
473     public void setValidateTimeout(final Duration validateTimeout) {
474         this.validateTimeout = validateTimeout;
475     }
476 
477     public Duration getValidatePeriod() {
478         return validatePeriod;
479     }
480 
481     public void setValidatePeriod(final Duration validatePeriod) {
482         this.validatePeriod = validatePeriod;
483     }
484 
485     public boolean isFailFast() {
486         return failFast;
487     }
488 
489     public void setFailFast(final boolean failFast) {
490         this.failFast = failFast;
491     }
492 
493     public Duration getIdleTime() {
494         return idleTime;
495     }
496 
497     public void setIdleTime(final Duration idleTime) {
498         this.idleTime = idleTime;
499     }
500 
501     public Duration getPrunePeriod() {
502         return prunePeriod;
503     }
504 
505     public void setPrunePeriod(final Duration prunePeriod) {
506         this.prunePeriod = prunePeriod;
507     }
508 
509     public Duration getBlockWaitTime() {
510         return blockWaitTime;
511     }
512 
513     public void setBlockWaitTime(final Duration blockWaitTime) {
514         this.blockWaitTime = blockWaitTime;
515     }
516 
517     public LdapConnectionStrategy getConnectionStrategy() {
518         return connectionStrategy;
519     }
520 
521     public void setConnectionStrategy(final LdapConnectionStrategy connectionStrategy) {
522         this.connectionStrategy = connectionStrategy;
523     }
524 
525     public boolean isUseStartTls() {
526         return useStartTls;
527     }
528 
529     public void setUseStartTls(final boolean useStartTls) {
530         this.useStartTls = useStartTls;
531     }
532 
533     public Duration getConnectTimeout() {
534         return connectTimeout;
535     }
536 
537     public void setConnectTimeout(final Duration connectTimeout) {
538         this.connectTimeout = connectTimeout;
539     }
540 
541     public Duration getResponseTimeout() {
542         return responseTimeout;
543     }
544 
545     public void setResponseTimeout(final Duration responseTimeout) {
546         this.responseTimeout = responseTimeout;
547     }
548 
549     public boolean isAllowMultipleDns() {
550         return allowMultipleDns;
551     }
552 
553     public void setAllowMultipleDns(final boolean allowMultipleDns) {
554         this.allowMultipleDns = allowMultipleDns;
555     }
556 
557     public boolean isAllowMultipleEntries() {
558         return allowMultipleEntries;
559     }
560 
561     public void setAllowMultipleEntries(final boolean allowMultipleEntries) {
562         this.allowMultipleEntries = allowMultipleEntries;
563     }
564 
565     public boolean isFollowReferrals() {
566         return followReferrals;
567     }
568 
569     public void setFollowReferrals(final boolean followReferrals) {
570         this.followReferrals = followReferrals;
571     }
572 
573     public List<String> getBinaryAttributes() {
574         return binaryAttributes;
575     }
576 
577     public void setBinaryAttributes(final List<String> binaryAttributes) {
578         this.binaryAttributes = binaryAttributes;
579     }
580 }