openamf/src/java/org/openamf AdvancedGateway.java,1.11,1.12

[email protected]
Newsgroups gmane.comp.java.openamf.cvs
Message-ID <[email protected]>
Update of /cvsroot/openamf/openamf/src/java/org/openamf
In directory sc8-pr-cvs1:/tmp/cvs-serv11087/src/java/org/openamf

Modified Files:
	AdvancedGateway.java 
Log Message:
added patch submitted by Richard Kunze






This is what Richard had to say about his patch:

Hello everyone,

I am using OpenAMF in a project where we need fine-grained access control on 
the web services provided to Flash clients. I've changed OpenAMF to fit the 
following requirements:

- Control over which methods in a service handler are available via AMF and 
which are not
- Control over which user may access which may access what method.

A patch against the current (May 21 2003, 2:15 PM CEST) CVS is attached. The 
patch consists of a unified diff containing the changes to existing classes 
("openamf.diff") and Java sources for two new classes.

I have implemented the first requirement by having the AdvancedGateway check 
each method call against the method configuration before passing it off to 
the invoker. If no matching entry is found in the configuration, a 
"java.lang.NoSuchMethodException" is thrown. In order to provide a convenient 
means to enable all methods in a service without having to write method 
configurations for each of them, I've introduced "*" as wildcard for an 
arbitrary method name.

The second requirement is implemented in terms of the servlet security model. 
I have introduced a new method-level configuration element named 
"<access-constraint>" which can contain an abritrary number of "<role-name>" 
elements. If an access contraint is configured for a method, calling this 
method is only allowed if the user currently logged in is in one of the 
security roles defined in the access constraint. Roles are checked via 
javax.servlet.http.HttpServletRequest.isUserInRole(), user authentication is 
delegated to the servlet engine (i.e., you define a security constraint on 
the gateway servlet in web.xml to force authentication).

Here's a small example. Consider these two service classes:

public class PublicService {
? public String freeForAll() { ... }
? public String membersOnly() { ... }
? public String notAvailableInAMF() { ... }
}

public class AdminService {
? public boolean addMember(String name) { ... }
? public boolean removeMember() { ... }
}


and the corresponding service definitions from openamf-config.xml:

<service>
? <name>PublicService</name>
? <service-location>PublicService</service-location>
? <invoker-ref>Java</invoker-ref>
? <method>
? ? <name>freeForAll</name> ? ?
? </method>
? <method>
? ? <name>membersOnly</name> ? ?
? ? <access-constraint>
? ? ? ?<role-name>Member</role-name>
? ? ? ?<role-name>Administrator</role-name>
? ? </access-constraint>
? </method>
</service>

<service>
? <name>AdminService</name>
? <service-location>AdminService</service-location>
? <invoker-ref>Java</invoker-ref>
? <method>
? ? <name>*</name> ? ?
? ? <parameter><type>*</type></parameter>
? ? <access-constraint>
? ? ? ?<role-name>Administrator</role-name>
? ? </access-constraint>
? </method>
</service>

With this configuration, PublicService.freeForAll() is accessible by everyone, 
PublicService.membersOnly() is only accessible if the accessing user is in 
the "Member" or "Admistrator" role and is blocked for anyone else, and 
PublicService.notAvailableInAMF() is not accessible at all.

In AdminService, all methods are accessible for users in the "Administrator" 
role.



Index: AdvancedGateway.java
===================================================================
RCS file: /cvsroot/openamf/openamf/src/java/org/openamf/AdvancedGateway.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -C2 -d -r1.11 -r1.12
*** AdvancedGateway.java	5 May 2003 00:55:37 -0000	1.11
--- AdvancedGateway.java	21 May 2003 01:36:59 -0000	1.12
***************
*** 2,5 ****
--- 2,6 ----
  
  import java.io.IOException;
+ import java.security.Principal;
  import java.util.ArrayList;
  import java.util.Iterator;
***************
*** 10,22 ****
  import org.apache.commons.logging.LogFactory;
  import org.openamf.config.Config;
  import org.openamf.config.ServiceConfig;
  import org.openamf.config.ServiceMethodConfig;
  import org.openamf.config.ServiceMethodParameterConfig;
  import org.openamf.config.StateBeanConfig;
- import org.openamf.config.FilterConfig;
- import org.openamf.invoker.ServiceInvocationException;
- import org.openamf.invoker.ServiceInvoker;
  import org.openamf.filter.FilterException;
  import org.openamf.filter.ResultFilter;
  import org.xml.sax.SAXException;
  
--- 11,25 ----
  import org.apache.commons.logging.LogFactory;
  import org.openamf.config.Config;
+ import org.openamf.config.FilterConfig;
  import org.openamf.config.ServiceConfig;
+ import org.openamf.config.ServiceMethodAccessConstraintConfig;
  import org.openamf.config.ServiceMethodConfig;
  import org.openamf.config.ServiceMethodParameterConfig;
  import org.openamf.config.StateBeanConfig;
  import org.openamf.filter.FilterException;
  import org.openamf.filter.ResultFilter;
+ import org.openamf.invoker.AccessDeniedException;
+ import org.openamf.invoker.ServiceInvocationException;
+ import org.openamf.invoker.ServiceInvoker;
  import org.xml.sax.SAXException;
  
***************
*** 41,44 ****
--- 44,83 ----
  				getMethodConfig(serviceConfig, request);
  
+ 			// abort if no method config is found. This allows us to restrict
+ 			// access to the service in the openamf confguration.
+ 			if (methodConfig == null) {
+ 				StringBuffer paramTypes = new StringBuffer("(");
+ 				for (Iterator i = request.getParameters().iterator(); i.hasNext();) {
+ 					String type = i.next().getClass().getName();
+ 					paramTypes.append(type);
+ 					if (i.hasNext()) {paramTypes.append(", "); }
+ 				}
+ 				paramTypes.append(")");
+ 				throw new NoSuchMethodException(request.getServiceMethodName()
+ 				                                + paramTypes.toString());
+ 			}
+ 			
+ 			// store methodConfig for later use
+ 			request.setServiceMethodConfig(methodConfig);
+ 
+ 			// Check access permissions if there are any in the configuration
+ 			Iterator constraints = 
+ 			   methodConfig.getAccessConstraintConfigs();
+ 			if (constraints.hasNext()) {
+ 				boolean accessDenied = true;
+ 				while (accessDenied && constraints.hasNext()) {
+ 					ServiceMethodAccessConstraintConfig constraint =
+ 					  (ServiceMethodAccessConstraintConfig)constraints.next();
+ 					accessDenied =
+ 						!httpServletRequest.isUserInRole(
+ 							constraint.getRoleName());
+ 				}
+ 				if (accessDenied) {
+ 					Principal user = httpServletRequest.getUserPrincipal(); 
+ 					throw new AccessDeniedException(
+ 					 	(user==null?"<anonymous user>":user.getName())); 
+ 				}
+ 			}
+ 			
  			addStateBeansToParams(httpServletRequest, request, methodConfig);
  			
***************
*** 209,214 ****
  
  			ServiceMethodConfig smc = (ServiceMethodConfig) smcs.next();
! 			log.debug("soc name: " + smc.getName());
! 			if (smc.getName().equals(request.getServiceMethodName())) {
  				log.debug("name matches, now to compare params");
  				//compare params
--- 248,255 ----
  
  			ServiceMethodConfig smc = (ServiceMethodConfig) smcs.next();
! 			String smcName = smc.getName();
! 			log.debug("soc name: " + smcName);
! 			if ("*".equals(smcName) 
! 			    || smcName.equals(request.getServiceMethodName())) {
  				log.debug("name matches, now to compare params");
  				//compare params
***************
*** 227,231 ****
  						sopc.getType().equals("?")
  							|| typesMatch(parameters, paramIndex, sopc)) {
! 						if (paramIndex == parameters.size()) {
  							log.debug("all parameters match");
  							methodConfig = smc;
--- 268,272 ----
  						sopc.getType().equals("?")
  							|| typesMatch(parameters, paramIndex, sopc)) {
! 						if (paramIndex == parameters.size()-1) {
  							log.debug("all parameters match");
  							methodConfig = smc;
***************
*** 240,246 ****
  			}
  		}
- 
- 		//store methodConfig in request so we don't have to get it again
- 		request.setServiceMethodConfig(methodConfig);
  
  		return methodConfig;
--- 281,284 ----




-------------------------------------------------------
This SF.net email is sponsored by: ObjectStore.
If flattening out C++ or Java code to make your application fit in a
relational database is painful, don't do it! Check out ObjectStore.
Now part of Progress Software. http://www.objectstore.net/sourceforge
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.