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