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   */
33  public class SSLParametersConfiguration extends ContextAwareBase {
34  
35      private String includedProtocols;
36      private String excludedProtocols;
37      private String includedCipherSuites;
38      private String excludedCipherSuites;
39      private Boolean needClientAuth;
40      private Boolean wantClientAuth;
41      private String[] enabledProtocols;
42      private String[] enabledCipherSuites;
43  
44      /**
45       * Configures SSL parameters on an {@link SSLConfigurable}.
46       * @param socket the subject configurable
47       */
48      public void configure(SSLConfigurable socket) {
49          socket.setEnabledProtocols(enabledProtocols(socket.getSupportedProtocols(), socket.getDefaultProtocols()));
50          socket.setEnabledCipherSuites(enabledCipherSuites(socket.getSupportedCipherSuites(), socket.getDefaultCipherSuites()));
51          if (isNeedClientAuth() != null) {
52              socket.setNeedClientAuth(isNeedClientAuth());
53          }
54          if (isWantClientAuth() != null) {
55              socket.setWantClientAuth(isWantClientAuth());
56          }
57      }
58  
59      /**
60       * Gets the set of enabled protocols based on the configuration.
61       * @param supportedProtocols protocols supported by the SSL engine 
62       * @param defaultProtocols default protocols enabled by the SSL engine
63       * @return enabled protocols
64       */
65      private String[] enabledProtocols(String[] supportedProtocols, String[] defaultProtocols) {
66          if (enabledProtocols == null) {
67              // we're assuming that the same engine is used for all configurables
68              // so once we determine the enabled set, we won't do it again
69              if (OptionHelper.isEmpty(getIncludedProtocols()) && OptionHelper.isEmpty(getExcludedProtocols())) {
70                  enabledProtocols = Arrays.copyOf(defaultProtocols, defaultProtocols.length);
71              } else {
72                  enabledProtocols = includedStrings(supportedProtocols, getIncludedProtocols(), getExcludedProtocols());
73              }
74              for (String protocol : enabledProtocols) {
75                  addInfo("enabled protocol: " + protocol);
76              }
77          }
78          return enabledProtocols;
79      }
80  
81      /**
82       * Gets the set of enabled cipher suites based on the configuration.
83       * @param supportedCipherSuites cipher suites supported by the SSL engine 
84       * @param defaultCipherSuites default cipher suites enabled by the SSL engine
85       * @return enabled cipher suites
86       */
87      private String[] enabledCipherSuites(String[] supportedCipherSuites, String[] defaultCipherSuites) {
88          if (enabledCipherSuites == null) {
89              // we're assuming that the same engine is used for all configurables
90              // so once we determine the enabled set, we won't do it again
91              if (OptionHelper.isEmpty(getIncludedCipherSuites()) && OptionHelper.isEmpty(getExcludedCipherSuites())) {
92                  enabledCipherSuites = Arrays.copyOf(defaultCipherSuites, defaultCipherSuites.length);
93              } else {
94                  enabledCipherSuites = includedStrings(supportedCipherSuites, getIncludedCipherSuites(), getExcludedCipherSuites());
95              }
96              for (String cipherSuite : enabledCipherSuites) {
97                  addInfo("enabled cipher suite: " + cipherSuite);
98              }
99          }
100         return enabledCipherSuites;
101     }
102 
103     /**
104      * Applies include and exclude patterns to an array of default string values
105      * to produce an array of strings included by the patterns.
106      * @param defaults default list of string values
107      * @param included comma-separated patterns that identity values to include
108      * @param excluded comma-separated patterns that identity string to exclude
109      * @return an array of strings containing those strings from {@code defaults}
110      *    that match at least one pattern in {@code included} that are not
111      *    matched by any pattern in {@code excluded}
112      */
113     private String[] includedStrings(String[] defaults, String included, String excluded) {
114         List<String> values = new ArrayList<String>(defaults.length);
115         values.addAll(Arrays.asList(defaults));
116         if (included != null) {
117             StringCollectionUtil.retainMatching(values, stringToArray(included));
118         }
119         if (excluded != null) {
120             StringCollectionUtil.removeMatching(values, stringToArray(excluded));
121         }
122         return values.toArray(new String[values.size()]);
123     }
124 
125     /**
126      * Splits a string containing comma-separated values into an array.
127      * @param s the subject string
128      * @return array of values contained in {@code s}
129      */
130     private String[] stringToArray(String s) {
131         return s.split("\\s*,\\s*");
132     }
133 
134     /**
135      * Gets the JSSE secure transport protocols to include.
136      * @return a string containing comma-separated JSSE secure transport 
137      *    protocol names (e.g. {@code TLSv1})
138      */
139     public String getIncludedProtocols() {
140         return includedProtocols;
141     }
142 
143     /**
144      * Sets the JSSE secure transport protocols to include.
145      * @param protocols a string containing comma-separated JSSE secure 
146      *    transport protocol names
147      * @see Java Cryptography Architecture Standard Algorithm Name Documentation
148      */
149     public void setIncludedProtocols(String protocols) {
150         this.includedProtocols = protocols;
151     }
152 
153     /**
154      * Gets the JSSE secure transport protocols to exclude.
155      * @return a string containing comma-separated JSSE secure transport 
156      *    protocol names (e.g. {@code TLSv1})
157      */
158     public String getExcludedProtocols() {
159         return excludedProtocols;
160     }
161 
162     /**
163      * Sets the JSSE secure transport protocols to exclude.
164      * @param protocols a string containing comma-separated JSSE secure 
165      *    transport protocol names
166      * @see Java Cryptography Architecture Standard Algorithm Name Documentation
167      */
168     public void setExcludedProtocols(String protocols) {
169         this.excludedProtocols = protocols;
170     }
171 
172     /**
173      * Gets the JSSE cipher suite names to include.
174      * @return a string containing comma-separated JSSE cipher suite names
175      *    (e.g. {@code TLS_DHE_RSA_WITH_AES_256_CBC_SHA})
176      */
177     public String getIncludedCipherSuites() {
178         return includedCipherSuites;
179     }
180 
181     /**
182      * Sets the JSSE cipher suite names to include.
183      * @param cipherSuites a string containing comma-separated JSSE cipher
184      *    suite names
185      * @see Java Cryptography Architecture Standard Algorithm Name Documentation
186      */
187     public void setIncludedCipherSuites(String cipherSuites) {
188         this.includedCipherSuites = cipherSuites;
189     }
190 
191     /**
192      * Gets the JSSE cipher suite names to exclude.
193      * @return a string containing comma-separated JSSE cipher suite names
194      *    (e.g. {@code TLS_DHE_RSA_WITH_AES_256_CBC_SHA})
195      */
196     public String getExcludedCipherSuites() {
197         return excludedCipherSuites;
198     }
199 
200     /**
201      * Sets the JSSE cipher suite names to exclude.
202      * @param cipherSuites a string containing comma-separated JSSE cipher
203      *    suite names
204      * @see Java Cryptography Architecture Standard Algorithm Name Documentation
205      */
206     public void setExcludedCipherSuites(String cipherSuites) {
207         this.excludedCipherSuites = cipherSuites;
208     }
209 
210     /**
211      * Gets a flag indicating whether client authentication is required.
212      * @return flag state
213      */
214     public Boolean isNeedClientAuth() {
215         return needClientAuth;
216     }
217 
218     /**
219      * Sets a flag indicating whether client authentication is required.
220      * @param needClientAuth the flag state to set
221      */
222     public void setNeedClientAuth(Boolean needClientAuth) {
223         this.needClientAuth = needClientAuth;
224     }
225 
226     /**
227      * Gets a flag indicating whether client authentication is desired.
228      * @return flag state
229      */
230     public Boolean isWantClientAuth() {
231         return wantClientAuth;
232     }
233 
234     /**
235      * Sets a flag indicating whether client authentication is desired.
236      * @param wantClientAuth the flag state to set
237      */
238     public void setWantClientAuth(Boolean wantClientAuth) {
239         this.wantClientAuth = wantClientAuth;
240     }
241 
242 }