Announcement Announcement Module
Collapse
No announcement yet.
Detecting User Login and Logout Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Detecting User Login and Logout

    Hi,

    I have a flex application that uses BlazeDS. I secure my application using Spring Security. I can login and logout without a problem, but I need to track that a user is logged in. Most importantly, I need to know when a user (session) disconnects. My security context has the following:

    Code:
    <security:global-method-security secured-annotations="enabled" jsr250-annotations="enabled" />
    
    <bean id="preAuthenticatedEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
    
    <security:http entry-point-ref="preAuthenticatedEntryPoint">
    	<security:anonymous enabled="false" />
    	<security:intercept-url pattern="*.swf" access="ROLE_USER"/>
    </security:http>
    	
    <bean id="userDetailService"
    	class="com.mycompany.security.UserDetailsService" init-method="initContext">
    	<property name="userService" ref="userService" />
    </bean>
    
    <security:authentication-manager>
    	<security:authentication-provider user-service-ref="userDetailService">
    		<security:password-encoder hash="md5"/>
    	</security:authentication-provider>
    </security:authentication-manager>
    The two things I want to do is execute a custom method to know when a user:

    1) logs in
    2) logs out
    3) session expires
    4) disconnects without logging out

    I've tried putting in a custom filter for logout like:

    Code:
    <bean id="logoutSuccessHandler" class="com.mycompany.security.TomsLogoutHandler"/>
    
    <bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
            <constructor-arg index="0" ref="logoutSuccessHandler"/>
            <constructor-arg index="1">
                <list>
                    <ref bean="securityContextLogoutHandler"/>
                </list>
            </constructor-arg>
    </bean>
    
    <bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
    
    <security:http entry-point-ref="preAuthenticatedEntryPoint">
    	<security:anonymous enabled="false" />
    	<security:intercept-url pattern="*.swf" access="ROLE_USER"/>
    	<security:custom-filter ref="logoutFilter" position="LOGOUT_FILTER"/>
    </security:http>
    but my filter never gets called even though on the client I issue a Channel.logout() command.

    web.xml
    Code:
    <!-- SECURITY FILTERS -->
    <filter>
    	<filter-name>springSecurityFilterChain</filter-name>
    	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    	
    <filter-mapping>
    	<filter-name>springSecurityFilterChain</filter-name>
    	<url-pattern>/*</url-pattern>
    </filter-mapping>
    I've searched the web to try and find a way to preserve the simplicity of the spring-based authentication and have been unable to get any of the ideas to work.

    Thanks in advance.

  • #2
    Because the BlazeDS authentication process has to happen at a deeper point in the request processing chain, most of Spring Security's filters are not pertinent in this environment. If you want to act on login/logout, you need to implement ApplicationEventListeners to process the proper Spring Security events.

    Comment


    • #3
      See also: http://forum.springframework.org/showthread.php?t=29115

      Comment


      • #4
        Retrieve bean in different context from logout

        I've been trying to detect session expiration for a user and I have been trying the logout filter approach and I've been going crazy. It's good to know now that the filters are not pertinent.

        I did get session expiration detection by ApplicationListener<HttpSessionDestroyedEvent> which I have working in my root security context. However, I have 3 separate contexts - one for blazeds, one for mvc and one for rest.

        Upon listening for the event, I need to "getBean" a bean in my blazeds context to perform some cleanup upon logout. HttpSessionDestroyedEvent's context returns the root context and the event does not have a request object for RequestContextUtils.getWebApplicationContext(). I've even tried ApplicationAware and I've tried publishing an event to the other context with no luck. I'm sandboxed and cannot get the bean I need. Is it possible to get a bean from a different context here?

        The only workaround I've found is to actually do jms remoting (rmi) with activemq. I create the necessary factories, queues and I can actually invoke the method directly. It seems this is a lot of overhead just to accomplish this. Please let me know if there is a better way of accomplishing this. Thanks in advance!

        Comment


        • #5
          Originally posted by hyperlink View Post
          Upon listening for the event, I need to "getBean" a bean in my blazeds context to perform some cleanup upon logout. HttpSessionDestroyedEvent's context returns the root context and the event does not have a request object for RequestContextUtils.getWebApplicationContext(). I've even tried ApplicationAware and I've tried publishing an event to the other context with no luck. I'm sandboxed and cannot get the bean I need. Is it possible to get a bean from a different context here?
          No, this is a known consequence of using a hierarchical ApplicationContext. The parent has no knowledge of the children, thus events fired in the parent do not propagate to the child contexts. People are often tempted to flatten everything down into the root context as a result of this, but I do believe there are reasonable ways to avoid having to do that.

          Originally posted by hyperlink View Post
          The only workaround I've found is to actually do jms remoting (rmi) with activemq. I create the necessary factories, queues and I can actually invoke the method directly. It seems this is a lot of overhead just to accomplish this. Please let me know if there is a better way of accomplishing this. Thanks in advance!
          This is actually a nice approach, as you still have nice loose coupling and are essentially just broadcasting the event in a different manner. That said, I think a lighter-weight solution can be had by using Spring Integration instead of JMS.

          Basically the pattern is the same...you receive the event in the parent context, publish a message to an SI channel defined in the parent context, but then have a consumer defined in the child context that picks up the message and invokes your service as a result.

          SI even has specific support for this pattern, via a combination of its ApplicationEventInboundChannelAdapter and <service-activator> tag.

          So, assuming Spring Integration 1.0 (some of this would be even cleaner in 2.0), you would have something like this in your root 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:int="http://www.springframework.org/schema/integration"
          	xsi:schemaLocation="http://www.springframework.org/schema/beans
          			http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          			http://www.springframework.org/schema/integration
          			http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">
          	
              <int:channel id="applicationEventChannel"/>
          	
              <!-- This is the SI 1.0.x version - there is namespace support for this in SI 2.0 -->
              <bean id="eventAdapter" class="org.springframework.integration.event.ApplicationEventInboundChannelAdapter">
                  <property name="outputChannel" ref="applicationEventChannel"/>
                  <property name="eventTypes">
                      <list>
                          <value>org.springframework.security.web.session.HttpSessionDestroyedEvent</value>
                      </list>
                  </property>
              </bean>
          
          </beans>
          then in the Flex child context, you would have:

          Code:
          <bean id="cleanupService" class="org.springframework.flex.samples.secured.CleanupService" />
          	
          <int:service-activator ref="cleanupService" input-channel="applicationEventChannel" method="cleanup"/>
          where CleanupService looks something like:

          Code:
          package org.springframework.flex.samples.secured;
          
          import org.springframework.security.web.session.HttpSessionDestroyedEvent;
          
          public class CleanupService {
              
              public void cleanup(HttpSessionDestroyedEvent event) {
                  //do cleanup here
              }
          
          }
          See here for further details in the SI docs:

          http://static.springsource.org/sprin...plicationevent

          http://static.springsource.org/sprin...ator-namespace

          Comment

          Working...
          X