Mass removal of all Tabs (Style Warnings)
[aaf/authz.git] / cadi / core / src / main / java / org / onap / aaf / cadi / config / SecurityInfo.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
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  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.cadi.config;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.net.InetAddress;
28 import java.net.UnknownHostException;
29 import java.rmi.AccessException;
30 import java.security.KeyManagementException;
31 import java.security.KeyStore;
32 import java.security.KeyStoreException;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.UnrecoverableKeyException;
35 import java.security.cert.CertificateException;
36 import java.security.cert.X509Certificate;
37 import java.util.ArrayList;
38
39 import javax.net.ssl.HostnameVerifier;
40 import javax.net.ssl.HttpsURLConnection;
41 import javax.net.ssl.KeyManager;
42 import javax.net.ssl.KeyManagerFactory;
43 import javax.net.ssl.SSLContext;
44 import javax.net.ssl.SSLSession;
45 import javax.net.ssl.SSLSocketFactory;
46 import javax.net.ssl.TrustManager;
47 import javax.net.ssl.TrustManagerFactory;
48 import javax.net.ssl.X509KeyManager;
49 import javax.net.ssl.X509TrustManager;
50
51 import org.onap.aaf.cadi.Access;
52 import org.onap.aaf.cadi.CadiException;
53 import org.onap.aaf.cadi.Access.Level;
54 import org.onap.aaf.cadi.util.MaskFormatException;
55 import org.onap.aaf.cadi.util.NetMask;
56
57 public class SecurityInfo {
58     private static final String SECURITY_ALGO = "RSA";
59     private static final String HTTPS_PROTOCOLS = "https.protocols";
60     private static final String JDK_TLS_CLIENT_PROTOCOLS = "jdk.tls.client.protocols";
61
62     public static final String HTTPS_PROTOCOLS_DEFAULT = "TLSv1.1,TLSv1.2";
63     public static final String REGEX_COMMA = "\\s*,\\s*";
64     public static final String SSL_KEY_MANAGER_FACTORY_ALGORITHM;
65     
66     private SSLSocketFactory socketFactory;
67     private X509KeyManager[] x509KeyManager;
68     private X509TrustManager[] x509TrustManager;
69     public final String defaultAlias;
70     private NetMask[] trustMasks;
71     private SSLContext context;
72     private HostnameVerifier maskHV;
73     public final Access access;
74
75     // Change Key Algorithms for IBM's VM.  Could put in others, if needed.
76     static {
77         if ("IBM Corporation".equalsIgnoreCase(System.getProperty("java.vm.vendor"))) {
78             SSL_KEY_MANAGER_FACTORY_ALGORITHM = "IbmX509";
79         } else {
80             SSL_KEY_MANAGER_FACTORY_ALGORITHM = "SunX509";
81         }
82     }
83     
84
85     public SecurityInfo(final Access access) throws CadiException {
86         try {
87             this.access = access;
88             // reuse DME2 Properties for convenience if specific Properties don't exist
89             
90             initializeKeyManager();
91             
92             initializeTrustManager();
93             
94             defaultAlias = access.getProperty(Config.CADI_ALIAS, null);
95             
96             initializeTrustMasks();
97
98             String httpsProtocols = Config.logProp(access, Config.CADI_PROTOCOLS,
99                         access.getProperty(HTTPS_PROTOCOLS, HTTPS_PROTOCOLS_DEFAULT)
100                         );
101             System.setProperty(HTTPS_PROTOCOLS, httpsProtocols);
102             System.setProperty(JDK_TLS_CLIENT_PROTOCOLS, httpsProtocols);
103             if ("1.7".equals(System.getProperty("java.specification.version")) && httpsProtocols.contains("TLSv1.2")) {
104                 System.setProperty(Config.HTTPS_CIPHER_SUITES, Config.HTTPS_CIPHER_SUITES_DEFAULT);
105             }            
106
107             context = SSLContext.getInstance("TLS");
108             context.init(x509KeyManager, x509TrustManager, null);
109             SSLContext.setDefault(context);
110             socketFactory = context.getSocketFactory();
111         } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | CertificateException | UnrecoverableKeyException | IOException e) {
112             throw new CadiException(e);
113         }
114     }
115
116     /**
117      * @return the scf
118      */
119     public SSLSocketFactory getSSLSocketFactory() {
120         return socketFactory;
121     }
122
123     public SSLContext getSSLContext() {
124         return context;
125     }
126
127     /**
128      * @return the km
129      */
130     public X509KeyManager[] getKeyManagers() {
131         return x509KeyManager;
132     }
133
134     public void checkClientTrusted(X509Certificate[] certarr) throws CertificateException {
135         for (X509TrustManager xtm : x509TrustManager) {
136             xtm.checkClientTrusted(certarr, SECURITY_ALGO);
137         }
138     }
139
140     public void checkServerTrusted(X509Certificate[] certarr) throws CertificateException {
141         for (X509TrustManager xtm : x509TrustManager) {
142             xtm.checkServerTrusted(certarr, SECURITY_ALGO);
143         }
144     }
145
146     public void setSocketFactoryOn(HttpsURLConnection hsuc) {
147         hsuc.setSSLSocketFactory(socketFactory);
148         if (maskHV != null && !maskHV.equals(hsuc.getHostnameVerifier())) {
149             hsuc.setHostnameVerifier(maskHV);
150         }
151     }
152     
153     protected void initializeKeyManager() throws CadiException, IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, UnrecoverableKeyException {
154         String keyStore = access.getProperty(Config.CADI_KEYSTORE, null);
155         if (keyStore != null && !new File(keyStore).exists()) {
156             throw new CadiException(keyStore + " does not exist");
157         }
158
159         String keyStorePasswd = access.getProperty(Config.CADI_KEYSTORE_PASSWORD, null);
160         keyStorePasswd = (keyStorePasswd == null) ? null : access.decrypt(keyStorePasswd, false);
161         if (keyStore == null || keyStorePasswd == null) { 
162             x509KeyManager = new X509KeyManager[0];
163             return;
164         }
165
166         String keyPasswd = access.getProperty(Config.CADI_KEY_PASSWORD, null);
167         keyPasswd = (keyPasswd == null) ? keyStorePasswd : access.decrypt(keyPasswd, false);
168
169         KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(SSL_KEY_MANAGER_FACTORY_ALGORITHM);
170
171         ArrayList<X509KeyManager> keyManagers = new ArrayList<>();
172         File file;
173         for (String ksname : keyStore.split(REGEX_COMMA)) {
174             String keystoreFormat;
175             if (ksname.endsWith(".p12") || ksname.endsWith(".pkcs12")) {
176                 keystoreFormat = "PKCS12";
177             } else {
178                 keystoreFormat = "JKS";
179             }
180
181             file = new File(ksname);
182             if (file.exists()) {
183                 FileInputStream fis = new FileInputStream(file);
184                 try {
185                     KeyStore ks = KeyStore.getInstance(keystoreFormat);
186                     ks.load(fis, keyStorePasswd.toCharArray());
187                     keyManagerFactory.init(ks, keyPasswd.toCharArray());
188                 } finally {
189                     fis.close();
190                 }
191             }
192         }
193         for (KeyManager keyManager : keyManagerFactory.getKeyManagers()) {
194             if (keyManager instanceof X509KeyManager) {
195                 keyManagers.add((X509KeyManager)keyManager);
196             }
197         }
198         x509KeyManager = new X509KeyManager[keyManagers.size()];
199         keyManagers.toArray(x509KeyManager);
200     }
201
202     protected void initializeTrustManager() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException, CadiException {
203         String trustStore = access.getProperty(Config.CADI_TRUSTSTORE, null);
204         if (trustStore != null && !new File(trustStore).exists()) {
205             throw new CadiException(trustStore + " does not exist");
206         }
207
208         if (trustStore == null) {
209             return;
210         }
211
212         String trustStorePasswd = access.getProperty(Config.CADI_TRUSTSTORE_PASSWORD, null);
213         trustStorePasswd = (trustStorePasswd == null) ? "changeit"/*defacto Java Trust Pass*/ : access.decrypt(trustStorePasswd, false);
214
215         TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(SSL_KEY_MANAGER_FACTORY_ALGORITHM);
216         File file;
217         for (String trustStoreName : trustStore.split(REGEX_COMMA)) {
218             file = new File(trustStoreName);
219             if (file.exists()) {
220                 FileInputStream fis = new FileInputStream(file);
221                 try {
222                     KeyStore ts = KeyStore.getInstance("JKS");
223                     ts.load(fis, trustStorePasswd.toCharArray());
224                     trustManagerFactory.init(ts); 
225                 } finally {
226                     fis.close();
227                 }
228             }
229         }
230
231         TrustManager trustManagers[] = trustManagerFactory.getTrustManagers();
232         if (trustManagers == null || trustManagers.length == 0) {
233             return;
234         }
235
236         x509TrustManager = new X509TrustManager[trustManagers.length];
237         for (int i = 0; i < trustManagers.length; ++i) {
238             try {
239                 x509TrustManager[i] = (X509TrustManager)trustManagers[i];
240             } catch (ClassCastException e) {
241                 access.log(Level.WARN, "Non X509 TrustManager", x509TrustManager[i].getClass().getName(), "skipped in SecurityInfo");
242             }
243         }
244     }
245     
246     protected void initializeTrustMasks() throws AccessException {
247         String tips = access.getProperty(Config.CADI_TRUST_MASKS, null);
248         if (tips == null) {
249             return;
250         }
251
252         access.log(Level.INIT, "Explicitly accepting valid X509s from", tips);
253         String[] ipsplit = tips.split(REGEX_COMMA);
254         trustMasks = new NetMask[ipsplit.length];
255         for (int i = 0; i < ipsplit.length; ++i) {
256             try {
257                 trustMasks[i] = new NetMask(ipsplit[i]);
258             } catch (MaskFormatException e) {
259                 throw new AccessException("Invalid IP Mask in " + Config.CADI_TRUST_MASKS, e);
260             }
261         }
262     
263         final HostnameVerifier origHV = HttpsURLConnection.getDefaultHostnameVerifier();
264         maskHV = new HostnameVerifier() {
265             @Override
266             public boolean verify(final String urlHostName, final SSLSession session) {
267                 try {
268                     // This will pick up /etc/host entries as well as DNS
269                     InetAddress ia = InetAddress.getByName(session.getPeerHost());
270                     for (NetMask tmask : trustMasks) {
271                         if (tmask.isInNet(ia.getHostAddress())) {
272                             return true;
273                         }
274                     }
275                 } catch (UnknownHostException e) {
276                     // It's ok. do normal Verify
277                 }
278                 return origHV.verify(urlHostName, session);
279             };
280         };
281         HttpsURLConnection.setDefaultHostnameVerifier(maskHV);
282     }
283     
284 }