Announcement Announcement Module
Collapse
No announcement yet.
1.0.0-RC1 MethodInvocation AOP problem Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 1.0.0-RC1 MethodInvocation AOP problem

    I am unable to use the AOP method interception via an AutoProxy. It seems whenever this code at line 288 in AbstractSecurityInterceptor

    Code:
    ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource()
                                                     .getAttributes(object);
    is called, it is always returning null, even though the method has been mapped with a role. I have included my mapping below. The acutal method invoked is

    Code:
    com.ata.adapter.datalex.DatalexAdapterImpl.searchRoundTrip
    However the method is never returned when invoked via an autoproxy. The bean is retreived from the providerFactory bean which simply checks that all providers implement the correct interface on intializiation. Can anyone give me a hand with this?

    Spring definition

    Code:
     <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    
     <!--  Add all service provider adapter to this auto proxy creator.  This will automagically add the
     acegi security method interceptor to every bean when requested from Spring -->
      <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="interceptorNames">
          <list><value>securityInterceptor</value></list>
        </property>
        <property name="beanNames">
          <list><value>datalexAdapter</value></list>
        </property>
      </bean>
    
      <!-- This bean specifies which roles are authorized to execute which methods. -->
      <bean id="securityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
        <!-- reject unauthorized invocations -->
        <property name="rejectPublicInvocations" value="true"/>
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="accessDecisionManager"/>
        
        <property name="objectDefinitionSource">
        <!--  all implementing classes need public method security added-->
          <value>
            com.ata.adapter.datalex.DatalexAdapterImpl.search*=ROLE_SEARCH
            com.ata.adapter.datalex.DatalexStatelessAdapterImpl.price*=ROLE_PRICE
            com.ata.adapter.datalex.DatalexStatelessAdapterImpl.book*=ROLE_BOOK
          </value>
        </property>
      </bean>
    
      <!-- This bean specifies which roles are assigned to each user.
      This sets a user map from our WebServiceUserParser -->
      <bean id="userDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
        <property name="userMap">
        	<ref bean="userMapFactoryBean"/>
        </property>
      </bean>
     
      <!-- This bean specifies that a user can access the protected methods 
       if they have any one of the roles specified in the objectDefinitionSource above. -->
      <bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
        <property name="decisionVoters">
          <list><ref bean="roleVoter"/></list>
        </property>
      </bean>
    
      <!-- The next three beans are boilerplate. They should be the same for nearly all applications. -->
      <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
        <property name="providers">
          <list><ref bean="authenticationProvider"/></list>
        </property>
      </bean>
    
      <!--  Use a DAO provider
      This still uses UsernamePasswordAuthenticationToken, but requires a 
      WSPasswordCallback as a credential so the password can be
      set into the callback for authentication during the message
      decryption in the additionalAuthenticationChecks method
       -->
      <bean id="authenticationProvider" class="com.ata.webservices.security.WebServiceSecurityDao">
        <property name="userDetailsService" ref="userDetailsService"/>
      </bean>
    
      <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"/>
      
      
      <!-- UserMapLoader bean -->
      <bean id="userMapLoader" class="com.ata.webservices.security.properties.loader.UserMapLoaderImpl">
      	<property name="permissionsFile"><value>webservicesusers.properties</value></property>
      </bean>
      
      <!-- Work around bean for InMemoryDAOImpl -->
      <bean id="userMapFactoryBean" class="com.ata.webservices.security.properties.loader.UserMapFactoryLoader">
      	<property name="loader"><ref bean="userMapLoader"/></property>
      </bean>
      
      <!-- our listener that checks every 30 seconds for a new security file -->
      <bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
    	  <!-- wait 10 seconds before starting repeated execution -->
    	  <property name="delay"><value>10000</value></property>
    	  <!-- run every 30 seconds -->
    	  <property name="period"><value>30000</value></property>
    	  <property name="timerTask"><ref bean="securityReloader"/></property>
      </bean>
      
      <!-- our actual time task -->
      <bean id="securityReloader" class="com.ata.webservices.security.properties.loader.UserPropertyReloader">
      	<property name="userDetailsService"><ref bean="userDetailsService"/></property>
      	<property name="userMapLoader"><ref bean="userMapLoader"/></property>
      	<property name="paranoid"><value>true</value></property>
      </bean>
      
      <!-- Our own web service implementations -->
      <bean id="flightBankWebService" class="com.ata.webservices.provider.ServiceProviderAdapter">
    	<!-- set the service provider factory -->
      	<property name="providerFactory">
      		<ref bean="providerFactory"/>
      	</property>
      	<!-- set the dozer mappings -->
      	<property name="mapper">
      		<ref bean="mapper"/>
      	</property>
      </bean>  
      
        <!-- Provider factory to grab a users business provider -->
      <bean id="providerFactory" class="com.ata.webservices.factory.ServiceProviderFactoryImpl">
    	
      	<property name="userDetailsService">
      		<ref bean="userDetailsService"/>
      	</property>
      	<property name="adapters">
      		<map>
      			<entry>
      				<key><value>datalex</value></key>
      				<ref bean="datalexAdapter"/>
      			</entry>
      		</map>
      	</property>
       
      </bean>
      
      
      <bean id="datalexAdapter" class="com.ata.adapter.datalex.DatalexStatelessAdapterImpl">
      	<property name="factory">
      		<ref bean="storeFrontFactory"/>
      	</property>
      </bean>
      
      <!-- datalex adapter config -->
      <bean id="storeFrontFactory" class="com.ata.adapter.datalex.factory.StoreFrontsFactory">
      	<property name="bookitProps"><value>FlightBankImpl.properties</value></property>
      </bean>
    
    
      
      
      <!-- dozer converter configuration -->
      <bean id="mapper" 
        class="net.sf.dozer.util.mapping.DozerBeanMapper" singleton="true">
        <property name="mappingFiles">
          <list>
          <value>dozerMappings.xml</value>
          </list>
        </property>
      </bean>
      
    </beans>

  • #2
    I have a little more information to provide. It appears the ACEGI is not getting the correct class on my Method invocation objects. The method

    Code:
    public Object invoke(MethodInvocation mi) throws Throwable
    of class MethodSecurityInterceptor (Line 75) is receiving a MethodInvocation object of instance ReflectiveMethodInvocation. It seems the values are not correct in this object. Both the target and the targetClass are the class

    Code:
    com.ata.adapter.datalex.DatalexStatelessAdapterImpl
    However, the method object is for

    Code:
    public abstract com.ata.adapter.beans.FlightSearchResults com.ata.adapter.SearchAdapter.searchRoundTrip(java.lang.String,java.lang.String,java.util.Date,java.util.Date,int,int,int) throws com.ata.adapter.exception.AdaptorException
    Which is the calling method, IE the method invoking the ACEGI security proxy, not the target of the security proxy. Here is my code for the SearchAdapter, as well as the provider lookup code.

    SearchAdapter searchRoundTrip

    Code:
    public FlightSearchResults searchRoundTrip(String origin,
    			String destination, Date departDate, Date returnDate,
    			int numAdults, int numChildren, int numSeniors) throws Exception {
    
    		com.ata.adapter.beans.FlightSearchResults results = providerFactory.getProvider()
    				.searchRoundTrip(origin, destination, departDate, returnDate,
    						numAdults, numChildren, numSeniors);
    
    		FlightSearchResults serviceResults = (FlightSearchResults) mapper.map(
    				results, FlightSearchResults.class);
    
    		return serviceResults;
    	}
    ProviderFactoryImpl.getProvider()

    Code:
    /**
    	 * Gets the adapter from the WebServiceUser object
    	 * @return
    	 */
    	public StatelessBookingAdapter getProvider() {
    		Object userName = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    		
    		UserDetails userDetails= userDetailsService.loadUserByUsername(userName.toString());
    		
    		//can we find the user
    		if(userDetails == null){
    			throw new WebServiceSecurityException("No user details were found for username '" + userName.toString() + "'");
    		}
    		
    		//make sure its the right type before we cast. Should never happen, but a sanity check
    		if(!(userDetails instanceof WebServiceUser)){
    			throw new WebServiceSecurityException("The user '" + userName.toString() + "' is not defined as WebServiceUser type");
    		}
    		
    		
    		String providerName = ((WebServiceUser)userDetails).getServiceProvider();
    		
    		StatelessBookingAdapter adapter = (StatelessBookingAdapter) adapters.get(providerName);
    		
    		//check one has been defined
    		if(adapter == null){
    			throw new WebServiceSecurityException("No service provider was found for the user '" + userName.toString() + "'");
    		}
    		
    		//if we get here we're good, return the provider.
    		
    		return adapter;

    Comment


    • #3
      Solution Found

      I have found the solution, if you use a org.springframework.aop.framework.autoproxy.BeanNa meAutoProxyCreator

      you MUST set

      <property name="proxyTargetClass" value="true"/>

      Otherwise, the method passed is the method on the caller of the proxied bean, NOT the target method. I am adding a request to get this into the documentation.

      Comment


      • #4
        I'll add a comment to the Acegi Security docs as well: http://opensource2.atlassian.com/pro...browse/SEC-157

        Comment

        Working...
        X