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