update missing aaf documentation
[aaf/authz.git] / docs / sections / configuration / service.rst
1 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
2 .. http://creativecommons.org/licenses/by/4.0
3
4 Service Configuration  - Connecting to AAF
5 ==========================================
6
7
8
9 Methods 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
29 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
30 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.  
31 Rogue Clients can and will be denied access to AAF.
32
33
34 J2EE (Servlet Filter) Method
35 ============================
36
37 1.      Per J2EE design, the Filter will deny any unauthenticated HTTP/S call; the Servlet will not even be invoked.
38 a.      Therefore, the Servlet can depend on any transaction making it to their code set is Authenticated.
39 b.      Identity can be viewed based on the HttpServletRequest Object (request.getUserPrincipal() )
40 2.      Per J2EE design, AAF Filter overloads the HttpServletRequest for a String related to "Role".  (request.isUserInRole("...") )
41 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".
42 3.      NOT REQUIRED: An added benefit, but not required, is a JASPI like interface, where you can add an Annotation to your Servlet. 
43 a.      When used, no transaction will come into your code if the listed Permissions are not Granted to the Incoming Transaction.  
44 b.      This might be helpful for covering separate Management Servlet implementations.
45
46
47
48 Servlet Code Snippet
49 =========================
50
51 public 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
72 Here is a working TestServlet, where you can play with different Permissions that you own on the URL, i.e.:
73 https://<your machine:port>/caditest/testme?PERM=org.onap.aaf.myapp.myPerm|*|write
74
75 Sample Servlet (Working example)
76 ================================
77 package org.onap.aaf.cadi.debug;
78 import java.io.FileInputStream;
79 import java.io.IOException;
80 import java.net.InetAddress;
81 import java.net.UnknownHostException;
82 import java.util.HashMap;
83 import java.util.Map;
84 import java.util.Map.Entry;
85 import java.util.Properties;
86 import javax.servlet.Servlet;
87 import javax.servlet.ServletConfig;
88 import javax.servlet.ServletException;
89 import javax.servlet.ServletRequest;
90 import javax.servlet.ServletResponse;
91 import javax.servlet.http.HttpServletRequest;
92 import org.eclipse.jetty.server.Server;
93 import org.eclipse.jetty.server.ServerConnector;
94 import org.eclipse.jetty.server.handler.ContextHandler;
95 import org.eclipse.jetty.servlet.FilterHolder;
96 import org.eclipse.jetty.servlet.FilterMapping;
97 import org.eclipse.jetty.servlet.ServletContextHandler;
98 import org.eclipse.jetty.servlet.ServletHandler;
99 import org.onap.aaf.cadi.filter.CadiFilter;
100 import org.onap.aaf.cadi.filter.RolesAllowed;
101 import org.onap.aaf.cadi.jetty.MiniJASPIWrap;
102  
103 public 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  
231 Java Direct (AAFLur) Method
232 ===========================
233 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
234 package org.onap.aaf.example;
235
236 import java.util.ArrayList;
237 import java.util.List;
238 import java.util.Properties;
239
240 import org.onap.aaf.cadi.Access;
241 import org.onap.aaf.cadi.Permission;
242 import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
243 import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
244 import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
245 import org.onap.aaf.cadi.config.Config;
246 import org.onap.aaf.cadi.lur.aaf.AAFPermission;
247 import org.onap.aaf.cadi.lur.aaf.test.TestAccess;
248
249 public 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
340 There 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
342 To 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