Announcement Announcement Module
Collapse
No announcement yet.
After Invocation Collection Filtering From an EJB (Stateless Session Bean) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • After Invocation Collection Filtering From an EJB (Stateless Session Bean)

    Hi,

    I am working on a proof of concept to integrate spring security into our J2EE application. I would like to use ACL to filter out search results from a returned collection. I looked through the dms example and found out about the AclEntryAfterInvocationCollectionFilteringProvider and its configuration. This would do exactly what I want but the problem is that the class containg the method to intercept is an EJB (a Stateless Session Bean).

    This application is deployed on a Weblogic 10.3.4 server as an ear. I have followed the steps to propagate the application context in the jar containing the ejb (http://blog.springsource.com/2007/06...g-application/). Here is what the ear looks like:

    my-app.ear
    ---web-client.war
    ------WEB-INF
    ---------web-context.xml
    ---------web.xml
    ---------...
    ---ejb-modules.jar
    ------beanRefContext.xml
    ------ejb-context.xml
    ------some/path/ClientAPI
    ------some/path/ClientAPIBean
    ------...
    ---...

    I looked at the available jee tags to lookup an EJB from JNDI and came up with the following line (in ejb-context.xml):

    Code:
    	
    ...
    	<jee:local-slsb id="clientAPIBean"
    		jndi-name="clientAPIBean#some.path.ClientAPI"
    		business-interface="some.path.ClientAPI" />
    ...
    Here is a snippet from web-context.xml which defines the MethodSecurityInterceptor and its dependencies:

    Code:
    ...
    	<bean id="methodSecurityInterceptor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
    		<property name="authenticationManager">
    			<ref bean="authenticationManager" />
    		</property>
    		<property name="accessDecisionManager">
    			<ref local="businessAccessDecisionManager" />
    		</property>
    		<property name="afterInvocationManager">
    			<ref local="afterInvocationManager" />
    		</property>
    		<property name="securityMetadataSource">
    			<value>
    			some.path.ClientAPI.retrieveAllItems=AFTER_ACL_COLLECTION_READ
    			</value>
    		</property>
    	</bean>
    ...
    Note that the some.path.ClientAPI EJB is used in a value tag so I cannot use the reference to the EJB I created in ejb-context.xml.

    After deploying the ear in Weblogic my log4j log states that beans are getting created and configured properly with no exceptions. The logs also state that spring successfully retireved the some.path.ClientAPI EJB from JNDI

    However, when the retrieveAllItems method is executed nothing gets printed to my log4j log as if the interceptor did not get called.

    What are my doing wrong? How would I get the MethodSecurityInterceptor to actually do something?

    Thank you!
    Last edited by McDuff; Aug 22nd, 2011, 04:10 PM. Reason: clarifications

  • #2
    Only configuring the MethodSecurityInterceptor isn't going to do much if you don't create a proxy which actually uses that interceptor. I suggest using the namespace instead of the classes, it saves you a lot of configuration. Also make sure that the method security is configured in the same application context that is used to create/retrieve the EJB else proxying isn't going to happen.

    Comment


    • #3
      MethodSecurityInterceptor still not triggered after calling my secured ejb method!

      Thank you for the reply.

      Following your suggestion I changed the ear's directory tree so my application context is contained in a single file (context.xml):

      my-app.ear
      ---web-client.war
      ------WEB-INF
      ---------web.xml
      ---------...
      ---ejb-modules.jar
      ------beanRefContext.xml
      ------context.xml
      ------some/path/ClientAPI
      ------some/path/ClientAPIBean
      ------...
      ---...

      Here is a snippet of my web.xml:
      Code:
      	
      ...
      	<context-param>
      		<param-name>parentContextKey</param-name>
      		<param-value>context</param-value>
      	</context-param>
      
      	<context-param>
      		<param-name>contextConfigLocation</param-name>
      		<param-value></param-value>
      	</context-param>
      	
      	<listener>
      		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      	</listener>
      	
      	<listener>
      	    	<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
      	</listener>
      ...
      This has the effect looking for the beanRefContext.xml file in the ejb-modules.jar which contains the ejb to secure. Here is the content of beanRefContext.xml:
      Code:
      	
      ...
      	<bean id="context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
      	    <constructor-arg>
      	        <list>
      	            <value>context.xml</value>
      	        </list>
      	    </constructor-arg>
      	</bean>
      ...
      context.xml, which contains all bean and security entries, is now getting used as the spring application context.

      Following your other suggestion, I added a proxy that uses my security method interceptor. Here is a snippet from context.xml:
      Code:
      	
      ...
      	
      	<jee:local-slsb id="clientAPIBean"
      		jndi-name="clientAPIBean#some.path.ClientAPI"
      		business-interface="some.path.ClientAPI" />
      
      	<bean id="methodSecurityMetadataSourceAdvisor"
      		class="org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor">
      		<constructor-arg ref="methodSecurityInterceptor" />
      	</bean>
      
      	<bean
      		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
      		id="defaultAdvisorAutoProxyCreator">
      		<property name="beanName" value="methodSecurityMetadataSourceAdvisor" />
      	</bean>
      
      	<bean id="methodSecurityInterceptor"
      		class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
      		<property name="authenticationManager">
      			<ref bean="authenticationManager" />
      		</property>
      		<property name="accessDecisionManager">
      			<ref local="businessAccessDecisionManager" />
      		</property>
      		<property name="afterInvocationManager">
      			<ref local="afterInvocationManager" />
      		</property>
      		<property name="securityMetadataSource">
      			<value>
      				some.path.ClientAPI.retrieveAllItems=AFTER_ACL_COLLECTION_READ
      			</value>
      		</property>
      	</bean>
      
      	<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter" />
      
      	<bean id="businessAccessDecisionManager"
      		class="org.springframework.security.access.vote.AffirmativeBased">
      		<property name="allowIfAllAbstainDecisions" value="true" />
      		<property name="decisionVoters">
      			<list>
      				<ref local="roleVoter" />
      			</list>
      		</property>
      	</bean>
      
      	<security:global-method-security
      		access-decision-manager-ref="businessAccessDecisionManager">
      	</security:global-method-security>
      ...
      When I deployed the ear to Weblogic, the log4j log still looks ok:
      Code:
      	
      ...
      [org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean] Located object with JNDI name [java:comp/env/ClientAPIBean#some.path.ClientAPI]
      [org.springframework.aop.framework.JdkDynamicAopProxy] Creating JDK dynamic proxy: target source is EmptyTargetSource: no target class, static
      [org.springframework.beans.factory.support.DefaultListableBeanFactory] Finished creating instance of bean 'clientAPIBean'
      ...
      [org.springframework.web.context.ContextLoader] Root WebApplicationContext: initialization completed in 4141 ms
      ...
      If I used my web UI to go through the use case where the some.path.ClientAPI.retrieveAllItems method is called, the log4j log does not show any other messages. I would expect to see method security interceptor related messages. Once again, it is not getting called.

      Is there anything else I can try?

      Thank you!

      PS: About your suggestion on using namespace style configuration, I did not find an application context descriptor in samples/examples that uses that style to declare method security interceptors and its dependencies. Do you know about any sample/example that would do such a thing?

      Also, I had a look at this page. How would I use the global-method-security to declare my interceptor?

      Comment


      • #4
        Currently you are mixing 2 strategies which I guess interfere with each other..

        Namespace configuration
        Code:
        <security:global-method-security
        		access-decision-manager-ref="businessAccessDecisionManager">
        	</security:global-method-security>
        Plain configuration
        Code:
        </bean>
        
        	<bean
        		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        		id="defaultAdvisorAutoProxyCreator">
        		<property name="beanName" value="methodSecurityMetadataSourceAdvisor" />
        	</bean>
        
        	<bean id="methodSecurityInterceptor"
        		class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
        		<property name="authenticationManager">
        			<ref bean="authenticationManager" />
        		</property>
        		<property name="accessDecisionManager">
        			<ref local="businessAccessDecisionManager" />
        		</property>
        		<property name="afterInvocationManager">
        			<ref local="afterInvocationManager" />
        		</property>
        		<property name="securityMetadataSource">
        			<value>
        				some.path.ClientAPI.retrieveAllItems=AFTER_ACL_COLLECTION_READ
        			</value>
        		</property>
        	</bean>
        
        	<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter" />
        
        	<bean id="businessAccessDecisionManager"
        		class="org.springframework.security.access.vote.AffirmativeBased">
        		<property name="allowIfAllAbstainDecisions" value="true" />
        		<property name="decisionVoters">
        			<list>
        				<ref local="roleVoter" />
        			</list>
        		</property>
        	</bean>
        I suggest the namespace and remove all plain configuration (for as far it isn't needed).

        Code:
        <security:global-method-security access-decision-manager-ref="businessAccessDecisionManager" after-invocation-provider="afterInvocationProvider">
          <security:protect-pointcut expression="execution(* some.path.ClientAPI+.retrieveAllItem(..))" access="AFTER_ACL_COLLECTION_READ" />
        </security:global-method-security>

        Comment


        • #5
          Still not working

          Thanks for your help Marten.

          I tried the namespace based configuration and my after invocation filtering still does not get triggered. I will continue to investigate and reply with more details later.

          I had another question. Is the jee:local-slsb tag in my initial configuration required? If so how does spring AOP knows to use the ejb retired via JNDI?

          Thanks again!
          Last edited by McDuff; Aug 24th, 2011, 11:33 AM.

          Comment


          • #6
            I had another question. Is the jee:local-slsb tag in my initial configuration required? If so how does spring AOP knows to use the ejb retired via JNDI?
            Well actually it doesn't know anything about the ejb, it knows that there is an object which implements the ClientAPI interface (a dynamically created proxy which handles all the ugly ejb stuff).

            Which makes me wonder that could be very well be the problem (because it is already a proxy), what you could try is create a simply bean that implements the ClientAPI interface and see what happens (just as a test).

            Another thing you can do is throw a (Runtime)Exception from the method mentioned and see if the MethodSecurity is applied (the interceptor should then show up in the stack trace).
            Last edited by Marten Deinum; Aug 24th, 2011, 01:55 PM.

            Comment


            • #7
              I threw a RuntimeException from the method to secure. The following is a snippet of the stack trace. The trace is identical if I use the jee tag to declare my ejb or if I don't declare it at all.

              Code:
                      at com.bea.core.repackaged.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
                      at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
                      at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
                      at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
                      at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
                      at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                      at com.bea.core.repackaged.springframework.jee.spi.MethodInvocationVisitorImpl.visit(MethodInvocationVisitorImpl.java:37)
                      at weblogic.ejb.container.injection.EnvironmentInterceptorCallbackImpl.callback(EnvironmentInterceptorCallbackImpl.java:54)
                      at com.bea.core.repackaged.springframework.jee.spi.EnvironmentInterceptor.invoke(EnvironmentInterceptor.java:50)
                      at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                      at com.bea.core.repackaged.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
                      at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                      at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
                      at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
                      at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                      at com.bea.core.repackaged.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
              I might try your other suggestion later. Right now I'm looking at manually invoking the decide method of AclEntryAfterInvocationCollectionFilteringProvider from my method.

              Thanks!

              Comment


              • #8
                I threw a RuntimeException from the method to secure. The following is a snippet of the stack trace. The trace is identical if I use the jee tag to declare my ejb or if I don't declare it at all.
                If it is exactly the same how do you get the ejb? Can you show me the code which is calling the ejb? Because it it doesn't make any difference that would indicate to me you aren't using the beans declared in your application context...

                Comment


                • #9
                  If it is exactly the same how do you get the ejb?
                  Code:
                  	<jee:local-slsb id="clientAPIBean"
                  		jndi-name="clientAPIBean#some.path.ClientAPI"
                  		business-interface="some.path.ClientAPI" />
                  Because if it doesn't make any difference that would indicate to me you aren't using the beans declared in your application context...
                  It does not make a difference because I do not know how to tell the AOP pointcut expression to use the ejb that was imported into the spring context. I presumed that the AOP pointcut expression would be smart enough to know it had to use my imported ejb. I had that concern in a previous post:

                  I had another question. Is the jee:local-slsb tag in my initial configuration required? If so how does spring AOP knows to use the ejb retired via JNDI?
                  Anyways, here is my config at the moment:

                  Code:
                  ...
                  	<security:global-method-security
                  		access-decision-manager-ref="accessDecisionManager">
                  		<security:protect-pointcut
                  			expression="execution(* some.path.ClientAPI+.retrieveItems(..))"
                  			access="ALWAYS_GRANT" />
                  		<security:after-invocation-provider
                  			ref="afterAclCollectionRead" />
                  	</security:global-method-security>
                  
                  	<jee:local-slsb id="clientAPIBean"
                  		jndi-name="clientAPIBean#some.path.ClientAPI"
                  		business-interface="some.path.ClientAPI" />
                  
                  	<bean id="accessDecisionManager"
                  		class="org.springframework.security.access.vote.AffirmativeBased">
                  		<property name="decisionVoters">
                  			<list>
                  				<ref local="alwaysGrantAccessVoter" />
                  			</list>
                  		</property>
                  	</bean>
                  
                  	<bean id="alwaysGrantAccessVoter" class="some.path.AlwaysGrantAccessVoter" />
                  
                  	<bean id="afterAclCollectionRead"
                  		class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
                  		<constructor-arg ref="aclService" />
                  		<constructor-arg>
                  			<list>
                  				<ref local="aclReadPermission" />
                  			</list>
                  		</constructor-arg>
                  	</bean>
                  
                  	<bean id="aclReadPermission"
                  		class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
                  		<property name="staticField">
                  			<value>org.springframework.security.acls.domain.BasePermission.READ
                  			</value>
                  		</property>
                  	</bean>
                  ...
                  If you require more snippets let me know!

                  Thanks!

                  Comment


                  • #10
                    It does not make a difference because I do not know how to tell the AOP pointcut expression to use the ejb that was imported into the spring context. I presumed that the AOP pointcut expression would be smart enough to know it had to use my imported ejb. I had that concern in a previous post:
                    You stated that if you remove the jee stuff from the context the stack trace is the same... I want to know HOW do you use/access the clientAPI from your code... My guess is that you do not use this.So which bean do you wire the bean named 'clientAPIBean' into.

                    Is it possible for you to attach the whole project? Or is that going to be problematic, if you want I can PM you my email so you can send it to me privately.

                    Comment


                    • #11
                      Marten,

                      My code retireves the clientAPIBean from JNDI in the ServiceImpl class. Once it obtains the clientAPIBean, it calls the retieveItems method. I am now trying to convert the code so it retrieves the clientAPIBean from the spring application context instead. This is probably why the method call is not intercepted. I will keep you posted.

                      Thank you!

                      Comment


                      • #12
                        I want to know HOW do you use/access the clientAPI from your code... My guess is that you do not use this.
                        The clientAPIBean is retrieved via JNDI by the SeviceImpl class which then calls the retrieveItems method. I modifed the ServiceImpl class so it retrieves the clientAPIBean from the spring context instead.

                        Snippet from SeviceImpl.java:

                        Code:
                        ...
                            ValueSearchResult<ItemValue> searchResult = this.getClientApiFromSpring().retrieveItems(searchParams);
                        ...
                            private ClientAPI getClientApiFromSpring() {
                            	ClientAPI clientAPI;
                            	BeanFactoryReference bf = ContextSingletonBeanFactoryLocator.getInstance().useBeanFactory("context");
                            	clientAPI = (clientAPI) bf.getFactory().getBean("clientAPIBean");		
                            	return rdmsClientAPI;
                            }
                        ...
                        In the log I can see that the clientAPIBean is successfully retrieved from the spring context and the call to retrieveItems worked as my UI is showing the search results as expected.

                        Code:
                        ...
                        2011-08-25 14:01:38,734 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] Returning cached instance of singleton bean 'context'
                        2011-08-25 14:01:38,734 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] Returning cached instance of singleton bean 'clientAPIBean'
                        2011-08-25 14:01:38,734 DEBUG [org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean] Trying to create reference to local EJB
                        2011-08-25 14:01:38,734 DEBUG [org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean] Obtained reference to local EJB: [BaseRemoteObject] home: weblogic.ejb.container.internal.StatelessEJBHomeImpl@136fcc4
                        ...
                        However, the interceptor is still not triggered! I do not see any AOP interceptor related messages in my logs. If I put a breakpoint in AclEntryAfterInvocationCollectionFilteringProvider .decide(...) it is never called. I also placed one in clientAPIBean.retireveItems and it is called. I printed the stack trace from clientAPIBean.retireveItems:

                        Code:
                        ...
                        2011-08-25 14:01:38,736 INFO  [some.path.web.ejb.ClientAPIBean] java.lang.RuntimeException: Security trace
                        	at some.path.web.ejb.ClientAPIBean.retrieveFrameworks(ClientAPIBean.java:304)
                        	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                        	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                        	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                        	at java.lang.reflect.Method.invoke(Method.java:597)
                        	at com.bea.core.repackaged.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
                        	at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
                        	at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
                        	at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
                        	at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
                        	at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                        	at com.bea.core.repackaged.springframework.jee.spi.MethodInvocationVisitorImpl.visit(MethodInvocationVisitorImpl.java:37)
                        	at weblogic.ejb.container.injection.EnvironmentInterceptorCallbackImpl.callback(EnvironmentInterceptorCallbackImpl.java:54)
                        	at com.bea.core.repackaged.springframework.jee.spi.EnvironmentInterceptor.invoke(EnvironmentInterceptor.java:50)
                        	at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                        	at com.bea.core.repackaged.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
                        	at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                        	at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
                        	at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
                        	at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
                        	at com.bea.core.repackaged.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
                        	at $Proxy339.retrieveFrameworks(Unknown Source)
                        	at some.path.web.ejb.ClientAPIBean_6no8ps_ClientAPIImpl.__WL_invoke(Unknown Source)
                        	at weblogic.ejb.container.internal.SessionRemoteMethodInvoker.invoke(SessionRemoteMethodInvoker.java:40)
                        	at some.path.web.ejb.ClientAPIBean_6no8ps_ClientAPIImpl.retrieveFrameworks(Unknown Source)
                        	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                        	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                        	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                        	at java.lang.reflect.Method.invoke(Method.java:597)
                        	at org.springframework.ejb.access.LocalSlsbInvokerInterceptor.invokeInContext(LocalSlsbInvokerInterceptor.java:71)
                        	at org.springframework.ejb.access.AbstractSlsbInvokerInterceptor.invoke(AbstractSlsbInvokerInterceptor.java:189)
                        	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
                        	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
                        	at $Proxy337.retrieveFrameworks(Unknown Source)
                        	at some.path.gwt.server.ServiceImpl.getAllFrameworks(ServiceImpl.java:725)
                        	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                        	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                        	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                        	at java.lang.reflect.Method.invoke(Method.java:597)
                        	at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:562)
                        	at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:188)
                        	at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:224)
                        	at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
                        	at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
                        	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
                        	at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
                        	at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
                        	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
                        	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:183)
                        	at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3717)
                        	at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3681)
                        	at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
                        	at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
                        	at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2277)
                        	at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2183)
                        	at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1454)
                        	at weblogic.work.ExecuteThread.execute(ExecuteThread.java:207)
                        ...
                        Is there anything else I can try?

                        Thanks!

                        PS: You can PM me your email if you want the full logs and config files.

                        Comment


                        • #13
                          You should simply inject the dependency into your bean and not retrieve it (that would also save a dependency on spring) if you don't use the configuration from spring it is pretty useless to configure at the first place .

                          Check your PM for my email...

                          Comment


                          • #14
                            Hi,

                            I pretty much gave up on the method interceptor problem. I decided to move on with my proof of concept by manually invoking the AclEntryAfterInvocationCollectionFilteringProvider from my EJB. Here is my solution.

                            Here is the context.xml file. Note that I am not using spring's authentication as users are already logged in and a principal object exists in the EJB context.
                            Code:
                            <?xml version="1.0" encoding="UTF-8"?>
                            <beans xmlns="http://www.springframework.org/schema/beans"
                            	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
                            	xmlns:context="http://www.springframework.org/schema/context"
                            	xmlns:security="http://www.springframework.org/schema/security"
                            	xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"
                            	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                            		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                            		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                            		http://www.springframework.org/schema/security	http://www.springframework.org/schema/security/spring-security-3.0.xsd
                            		http://www.springframework.org/schema/util	http://www.springframework.org/schema/util/spring-util-3.0.xsd
                            		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
                            	">
                            
                            	<!-- ACL Service Configuration -->
                            	<bean id="aclService"
                            		class="org.springframework.security.acls.jdbc.JdbcAclService">
                            		<constructor-arg ref="dataSource" />
                            		<constructor-arg ref="lookupStrategy" />
                            		<constructor-arg ref="aclCache" />
                            	</bean>
                            
                            	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
                            		destroy-method="close">
                            		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
                            		<property name="url" value="jdbc:oracle:thin:@the:1521:oss" />
                            		<property name="username" value="edufresne" />
                            		<property name="password" value="ossadmin" />
                            	</bean>
                            
                            	<bean class="org.springframework.security.acls.jdbc.BasiLookupStrategy" id="lookupStrategy">
                            		<constructor-arg ref="dataSource" />
                            		<constructor-arg ref="aclCache" />
                            		<constructor-arg ref="aclAuthzStrategy" />
                            		<constructor-arg ref="aclAuditLogger" />
                            	</bean>
                            
                            	<bean class="some.path.NullAclCache" id="aclCache" />
                            
                            	<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"
                            		id="aclAuditLogger" />
                            
                            	<bean
                            		class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl"
                            		id="aclAuthzStrategy">
                            		<constructor-arg>
                            			<array>
                            				<ref local="aclAdminAuthority" />
                            				<ref local="aclAdminAuthority" />
                            				<ref local="aclAdminAuthority" />
                            			</array>
                            		</constructor-arg>
                            	</bean>
                            
                            	<bean
                            		class="org.springframework.security.core.authority.GrantedAuthorityImpl"
                            		id="aclAdminAuthority">
                            		<constructor-arg value="ROLE_ADMIN" />
                            	</bean>
                            
                            	<!-- Collection Filtering Configuration -->
                            	<bean id="afterAclCollectionRead"
                            		class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
                            		<constructor-arg ref="aclService" />
                            		<constructor-arg>
                            			<list>
                            				<ref local="aclReadPermission" />
                            			</list>
                            		</constructor-arg>
                            	</bean>
                            
                            	<bean id="aclReadPermission"
                            		class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
                            		<property name="staticField">
                            			<value>org.springframework.security.acls.domain.BasePermission.READ</value>
                            		</property>
                            	</bean>
                            
                            </beans>
                            I created the ACL database schema using the SQL scripts provided with spring security. I added data using the following SQL:

                            Code:
                            insert into acl_class (class) values ('some.path.Item');
                            
                            insert into acl_sid (principal, sid) values (1, 'someuser');
                            
                            insert into acl_object_identity (object_id_class,object_id_identity,parent_object,owner_sid,entries_inheriting)
                            select cl.id, 12345, null, sid.id, 0
                            from acl_class cl, acl_sid sid
                            where cl.class='some.path.Item' and sid.sid='someuser';
                            
                            insert into acl_entry (acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)
                            select oi.id, 1, si.id, 1, 1, 1, 1
                            from acl_object_identity oi, acl_sid si
                            where si.sid = 'someuser';
                            Since the EJB I wanted to secure resides in an EJP project, I could not trigger the initialization of the spring application context in a web.xml because there is no such file. Therefore, for this simple proof of concept, I initialiazed the application context directly from the EJB that is going to use it. I used the @PostConstruct annotation to trigger the initialization of the ClassPathXmlApplicationContext. Here is the EJB's code:

                            Code:
                            ...
                                @Resource
                                private EJBContext ejbContext;
                            ...
                                private ApplicationContext springContext;
                            ...
                                @PostConstruct
                                public void init() {
                                    springContext = new 
                            		ClassPathXmlApplicationContext("classpath*:context.xml");
                                }
                            ...
                                @Override
                                public Collection<Items> retrieveAllItems() {
                                	
                                	Collection<Items> results = ... // obtain the items.
                                	
                                    // --- Filter out the items the requesting user does not have access to ---
                            
                                    // Create an empty authorities collection.
                                    Collection<GrantedAuthorityImpl> authorities = new ArrayList<GrantedAuthorityImpl>();
                                    // Create an authentication token containing the principal's info.
                                    PreAuthenticatedAuthenticationToken preAuthToken = 
                                            new PreAuthenticatedAuthenticationToken(ejbContext.getCallerPrincipal(), null, authorities);
                                    // Create an config collection that hold the required permission name.
                                    SecurityConfig config = new SecurityConfig("AFTER_ACL_COLLECTION_READ");
                                    Collection<ConfigAttribute> configs = new ArrayList<ConfigAttribute>();
                                    configs.add(config);
                                    // Retrieve the afterAclCollectionRead.
                                    AclEntryAfterInvocationCollectionFilteringProvider afterAclCollectionRead = 
                                    	(AclEntryAfterInvocationCollectionFilteringProvider) springContext.getBean("afterAclCollectionRead");
                                    // Perform the filtering
                                    Collection<Items> filteredResult = 
                            			(Collection<Items>) afterAclCollectionRead.decide(preAuthToken, null, configs, results);
                                	
                                   
                                    return filteredResult;
                                }
                            ...
                            The code starts by setting up the required spring objects for collection filtering. It creates a list of empty granted authorities. Usually, this list contains the roles the current user has (SIDs). This list is later used to decide if the a collection entry should be kept or not. My example uses the principal's name as the SID so we leave the list of granted authorities empty. The pre-authentication token is the object spring reads the SIDs from. Therefore, we retrieve the EJB's principal information and insert it in this token along with the empty list of granted authorities. Next we need to specify the security configuration to apply when filtering. This is required as the acl entry after invocation collection filtering provider expects to see this config in order to decide if it must filter the collection or not. We can then retrieve the acl entry after invocation collection filtering provider from the application context. Finally, we invoke the decide method manually and let spring security's ACL implementation perform its magic!

                            My database only contains two Items instances and only one of them has an ACL entry. Therefore, when I execute the retrievedAllItems method while I am logged on as someuser, I only get the Item that has an ACL entry.

                            That's it! Thank you very much for all your support. I hope this solution will be usefull for some of you.

                            Cheers!

                            Comment


                            • #15
                              Why did you give up?!


                              The clientAPIBean is retrieved via JNDI by the SeviceImpl class which then calls the retrieveItems method. I modifed the ServiceImpl class so it retrieves the clientAPIBean from the spring context instead.
                              Which basically says I don't use the spring configured beans.. To which I replied...

                              Originally posted by mdeinum
                              You should simply inject the dependency into your bean and not retrieve it (that would also save a dependency on spring) if you don't use the configuration from spring it is pretty useless to configure at the first place .
                              So not sure why you didn't try that...

                              Comment

                              Working...
                              X