c5849d05c221031f4a590a3738177f5680305c28
[aaf/authz.git] / auth / auth-core / src / main / java / org / onap / aaf / auth / server / JettyServiceStarter.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 package org.onap.aaf.auth.server;
22
23 import java.io.IOException;
24 import java.net.Inet4Address;
25 import java.net.InetAddress;
26 import java.util.Properties;
27
28 import javax.servlet.Filter;
29 import javax.servlet.FilterChain;
30 import javax.servlet.ServletException;
31 import javax.servlet.ServletRequest;
32 import javax.servlet.ServletResponse;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35
36 import org.eclipse.jetty.http.HttpVersion;
37 import org.eclipse.jetty.server.HttpConfiguration;
38 import org.eclipse.jetty.server.HttpConnectionFactory;
39 import org.eclipse.jetty.server.Request;
40 import org.eclipse.jetty.server.SecureRequestCustomizer;
41 import org.eclipse.jetty.server.Server;
42 import org.eclipse.jetty.server.ServerConnector;
43 import org.eclipse.jetty.server.SslConnectionFactory;
44 import org.eclipse.jetty.server.handler.AbstractHandler;
45 import org.eclipse.jetty.util.ssl.SslContextFactory;
46 import org.onap.aaf.auth.org.OrganizationException;
47 import org.onap.aaf.auth.rserv.RServlet;
48 import org.onap.aaf.cadi.CadiException;
49 import org.onap.aaf.cadi.LocatorException;
50 import org.onap.aaf.cadi.Access.Level;
51 import org.onap.aaf.cadi.config.Config;
52 import org.onap.aaf.cadi.config.SecurityInfo;
53 import org.onap.aaf.misc.env.Trans;
54 import org.onap.aaf.misc.env.util.Split;
55 import org.onap.aaf.misc.rosetta.env.RosettaEnv;
56
57
58 public class JettyServiceStarter<ENV extends RosettaEnv, TRANS extends Trans> extends AbsServiceStarter<ENV,TRANS> {
59
60     private boolean secure;
61
62     public JettyServiceStarter(final AbsService<ENV,TRANS> service) throws OrganizationException {
63         super(service);
64         secure = true;
65     }
66     
67     /**
68      * Specifically set this Service starter to Insecure (HTTP) Mode. 
69      * @return
70      */
71     public JettyServiceStarter<ENV,TRANS> insecure() {
72         secure = false;
73         return this;
74     }
75
76 //    @Override
77 //    public void _propertyAdjustment() {
78 //        Properties props = access().getProperties();
79 //        Object temp = null;
80 //        // Critical - if no Security Protocols set, then set it.  We'll just get messed up if not
81 //        if ((temp=props.get(Config.CADI_PROTOCOLS))==null) {
82 //            if ((temp=props.get(Config.HTTPS_PROTOCOLS))==null) {
83 //                props.put(Config.CADI_PROTOCOLS, SecurityInfo.HTTPS_PROTOCOLS_DEFAULT);
84 //            } else {
85 //                props.put(Config.CADI_PROTOCOLS, temp);
86 //            }
87 //        }
88 //    
89 //        if ("1.7".equals(System.getProperty("java.specification.version"))) {
90 //            System.setProperty(Config.HTTPS_CIPHER_SUITES, Config.HTTPS_CIPHER_SUITES_DEFAULT);
91 //        }
92 //        System.setProperty(Config.HTTPS_CIPHER_SUITES, temp.toString());
93 //    }
94
95     @Override
96     public void _propertyAdjustment() {
97 //        System.setProperty("com.sun.management.jmxremote.port", "8081");
98         Properties props = access().getProperties();
99         Object httpproto = null;
100         // Critical - if no Security Protocols set, then set it.  We'll just get messed up if not
101         if ((httpproto=props.get(Config.CADI_PROTOCOLS))==null) {
102             if ((httpproto=props.get(Config.HTTPS_PROTOCOLS))==null) {
103                 props.put(Config.CADI_PROTOCOLS, (httpproto=SecurityInfo.HTTPS_PROTOCOLS_DEFAULT));
104             } else {
105                 props.put(Config.CADI_PROTOCOLS, httpproto);
106             }
107         }
108     
109         if ("1.7".equals(System.getProperty("java.specification.version")) && (httpproto==null || (httpproto instanceof String && ((String)httpproto).contains("TLSv1.2")))) {
110             System.setProperty(Config.HTTPS_CIPHER_SUITES, Config.HTTPS_CIPHER_SUITES_DEFAULT);
111         }
112     }
113
114     @Override
115     public void _start(RServlet<TRANS> rserv) throws Exception {
116         String hostname = access().getProperty(Config.HOSTNAME, null);
117         if (hostname==null) {
118             hostname = Inet4Address.getLocalHost().getHostName();
119         }
120         final int port = Integer.parseInt(access().getProperty("port","0"));
121         final String keystore = access().getProperty(Config.CADI_KEYSTORE, null);
122         final int IDLE_TIMEOUT = Integer.parseInt(access().getProperty(Config.AAF_CONN_IDLE_TIMEOUT, Config.AAF_CONN_IDLE_TIMEOUT_DEF));
123         Server server = new Server();
124         
125         ServerConnector conn;
126         String protocol;
127         if (!secure || keystore==null) {
128             conn = new ServerConnector(server);
129             protocol = "http";
130         } else {
131             protocol = "https";
132
133             String keystorePassword = access().getProperty(Config.CADI_KEYSTORE_PASSWORD, null);
134             if (keystorePassword==null) {
135                 throw new CadiException("No Keystore Password configured for " + keystore);
136             }
137             SslContextFactory sslContextFactory = new SslContextFactory();
138             sslContextFactory.setKeyStorePath(keystore);
139             String temp;
140             sslContextFactory.setKeyStorePassword(temp=access().decrypt(keystorePassword, true)); // don't allow unencrypted
141             sslContextFactory.setKeyManagerPassword(temp);
142             temp=null; // don't leave lying around
143             
144             String truststore = access().getProperty(Config.CADI_TRUSTSTORE, null);
145             if (truststore!=null) {
146                 String truststorePassword = access().getProperty(Config.CADI_TRUSTSTORE_PASSWORD, null);
147                 if (truststorePassword==null) {
148                     throw new CadiException("No Truststore Password configured for " + truststore);
149                 }
150                 sslContextFactory.setTrustStorePath(truststore);
151                 sslContextFactory.setTrustStorePassword(access().decrypt(truststorePassword, true)); 
152             }
153             // Be able to accept only certain protocols, i.e. TLSv1.1+
154             final String[] protocols = Split.splitTrim(',', access().getProperty(Config.CADI_PROTOCOLS, SecurityInfo.HTTPS_PROTOCOLS_DEFAULT));
155             sslContextFactory.setIncludeProtocols(protocols);
156             
157             // Want to use Client Certificates, if they exist.
158             sslContextFactory.setWantClientAuth(true);
159             
160             // Optional future checks.
161             //   sslContextFactory.setValidateCerts(true);
162             //     sslContextFactory.setValidatePeerCerts(true);
163             //     sslContextFactory.setEnableCRLDP(false);
164             //     sslContextFactory.setEnableOCSP(false);
165             String certAlias = access().getProperty(Config.CADI_ALIAS, null);
166             if (certAlias!=null) {
167                 sslContextFactory.setCertAlias(certAlias);
168             }
169             
170             HttpConfiguration httpConfig = new HttpConfiguration();
171             httpConfig.setSecureScheme(protocol);
172             httpConfig.setSecurePort(port);
173             httpConfig.addCustomizer(new SecureRequestCustomizer());
174             //  httpConfig.setOutputBufferSize(32768);  Not sure why take this setting
175             
176             conn = new ServerConnector(server,
177                 new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
178                     new HttpConnectionFactory(httpConfig)
179                 );
180         }
181         
182         // Setup JMX 
183         // TODO trying to figure out how to set up/log ports
184 //        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
185 //        MBeanContainer mbContainer=new MBeanContainer(mbeanServer);
186 //        server.addEventListener(mbContainer);
187 //        server.addBean(mbContainer);
188         
189         // Add loggers MBean to server (will be picked up by MBeanContainer above)
190 //        server.addBean(Log.getLog());
191     
192         conn.setHost(hostname);
193         conn.setPort(port);
194         conn.setIdleTimeout(IDLE_TIMEOUT);
195         server.addConnector(conn);
196         
197         server.setHandler(new AbstractHandler() {
198                 private FilterChain fc = buildFilterChain(service,new FilterChain() {
199                     @Override
200                     public void doFilter(ServletRequest req, ServletResponse resp) throws IOException, ServletException {
201                         rserv.service(req, resp);
202                     }
203                 });
204                 
205                 @Override
206                 public void handle(String target, Request baseRequest, HttpServletRequest hreq, HttpServletResponse hresp) throws IOException, ServletException {
207                     try {
208                         fc.doFilter(hreq,hresp);
209                     } catch (Exception e) {
210                         service.access.log(e, "Error Processing " + target);
211                         hresp.setStatus(500 /* Service Error */);
212                     }
213                     baseRequest.setHandled(true);
214                 }
215             }
216         );
217         
218         try {
219             access().printf(Level.INIT, "Starting service on %s:%d (%s)",hostname,port,InetAddress.getLocalHost().getHostAddress());
220             server.start();
221             access().log(Level.INIT,server.dump());
222         } catch (Exception e) {
223             access().log(e,"Error starting " + service.app_name);
224             String doExit = access().getProperty("cadi_exitOnFailure", "true");
225             if (doExit == "true") {
226                 System.exit(1);
227             } else {
228                 throw e;
229             }
230         }
231         try {
232             register(service.registrants(port));
233             access().printf(Level.INIT, "Starting Jetty Service for %s, version %s, on %s://%s:%d", service.app_name,service.app_version,protocol,hostname,port);
234             server.join();
235         } catch (Exception e) {
236             access().log(e,"Error registering " + service.app_name);
237             String doExit = access().getProperty("cadi_exitOnFailure", "true");
238             if (doExit == "true") {
239                 System.exit(1);
240             } else {
241                 throw e;
242             }
243         }
244     }
245
246     private FilterChain buildFilterChain(final AbsService<?,?> as, final FilterChain doLast) throws CadiException, LocatorException {
247         Filter[] filters = as.filters();
248         FilterChain fc = doLast;
249         for (int i=filters.length-1;i>=0;--i) {
250             fc = new FCImpl(filters[i],fc);
251         }
252         return fc;
253     }
254     
255     private class FCImpl implements FilterChain {
256         private Filter f;
257         private FilterChain next;
258         
259         public FCImpl(final Filter f, final FilterChain fc) {
260             this.f=f;
261             next = fc;
262             
263         }
264         @Override
265         public void doFilter(ServletRequest req, ServletResponse resp) throws IOException, ServletException {
266             f.doFilter(req,resp, next);
267         }
268     }
269 }