Announcement Announcement Module
Collapse
No announcement yet.
Concurrent Logins -- Is it in 0.8x? Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Concurrent Logins -- Is it in 0.8x?

    Hey There,

    I read the original 0.80 announcement and it listed among its new ingredients the concurrent login support. However, the reference guide makes no mention of it. Is it hidden in some other feature and I've failed to connect the two?

    Thanks,
    Bill

  • #2
    Version 0.8.1 does contain Concurrent Login support. There was bug found in 0.8.0 that prevented it from handling logouts correctly.

    Comment


    • #3
      Thanks...

      Thanks. I did poke around in the Javadoc and find some classes that looked like a part of the functionality, but didn't find any obvious documentation. Is there any?

      Comment


      • #4
        Sorry, I hit send before I finished typing what I wanted to say :P

        There is currently no documentation in the reference material related to the Concurrent Session Controller (CSC) implementation. What you see below will end up there shortly though.

        Let me see if I can sum it up for you, and anyone else that's interested.

        First you'll need an HttpSessionEventPublisher declared in web.xml. This peice is critical, it converts Servlet API HttpSessionListener events to Spring ApplicationEvents. Those events are what tells the CSC code to stop watching a session.
        Code:
        <listener>
          <listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
        </listener>
        You can actually see that in the contacts-filter example.

        Next you will need to configure your ProviderManager in your Spring ApplicationContext xml. The example below shows that you are setting the "sessionController" property.
        Code:
            <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
                <property name="providers">
                ----Your providers go here----
                </property>
                <property name="sessionController">
                    <ref bean="concurrentSessionController"/>
                </property>
            </bean>
        
            <!-- ConcurrentSessionController limits the number of connections a single logged in user can have-->
            <bean id="concurrentSessionController" class="net.sf.acegisecurity.providers.ConcurrentSessionControllerImpl">
                <property name="maxSessions">
                    <value>1</value>
                </property>
            </bean>
        In the code example XML above we are configuring the ProviderManager "sessionController" property to reference the "concurrentSessionController" bean. It is important to remember do not in-line the ConcurrentSessionControllerImpl when declaring it in your xml. This is important because it seems that in-lined bean declarations will not recieve ApplicationEvents. If it turns out I'm wrong on this part, good, but this is the behavior I have seen.

        The ConcurrentSessionControllerImpl relies heavily on the Authentication.getPrincipal().equals() method. If you are using a custom Authentication object keep this in mind.

        In order for the CSC code to release a given session, and thus let the user log in to a new session, the existing session must be invalidated. For example: If Batman logs in, checks for crimes being commited, and then just closes his browser with out "logging out", he will not be able to log back in until his session is timed out by the server. You would have to look at your containers documentation to find out the default timeout. You can also configure the session timeout in your web.xml...
        Code:
            <session-config>
              <session-timeout>30</session-timeout> 
            </session-config>

        Comment


        • #5
          I just added Ray's instructions to the reference guide, which will be published within 24 hours to http://acegisecurity.sourceforge.net/docbook/acegi.html.

          Comment


          • #6
            Thanks again...

            ...you guys are GREAT!

            Comment


            • #7
              In order for the CSC code to release a given session, and thus let the user log in to a new session, the existing session must be invalidated. For example: If Batman logs in, checks for crimes being commited, and then just closes his browser with out "logging out", he will not be able to log back in until his session is timed out by the server.
              Hi,
              I do not think this behaviour is intuitive. Oftentimes users close their browsers without logging out. This may be by mistake, habit or if, for example, the browser crashes. I feel that locking them out till their previous session expires is undesirable.

              Take the case of a web app like Yahoo mail. If the same user logs in using a new session, the previous session gets invalidated. I think this is more in line with what users have come to expect from web apps that require a login.

              Let me know your thoughts.

              Thanks,
              Sanjiv

              Comment


              • #8
                I agree that the behavior as described is not what most users will expect, nor what most applications will want to implement. The support desk calls will be horrendous. "I'm sorry sir, you'll have to wait 20 minutes & try again."

                I worked for a number of years at pioneering company in the internet banking software business, and what we found was that users expect to be able to close their browser, and then open a new browser & login immediately, assuming they have the correct password. I don't know all the details of the implementation, but the original session was flagged as "forced off" when the user logged in again & an active session was found for the same principal. If the user still has the original browser window open, opens a new window, logs in in the new window, and then goes back to the original window & submits a request, they would be sent back to the login page with a message that their session had been ended because they had logged in elsewhere.

                How difficult would this be to implement within the Acegi concurrent session controller?

                Comment


                • #9
                  Keep in mind that the ProviderManager does not limit sessions by default, if this functionality is desired, it has to be configured in the application. That being said...

                  The ProviderManager "sessionController" property takes an instance of the ConcurrentSessionController interface. There are two implementations of that interface currently in Acegi; the NullConcurrentSessionController (which does nothing at all), and the ConcurrentSessionControllerImpl (which acts as described above).

                  Another implementation of the ConcurrentSessionController interface could be built that operates in a "last one in wins". If someone were to write this it sounds like it would be a valuable contribution.

                  There was also talk about putting in some other threads about JavaScript that handled the "browser closed events" to do a logout, but I don't know if that is even possible.

                  The ConcurrentSessionContollerImpl also has a "maxSessions" property that was not explained in my post above. The maxSessions property can be set to something like 10 to allow the usre 10 active sessions, and no more.

                  The current ConcurrentSessionContollerImpl is not intended to be the be-all-end-all solution for everyone. We just hope to provide something that works for many.

                  The ProviderManager is initialy configured with the NullConcurrentSessionController, meaning it does nothing with session tracking.

                  Comment


                  • #10
                    When is the session invalidated?

                    Hi,
                    I do not think this behaviour is intuitive. Oftentimes users close their browsers without logging out. This may be by mistake, habit or if, for example, the browser crashes. I feel that locking them out till their previous session expires is undesirable.
                    But if they come back with the same browser, even if they shut it down and restarted it, shouldn't the session still be valid? The only real problems would be when:

                    1) The user doesn't accept cookies and the session management is done via URL rewriting
                    2) The user comes in with a different browser, for example IE after they were using Mozilla

                    I don't think these 2 cases are that big a deal...

                    Comment


                    • #11
                      Another implementation of the ConcurrentSessionController interface could be built that operates in a "last one in wins". If someone were to write this it sounds like it would be a valuable contribution.
                      This sounds like it should be fairly easy to implement. I'm not sure when I'll have time to investigate more fully, but if we get to this before anyone else posts a solution (or submits a patch), we'll share our results.

                      Comment


                      • #12
                        I don't think it would be too hard to support this functionality by modification of ConcurrentSessionControllerImpl. I'd prefer to see us keep a single ConcurrentSessionController concrete implementation in Acegi Security (minimises support issues, deployment complexity, and maintaining similar code in multiple classes).

                        One use case clarification I'd like some comments on is which HttpSession are we going to flag as invalid when a new HttpSession starts up? We could do it randomly (pick any of the existing HttpSessions used by the principal that has exceeded the session limit) or the oldest (based on Date of last request).

                        Comment


                        • #13
                          Do you have information on when the last request was made using that session? It would be nice to invalidate the one which has been idle the longest.... Maybe if you integrated another filter in there.

                          Originally posted by Ben Alex
                          One use case clarification I'd like some comments on is which HttpSession are we going to flag as invalid when a new HttpSession starts up? We could do it randomly (pick any of the existing HttpSessions used by the principal that has exceeded the session limit) or the oldest (based on Date of last request).

                          Comment


                          • #14
                            Originally posted by jcarreira
                            Do you have information on when the last request was made using that session? It would be nice to invalidate the one which has been idle the longest.... Maybe if you integrated another filter in there.
                            We already have a number of Maps inside ConcurrentSessionControllerImpl. It shouldn't be hard to have another that stores a Date, or refactor the internal design to achieve it. I don't think another Filter should be necessary.

                            Comment


                            • #15
                              It appears that we can get the last access time for a session with HTTPSession.getLastAccessedTime().

                              So, in ConcurrentSessionControllerImpl.enforceConcurrentL ogins, we could have something like:

                              Code:
                              if &#40;!isActiveSession&#40;principal, sessionId&#41;&#41; &#123;
                              	if &#40;maxSessions == countSessions&#40;principal&#41;&#41; &#123;
                              		if &#40;disallowLogin&#41; &#123;
                              			//Publish the event                    
                              			publishViolationEvent&#40;request&#41;;
                              
                              			//The user is AT their max, toss them out
                              			throw new ConcurrentLoginException&#40;principal
                              			    + " has reached the maximum concurrent logins"&#41;;
                              		&#125;
                              		//Publish the event                    
                              		publishInvalidationEvent&#40;request&#41;;
                              
                              		//The user is AT their max, invalidate least-recently used session
                              		invalidateLRUSession&#40;principal&#41;;
                              	&#125;
                              &#125;
                              This introduces a new configuration variable disallowLogin to determine whether we throw an exception, or silently invalidate the least-recently-accessed session.

                              The invalidateLRUSession(principal) method would iterate the principal's sessions, finding the session with the lowest getLastAccessedTime() value & calling invalidate() on it.

                              Does this seem like a workable approach?

                              Comment

                              Working...
                              X