f63de20c4bccceb1b8e7a1fdb4905ac26294c66d
[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 }