View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2016 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.caravan.jaxws.consumer.impl;
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileNotFoundException;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.security.GeneralSecurityException;
28  import java.security.KeyStore;
29  
30  import javax.net.ssl.KeyManagerFactory;
31  import javax.net.ssl.TrustManagerFactory;
32  
33  import org.apache.commons.lang3.StringUtils;
34  
35  import io.wcm.caravan.jaxws.consumer.JaxWsClientInitializer;
36  
37  /**
38   * Helper class for loading certificates for SSL communication.
39   */
40  public final class CertificateLoader {
41  
42    /**
43     * Default SSL context type
44     */
45    public static final String SSL_CONTEXT_TYPE_DEFAULT = "TLS";
46  
47    /**
48     * Default key manager type
49     */
50    public static final String KEY_MANAGER_TYPE_DEFAULT = "SunX509";
51  
52    /**
53     * Default key store type
54     */
55    public static final String KEY_STORE_TYPE_DEFAULT = "PKCS12";
56  
57    /**
58     * Default trust manager type
59     */
60    public static final String TRUST_MANAGER_TYPE_DEFAULT = "SunX509";
61  
62    /**
63     * Default trust store type
64     */
65    public static final String TRUST_STORE_TYPE_DEFAULT = "JKS";
66  
67  
68    private CertificateLoader() {
69      // static methods only
70    }
71  
72    /**
73     * Get key manager factory
74     * @param config Config
75     * @return Key manager factory
76     * @throws IOException
77     * @throws GeneralSecurityException
78     */
79    public static KeyManagerFactory getKeyManagerFactory(JaxWsClientInitializer config)
80        throws IOException, GeneralSecurityException {
81      return getKeyManagerFactory(config.getKeyStorePath(), new StoreProperties(config.getKeyStorePassword(),
82          config.getKeyManagerType(), config.getKeyStoreType(), config.getKeyStoreProvider()));
83    }
84  
85    /**
86     * Get key manager factory
87     * @param keyStoreFilename Keystore file name
88     * @param storeProperties store properties
89     * @return Key manager factory
90     * @throws IOException
91     * @throws GeneralSecurityException
92     */
93    private static KeyManagerFactory getKeyManagerFactory(String keyStoreFilename, StoreProperties storeProperties)
94        throws IOException, GeneralSecurityException {
95      InputStream is = getResourceAsStream(keyStoreFilename);
96      if (is == null) {
97        throw new FileNotFoundException("Certificate file not found: " + getFilenameInfo(keyStoreFilename));
98      }
99      try {
100       return getKeyManagerFactory(is, storeProperties);
101     }
102     finally {
103       try {
104         is.close();
105       }
106       catch (IOException ex) {
107         // ignore
108       }
109     }
110   }
111 
112   /**
113    * Get key manager factory
114    * @param keyStoreStream Keystore input stream
115    * @param storeProperties store properties
116    * @return Key manager factory
117    * @throws IOException
118    * @throws GeneralSecurityException
119    */
120   private static KeyManagerFactory getKeyManagerFactory(InputStream keyStoreStream, StoreProperties storeProperties)
121       throws IOException, GeneralSecurityException {
122     // use provider if given, otherwise use the first matching security provider
123     final KeyStore ks;
124     if (StringUtils.isNotBlank(storeProperties.getProvider())) {
125       ks = KeyStore.getInstance(storeProperties.getType(), storeProperties.getProvider());
126     }
127     else {
128       ks = KeyStore.getInstance(storeProperties.getType());
129     }
130     ks.load(keyStoreStream, storeProperties.getPassword().toCharArray());
131     KeyManagerFactory kmf = KeyManagerFactory.getInstance(storeProperties.getManagerType());
132     kmf.init(ks, storeProperties.getPassword().toCharArray());
133     return kmf;
134   }
135 
136   /**
137    * Build TrustManagerFactory.
138    * @param config Config
139    * @return TrustManagerFactory
140    * @throws IOException
141    * @throws GeneralSecurityException
142    */
143   public static TrustManagerFactory getTrustManagerFactory(JaxWsClientInitializer config)
144       throws IOException, GeneralSecurityException {
145     return getTrustManagerFactory(config.getTrustStorePath(), new StoreProperties(config.getTrustStorePassword(),
146         config.getTrustManagerType(), config.getTrustStoreType(), config.getTrustStoreProvider()));
147   }
148 
149   /**
150    * Build TrustManagerFactory.
151    * @param trustStoreFilename Truststore file name
152    * @param storeProperties store properties
153    * @return TrustManagerFactory
154    * @throws IOException
155    * @throws GeneralSecurityException
156    */
157   private static TrustManagerFactory getTrustManagerFactory(String trustStoreFilename, StoreProperties storeProperties)
158       throws IOException, GeneralSecurityException {
159     InputStream is = getResourceAsStream(trustStoreFilename);
160     if (is == null) {
161       throw new FileNotFoundException("Certificate file not found: " + getFilenameInfo(trustStoreFilename));
162     }
163     try {
164       return getTrustManagerFactory(is, storeProperties);
165     }
166     finally {
167       try {
168         is.close();
169       }
170       catch (IOException ex) {
171         // ignore
172       }
173     }
174   }
175 
176   /**
177    * Build TrustManagerFactory.
178    * @param trustStoreStream Truststore input stream
179    * @param storeProperties store properties
180    * @return TrustManagerFactory
181    * @throws IOException
182    * @throws GeneralSecurityException
183    */
184   private static TrustManagerFactory getTrustManagerFactory(InputStream trustStoreStream, StoreProperties storeProperties)
185       throws IOException, GeneralSecurityException {
186     // use provider if given, otherwise use the first matching security provider
187     final KeyStore ks;
188     if (StringUtils.isNotBlank(storeProperties.getProvider())) {
189       ks = KeyStore.getInstance(storeProperties.getType(), storeProperties.getProvider());
190     }
191     else {
192       ks = KeyStore.getInstance(storeProperties.getType());
193     }
194     ks.load(trustStoreStream, storeProperties.getPassword().toCharArray());
195     TrustManagerFactory tmf = TrustManagerFactory.getInstance(storeProperties.getManagerType());
196     tmf.init(ks);
197     return tmf;
198   }
199 
200   /**
201    * Tries to load the given resource as file, or if no file exists as classpath resource.
202    * @param path Filesystem or classpath path
203    * @return InputStream or null if neither file nor classpath resource is found
204    * @throws IOException
205    */
206   private static InputStream getResourceAsStream(String path) throws IOException {
207     if (StringUtils.isEmpty(path)) {
208       return null;
209     }
210 
211     // first try to load as file
212     File file = new File(path);
213     if (file.exists() && file.isFile()) {
214       return new FileInputStream(file);
215     }
216 
217     // if not a file fallback to classloder resource
218     return CertificateLoader.class.getResourceAsStream(path);
219   }
220 
221   /**
222    * Generate filename info for given path for error messages.
223    * @param path Path
224    * @return Absolute path
225    */
226   private static String getFilenameInfo(String path) {
227     if (StringUtils.isEmpty(path)) {
228       return null;
229     }
230     try {
231       return new File(path).getCanonicalPath();
232     }
233     catch (IOException ex) {
234       return new File(path).getAbsolutePath();
235     }
236   }
237 
238   /**
239    * Checks whether a SSL key store is configured.
240    * @param config Http client configuration
241    * @return true if client certificates are enabled
242    */
243   public static boolean isSslKeyManagerEnabled(JaxWsClientInitializer config) {
244     return StringUtils.isNotEmpty(config.getSslContextType())
245         && StringUtils.isNotEmpty(config.getKeyManagerType())
246         && StringUtils.isNotEmpty(config.getKeyStoreType())
247         && StringUtils.isNotEmpty(config.getKeyStorePath());
248   }
249 
250   /**
251    * Checks whether a SSL trust store is configured.
252    * @param config Http client configuration
253    * @return true if client certificates are enabled
254    */
255   public static boolean isSslTrustStoreEnbaled(JaxWsClientInitializer config) {
256     return StringUtils.isNotEmpty(config.getSslContextType())
257         && StringUtils.isNotEmpty(config.getTrustManagerType())
258         && StringUtils.isNotEmpty(config.getTrustStoreType())
259         && StringUtils.isNotEmpty(config.getTrustStorePath());
260   }
261 
262 }