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