Add documentation to aaf authz

Issue-id: AAF-59
Change-Id: I1408740737048e884c08b93544d18da94d689aeb
Signed-off-by: sg481n <sg481n@att.com>
diff --git a/docs/AAF-API-Documentation/Connecting-to-AAF.rst b/docs/AAF-API-Documentation/Connecting-to-AAF.rst
new file mode 100644
index 0000000..2c13f3e
--- /dev/null
+++ b/docs/AAF-API-Documentation/Connecting-to-AAF.rst
@@ -0,0 +1,353 @@
+=================

+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>cadi-aaf</artifactId>

+<version>THE_LATEST_VERSION</version>

+<classifier>full</classifier> 

+</dependency>

+   If you need the Java Client definitions only, 

+ 

+   Also needed are the DME2 Client libraries:

+•	dme2-<version>.jar

+•	discovery-clt-<version>.jar

+