3a9180726dae0b971dc11533c800cae3c0e4ecae
[aaf/authz.git] / authz-service / src / main / java / org / onap / aaf / authz / service / AuthAPI.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package org.onap.aaf.authz.service;\r
24 \r
25 import java.io.IOException;\r
26 import java.net.HttpURLConnection;\r
27 import java.security.GeneralSecurityException;\r
28 import java.util.ArrayList;\r
29 import java.util.EnumSet;\r
30 import java.util.List;\r
31 import java.util.Properties;\r
32 \r
33 import org.onap.aaf.authz.cadi.DirectAAFLur;\r
34 import org.onap.aaf.authz.cadi.DirectAAFUserPass;\r
35 import org.onap.aaf.authz.cadi.DirectCertIdentity;\r
36 import org.onap.aaf.authz.env.AuthzEnv;\r
37 import org.onap.aaf.authz.env.AuthzTrans;\r
38 import org.onap.aaf.authz.env.AuthzTransFilter;\r
39 import org.onap.aaf.authz.facade.AuthzFacadeFactory;\r
40 import org.onap.aaf.authz.facade.AuthzFacade_2_0;\r
41 import org.onap.aaf.authz.org.OrganizationFactory;\r
42 import org.onap.aaf.authz.server.AbsServer;\r
43 import org.onap.aaf.authz.service.api.API_Api;\r
44 import org.onap.aaf.authz.service.api.API_Approval;\r
45 import org.onap.aaf.authz.service.api.API_Creds;\r
46 import org.onap.aaf.authz.service.api.API_Delegate;\r
47 import org.onap.aaf.authz.service.api.API_History;\r
48 import org.onap.aaf.authz.service.api.API_Mgmt;\r
49 import org.onap.aaf.authz.service.api.API_NS;\r
50 import org.onap.aaf.authz.service.api.API_Perms;\r
51 import org.onap.aaf.authz.service.api.API_Roles;\r
52 import org.onap.aaf.authz.service.api.API_User;\r
53 import org.onap.aaf.authz.service.api.API_UserRole;\r
54 import org.onap.aaf.authz.service.mapper.Mapper.API;\r
55 import org.onap.aaf.cssa.rserv.HttpMethods;\r
56 import org.onap.aaf.dao.CassAccess;\r
57 import org.onap.aaf.dao.aaf.cass.CacheInfoDAO;\r
58 import org.onap.aaf.dao.aaf.hl.Question;\r
59 \r
60 import com.att.aft.dme2.api.DME2Exception;\r
61 //import com.att.aft.dme2.api.DME2FilterHolder;\r
62 //import com.att.aft.dme2.api.DME2FilterHolder.RequestDispatcherType;\r
63 import com.att.aft.dme2.api.DME2Manager;\r
64 import com.att.aft.dme2.api.DME2Server;\r
65 import com.att.aft.dme2.api.DME2ServerProperties;\r
66 import com.att.aft.dme2.api.DME2ServiceHolder;\r
67 import com.att.aft.dme2.api.util.DME2FilterHolder;\r
68 import com.att.aft.dme2.api.util.DME2FilterHolder.RequestDispatcherType;\r
69 import com.att.aft.dme2.api.util.DME2ServletHolder;\r
70 import org.onap.aaf.cadi.CadiException;\r
71 import org.onap.aaf.cadi.LocatorException;\r
72 import org.onap.aaf.cadi.SecuritySetter;\r
73 import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker;\r
74 import org.onap.aaf.cadi.config.Config;\r
75 import org.onap.aaf.cadi.config.SecurityInfoC;\r
76 import org.onap.aaf.cadi.http.HBasicAuthSS;\r
77 import org.onap.aaf.cadi.http.HMangr;\r
78 import org.onap.aaf.cadi.http.HX509SS;\r
79 import org.onap.aaf.cadi.locator.DME2Locator;\r
80 import org.onap.aaf.cadi.taf.basic.BasicHttpTaf;\r
81 import org.onap.aaf.inno.env.APIException;\r
82 import org.onap.aaf.inno.env.Data;\r
83 import org.onap.aaf.inno.env.Env;\r
84 import com.datastax.driver.core.Cluster;\r
85 \r
86 public class AuthAPI extends AbsServer {\r
87 \r
88         private static final String ORGANIZATION = "Organization.";\r
89         private static final String DOMAIN = "openecomp.org";\r
90 \r
91 // TODO Add Service Metrics\r
92 //      private Metric serviceMetric;\r
93         public final Question question;\r
94 //      private final SessionFilter sessionFilter;\r
95         private AuthzFacade_2_0 facade;\r
96         private AuthzFacade_2_0 facade_XML;\r
97         private DirectAAFUserPass directAAFUserPass;\r
98         \r
99         /**\r
100          * Construct AuthzAPI with all the Context Supporting Routes that Authz needs\r
101          * \r
102          * @param env\r
103          * @param decryptor \r
104          * @throws APIException \r
105          */\r
106         public AuthAPI(AuthzEnv env) throws Exception {\r
107                 super(env,"AAF");\r
108         \r
109                 // Set "aaf_url" for peer communication based on Service DME2 URL\r
110                 env.setProperty(Config.AAF_URL, "https://DME2RESOLVE/"+env.getProperty("DMEServiceName"));\r
111                 \r
112                 // Setup Log Names\r
113                 env.setLog4JNames("log4j.properties","authz","authz|service","audit","init","trace");\r
114 \r
115                 final Cluster cluster = org.onap.aaf.dao.CassAccess.cluster(env,null);\r
116 \r
117                 // jg 4/2015 SessionFilter unneeded... DataStax already deals with Multithreading well\r
118                 \r
119                 // Setup Shutdown Hooks for Cluster and Pooled Sessions\r
120                 Runtime.getRuntime().addShutdownHook(new Thread() {\r
121                         @Override\r
122                         public void run() {\r
123 //                              sessionFilter.destroy();\r
124                                 cluster.close();\r
125                         }\r
126                 }); \r
127                 \r
128                 // Initialize Facade for all uses\r
129                 AuthzTrans trans = env.newTrans();\r
130 \r
131                 // Initialize Organizations... otherwise, first pass may miss\r
132                 int org_size = ORGANIZATION.length();\r
133                 for(String n : env.existingStaticSlotNames()) {\r
134                         if(n.startsWith(ORGANIZATION)) {\r
135                                 OrganizationFactory.obtain(env, n.substring(org_size));\r
136                         }\r
137                 }\r
138                 \r
139                 // Need Question for Security purposes (direct User/Authz Query in Filter)\r
140                 // Start Background Processing\r
141                 question = new Question(trans, cluster, CassAccess.KEYSPACE, true);\r
142                 \r
143                 DirectCertIdentity.set(question.certDAO);\r
144                 \r
145                 facade = AuthzFacadeFactory.v2_0(env,trans,Data.TYPE.JSON,question);\r
146                 facade_XML = AuthzFacadeFactory.v2_0(env,trans,Data.TYPE.XML,question);\r
147 \r
148                 directAAFUserPass = new DirectAAFUserPass(\r
149                         trans.env(),question,trans.getProperty("Unknown"));\r
150 \r
151                 \r
152                 // Print results and cleanup\r
153                 StringBuilder sb = new StringBuilder();\r
154                 trans.auditTrail(0, sb);\r
155                 if(sb.length()>0)env.init().log(sb);\r
156                 trans = null;\r
157                 sb = null;\r
158 \r
159                 ////////////////////////////////////////////////////////////////////////////\r
160                 // Time Critical\r
161                 //  These will always be evaluated first\r
162                 ////////////////////////////////////////////////////////////////////////\r
163                 API_Creds.timeSensitiveInit(env, this, facade,directAAFUserPass);\r
164                 API_Perms.timeSensitiveInit(this, facade);\r
165                 ////////////////////////////////////////////////////////////////////////\r
166                 // Service APIs\r
167                 ////////////////////////////////////////////////////////////////////////\r
168                 API_Creds.init(this, facade);\r
169                 API_UserRole.init(this, facade);\r
170                 API_Roles.init(this, facade);\r
171                 API_Perms.init(this, facade);\r
172                 API_NS.init(this, facade);\r
173                 API_User.init(this, facade);\r
174                 API_Delegate.init(this,facade);\r
175                 API_Approval.init(this, facade);\r
176                 API_History.init(this, facade);\r
177 \r
178                 ////////////////////////////////////////////////////////////////////////\r
179                 // Management APIs\r
180                 ////////////////////////////////////////////////////////////////////////\r
181                 // There are several APIs around each concept, and it gets a bit too\r
182                 // long in this class to create.  The initialization of these Management\r
183                 // APIs have therefore been pushed to StandAlone Classes with static\r
184                 // init functions\r
185                 API_Mgmt.init(this, facade);\r
186                 API_Api.init(this, facade);\r
187                 \r
188         }\r
189         \r
190         /**\r
191          * Setup XML and JSON implementations for each supported Version type\r
192          * \r
193          * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties\r
194          * to do Versions and Content switches\r
195          * \r
196          */\r
197         public void route(HttpMethods meth, String path, API api, Code code) throws Exception {\r
198                 String version = "2.0";\r
199                 Class<?> respCls = facade.mapper().getClass(api); \r
200                 if(respCls==null) throw new Exception("Unknown class associated with " + api.getClass().getName() + ' ' + api.name());\r
201                 String application = applicationJSON(respCls, version);\r
202 \r
203                 route(env,meth,path,code,application,"application/json;version=2.0","*/*");\r
204                 application = applicationXML(respCls, version);\r
205                 route(env,meth,path,code.clone(facade_XML,false),application,"text/xml;version=2.0");\r
206         }\r
207 \r
208         /**\r
209          * Start up AuthzAPI as DME2 Service\r
210          * @param env\r
211          * @param props\r
212          * @throws Exception \r
213          * @throws LocatorException \r
214          * @throws CadiException \r
215          * @throws NumberFormatException \r
216          * @throws IOException \r
217          * @throws GeneralSecurityException \r
218          * @throws APIException \r
219          */\r
220         public void startDME2(Properties props) throws Exception {\r
221         DME2Manager dme2 = new DME2Manager("AuthzServiceDME2Manager",props);\r
222         String s = dme2.getStringProp(Config.AFT_DME2_SSL_INCLUDE_PROTOCOLS,null);\r
223         env.init().log("DME2 Service TLS Protocols are set to",(s==null?"DME2 Default":s));\r
224         \r
225         DME2ServiceHolder svcHolder;\r
226         List<DME2ServletHolder> slist = new ArrayList<DME2ServletHolder>();\r
227         svcHolder = new DME2ServiceHolder();\r
228         String serviceName = env.getProperty("DMEServiceName",null);\r
229         if(serviceName!=null) {\r
230                 svcHolder.setServiceURI(serviceName);\r
231                 svcHolder.setManager(dme2);\r
232                 svcHolder.setContext("/");\r
233                 DME2ServletHolder srvHolder = new DME2ServletHolder(this, new String[]{"/authz","/authn","/mgmt"});\r
234                 srvHolder.setContextPath("/*");\r
235                 slist.add(srvHolder);\r
236                 \r
237                 EnumSet<RequestDispatcherType> edlist = EnumSet.of(\r
238                                 RequestDispatcherType.REQUEST,\r
239                                 RequestDispatcherType.FORWARD,\r
240                                 RequestDispatcherType.ASYNC\r
241                                 );\r
242                 \r
243                 List<DME2FilterHolder> flist = new ArrayList<DME2FilterHolder>();\r
244 \r
245                 // Add DME2 Metrics\r
246                 // DME2 removed the Metrics Filter in 2.8.8.5\r
247                 // flist.add(new DME2FilterHolder(new DME2MetricsFilter(serviceName),"/*",edlist));\r
248                 \r
249                 // Note: Need CADI to fill out User for AuthTransFilter... so it's first\r
250                 // Make sure there is no AAF TAF configured for Filters\r
251                 env.setProperty(Config.AAF_URL,null);\r
252 \r
253                 flist.add(\r
254                         new DME2FilterHolder(\r
255                                 new AuthzTransFilter(env, null /* no connection to AAF... it is AAF */,\r
256                                         new AAFTrustChecker((Env)env),\r
257                                 new DirectAAFLur(env,question), // Note, this will be assigned by AuthzTransFilter to TrustChecker\r
258                                 new BasicHttpTaf(env, directAAFUserPass,\r
259                                                 DOMAIN,Long.parseLong(env.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF)),\r
260                                                 false\r
261                                                 ) // Add specialty Direct TAF\r
262                                         ),\r
263                                 "/*", edlist));\r
264 \r
265                 svcHolder.setFilters(flist);\r
266                 svcHolder.setServletHolders(slist);\r
267                 \r
268                 DME2Server dme2svr = dme2.getServer();\r
269                 \r
270                 String hostname = env.getProperty("HOSTNAME",null);\r
271                 if(hostname!=null) {\r
272                         //dme2svr.setHostname(hostname);\r
273                         hostname=null;\r
274                 }\r
275                // dme2svr.setGracefulShutdownTimeMs(5000);\r
276         \r
277                 env.init().log("Starting AAF Jetty/DME2 server...");\r
278                 dme2svr.start();\r
279                 try {\r
280 //                      if(env.getProperty("NO_REGISTER",null)!=null)\r
281                         dme2.bindService(svcHolder);\r
282                         //env.init().log("DME2 is available as HTTPS on port:",dme2svr.getPort());\r
283                         \r
284                         // Start CacheInfo Listener\r
285                         HMangr hman = new HMangr(env, new DME2Locator(env, dme2,"https://DME2RESOLVE/"+serviceName,true /*remove self from cache*/));\r
286                                 SecuritySetter<HttpURLConnection> ss;\r
287                                 \r
288 //                              InetAddress ip = InetAddress.getByName(dme2svr.getHostname());\r
289                                 SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(env);\r
290                                 String mechID;\r
291                                 if((mechID=env.getProperty(Config.AAF_MECHID))==null) {\r
292                                         String alias = env.getProperty(Config.CADI_ALIAS);\r
293                                         if(alias==null) {\r
294                                                 env.init().log(Config.CADI_ALIAS, "is required for AAF Authentication by Certificate.  Alternately, set",Config.AAF_MECHID,"and",Config.AAF_MECHPASS);\r
295                                                 System.exit(1);\r
296                                         }\r
297                                         ss = new HX509SS(alias,si,true);\r
298                                         env.init().log("X509 Certificate Client configured:", alias);\r
299                                 } else {\r
300                                         String pass = env.getProperty(Config.AAF_MECHPASS);\r
301                                         if(pass==null) {\r
302                                                 env.init().log(Config.AAF_MECHPASS, "is required for AAF Authentication by ID/Pass");\r
303                                                 System.exit(1);\r
304                                         }\r
305                                         ss = new HBasicAuthSS(mechID,env.decrypt(pass, true),si,true);\r
306                                         env.init().log("BasicAuth (ID/Pass) Client configured.");\r
307                                 }\r
308                                 \r
309                                 //TODO Reenable Cache Update\r
310                         //CacheInfoDAO.startUpdate(env, hman, ss, dme2svr.getHostname(), dme2svr.getPort());\r
311                         \r
312                     while(true) { // Per DME2 Examples...\r
313                         Thread.sleep(5000);\r
314                     }\r
315                 } catch(DME2Exception e) { // Error binding service doesn't seem to stop DME2 or Process\r
316                     env.init().log(e,"DME2 Initialization Error");\r
317                         dme2svr.stop();\r
318                         System.exit(1);\r
319                 } catch(InterruptedException e) {\r
320                     env.init().log("AAF Jetty Server interrupted!");\r
321                 }\r
322         } else {\r
323                 env.init().log("Properties must contain 'DMEServiceName'");\r
324         }\r
325         }\r
326 \r
327         public static void main(String[] args) {\r
328                 setup(AuthAPI.class,"authAPI.props");\r
329         }\r
330 }\r