2d252ea941e61bc5433ef875b0d5e9ea757eb9b9
[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 SslKeyManagerFactoryAlgorithm;
65         
66         private SSLSocketFactory scf;
67         private X509KeyManager[] km;
68         private X509TrustManager[] tm;
69         public final String default_alias;
70         private NetMask[] trustMasks;
71         private SSLContext ctx;
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(System.getProperty("java.vm.vendor").equalsIgnoreCase("IBM Corporation")) {
78                         SslKeyManagerFactoryAlgorithm = "IbmX509";
79                 } else {
80                         SslKeyManagerFactoryAlgorithm = "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                         default_alias = access.getProperty(Config.CADI_ALIAS, null);
95                         
96                         initializeTrustMasks();
97
98                         String https_protocols = Config.logProp(access, Config.CADI_PROTOCOLS,
99                                                 access.getProperty(HTTPS_PROTOCOLS, HTTPS_PROTOCOLS_DEFAULT)
100                                                 );
101                         System.setProperty(HTTPS_PROTOCOLS, https_protocols);
102                         System.setProperty(JDK_TLS_CLIENT_PROTOCOLS, https_protocols);
103                         if("1.7".equals(System.getProperty("java.specification.version")) && https_protocols.contains("TLSv1.2")) {
104                                 System.setProperty(Config.HTTPS_CIPHER_SUITES, Config.HTTPS_CIPHER_SUITES_DEFAULT);
105                         }                       
106
107                         ctx = SSLContext.getInstance("TLS");
108                         ctx.init(km, tm, null);
109                         SSLContext.setDefault(ctx);
110                         scf = ctx.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 scf;
121         }
122
123         public SSLContext getSSLContext() {
124                 return ctx;
125         }
126
127         /**
128          * @return the km
129          */
130         public X509KeyManager[] getKeyManagers() {
131                 return km;
132         }
133
134         public void checkClientTrusted(X509Certificate[] certarr) throws CertificateException {
135                 for(X509TrustManager xtm : tm) {
136                         xtm.checkClientTrusted(certarr, SECURITY_ALGO);
137                 }
138         }
139
140         public void checkServerTrusted(X509Certificate[] certarr) throws CertificateException {
141                 for(X509TrustManager xtm : tm) {
142                         xtm.checkServerTrusted(certarr, SECURITY_ALGO);
143                 }
144         }
145
146         public void setSocketFactoryOn(HttpsURLConnection hsuc) {
147                 hsuc.setSSLSocketFactory(scf);
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
162                 String keyPasswd = access.getProperty(Config.CADI_KEY_PASSWORD, null);
163                 keyPasswd = (keyPasswd == null) ? keyStorePasswd : access.decrypt(keyPasswd, false);
164
165                 KeyManagerFactory kmf = KeyManagerFactory.getInstance(SslKeyManagerFactoryAlgorithm);
166                 if(keyStore == null || keyStorePasswd == null) { 
167                         km = new X509KeyManager[0];
168                 } else {
169                         ArrayList<X509KeyManager> kmal = new ArrayList<X509KeyManager>();
170                         File file;
171                         for(String ksname : keyStore.split(REGEX_COMMA)) {
172                                 file = new File(ksname);
173                                 String keystoreFormat;
174                                 if(ksname.endsWith(".p12") || ksname.endsWith(".pkcs12")) {
175                                         keystoreFormat = "PKCS12";
176                                 } else {
177                                         keystoreFormat = "JKS";
178                                 }
179                                 if(file.exists()) {
180                                         FileInputStream fis = new FileInputStream(file);
181                                         try {
182                                                 KeyStore ks = KeyStore.getInstance(keystoreFormat);
183                                                 ks.load(fis, keyStorePasswd.toCharArray());
184                                                 kmf.init(ks, keyPasswd.toCharArray());
185                                         } finally {
186                                                 fis.close();
187                                         }
188                                 }
189                         }
190                         for(KeyManager km : kmf.getKeyManagers()) {
191                                 if(km instanceof X509KeyManager) {
192                                         kmal.add((X509KeyManager)km);
193                                 }
194                         }
195                         km = new X509KeyManager[kmal.size()];
196                         kmal.toArray(km);
197                 }
198         }
199
200         protected void initializeTrustManager() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException, CadiException {
201                 String trustStore = access.getProperty(Config.CADI_TRUSTSTORE, null);
202                 if(trustStore != null && !new File(trustStore).exists()) {
203                         throw new CadiException(trustStore + " does not exist");
204                 }
205
206                 String trustStorePasswd = access.getProperty(Config.CADI_TRUSTSTORE_PASSWORD, null);
207                 trustStorePasswd = (trustStorePasswd == null) ? "changeit"/*defacto Java Trust Pass*/ : access.decrypt(trustStorePasswd, false);
208
209                 TrustManagerFactory tmf = TrustManagerFactory.getInstance(SslKeyManagerFactoryAlgorithm);
210                 if(trustStore != null) {
211                         File file;
212                         for(String tsname : trustStore.split(REGEX_COMMA)) {
213                                 file = new File(tsname);
214                                 if(file.exists()) {
215                                         FileInputStream fis = new FileInputStream(file);
216                                         try {
217                                                 KeyStore ts = KeyStore.getInstance("JKS");
218                                                 ts.load(fis, trustStorePasswd.toCharArray());
219                                                 tmf.init(ts); 
220                                         } finally {
221                                                 fis.close();
222                                         }
223                                 }
224                         }
225
226                         TrustManager tms[] = tmf.getTrustManagers();
227                         if(tms != null) {
228                                 tm = new X509TrustManager[(tms == null) ? 0 : tms.length];
229                                 for(int i = 0; i < tms.length; ++i) {
230                                         try {
231                                                 tm[i] = (X509TrustManager)tms[i];
232                                         } catch (ClassCastException e) {
233                                                 access.log(Level.WARN, "Non X509 TrustManager", tm[i].getClass().getName(), "skipped in SecurityInfo");
234                                         }
235                                 }
236                         }
237                 }
238
239         }
240         
241         protected void initializeTrustMasks() throws AccessException {
242                 String tips = access.getProperty(Config.CADI_TRUST_MASKS, null);
243                 if(tips != null) {
244                         access.log(Level.INIT, "Explicitly accepting valid X509s from", tips);
245                         String[] ipsplit = tips.split(REGEX_COMMA);
246                         trustMasks = new NetMask[ipsplit.length];
247                         for(int i = 0; i < ipsplit.length; ++i) {
248                                 try {
249                                         trustMasks[i] = new NetMask(ipsplit[i]);
250                                 } catch (MaskFormatException e) {
251                                         throw new AccessException("Invalid IP Mask in " + Config.CADI_TRUST_MASKS, e);
252                                 }
253                         }
254                 }
255                 
256                 if(trustMasks != null) {
257                         final HostnameVerifier origHV = HttpsURLConnection.getDefaultHostnameVerifier();
258                         HttpsURLConnection.setDefaultHostnameVerifier(maskHV = new HostnameVerifier() {
259                                 @Override
260                                 public boolean verify(final String urlHostName, final SSLSession session) {
261                                         try {
262                                                 // This will pick up /etc/host entries as well as DNS
263                                                 InetAddress ia = InetAddress.getByName(session.getPeerHost());
264                                                 for(NetMask tmask : trustMasks) {
265                                                         if(tmask.isInNet(ia.getHostAddress())) {
266                                                                 return true;
267                                                         }
268                                                 }
269                                         } catch (UnknownHostException e) {
270                                                 // It's ok. do normal Verify
271                                         }
272                                         return origHV.verify(urlHostName, session);
273                                 };
274                         });
275                 }
276         }
277         
278 }