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