Missing Licenses
[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 .. Copyright © 2017 AT&T Intellectual Property. All rights reserved.
4
5 Service Configuration  - Connecting to AAF
6 ==========================================
7
8
9
10 Methods 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
30 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
31 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.  
32 Rogue Clients can and will be denied access to AAF.
33
34
35 J2EE (Servlet Filter) Method
36 ============================
37
38 1.      Per J2EE design, the Filter will deny any unauthenticated HTTP/S call; the Servlet will not even be invoked.
39 a.      Therefore, the Servlet can depend on any transaction making it to their code set is Authenticated.
40 b.      Identity can be viewed based on the HttpServletRequest Object (request.getUserPrincipal() )
41 2.      Per J2EE design, AAF Filter overloads the HttpServletRequest for a String related to "Role".  (request.isUserInRole("...") )
42 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".
43 3.      NOT REQUIRED: An added benefit, but not required, is a JASPI like interface, where you can add an Annotation to your Servlet. 
44 a.      When used, no transaction will come into your code if the listed Permissions are not Granted to the Incoming Transaction.  
45 b.      This might be helpful for covering separate Management Servlet implementations.
46
47
48
49 Servlet Code Snippet
50 =========================
51
52 .. 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       }
61      
62       // 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"
65  
66       // 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  
73     }
74
75 Here is a working TestServlet, where you can play with different Permissions that you own on the URL, i.e.:
76 https://<your machine:port>/caditest/testme?PERM=org.onap.aaf.myapp.myPerm|*|write
77
78 Sample Servlet (Working example)
79 ================================
80
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;
108  
109   public class CSPServletTest {
110     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     }
235    }
236  
237 Java Direct (AAFLur) Method
238 ===========================
239 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
240
241 .. code-block:: java
242
243   package org.onap.aaf.example;
244
245   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 {
259         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
271   //            props.setProperty("DME2_EP_REGISTRY_CLASS","DME2FS");
272   //            props.setProperty("AFT_DME2_EP_REGISTRY_FS_DIR","../../authz/dme2reg");
273
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         }
347   }
348
349   
350 There 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
352 To 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