View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.net.ssl;
15  
16  import java.util.ArrayList;
17  import java.util.Arrays;
18  import java.util.List;
19  
20  import javax.net.ssl.SSLEngine;
21  
22  import org.codehaus.janino.Java;
23  
24  import ch.qos.logback.core.spi.ContextAwareBase;
25  import ch.qos.logback.core.util.OptionHelper;
26  import ch.qos.logback.core.util.StringCollectionUtil;
27  
28  /**
29   * A configuration of SSL parameters for an {@link SSLEngine}.
30   *
31   * @author Carl Harris
32   * @author Bruno Harbulot
33   */
34  public class SSLParametersConfiguration extends ContextAwareBase {
35  
36      private String includedProtocols;
37      private String excludedProtocols;
38      private String includedCipherSuites;
39      private String excludedCipherSuites;
40      private Boolean needClientAuth;
41      private Boolean wantClientAuth;
42      private String[] enabledProtocols;
43      private String[] enabledCipherSuites;
44      private Boolean hostnameVerification;
45  
46      /**
47       * Configures SSL parameters on an {@link SSLConfigurable}.
48       * 
49       * @param socket the subject configurable
50       */
51      public void configure(SSLConfigurable socket) {
52          socket.setEnabledProtocols(enabledProtocols(socket.getSupportedProtocols(), socket.getDefaultProtocols()));
53          socket.setEnabledCipherSuites(
54                  enabledCipherSuites(socket.getSupportedCipherSuites(), socket.getDefaultCipherSuites()));
55          if (isNeedClientAuth() != null) {
56              socket.setNeedClientAuth(isNeedClientAuth());
57          }
58          if (isWantClientAuth() != null) {
59              socket.setWantClientAuth(isWantClientAuth());
60          }
61          if (hostnameVerification != null) {
62              addInfo("hostnameVerification=" + hostnameVerification);
63              socket.setHostnameVerification(hostnameVerification);
64          }
65      }
66  
67      public boolean getHostnameVerification() {
68          if (hostnameVerification == null)
69              return false;
70          return hostnameVerification;
71      }
72  
73      public void setHostnameVerification(boolean hostnameVerification) {
74          this.hostnameVerification = hostnameVerification;
75      }
76  
77      /**
78       * Gets the set of enabled protocols based on the configuration.
79       * 
80       * @param supportedProtocols protocols supported by the SSL engine
81       * @param defaultProtocols   default protocols enabled by the SSL engine
82       * @return enabled protocols
83       */
84      private String[] enabledProtocols(String[] supportedProtocols, String[] defaultProtocols) {
85          if (enabledProtocols == null) {
86              // we're assuming that the same engine is used for all configurables
87              // so once we determine the enabled set, we won't do it again
88              if (OptionHelper.isNullOrEmptyOrAllSpaces(getIncludedProtocols())
89                      && OptionHelper.isNullOrEmptyOrAllSpaces(getExcludedProtocols())) {
90                  enabledProtocols = Arrays.copyOf(defaultProtocols, defaultProtocols.length);
91              } else {
92                  enabledProtocols = includedStrings(supportedProtocols, getIncludedProtocols(), getExcludedProtocols());
93              }
94              for (String protocol : enabledProtocols) {
95                  addInfo("enabled protocol: " + protocol);
96              }
97          }
98          return enabledProtocols;
99      }
100 
101     /**
102      * Gets the set of enabled cipher suites based on the configuration.
103      * 
104      * @param supportedCipherSuites cipher suites supported by the SSL engine
105      * @param defaultCipherSuites   default cipher suites enabled by the SSL engine
106      * @return enabled cipher suites
107      */
108     private String[] enabledCipherSuites(String[] supportedCipherSuites, String[] defaultCipherSuites) {
109         if (enabledCipherSuites == null) {
110             // we're assuming that the same engine is used for all configurables
111             // so once we determine the enabled set, we won't do it again
112             if (OptionHelper.isNullOrEmptyOrAllSpaces(getIncludedCipherSuites())
113                     && OptionHelper.isNullOrEmptyOrAllSpaces(getExcludedCipherSuites())) {
114                 enabledCipherSuites = Arrays.copyOf(defaultCipherSuites, defaultCipherSuites.length);
115             } else {
116                 enabledCipherSuites = includedStrings(supportedCipherSuites, getIncludedCipherSuites(),
117                         getExcludedCipherSuites());
118             }
119             for (String cipherSuite : enabledCipherSuites) {
120                 addInfo("enabled cipher suite: " + cipherSuite);
121             }
122         }
123         return enabledCipherSuites;
124     }
125 
126     /**
127      * Applies include and exclude patterns to an array of default string values to
128      * produce an array of strings included by the patterns.
129      * 
130      * @param defaults default list of string values
131      * @param included comma-separated patterns that identity values to include
132      * @param excluded comma-separated patterns that identity string to exclude
133      * @return an array of strings containing those strings from {@code defaults}
134      *         that match at least one pattern in {@code included} that are not
135      *         matched by any pattern in {@code excluded}
136      */
137     private String[] includedStrings(String[] defaults, String included, String excluded) {
138         List<String> values = new ArrayList<String>(defaults.length);
139         values.addAll(Arrays.asList(defaults));
140         if (included != null) {
141             StringCollectionUtil.retainMatching(values, stringToArray(included));
142         }
143         if (excluded != null) {
144             StringCollectionUtil.removeMatching(values, stringToArray(excluded));
145         }
146         return values.toArray(new String[values.size()]);
147     }
148 
149     /**
150      * Splits a string containing comma-separated values into an array.
151      * 
152      * @param s the subject string
153      * @return array of values contained in {@code s}
154      */
155     private String[] stringToArray(String s) {
156         return s.split("\\s*,\\s*");
157     }
158 
159     /**
160      * Gets the JSSE secure transport protocols to include.
161      * 
162      * @return a string containing comma-separated JSSE secure transport protocol
163      *         names (e.g. {@code TLSv1})
164      */
165     public String getIncludedProtocols() {
166         return includedProtocols;
167     }
168 
169     /**
170      * Sets the JSSE secure transport protocols to include.
171      * 
172      * @param protocols a string containing comma-separated JSSE secure transport
173      *                  protocol names
174      * @see Java Cryptography Architecture Standard Algorithm Name Documentation
175      */
176     public void setIncludedProtocols(String protocols) {
177         this.includedProtocols = protocols;
178     }
179 
180     /**
181      * Gets the JSSE secure transport protocols to exclude.
182      * 
183      * @return a string containing comma-separated JSSE secure transport protocol
184      *         names (e.g. {@code TLSv1})
185      */
186     public String getExcludedProtocols() {
187         return excludedProtocols;
188     }
189 
190     /**
191      * Sets the JSSE secure transport protocols to exclude.
192      * 
193      * @param protocols a string containing comma-separated JSSE secure transport
194      *                  protocol names
195      * @see Java Cryptography Architecture Standard Algorithm Name Documentation
196      */
197     public void setExcludedProtocols(String protocols) {
198         this.excludedProtocols = protocols;
199     }
200 
201     /**
202      * Gets the JSSE cipher suite names to include.
203      * 
204      * @return a string containing comma-separated JSSE cipher suite names (e.g.
205      *         {@code TLS_DHE_RSA_WITH_AES_256_CBC_SHA})
206      */
207     public String getIncludedCipherSuites() {
208         return includedCipherSuites;
209     }
210 
211     /**
212      * Sets the JSSE cipher suite names to include.
213      * 
214      * @param cipherSuites a string containing comma-separated JSSE cipher suite
215      *                     names
216      * @see Java Cryptography Architecture Standard Algorithm Name Documentation
217      */
218     public void setIncludedCipherSuites(String cipherSuites) {
219         this.includedCipherSuites = cipherSuites;
220     }
221 
222     /**
223      * Gets the JSSE cipher suite names to exclude.
224      * 
225      * @return a string containing comma-separated JSSE cipher suite names (e.g.
226      *         {@code TLS_DHE_RSA_WITH_AES_256_CBC_SHA})
227      */
228     public String getExcludedCipherSuites() {
229         return excludedCipherSuites;
230     }
231 
232     /**
233      * Sets the JSSE cipher suite names to exclude.
234      * 
235      * @param cipherSuites a string containing comma-separated JSSE cipher suite
236      *                     names
237      * @see Java Cryptography Architecture Standard Algorithm Name Documentation
238      */
239     public void setExcludedCipherSuites(String cipherSuites) {
240         this.excludedCipherSuites = cipherSuites;
241     }
242 
243     /**
244      * Gets a flag indicating whether client authentication is required.
245      * 
246      * @return flag state
247      */
248     public Boolean isNeedClientAuth() {
249         return needClientAuth;
250     }
251 
252     /**
253      * Sets a flag indicating whether client authentication is required.
254      * 
255      * @param needClientAuth the flag state to set
256      */
257     public void setNeedClientAuth(Boolean needClientAuth) {
258         this.needClientAuth = needClientAuth;
259     }
260 
261     /**
262      * Gets a flag indicating whether client authentication is desired.
263      * 
264      * @return flag state
265      */
266     public Boolean isWantClientAuth() {
267         return wantClientAuth;
268     }
269 
270     /**
271      * Sets a flag indicating whether client authentication is desired.
272      * 
273      * @param wantClientAuth the flag state to set
274      */
275     public void setWantClientAuth(Boolean wantClientAuth) {
276         this.wantClientAuth = wantClientAuth;
277     }
278 
279 }