View Javadoc
1   /*
2    * Copyright 2019 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.data.ldaptive;
18  
19  import static org.springframework.util.Assert.notNull;
20  
21  import java.util.function.Predicate;
22  import org.ldaptive.BindConnectionInitializer;
23  import org.ldaptive.ClosedRetryMetadata;
24  import org.ldaptive.ConnectionConfig;
25  import org.ldaptive.ConnectionInitializer;
26  import org.ldaptive.Credential;
27  import org.ldaptive.RetryMetadata;
28  import org.ldaptive.ssl.CredentialConfig;
29  import org.ldaptive.ssl.SslConfig;
30  import org.ldaptive.ssl.X509CredentialConfig;
31  import org.springframework.util.StringUtils;
32  
33  /**
34   * The connection config factory.
35   *
36   * @author Christian Bremer
37   */
38  @SuppressWarnings("unused")
39  public interface LdaptiveConnectionConfigFactory {
40  
41    /**
42     * Create connection config.
43     *
44     * @param properties the properties
45     * @return the connection config
46     */
47    default ConnectionConfig createConnectionConfig(LdaptiveProperties properties) {
48      notNull(properties, "Ldaptive properties must not be null.");
49      return createConnectionConfig(
50          properties,
51          properties.getBindDn(),
52          properties.getBindCredentials());
53    }
54  
55    /**
56     * Create connection config.
57     *
58     * @param properties the properties
59     * @param bindDn the bind dn
60     * @param bindCredential the bind credential
61     * @return the connection config
62     */
63    ConnectionConfig createConnectionConfig(
64        LdaptiveProperties properties,
65        String bindDn,
66        String bindCredential);
67  
68    /**
69     * Get default connection config factory.
70     *
71     * @return the default connection config factory
72     */
73    static LdaptiveConnectionConfigFactory defaultFactory() {
74      return new Default();
75    }
76  
77    /**
78     * The default connection config factory.
79     */
80    class Default implements LdaptiveConnectionConfigFactory {
81  
82      @Override
83      public ConnectionConfig createConnectionConfig(
84          final LdaptiveProperties properties,
85          final String bindDn,
86          final String bindCredentials) {
87  
88        notNull(properties, "Ldaptive properties must not be null.");
89        return ConnectionConfig.builder()
90            .autoReconnect(properties.isAutoReconnect())
91            .autoReconnectCondition(autoReconnectCondition(properties))
92            .autoReplay(properties.isAutoReplay())
93            .connectionInitializers(connectionInitializers(properties, bindDn, bindCredentials))
94            .connectTimeout(properties.getConnectTimeout())
95            .reconnectTimeout(properties.getReconnectTimeout())
96            .responseTimeout(properties.getResponseTimeout())
97            .sslConfig(sslConfig(properties))
98            .url(properties.getLdapUrl())
99            .useStartTLS(properties.isUseStartTls())
100           .build();
101     }
102 
103     private Predicate<RetryMetadata> autoReconnectCondition(LdaptiveProperties properties) {
104       return metadata -> {
105         if (properties.getReconnectAttempts() > 0 && metadata instanceof ClosedRetryMetadata) {
106           if (metadata.getAttempts() > properties.getReconnectAttempts()) {
107             return false;
108           }
109           if (metadata.getAttempts() > 0) {
110             try {
111               long delay = Math.abs(properties.getReconnectBackoffDelay().toMillis());
112               double multiplier = Math.abs(properties.getReconnectBackoffMultiplier() * metadata.getAttempts());
113               int attempts = metadata.getAttempts();
114               long millis = Math.round(delay * multiplier * attempts);
115               Thread.sleep(millis);
116             } catch (InterruptedException e) {
117               // nothing to do
118             }
119           }
120           return true;
121         }
122         return false;
123       };
124     }
125 
126     private ConnectionInitializer[] connectionInitializers(
127         LdaptiveProperties properties,
128         String bindDn,
129         String bindCredentials) {
130 
131       String username;
132       String password;
133       if (StringUtils.hasText(bindDn)) {
134         username = bindDn;
135         password = bindCredentials;
136       } else {
137         username = properties.getBindDn();
138         password = properties.getBindCredentials();
139       }
140       if (StringUtils.hasText(username)) {
141         return new ConnectionInitializer[]{
142             connectionInitializer(username, password)
143         };
144       }
145       return new ConnectionInitializer[]{};
146     }
147 
148     private ConnectionInitializer connectionInitializer(String bindDn, String bindCredential) {
149       // sasl is not supported at the moment
150       final BindConnectionInitializer bci = new BindConnectionInitializer();
151       bci.setBindDn(bindDn);
152       bci.setBindCredential(new Credential(bindCredential));
153       return bci;
154     }
155 
156     private SslConfig sslConfig(LdaptiveProperties properties) {
157       if (hasSslConfig(properties)) {
158         SslConfig sc = new SslConfig();
159         sc.setCredentialConfig(sslCredentialConfig(properties));
160         return sc;
161       }
162       return null;
163     }
164 
165     private boolean hasSslConfig(LdaptiveProperties properties) {
166       return StringUtils.hasText(properties.getTrustCertificates())
167           || StringUtils.hasText(properties.getAuthenticationCertificate())
168           || StringUtils.hasText(properties.getAuthenticationKey());
169     }
170 
171     private CredentialConfig sslCredentialConfig(LdaptiveProperties properties) {
172       X509CredentialConfig x509 = new X509CredentialConfig();
173       if (StringUtils.hasText(properties.getAuthenticationCertificate())) {
174         x509.setAuthenticationCertificate(properties.getAuthenticationCertificate());
175       }
176       if (StringUtils.hasText(properties.getAuthenticationKey())) {
177         x509.setAuthenticationKey(properties.getAuthenticationKey());
178       }
179       if (StringUtils.hasText(properties.getTrustCertificates())) {
180         x509.setTrustCertificates(properties.getTrustCertificates());
181       }
182       return x509;
183     }
184 
185   }
186 }