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