update missing aaf documentation 25/54925/1
authorSai Gandham <sg481n@att.com>
Fri, 15 Jun 2018 05:44:18 +0000 (00:44 -0500)
committerSai Gandham <sg481n@att.com>
Fri, 15 Jun 2018 05:44:25 +0000 (00:44 -0500)
Issue-ID: AAF-359
Change-Id: Iec79822da2d08c19847acc124cbe060f0b296fc8
Signed-off-by: Sai Gandham <sg481n@att.com>
docs/sections/configuration/client.rst
docs/sections/configuration/service.rst

index 31106b8..4b8fe20 100644 (file)
@@ -29,183 +29,4 @@ For Beijing, full TLS is expected among all components.  AAF provides the "Certi
 
 Example Source Code
 -------------------
-Note the FULL class is available in the authz repo, cadi_aaf/org/onap/aaf/client/sample/Sample.java
-
-.. code:: java
-
-/**
- * ============LICENSE_START====================================================
- * org.onap.aaf
- * ===========================================================================
- * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
- * ===========================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END====================================================
- *
- */
-package org.onap.aaf.client.sample;
-import java.io.IOException;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.List;
-import org.onap.aaf.cadi.Access;
-import org.onap.aaf.cadi.CadiException;
-import org.onap.aaf.cadi.LocatorException;
-import org.onap.aaf.cadi.Permission;
-import org.onap.aaf.cadi.PropAccess;
-import org.onap.aaf.cadi.aaf.AAFPermission;
-import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
-import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp;
-import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
-import org.onap.aaf.cadi.principal.UnAuthPrincipal;
-import org.onap.aaf.cadi.util.Split;
-import org.onap.aaf.misc.env.APIException;
-public class Sample {
-    private static Sample singleton;
-    final private AAFConHttp aafcon;
-    final private AAFLurPerm aafLur;
-    final private AAFAuthn<?> aafAuthn;
-     
-    /**
-     * This method is to emphasize the importance of not creating the AAFObjects over and over again.
-     * @return
-     */
-    public static Sample singleton() {
-        return singleton;
-    }
-    public Sample(Access myAccess) throws APIException, CadiException, LocatorException {
-        aafcon = new AAFConHttp(myAccess);
-        aafLur = aafcon.newLur();
-        aafAuthn = aafcon.newAuthn(aafLur);
-    }
-     
-    /**
-     * Checking credentials outside of HTTP/S presents fewer options initially. There is not, for instance,
-     * the option of using 2-way TLS HTTP/S.
-     * 
-     *  However, Password Checks are still useful, and, if the Client Certificate could be obtained in other ways, the
-     *  Interface can be expanded in the future to include Certificates.
-     * @throws CadiException
-     * @throws IOException
-     */
-    public Principal checkUserPass(String fqi, String pass) throws IOException, CadiException {
-        String ok = aafAuthn.validate(fqi, pass);
-        if(ok==null) {
-            System.out.println("Success!");
-            /*
-             UnAuthPrincipal means that it is not coming from the official Authorization chain.
-             This is useful for Security Plugins which don't use Principal as the tie between
-             Authentication and Authorization
-             
-             You can also use this if you want to check Authorization without actually Authenticating, as may
-             be the case with certain Onboarding Tooling.
-            */
-            return new UnAuthPrincipal(fqi);
-        } else {
-            System.out.printf("Failure: %s\n",ok);
-            return null;
-        }
-         
-    }
-    /**
-     * An example of looking for One Permission within all the permissions user has.  CADI does cache these,
-     * so the call is not expensive.
-     *
-     * Note: If you are using "J2EE" (Servlets), CADI ties this function to the method:
-     *    HttpServletRequest.isUserInRole(String user)
-     *   
-     *  The J2EE user can expect that his servlet will NOT be called without a Validated Principal, and that
-     *  "isUserInRole()" will validate if the user has the Permission designated.
-     * 
-     */
-    public boolean oneAuthorization(Principal fqi, Permission p) {
-        return aafLur.fish(fqi, p);
-    }
-     
-    public List<Permission> allAuthorization(Principal fqi) {
-        List<Permission> pond = new ArrayList<Permission>();
-        aafLur.fishAll(fqi, pond);
-        return pond;
-    }
-     
-     
-    public static void main(String[] args) {
-        // Note: you can pick up Properties from Command line as well as VM Properties
-        // Code "user_fqi=... user_pass=..." (where user_pass can be encrypted) in the command line for this sample.
-        // Also code "perm=<perm type>|<instance>|<action>" to test a specific Permission
-        PropAccess myAccess = new PropAccess(args);
-        try {
-            /*
-             * NOTE:  Do NOT CREATE new aafcon, aafLur and aafAuthn each transaction.  They are built to be
-             * reused!
-             *
-             * This is why this code demonstrates "Sample" as a singleton.
-             */
-            singleton = new Sample(myAccess);
-            String user = myAccess.getProperty("user_fqi");
-            String pass= myAccess.getProperty("user_pass");
-             
-            if(user==null || pass==null) {
-                System.err.println("This Sample class requires properties user_fqi and user_pass");
-            } else {
-                pass =  myAccess.decrypt(pass, false); // Note, with "false", decryption will only happen if starts with "enc:"
-                // See the CODE for Java Methods used
-                Principal fqi = Sample.singleton().checkUserPass(user,pass);
-                 
-                if(fqi==null) {
-                    System.out.println("OK, normally, you would cease processing for an "
-                            + "unauthenticated user, but for the purpose of Sample, we'll keep going.\n");
-                    fqi=new UnAuthPrincipal(user);
-                }
-                 
-                // AGAIN, NOTE: If your client fails Authentication, the right behavior 99.9%
-                // of the time is to drop the transaction.  We continue for sample only.
-                 
-                // note, default String for perm
-                String permS = myAccess.getProperty("perm","org.osaaf.aaf.access|*|read");
-                String[] permA = Split.splitTrim('|', permS);
-                if(permA.length>2) {
-                    final Permission perm = new AAFPermission(permA[0],permA[1],permA[2]);
-                    // See the CODE for Java Methods used
-                    if(singleton().oneAuthorization(fqi, perm)) {
-                        System.out.printf("Success: %s has %s\n",fqi.getName(),permS);
-                    } else {
-                        System.out.printf("%s does NOT have %s\n",fqi.getName(),permS);
-                    }
-                }
-                 
-                 
-                // Another form, you can get ALL permissions in a list
-                // See the CODE for Java Methods used
-                List<Permission> permL = singleton().allAuthorization(fqi);
-                if(permL.size()==0) {
-                    System.out.printf("User %s has no Permissions THAT THE CALLER CAN SEE",fqi.getName());
-                } else {
-                    System.out.print("Success:\n");
-                    for(Permission p : permL) {
-                        System.out.printf("\t%s has %s\n",fqi.getName(),p.getKey());
-                    }
-                }
-            }
-        } catch (APIException | CadiException | LocatorException | IOException e) {
-            e.printStackTrace();
-        }
-    }
-}
\ No newline at end of file
+Note the FULL class is available in the authz repo, cadi_aaf/org/onap/aaf/client/sample/Sample.java
\ No newline at end of file
index 7cbbb74..ae5d030 100644 (file)
@@ -1,5 +1,353 @@
 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
 .. http://creativecommons.org/licenses/by/4.0
 
-Service Configuration
-=====================
+Service Configuration  - Connecting to AAF
+==========================================
+
+
+
+Methods to Connect
+==================
+
+•    If you are a Servlet in a Container, use CADI Framework with AAF Plugin.  It's very easy, and includes BasicAuth for Services.  
+•    Java Technologies
+•    Technologies using Servlet Filters
+•    DME2 (and other Servlet Containers) can use Servlet Filters
+•    Any WebApp can plug in CADI as a Servlet Filter
+•    Jetty can attach a Servlet Filter with Code, or as WebApp
+•    Tomcat 7 has a "Valve" plugin, which is similar and supported
+•    Use the AAFLur Code directly (shown)
+•    All Java Technologies utilize Configuration to set what Security elements are required
+•    example: Global Login can be turned on/off, AAF Client needs information to connect to AAF Service
+•    There are several specialty cases, which AAF can work with, including embedding all properties in a Web.xml, but the essentials needed are:
+•    CADI Jars
+•    cadi.properties file (configured the same for all technologies)
+•    Encrypt passwords with included CADI technology, so that there are no Clear Text Passwords in Config Files (ASPR)
+•    See CADI Deployment on how to perform this with several different technologies.
+•    AAF Restfully (see RESTFul APIS)
+
+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
+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.  
+Rogue Clients can and will be denied access to AAF.
+
+
+J2EE (Servlet Filter) Method
+============================
+
+1.     Per J2EE design, the Filter will deny any unauthenticated HTTP/S call; the Servlet will not even be invoked.
+a.     Therefore, the Servlet can depend on any transaction making it to their code set is Authenticated.
+b.     Identity can be viewed based on the HttpServletRequest Object (request.getUserPrincipal() )
+2.     Per J2EE design, AAF Filter overloads the HttpServletRequest for a String related to "Role".  (request.isUserInRole("...") )
+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".
+3.     NOT REQUIRED: An added benefit, but not required, is a JASPI like interface, where you can add an Annotation to your Servlet. 
+a.     When used, no transaction will come into your code if the listed Permissions are not Granted to the Incoming Transaction.  
+b.     This might be helpful for covering separate Management Servlet implementations.
+
+
+
+Servlet Code Snippet
+=========================
+
+public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
+    HttpServletRequest request;
+    try {
+        request = (HttpServletRequest)req;
+    } catch (ClassCastException e) {
+        throw new ServletException("Only serving HTTP today",e);
+    }
+     
+    // Note: CADI is OVERLOADING the concept of "isUserInRole".. You need to think "doesUserHavePermssion()"
+    // Assume that you have CREATED and GRANTED An AAF Permission in YOUR Namespace
+    // Example Permission:   "org.onap.aaf.myapp.myPerm * write"
+    // Think in your head, "Does user have write permission on any instance of org.onap.aaf.myapp.myPerm
+    if(request.isUserInRole("org.onap.aaf.myapp.myPerm|*|write")) { 
+        // *** Do something here that someone with "myPerm write" permissions is allowed to do
+    } else {
+        // *** Do something reasonable if user is denied, like an Error Message
+    }
+}
+
+Here is a working TestServlet, where you can play with different Permissions that you own on the URL, i.e.:
+https://<your machine:port>/caditest/testme?PERM=org.onap.aaf.myapp.myPerm|*|write
+
+Sample Servlet (Working example)
+================================
+package org.onap.aaf.cadi.debug;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.FilterMapping;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.onap.aaf.cadi.filter.CadiFilter;
+import org.onap.aaf.cadi.filter.RolesAllowed;
+import org.onap.aaf.cadi.jetty.MiniJASPIWrap;
+public class CSPServletTest {
+    public static void main(String[] args) {
+        // Go ahead and print Test reports in cadi-core first
+        Test.main(args);
+        String hostname=null;
+        try {
+            hostname = InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+        Properties props = new Properties();
+        Map<String,String> map = new HashMap<String,String>();
+        try {
+            FileInputStream fis = new FileInputStream("run/cadi.properties");
+            try {
+                props.load(fis);
+                String key,value;
+                for( Entry<Object, Object> es  : props.entrySet()) {
+                    key = es.getKey().toString();
+                    value = es.getValue().toString();
+                    map.put(key,value);
+                    if(key.startsWith("AFT_") || key.startsWith("DME2")) {
+                        System.setProperty(key,value);
+                    }
+                }
+            } finally {
+                fis.close();
+            }
+        } catch(IOException e) {
+            System.err.println("Cannot load run/cadi.properties");
+            System.exit(1);
+        }
+        String portStr = System.getProperty("port");
+        int port = portStr==null?8080:Integer.parseInt(portStr);
+        try {
+            // Add ServletHolder(s) and Filter(s) to a ServletHandler
+            ServletHandler shand = new ServletHandler();
+             
+            FilterHolder cfh = new FilterHolder(CadiFilter.class);
+            cfh.setInitParameters(map);
+             
+            shand.addFilterWithMapping(cfh, "/*", FilterMapping.ALL);
+            shand.addServletWithMapping(new MiniJASPIWrap(MyServlet.class),"/*");
+            // call initialize after start
+             
+            ContextHandler ch = new ServletContextHandler();
+            ch.setContextPath("/caditest");
+            ch.setHandler(shand);
+            for( Entry<Object,Object> es : props.entrySet()) {
+                ch.getInitParams().put(es.getKey().toString(), es.getValue().toString());
+            }
+            //ch.setErrorHandler(new MyErrorHandler());
+             
+            // Create Server and Add Context Handler
+            final Server server = new Server();
+            ServerConnector http = new ServerConnector(server);
+            http.setPort(port);
+            server.addConnector(http);
+            server.setHandler(ch);
+         
+            // Start
+            server.start();
+            shand.initialize();
+             
+            System.out.println("To test, put http://"+ hostname + ':' + port + "/caditest/testme in a browser or 'curl'");
+            // if we were really a server, we'd block the main thread with this join...
+            // server.join();
+            // But... since we're a test service, we'll block on StdIn
+            System.out.println("Press <Return> to end service...");
+            System.in.read();
+            server.stop();
+            System.out.println("All done, have a good day!");
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+    @RolesAllowed({"org.onap.aaf.myapp.myPerm|myInstance|myAction"})
+    public static class MyServlet implements Servlet {
+        private ServletConfig servletConfig;
+     
+        public void init(ServletConfig config) throws ServletException {
+            servletConfig = config;
+        }
+     
+        public ServletConfig getServletConfig() {
+            return servletConfig;
+        }
+     
+        public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
+            HttpServletRequest request;
+            try {
+                request = (HttpServletRequest)req;
+            } catch (ClassCastException e) {
+                throw new ServletException("Only serving HTTP today",e);
+            }
+             
+            res.getOutputStream().print("<html><header><title>CSP Servlet Test</title></header><body><h1>You're good to go!</h1><pre>" +
+                    request.getUserPrincipal());
+             
+            String perm = request.getParameter("PERM");
+            if(perm!=null)
+                if(request.isUserInRole(perm)) {
+                    if(perm.indexOf('|')<0) 
+                        res.getOutputStream().print("\nCongrats!, You are in Role " + perm);
+                      else
+                        res.getOutputStream().print("\nCongrats!, You have Permission " + perm);
+                } else {
+                    if(perm.indexOf('|')<0) 
+                        res.getOutputStream().print("\nSorry, you are NOT in Role " + perm);
+                      else
+                        res.getOutputStream().print("\nSorry, you do NOT have Permission " + perm);
+                }
+             
+            res.getOutputStream().print("</pre></body></html>");
+             
+        }
+     
+        public String getServletInfo() {
+            return "MyServlet";
+        }
+     
+        public void destroy() {
+        }
+    }
+}
+Java Direct (AAFLur) Method
+===========================
+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
+package org.onap.aaf.example;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.Permission;
+import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
+import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
+import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.lur.aaf.AAFPermission;
+import org.onap.aaf.cadi.lur.aaf.test.TestAccess;
+
+public class ExamplePerm2_0 {
+       public static void main(String args[]) {
+               // Normally, these should be set in environment.  Setting here for clarity
+               Properties props = System.getProperties();
+               props.setProperty("AFT_LATITUDE", "32.780140");
+               props.setProperty("AFT_LONGITUDE", "-96.800451");
+               props.setProperty("AFT_ENVIRONMENT", "AFTUAT");
+               props.setProperty(Config.AAF_URL,
+               "https://DME2RESOLVE/service=org.onap.aaf.authz.AuthorizationService/version=2.0/envContext=TEST/routeOffer=BAU_SE"
+                               );
+               props.setProperty(Config.AAF_USER_EXPIRES,Integer.toString(5*60000));   // 5 minutes for found items to live in cache
+               props.setProperty(Config.AAF_HIGH_COUNT,Integer.toString(400));         // Maximum number of items in Cache);
+               props.setProperty(Config.CADI_KEYFILE,"keyfile"); //Note: Be sure to generate with java -jar <cadi_path>/lib/cadi-core*.jar keygen keyfile
+//             props.setProperty("DME2_EP_REGISTRY_CLASS","DME2FS");
+//             props.setProperty("AFT_DME2_EP_REGISTRY_FS_DIR","../../authz/dme2reg");
+
+               
+               // Link or reuse to your Logging mechanism
+               Access myAccess = new TestAccess(); // 
+               
+               // 
+               try {
+                       AAFCon<?> con = new AAFConDME2(myAccess);
+                       
+                       // AAFLur has pool of DME clients as needed, and Caches Client lookups
+                       AAFLurPerm aafLur = con.newLur();
+                       // Note: If you need both Authn and Authz construct the following:
+                       AAFAuthn<?> aafAuthn = con.newAuthn(aafLur);
+
+                       // Do not set Mech ID until after you construct AAFAuthn,
+                       // because we initiate  "401" info to determine the Realm of 
+                       // of the service we're after.
+                       con.basicAuth("xxxx@aaf.abc.com", "XXXXXX");
+
+                       try {
+                               
+                               // Normally, you obtain Principal from Authentication System.
+                               // For J2EE, you can ask the HttpServletRequest for getUserPrincipal()
+                               // If you use CADI as Authenticator, it will get you these Principals from
+                               // CSP or BasicAuth mechanisms.
+                               String id = "xxxx@aaf.abc.com"; //"cluster_admin@gridcore.abc.com";
+
+                               // If Validate succeeds, you will get a Null, otherwise, you will a String for the reason.
+                               String ok = aafAuthn.validate(id, "XXXXXX");
+                               if(ok!=null)System.out.println(ok);
+                               
+                               ok = aafAuthn.validate(id, "wrongPass");
+                               if(ok!=null)System.out.println(ok);
+
+
+                               // AAF Style permissions are in the form
+                               // Type, Instance, Action 
+                               AAFPermission perm = new AAFPermission("org.onap.aaf.grid.core.coh",":dev_cluster", "WRITE");
+                               
+                               // Now you can ask the LUR (Local Representative of the User Repository about Authorization
+                               // With CADI, in J2EE, you can call isUserInRole("org.onap.aaf.mygroup|mytype|write") on the Request Object 
+                               // instead of creating your own LUR
+                               System.out.println("Does " + id + " have " + perm);
+                               if(aafLur.fish(id, perm)) {
+                                       System.out.println("Yes, you have permission");
+                               } else {
+                                       System.out.println("No, you don't have permission");
+                               }
+
+                               System.out.println("Does Bogus have " + perm);
+                               if(aafLur.fish("Bogus", perm)) {
+                                       System.out.println("Yes, you have permission");
+                               } else {
+                                       System.out.println("No, you don't have permission");
+                               }
+
+                               // Or you can all for all the Permissions available
+                               List<Permission> perms = new ArrayList<Permission>();
+                               
+                               aafLur.fishAll(id,perms);
+                               for(Permission prm : perms) {
+                                       System.out.println(prm.getKey());
+                               }
+                               
+                               // It might be helpful in some cases to clear the User's identity from the Cache
+                               aafLur.remove(id);
+                       } finally {
+                               aafLur.destroy();
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+       }
+}
+
+There are two current AAF Lurs which you can utilize:
+•    Org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm is the default, and will fish based on the Three-fold "Permission" standard in AAF
+To run this code, you will need from a SWM deployment (org.onap.aaf.cadi:cadi, then soft link to jars needed):
+•    cadi-core-<version>.jar
+•    cadi-aaf-<version>-full.jar
+   or by Maven
+<dependency>
+<groupId>org.onap.aaf.cadi</groupId>
+<artifactId>aaf-cadi-aaf</artifactId>
+<version>THE_LATEST_VERSION</version>
+<classifier>full</classifier> 
+</dependency>
+
+