Announcement Announcement Module
Collapse
No announcement yet.
Concurrent Session Control Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Concurrent Session Control

    Hello all! I'm using Spring Security 3.0.2. I'm trying to configure concurrent session control to prevent a user from logging in more than once and to invalidate the first session when the user logs in a second time. I'm unsuccessful at configuring spring security to behave in this manner. With my current config, a user can still log in multiple times. What am I missing? I have HttpSessionEventPublisher in my web.xml.

    spring security config
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                                     http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
                                     
     <http auto-config="true" access-denied-page="/WEB-INF/view/common/accessDenied.jsp">
      <session-management session-fixation-protection="migrateSession" invalid-session-url="/index.jsp?errorMessage=The session has expired." session-authentication-error-url="/index.jsp?errorMessage=A user authenticaion problem has been encountered.">
       <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" expired-url="/index.jsp?errorMessage=The session is expired due to another user logging in with your user name and password."/>
      </session-management>
       
       <!-- Intercept patterns will be evaluated in the order listed and the first match will be used. 
            The most specific matches must be put at the top 
       -->
       <intercept-url pattern="/cacLogin.cmd" filters="none"/> 
       <intercept-url pattern="/dbSignFailure.jsp" filters="none"/>   
       <intercept-url pattern="/cacSignature.jsp" filters="none"/>
       <intercept-url pattern="/eula.jsp" filters="none"/>
       <intercept-url pattern="/index.jsp" filters="none"/>
       <intercept-url pattern="/newTask.cmd" access="ROLE_CREATE_TASK"/>
       <intercept-url pattern="/css/**" filters="none"/>
       <intercept-url pattern="/images/**" filters="none"/>
       <intercept-url pattern="/javascript/**" filters="none"/>
       <intercept-url pattern="/**" access="ROLE_USER"/>
       
       <form-login login-page="/index.jsp" default-target-url="/show/perspective.cmd" authentication-failure-url="/index.jsp?errorMessage=The entered user name and password is incorrect."/>
       <logout invalidate-session="true" logout-url="/logout" logout-success-url="/index.jsp"/>
     </http>
     
      <authentication-manager>
       <authentication-provider user-service-ref="userDetailsService">
        <password-encoder hash="md5"/>
       </authentication-provider>
      </authentication-manager>
     
     <beans:bean id="userDetailsService" class="com.nmt.green.spring.security.UserDetailsServiceImp">
       <beans:property name="userFacade"><beans:ref bean="userFacade"/></beans:property>
     </beans:bean>
    
    </beans:beans>

  • #2
    How are you verifying that a user can log in multiple times? A common mistake is to try testing with the same browser instance (which will reuse the JSESSIONID). Make sure you are verifying with separate browsers.

    Comment


    • #3
      Your configuration is wrong.

      With your current configuration the first user logs in, then the second comes, the session of the first is invalidated and the second logs in.

      Code:
         <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" expired-url="/index.jsp?errorMessage=The session is expired due to another user logging in with your user name and password."/>
      Set the red part to true and you will get an exception at the second login.

      Next to that take into account what pmularien tells you, make sure it are 2 seperate browsers (and CTRL+N from a browser windows doesn't count as a seperate browser).

      Comment


      • #4
        Thanks for replying. I have been testing in different browser instances. I want the first session to be invalidated when the user successfully logs in a second time. To my understanding, error-if-maximum-exceeded="false" accomplishes this behavior. I did try setting it to true but the behavior didn't change. It still allows me to log in mulitple times as the same user. I recently migrated to spring security 3.0.2 from 2.0.4. When using 2.0.4, concurrent session control performed as expected.

        Comment


        • #5
          Maybe there's an issue associated with the redesign of concurrent session control https://jira.springsource.org/browse/SEC-1229. I've followed the reference guide. I'm not doing anything custom other than a UserDetailsService implementation to load the principal via Hibernate.

          Code:
          public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException
          {
             User user = userFacade.getUser(userName);
             if(user != null)
             {
                PrincipalUser principalUser;
                principalUser = new PrincipalUser(user);
                return principalUser;
             }
          			
             else throw new UsernameNotFoundException("No user can be found with the user name '" + userName + "'");
          }
          I'm relying on namespace configuration. Are there any beans I need to explicitly define in order for this to work.

          Comment


          • #6
            Thanks for replying. I have been testing in different browser instances. I want the first session to be invalidated when the user successfully logs in a second time. To my understanding, error-if-maximum-exceeded="false" accomplishes this behavior. I did try setting it to true but the behavior didn't change. It still allows me to log in mulitple times as the same user. I recently migrated to spring security 3.0.2 from 2.0.4. When using 2.0.4, concurrent session control performed as expected.
            Well that is happening but if there is remember me, or cookies enabled, the first user logs in automatically again, invalidating the second session. Well and that is going to go on for a long time .

            Setting it to true would throw an exception so there must be something wrong with your setup.

            Comment


            • #7
              Some tips:
              1> Enable and watch the logs.
              2> Verify you have the listener in web.xml correctly.
              3> If all else fails, use a debugger.

              As Marten said, if you are using remember me, you really won't see things break down, because the user who has been expired will just automatically log back in.

              You aren't overriding the filter chain, are you? Or any other config you haven't told us about?

              Comment


              • #8
                I'm not doing anything custom other than a UserDetailsService implementation to load the principal via Hibernate. I have verified that the listener is in the web.xml. I'm not using any remember me functionality. I'll take a look at the logs and do some debugging and see if that uncovers anything. Thanks again!

                Comment


                • #9
                  Here is what I found in the log.

                  the form post for the first login (IE):
                  Code:
                  2010-05-10 09:37:34,906 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - HttpSession returned null object for SPRING_SECURITY_CONTEXT
                  2010-05-10 09:37:34,906 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@c386d. A new one will be created.
                  2010-05-10 09:37:34,937 DEBUG [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter] - Request is to process authentication
                  2010-05-10 09:37:34,937 DEBUG [org.springframework.security.authentication.ProviderManager] - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy] - Invalidating session with Id 'D5616CB995DE7DF573E7B0D862CC031C' and migrating attributes.
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.session.HttpSessionEventPublisher] - Publishing event: org.springframework.security.web.session.HttpSessionDestroyedEvent[source=org.apache.catalina.session.StandardSessionFacade@c386d]
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.session.HttpSessionEventPublisher] - Publishing event: org.springframework.security.web.session.HttpSessionCreatedEvent[source=org.apache.catalina.session.StandardSessionFacade@aa1384]
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy] - Started new session: 3CAC8A28D5A21A146289C5B6BC7F2A66
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.core.session.SessionRegistryImpl] - Registering session 3CAC8A28D5A21A146289C5B6BC7F2A66, for principal com.nmt.green.spring.security.PrincipalUser@1f08e98
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter] - Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6c7be66a: Principal: com.nmt.green.spring.security.PrincipalUser@1f08e98; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@255f8: RemoteIpAddress: 127.0.0.1; SessionId: D5616CB995DE7DF573E7B0D862CC031C; Granted Authorities: ROLE_USER
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler] - Using default Url: /show/perspective.cmd
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.DefaultRedirectStrategy] - Redirecting to '/green_web/show/perspective.cmd'
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - SecurityContext stored to HttpSession: '[email protected]be66a: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6c7be66a: Principal: com.nmt.green.spring.security.PrincipalUser@1f08e98; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@255f8: RemoteIpAddress: 127.0.0.1; SessionId: D5616CB995DE7DF573E7B0D862CC031C; Granted Authorities: ROLE_USER'
                  2010-05-10 09:37:35,328 DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] - SecurityContextHolder now cleared, as request processing completed
                  2010-05-10 09:37:35,343 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: '[email protected]be66a: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6c7be66a: Principal: com.nmt.green.spring.security.PrincipalUser@1f08e98; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@255f8: RemoteIpAddress: 127.0.0.1; SessionId: D5616CB995DE7DF573E7B0D862CC031C; Granted Authorities: ROLE_USER'
                  2010-05-10 09:37:35,343 DEBUG [org.springframework.security.web.authentication.AnonymousAuthenticationFilter] - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6c7be66a: Principal: com.nmt.green.spring.security.PrincipalUser@1f08e98; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@255f8: RemoteIpAddress: 127.0.0.1; SessionId: D5616CB995DE7DF573E7B0D862CC031C; Granted Authorities: ROLE_USER'
                  2010-05-10 09:37:35,343 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Secure object: FilterInvocation: URL: /show/perspective.cmd; Attributes: [ROLE_USER]
                  2010-05-10 09:37:35,343 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6c7be66a: Principal: com.nmt.green.spring.security.PrincipalUser@1f08e98; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@255f8: RemoteIpAddress: 127.0.0.1; SessionId: D5616CB995DE7DF573E7B0D862CC031C; Granted Authorities: ROLE_USER
                  2010-05-10 09:37:35,343 DEBUG [org.springframework.security.access.vote.AffirmativeBased] - Voter: org.springframework.security.access.vote.RoleVoter@f5498f, returned: 1
                  2010-05-10 09:37:35,343 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Authorization successful
                  2010-05-10 09:37:35,343 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - RunAsManager did not change Authentication object
                  2010-05-10 09:37:35,343 DEBUG [org.springframework.security.web.FilterChainProxy] - /show/perspective.cmd reached end of additional filter chain; proceeding with original chain
                  2010-05-10 09:37:36,859 DEBUG [org.springframework.security.web.access.ExceptionTranslationFilter] - Chain processed normally
                  2010-05-10 09:37:36,875 DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] - SecurityContextHolder now cleared, as request processing completed

                  Comment


                  • #10
                    the form post for the second login (Firefox):
                    Code:
                    2010-05-10 09:48:34,703 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - HttpSession returned null object for SPRING_SECURITY_CONTEXT
                    2010-05-10 09:48:34,703 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@2596c1. A new one will be created.
                    2010-05-10 09:48:34,703 DEBUG [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter] - Request is to process authentication
                    2010-05-10 09:48:34,703 DEBUG [org.springframework.security.authentication.ProviderManager] - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
                    2010-05-10 09:48:34,859 DEBUG [org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy] - Invalidating session with Id 'ECEF4A7531D8F16B4DF6C18A73B52C9D' and migrating attributes.
                    2010-05-10 09:48:34,859 DEBUG [org.springframework.security.web.session.HttpSessionEventPublisher] - Publishing event: org.springframework.security.web.session.HttpSessionDestroyedEvent[source=org.apache.catalina.session.StandardSessionFacade@2596c1]
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.session.HttpSessionEventPublisher] - Publishing event: org.springframework.security.web.session.HttpSessionCreatedEvent[source=org.apache.catalina.session.StandardSessionFacade@a16977]
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy] - Started new session: 46B76FC728E60FABA545CD860AEEF13B
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.core.session.SessionRegistryImpl] - Registering session 46B76FC728E60FABA545CD860AEEF13B, for principal com.nmt.green.spring.security.PrincipalUser@64a937
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter] - Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6dec5447: Principal: com.nmt.green.spring.security.PrincipalUser@64a937; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@1c07a: RemoteIpAddress: 127.0.0.1; SessionId: ECEF4A7531D8F16B4DF6C18A73B52C9D; Granted Authorities: ROLE_USER
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler] - Using default Url: /show/perspective.cmd
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.DefaultRedirectStrategy] - Redirecting to '/green_web/show/perspective.cmd;jsessionid=46B76FC728E60FABA545CD860AEEF13B'
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - SecurityContext stored to HttpSession: '[email protected]c5447: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6dec5447: Principal: com.nmt.green.spring.security.PrincipalUser@64a937; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@1c07a: RemoteIpAddress: 127.0.0.1; SessionId: ECEF4A7531D8F16B4DF6C18A73B52C9D; Granted Authorities: ROLE_USER'
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] - SecurityContextHolder now cleared, as request processing completed
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: '[email protected]c5447: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6dec5447: Principal: com.nmt.green.spring.security.PrincipalUser@64a937; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@1c07a: RemoteIpAddress: 127.0.0.1; SessionId: ECEF4A7531D8F16B4DF6C18A73B52C9D; Granted Authorities: ROLE_USER'
                    2010-05-10 09:48:34,875 DEBUG [org.springframework.security.web.authentication.AnonymousAuthenticationFilter] - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6dec5447: Principal: com.nmt.green.spring.security.PrincipalUser@64a937; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@1c07a: RemoteIpAddress: 127.0.0.1; SessionId: ECEF4A7531D8F16B4DF6C18A73B52C9D; Granted Authorities: ROLE_USER'
                    2010-05-10 09:48:34,890 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Secure object: FilterInvocation: URL: /show/perspective.cmd; Attributes: [ROLE_USER]
                    2010-05-10 09:48:34,890 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6dec5447: Principal: com.nmt.green.spring.security.PrincipalUser@64a937; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@1c07a: RemoteIpAddress: 127.0.0.1; SessionId: ECEF4A7531D8F16B4DF6C18A73B52C9D; Granted Authorities: ROLE_USER
                    2010-05-10 09:48:34,890 DEBUG [org.springframework.security.access.vote.AffirmativeBased] - Voter: org.springframework.security.access.vote.RoleVoter@f5498f, returned: 1
                    2010-05-10 09:48:34,890 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Authorization successful
                    2010-05-10 09:48:34,890 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - RunAsManager did not change Authentication object
                    2010-05-10 09:48:35,843 DEBUG [org.springframework.security.web.access.ExceptionTranslationFilter] - Chain processed normally
                    2010-05-10 09:48:35,843 DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] - SecurityContextHolder now cleared, as request processing completed
                    A request with the first user(IE):
                    Code:
                    2010-05-10 09:51:14,953 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: '[email protected]be66a: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6c7be66a: Principal: com.nmt.green.spring.security.PrincipalUser@1f08e98; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@255f8: RemoteIpAddress: 127.0.0.1; SessionId: D5616CB995DE7DF573E7B0D862CC031C; Granted Authorities: ROLE_USER'
                    2010-05-10 09:51:15,031 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Secure object: FilterInvocation: URL: /tasks/task.cmd?filterTaskAmendments=false&filterTaskExecutionYear=2010&filterMissionID=81&filterTaskApprovalStatusID=1; Attributes: [ROLE_USER]
                    2010-05-10 09:51:15,031 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@6c7be66a: Principal: com.nmt.green.spring.security.PrincipalUser@1f08e98; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@255f8: RemoteIpAddress: 127.0.0.1; SessionId: D5616CB995DE7DF573E7B0D862CC031C; Granted Authorities: ROLE_USER
                    2010-05-10 09:51:15,031 DEBUG [org.springframework.security.access.vote.AffirmativeBased] - Voter: org.springframework.security.access.vote.RoleVoter@f5498f, returned: 1
                    2010-05-10 09:51:15,031 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Authorization successful
                    2010-05-10 09:51:15,031 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - RunAsManager did not change Authentication object
                    2010-05-10 09:51:15,625 DEBUG [org.springframework.security.web.access.ExceptionTranslationFilter] - Chain processed normally
                    2010-05-10 09:51:15,625 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] - SecurityContext stored to HttpSession: '[email protected]0de41: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@5b30de41: Principal: com.nmt.green.spring.security.PrincipalUser@ca6f82; Password: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER'
                    2010-05-10 09:51:15,625 DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] - SecurityContextHolder now cleared, as request processing completed

                    Comment


                    • #11
                      The request with the first user that logged in should have not been successful. The second login with the same user credentials should have triggered the invalidation of the first session. This is not occurring.

                      Comment


                      • #12
                        I'm having the exact same problem. What application server are you using? I'm on WebSphere 7 unfortunately.

                        Comment


                        • #13
                          I'm using Apache Tomcat. I haven't yet solved this issue.

                          Comment


                          • #14
                            The only thing that I note is that you are using a custom object as your Principal (com.nmt...). The SessionRegistryImpl is backed by a HashMap, keyed on the Principal. If your custom Principal object doesn't properly implement equals/hashCode such that the same principal loaded in two separate sessions does not hash to the same hash key, prior sessions will not be invalidated. The best way to diagnose this is to use a debugger and set a breakpoint in the appropriate section(s) of SessionRegistryImpl.

                            This functionality definitely works on Tomcat, with standard Principal objects.

                            Comment


                            • #15
                              Originally posted by pmularien View Post
                              The only thing that I note is that you are using a custom object as your Principal (com.nmt...). The SessionRegistryImpl is backed by a HashMap, keyed on the Principal. If your custom Principal object doesn't properly implement equals/hashCode such that the same principal loaded in two separate sessions does not hash to the same hash key, prior sessions will not be invalidated. The best way to diagnose this is to use a debugger and set a breakpoint in the appropriate section(s) of SessionRegistryImpl.

                              This functionality definitely works on Tomcat, with standard Principal objects.
                              In my case I am also using a custom principal but I extend LdapUserDetailsImpl since I'm using the ldap provider and checking the code it doesnt implement either method. I'll do this in my subclass and let you know. Thanks.

                              Comment

                              Working...
                              X