From 5e236c7f723de49456d56e06b524b6ef3e2a51d7 Mon Sep 17 00:00:00 2001 From: Sai Gandham Date: Fri, 15 Jun 2018 00:44:18 -0500 Subject: update missing aaf documentation Issue-ID: AAF-359 Change-Id: Iec79822da2d08c19847acc124cbe060f0b296fc8 Signed-off-by: Sai Gandham --- docs/sections/configuration/client.rst | 181 +--------------- docs/sections/configuration/service.rst | 352 +++++++++++++++++++++++++++++++- 2 files changed, 351 insertions(+), 182 deletions(-) (limited to 'docs') diff --git a/docs/sections/configuration/client.rst b/docs/sections/configuration/client.rst index 31106b88..4b8fe205 100644 --- a/docs/sections/configuration/client.rst +++ b/docs/sections/configuration/client.rst @@ -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 allAuthorization(Principal fqi) { - List pond = new ArrayList(); - 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=||" 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 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 diff --git a/docs/sections/configuration/service.rst b/docs/sections/configuration/service.rst index 7cbbb748..ae5d0305 100644 --- a/docs/sections/configuration/service.rst +++ b/docs/sections/configuration/service.rst @@ -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:///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 map = new HashMap(); + try { + FileInputStream fis = new FileInputStream("run/cadi.properties"); + try { + props.load(fis); + String key,value; + for( Entry 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 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 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("
CSP Servlet Test

You're good to go!

" +
+                    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("
"); + + } + + 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 /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 perms = new ArrayList(); + + 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-.jar +• cadi-aaf--full.jar + or by Maven + +org.onap.aaf.cadi +aaf-cadi-aaf +THE_LATEST_VERSION +full + + + -- cgit 1.2.3-korg