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