blob: bf8bb823210ba18f35786da8cb4b07eea9c593f2 [file] [log] [blame]
Sai Gandhamd67a9de2018-05-25 15:48:11 +00001.. This work is licensed under a Creative Commons Attribution 4.0 International License.
2.. http://creativecommons.org/licenses/by/4.0
Instrumental7a1817b2018-11-05 11:11:15 -06003.. Copyright © 2017 AT&T Intellectual Property. All rights reserved.
Sai Gandhamd67a9de2018-05-25 15:48:11 +00004
Sai Gandham5e236c72018-06-15 00:44:18 -05005Service Configuration - Connecting to AAF
6==========================================
7
8
9
10Methods to Connect
11==================
12
13 If you are a Servlet in a Container, use CADI Framework with AAF Plugin. It's very easy, and includes BasicAuth for Services.
14• Java Technologies
15• Technologies using Servlet Filters
16• DME2 (and other Servlet Containers) can use Servlet Filters
17• Any WebApp can plug in CADI as a Servlet Filter
18• Jetty can attach a Servlet Filter with Code, or as WebApp
19• Tomcat 7 has a "Valve" plugin, which is similar and supported
20• Use the AAFLur Code directly (shown)
21• All Java Technologies utilize Configuration to set what Security elements are required
22• example: Global Login can be turned on/off, AAF Client needs information to connect to AAF Service
23• There are several specialty cases, which AAF can work with, including embedding all properties in a Web.xml, but the essentials needed are:
24• CADI Jars
25• cadi.properties file (configured the same for all technologies)
26• Encrypt passwords with included CADI technology, so that there are no Clear Text Passwords in Config Files (ASPR)
27• See CADI Deployment on how to perform this with several different technologies.
28• AAF Restfully (see RESTFul APIS)
29
30IMPORTANT: If Direct RESTFul API is used, then it is the Client's responsibility to Cache and avoid making an AAF Service Calls too often
31Example: A Tool like Cassandra will ask for Authentication hundreds of times a second for the same identity during a transaction. Calling the AAF Service for each would be slow for the client, and wasteful of Network and AAF Service Capacities.
32Rogue Clients can and will be denied access to AAF.
33
34
35J2EE (Servlet Filter) Method
36============================
37
381. Per J2EE design, the Filter will deny any unauthenticated HTTP/S call; the Servlet will not even be invoked.
39a. Therefore, the Servlet can depend on any transaction making it to their code set is Authenticated.
40b. Identity can be viewed based on the HttpServletRequest Object (request.getUserPrincipal() )
412. Per J2EE design, AAF Filter overloads the HttpServletRequest for a String related to "Role". (request.isUserInRole("...") )
42a. For AAF, do not put in "Role", but the three parts of requested "Permission", separated by "|", i.e. "org.onap.aaf.myapp.myperm|myInstance|myAction".
433. NOT REQUIRED: An added benefit, but not required, is a JASPI like interface, where you can add an Annotation to your Servlet.
44a. When used, no transaction will come into your code if the listed Permissions are not Granted to the Incoming Transaction.
45b. This might be helpful for covering separate Management Servlet implementations.
46
47
48
49Servlet Code Snippet
50=========================
51
Sai Gandham4e6f7bc2018-06-15 08:37:30 -050052.. code-block:: java
53
54 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
55 HttpServletRequest request;
56 try {
57 request = (HttpServletRequest)req;
58 } catch (ClassCastException e) {
59 throw new ServletException("Only serving HTTP today",e);
60 }
Sai Gandham5e236c72018-06-15 00:44:18 -050061
Sai Gandham4e6f7bc2018-06-15 08:37:30 -050062 // Note: CADI is OVERLOADING the concept of "isUserInRole".. You need to think "doesUserHavePermssion()"
63 // Assume that you have CREATED and GRANTED An AAF Permission in YOUR Namespace
64 // Example Permission: "org.onap.aaf.myapp.myPerm * write"
Sai Gandham5e236c72018-06-15 00:44:18 -050065
Sai Gandham4e6f7bc2018-06-15 08:37:30 -050066 // Think in your head, "Does user have write permission on any instance of org.onap.aaf.myapp.myPerm
67 if(request.isUserInRole("org.onap.aaf.myapp.myPerm|*|write")) {
68 // *** Do something here that someone with "myPerm write" permissions is allowed to do
69 } else {
70 // *** Do something reasonable if user is denied, like an Error Message
71 }
72
Sai Gandham5e236c72018-06-15 00:44:18 -050073 }
Sai Gandham5e236c72018-06-15 00:44:18 -050074
75Here is a working TestServlet, where you can play with different Permissions that you own on the URL, i.e.:
76https://<your machine:port>/caditest/testme?PERM=org.onap.aaf.myapp.myPerm|*|write
77
78Sample Servlet (Working example)
79================================
Sai Gandham4e6f7bc2018-06-15 08:37:30 -050080
81.. code-block:: java
82
83 package org.onap.aaf.cadi.debug;
84 import java.io.FileInputStream;
85 import java.io.IOException;
86 import java.net.InetAddress;
87 import java.net.UnknownHostException;
88 import java.util.HashMap;
89 import java.util.Map;
90 import java.util.Map.Entry;
91 import java.util.Properties;
92 import javax.servlet.Servlet;
93 import javax.servlet.ServletConfig;
94 import javax.servlet.ServletException;
95 import javax.servlet.ServletRequest;
96 import javax.servlet.ServletResponse;
97 import javax.servlet.http.HttpServletRequest;
98 import org.eclipse.jetty.server.Server;
99 import org.eclipse.jetty.server.ServerConnector;
100 import org.eclipse.jetty.server.handler.ContextHandler;
101 import org.eclipse.jetty.servlet.FilterHolder;
102 import org.eclipse.jetty.servlet.FilterMapping;
103 import org.eclipse.jetty.servlet.ServletContextHandler;
104 import org.eclipse.jetty.servlet.ServletHandler;
105 import org.onap.aaf.cadi.filter.CadiFilter;
106 import org.onap.aaf.cadi.filter.RolesAllowed;
107 import org.onap.aaf.cadi.jetty.MiniJASPIWrap;
Sai Gandham5e236c72018-06-15 00:44:18 -0500108
Sai Gandham4e6f7bc2018-06-15 08:37:30 -0500109 public class CSPServletTest {
Sai Gandham5e236c72018-06-15 00:44:18 -0500110 public static void main(String[] args) {
111 // Go ahead and print Test reports in cadi-core first
112 Test.main(args);
113 String hostname=null;
114 try {
115 hostname = InetAddress.getLocalHost().getHostName();
116 } catch (UnknownHostException e) {
117 e.printStackTrace();
118 System.exit(1);
119 }
120 Properties props = new Properties();
121 Map<String,String> map = new HashMap<String,String>();
122 try {
123 FileInputStream fis = new FileInputStream("run/cadi.properties");
124 try {
125 props.load(fis);
126 String key,value;
127 for( Entry<Object, Object> es : props.entrySet()) {
128 key = es.getKey().toString();
129 value = es.getValue().toString();
130 map.put(key,value);
131 if(key.startsWith("AFT_") || key.startsWith("DME2")) {
132 System.setProperty(key,value);
133 }
134 }
135 } finally {
136 fis.close();
137 }
138 } catch(IOException e) {
139 System.err.println("Cannot load run/cadi.properties");
140 System.exit(1);
141 }
142 String portStr = System.getProperty("port");
143 int port = portStr==null?8080:Integer.parseInt(portStr);
144 try {
145 // Add ServletHolder(s) and Filter(s) to a ServletHandler
146 ServletHandler shand = new ServletHandler();
147
148 FilterHolder cfh = new FilterHolder(CadiFilter.class);
149 cfh.setInitParameters(map);
150
151 shand.addFilterWithMapping(cfh, "/*", FilterMapping.ALL);
152 shand.addServletWithMapping(new MiniJASPIWrap(MyServlet.class),"/*");
153 // call initialize after start
154
155 ContextHandler ch = new ServletContextHandler();
156 ch.setContextPath("/caditest");
157 ch.setHandler(shand);
158 for( Entry<Object,Object> es : props.entrySet()) {
159 ch.getInitParams().put(es.getKey().toString(), es.getValue().toString());
160 }
161 //ch.setErrorHandler(new MyErrorHandler());
162
163 // Create Server and Add Context Handler
164 final Server server = new Server();
165 ServerConnector http = new ServerConnector(server);
166 http.setPort(port);
167 server.addConnector(http);
168 server.setHandler(ch);
169
170 // Start
171 server.start();
172 shand.initialize();
173
174 System.out.println("To test, put http://"+ hostname + ':' + port + "/caditest/testme in a browser or 'curl'");
175 // if we were really a server, we'd block the main thread with this join...
176 // server.join();
177 // But... since we're a test service, we'll block on StdIn
178 System.out.println("Press <Return> to end service...");
179 System.in.read();
180 server.stop();
181 System.out.println("All done, have a good day!");
182 } catch (Exception e) {
183 e.printStackTrace();
184 System.exit(1);
185 }
186 }
187 @RolesAllowed({"org.onap.aaf.myapp.myPerm|myInstance|myAction"})
188 public static class MyServlet implements Servlet {
189 private ServletConfig servletConfig;
190
191 public void init(ServletConfig config) throws ServletException {
192 servletConfig = config;
193 }
194
195 public ServletConfig getServletConfig() {
196 return servletConfig;
197 }
198
199 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
200 HttpServletRequest request;
201 try {
202 request = (HttpServletRequest)req;
203 } catch (ClassCastException e) {
204 throw new ServletException("Only serving HTTP today",e);
205 }
206
207 res.getOutputStream().print("<html><header><title>CSP Servlet Test</title></header><body><h1>You're good to go!</h1><pre>" +
208 request.getUserPrincipal());
209
210 String perm = request.getParameter("PERM");
211 if(perm!=null)
212 if(request.isUserInRole(perm)) {
213 if(perm.indexOf('|')<0)
214 res.getOutputStream().print("\nCongrats!, You are in Role " + perm);
215 else
216 res.getOutputStream().print("\nCongrats!, You have Permission " + perm);
217 } else {
218 if(perm.indexOf('|')<0)
219 res.getOutputStream().print("\nSorry, you are NOT in Role " + perm);
220 else
221 res.getOutputStream().print("\nSorry, you do NOT have Permission " + perm);
222 }
223
224 res.getOutputStream().print("</pre></body></html>");
225
226 }
227
228 public String getServletInfo() {
229 return "MyServlet";
230 }
231
232 public void destroy() {
233 }
234 }
Sai Gandham4e6f7bc2018-06-15 08:37:30 -0500235 }
Sai Gandham5e236c72018-06-15 00:44:18 -0500236
237Java Direct (AAFLur) Method
238===========================
239The AAFLur is the exact component used within all the Plugins mentioned above. It is written so that it can be called standalone as well, see the Example as follows
Sai Gandham5e236c72018-06-15 00:44:18 -0500240
Sai Gandham4e6f7bc2018-06-15 08:37:30 -0500241.. code-block:: java
Sai Gandham5e236c72018-06-15 00:44:18 -0500242
Sai Gandham4e6f7bc2018-06-15 08:37:30 -0500243 package org.onap.aaf.example;
Sai Gandham5e236c72018-06-15 00:44:18 -0500244
Sai Gandham4e6f7bc2018-06-15 08:37:30 -0500245 import java.util.ArrayList;
246 import java.util.List;
247 import java.util.Properties;
248
249 import org.onap.aaf.cadi.Access;
250 import org.onap.aaf.cadi.Permission;
251 import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
252 import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
253 import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
254 import org.onap.aaf.cadi.config.Config;
255 import org.onap.aaf.cadi.lur.aaf.AAFPermission;
256 import org.onap.aaf.cadi.lur.aaf.test.TestAccess;
257
258 public class ExamplePerm2_0 {
Sai Gandham5e236c72018-06-15 00:44:18 -0500259 public static void main(String args[]) {
260 // Normally, these should be set in environment. Setting here for clarity
261 Properties props = System.getProperties();
262 props.setProperty("AFT_LATITUDE", "32.780140");
263 props.setProperty("AFT_LONGITUDE", "-96.800451");
264 props.setProperty("AFT_ENVIRONMENT", "AFTUAT");
265 props.setProperty(Config.AAF_URL,
266 "https://DME2RESOLVE/service=org.onap.aaf.authz.AuthorizationService/version=2.0/envContext=TEST/routeOffer=BAU_SE"
267 );
268 props.setProperty(Config.AAF_USER_EXPIRES,Integer.toString(5*60000)); // 5 minutes for found items to live in cache
269 props.setProperty(Config.AAF_HIGH_COUNT,Integer.toString(400)); // Maximum number of items in Cache);
270 props.setProperty(Config.CADI_KEYFILE,"keyfile"); //Note: Be sure to generate with java -jar <cadi_path>/lib/cadi-core*.jar keygen keyfile
Sai Gandham4e6f7bc2018-06-15 08:37:30 -0500271 // props.setProperty("DME2_EP_REGISTRY_CLASS","DME2FS");
272 // props.setProperty("AFT_DME2_EP_REGISTRY_FS_DIR","../../authz/dme2reg");
Sai Gandham5e236c72018-06-15 00:44:18 -0500273
274
275 // Link or reuse to your Logging mechanism
276 Access myAccess = new TestAccess(); //
277
278 //
279 try {
280 AAFCon<?> con = new AAFConDME2(myAccess);
281
282 // AAFLur has pool of DME clients as needed, and Caches Client lookups
283 AAFLurPerm aafLur = con.newLur();
284 // Note: If you need both Authn and Authz construct the following:
285 AAFAuthn<?> aafAuthn = con.newAuthn(aafLur);
286
287 // Do not set Mech ID until after you construct AAFAuthn,
288 // because we initiate "401" info to determine the Realm of
289 // of the service we're after.
290 con.basicAuth("xxxx@aaf.abc.com", "XXXXXX");
291
292 try {
293
294 // Normally, you obtain Principal from Authentication System.
295 // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()
296 // If you use CADI as Authenticator, it will get you these Principals from
297 // CSP or BasicAuth mechanisms.
298 String id = "xxxx@aaf.abc.com"; //"cluster_admin@gridcore.abc.com";
299
300 // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.
301 String ok = aafAuthn.validate(id, "XXXXXX");
302 if(ok!=null)System.out.println(ok);
303
304 ok = aafAuthn.validate(id, "wrongPass");
305 if(ok!=null)System.out.println(ok);
306
307
308 // AAF Style permissions are in the form
309 // Type, Instance, Action
310 AAFPermission perm = new AAFPermission("org.onap.aaf.grid.core.coh",":dev_cluster", "WRITE");
311
312 // Now you can ask the LUR (Local Representative of the User Repository about Authorization
313 // With CADI, in J2EE, you can call isUserInRole("org.onap.aaf.mygroup|mytype|write") on the Request Object
314 // instead of creating your own LUR
315 System.out.println("Does " + id + " have " + perm);
316 if(aafLur.fish(id, perm)) {
317 System.out.println("Yes, you have permission");
318 } else {
319 System.out.println("No, you don't have permission");
320 }
321
322 System.out.println("Does Bogus have " + perm);
323 if(aafLur.fish("Bogus", perm)) {
324 System.out.println("Yes, you have permission");
325 } else {
326 System.out.println("No, you don't have permission");
327 }
328
329 // Or you can all for all the Permissions available
330 List<Permission> perms = new ArrayList<Permission>();
331
332 aafLur.fishAll(id,perms);
333 for(Permission prm : perms) {
334 System.out.println(prm.getKey());
335 }
336
337 // It might be helpful in some cases to clear the User's identity from the Cache
338 aafLur.remove(id);
339 } finally {
340 aafLur.destroy();
341 }
342 } catch (Exception e) {
343 e.printStackTrace();
344 }
345
346 }
Sai Gandham4e6f7bc2018-06-15 08:37:30 -0500347 }
Sai Gandham5e236c72018-06-15 00:44:18 -0500348
Sai Gandham4e6f7bc2018-06-15 08:37:30 -0500349
Sai Gandham5e236c72018-06-15 00:44:18 -0500350There are two current AAF Lurs which you can utilize:
351 Org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm is the default, and will fish based on the Three-fold "Permission" standard in AAF
352To run this code, you will need from a SWM deployment (org.onap.aaf.cadi:cadi, then soft link to jars needed):
353 cadi-core-<version>.jar
354 cadi-aaf-<version>-full.jar
355 or by Maven
356<dependency>
357<groupId>org.onap.aaf.cadi</groupId>
358<artifactId>aaf-cadi-aaf</artifactId>
359<version>THE_LATEST_VERSION</version>
360<classifier>full</classifier>
361</dependency>
362
363