1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\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
11 * * http://www.apache.org/licenses/LICENSE-2.0
\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
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package org.onap.aaf.authz.service;
\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
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
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
86 public class AuthAPI extends AbsServer {
\r
88 private static final String ORGANIZATION = "Organization.";
\r
89 private static final String DOMAIN = "openecomp.org";
\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
100 * Construct AuthzAPI with all the Context Supporting Routes that Authz needs
\r
103 * @param decryptor
\r
104 * @throws APIException
\r
106 public AuthAPI(AuthzEnv env) throws Exception {
\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
113 env.setLog4JNames("log4j.properties","authz","authz|service","audit","init","trace");
\r
115 final Cluster cluster = org.onap.aaf.dao.CassAccess.cluster(env,null);
\r
117 // jg 4/2015 SessionFilter unneeded... DataStax already deals with Multithreading well
\r
119 // Setup Shutdown Hooks for Cluster and Pooled Sessions
\r
120 Runtime.getRuntime().addShutdownHook(new Thread() {
\r
122 public void run() {
\r
123 // sessionFilter.destroy();
\r
128 // Initialize Facade for all uses
\r
129 AuthzTrans trans = env.newTrans();
\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
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
143 DirectCertIdentity.set(question.certDAO);
\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
148 directAAFUserPass = new DirectAAFUserPass(
\r
149 trans.env(),question,trans.getProperty("Unknown"));
\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
159 ////////////////////////////////////////////////////////////////////////////
\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
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
178 ////////////////////////////////////////////////////////////////////////
\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
185 API_Mgmt.init(this, facade);
\r
186 API_Api.init(this, facade);
\r
191 * Setup XML and JSON implementations for each supported Version type
\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
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
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
209 * Start up AuthzAPI as DME2 Service
\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
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
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
237 EnumSet<RequestDispatcherType> edlist = EnumSet.of(
\r
238 RequestDispatcherType.REQUEST,
\r
239 RequestDispatcherType.FORWARD,
\r
240 RequestDispatcherType.ASYNC
\r
243 List<DME2FilterHolder> flist = new ArrayList<DME2FilterHolder>();
\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
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
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
261 ) // Add specialty Direct TAF
\r
265 svcHolder.setFilters(flist);
\r
266 svcHolder.setServletHolders(slist);
\r
268 DME2Server dme2svr = dme2.getServer();
\r
270 String hostname = env.getProperty("HOSTNAME",null);
\r
271 if(hostname!=null) {
\r
272 //dme2svr.setHostname(hostname);
\r
275 // dme2svr.setGracefulShutdownTimeMs(5000);
\r
277 env.init().log("Starting AAF Jetty/DME2 server...");
\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
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
288 // InetAddress ip = InetAddress.getByName(dme2svr.getHostname());
\r
289 SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(env);
\r
291 if((mechID=env.getProperty(Config.AAF_MECHID))==null) {
\r
292 String alias = env.getProperty(Config.CADI_ALIAS);
\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
297 ss = new HX509SS(alias,si,true);
\r
298 env.init().log("X509 Certificate Client configured:", alias);
\r
300 String pass = env.getProperty(Config.AAF_MECHPASS);
\r
302 env.init().log(Config.AAF_MECHPASS, "is required for AAF Authentication by ID/Pass");
\r
305 ss = new HBasicAuthSS(mechID,env.decrypt(pass, true),si,true);
\r
306 env.init().log("BasicAuth (ID/Pass) Client configured.");
\r
309 //TODO Reenable Cache Update
\r
310 //CacheInfoDAO.startUpdate(env, hman, ss, dme2svr.getHostname(), dme2svr.getPort());
\r
312 while(true) { // Per DME2 Examples...
\r
313 Thread.sleep(5000);
\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
319 } catch(InterruptedException e) {
\r
320 env.init().log("AAF Jetty Server interrupted!");
\r
323 env.init().log("Properties must contain 'DMEServiceName'");
\r
327 public static void main(String[] args) {
\r
328 setup(AuthAPI.class,"authAPI.props");
\r