1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\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
12 * * http://www.apache.org/licenses/LICENSE-2.0
\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
21 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
23 ******************************************************************************/
\r
24 package com.att.authz.service;
\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
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
87 public class AuthAPI extends AbsServer {
\r
89 private static final String ORGANIZATION = "Organization.";
\r
90 private static final String DOMAIN = "openecomp.org";
\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
101 * Construct AuthzAPI with all the Context Supporting Routes that Authz needs
\r
104 * @param decryptor
\r
105 * @throws APIException
\r
107 public AuthAPI(AuthzEnv env) throws Exception {
\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
114 env.setLog4JNames("log4j.properties","authz","authz|service","audit","init","trace");
\r
116 final Cluster cluster = com.att.dao.CassAccess.cluster(env,null);
\r
118 // jg 4/2015 SessionFilter unneeded... DataStax already deals with Multithreading well
\r
120 // Setup Shutdown Hooks for Cluster and Pooled Sessions
\r
121 Runtime.getRuntime().addShutdownHook(new Thread() {
\r
123 public void run() {
\r
124 // sessionFilter.destroy();
\r
129 // Initialize Facade for all uses
\r
130 AuthzTrans trans = env.newTrans();
\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
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
144 DirectCertIdentity.set(question.certDAO);
\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
149 directAAFUserPass = new DirectAAFUserPass(
\r
150 trans.env(),question,trans.getProperty("Unknown"));
\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
160 ////////////////////////////////////////////////////////////////////////////
\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
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
179 ////////////////////////////////////////////////////////////////////////
\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
186 API_Mgmt.init(this, facade);
\r
187 API_Api.init(this, facade);
\r
192 * Setup XML and JSON implementations for each supported Version type
\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
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
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
210 * Start up AuthzAPI as DME2 Service
\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
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
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
238 EnumSet<RequestDispatcherType> edlist = EnumSet.of(
\r
239 RequestDispatcherType.REQUEST,
\r
240 RequestDispatcherType.FORWARD,
\r
241 RequestDispatcherType.ASYNC
\r
244 List<DME2FilterHolder> flist = new ArrayList<DME2FilterHolder>();
\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
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
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
262 ) // Add specialty Direct TAF
\r
266 svcHolder.setFilters(flist);
\r
267 svcHolder.setServletHolders(slist);
\r
269 DME2Server dme2svr = dme2.getServer();
\r
271 String hostname = env.getProperty("HOSTNAME",null);
\r
272 if(hostname!=null) {
\r
273 //dme2svr.setHostname(hostname);
\r
276 // dme2svr.setGracefulShutdownTimeMs(5000);
\r
278 env.init().log("Starting AAF Jetty/DME2 server...");
\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
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
289 // InetAddress ip = InetAddress.getByName(dme2svr.getHostname());
\r
290 SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(env);
\r
292 if((mechID=env.getProperty(Config.AAF_MECHID))==null) {
\r
293 String alias = env.getProperty(Config.CADI_ALIAS);
\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
298 ss = new HX509SS(alias,si,true);
\r
299 env.init().log("X509 Certificate Client configured:", alias);
\r
301 String pass = env.getProperty(Config.AAF_MECHPASS);
\r
303 env.init().log(Config.AAF_MECHPASS, "is required for AAF Authentication by ID/Pass");
\r
306 ss = new HBasicAuthSS(mechID,env.decrypt(pass, true),si,true);
\r
307 env.init().log("BasicAuth (ID/Pass) Client configured.");
\r
310 //TODO Reenable Cache Update
\r
311 //CacheInfoDAO.startUpdate(env, hman, ss, dme2svr.getHostname(), dme2svr.getPort());
\r
313 while(true) { // Per DME2 Examples...
\r
314 Thread.sleep(5000);
\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
320 } catch(InterruptedException e) {
\r
321 env.init().log("AAF Jetty Server interrupted!");
\r
324 env.init().log("Properties must contain 'DMEServiceName'");
\r
328 public static void main(String[] args) {
\r
329 setup(AuthAPI.class,"authAPI.props");
\r