1 2 Previous Next 16 Replies Latest reply on May 29, 2005 12:42 AM by bstansberry

    ClusteredSingleSignOn help

    groboclown

      I've been trying to get the ClusteredSingleSignOn in an HTTP session replicated JBoss 4.0.0 install running, and I've been encountering problems with the replication of the session.

      To give a bit more background of the environment:
      - Cluster has 2 JBoss instances running with identical configurations on two separate machines. Both are running on Windows platforms, using Sun JVM 1.4.2_06.
      - Using Apache as a front-end proxy server, using a 50/50 load balancing round-robin approach. This causes my tests to have each request jump back and forth between the JBoss instances. This is using mod_jk to handle LB. Running on Windows 2000.
      - Tomcat's UseLocalCache is "false"
      - SingleSignOn is commented out, and ClusteredSingleSignOn is uncommented.
      - Cluster logging is enabled.

      I can see in the clustering logs the two JBoss instances of the cluster talking to each other, and a log message stating "Enabled clustering support" for the web-apps.

      When I first hit the application with my web browser, I see the login page (a custom authentication web page, not an authentication pop-up). At this point, it looks as if the sessions are being replicated correctly between the machines by looking at the clustering logs.

      I then submit the authentication username/password, and, due to the load balancing, the browser is proxied over to the second machine. This request is then directed to "j_security_check" and a JBoss "HTTP Status 400 - Invalid direct reference to form login page" error is reported.

      If I force a refresh, then the request is redirected back to the original JBoss instance, and the authentication is correct.

      Does anyone have any idea why the authentication credentials aren't being replicated correctly? Thanks.

        • 1. Re: ClusteredSingleSignOn help
          groboclown

          Still getting my jargon down. The issue seems to be that the principal isn't being replicated for the session using form based authentication. From other posts, this would seem to indicate that it's not using ClusteredSingleSignOn. However, I clearly see a log message:

          2005-05-19 13:28:30,366 INFO [org.jboss.web.tomcat.tc5.Tomcat5] Setting the cache name to jboss.cache:service=TomcatClusteringCache on jboss.web:host=recliner,name=ClusteredSingleSignOn,type=Valve

          Which shows that the sign on is being picked up.

          I'm wondering if for some reason they're being registered to different channels or different partitions. Based on the in-line documentation, they should have the same partition name since the name attributes are identical on both servers. Manually setting this to a value didn't change the observed behavior.

          I can't see any logging generated by single sign on, even with debug="2" and log4j.xml has org.jboss at debug level.

          • 2. Re: ClusteredSingleSignOn help

            Here's what I believe is happening:

            Original request goes to server A. A's FormAuthenticator detects the need for a login, so it caches the request info in the session object and sends the login page. The request info is cached so the originally requested URL can be returned once authentication succeeds. This request info is cached in an internal data structure of the session object (the "notes" map), not in the attribute map that user code can manipulate using HttpSession.get/setAttribute(). I don't believe JBoss session replication replicates session notes, so the original request info is not replicated across the cluster.

            Login form submission goes to server B. B's FormAuthenticator authenticates you, but then checks your session for the note with the original request URL. It cannot find the note (wasn't replicated) so it issues a 400 error response. Normally it would issue a redirect response sending the browser back to the original request URL.

            If I force a refresh, then the request is redirected back to the original JBoss instance, and the authentication is correct.


            When you refresh, is the browser re-posting the login form, or is it resubmitting a GET for the original URL? I expect the former; if instead of refreshing you entered the original URL in the address bar and hit enter I expect you'd get the login page again. Would like to know for sure.

            The SSO context is not created until a user successfully authenticates, is redirected and the browser re-requests the original URL. So, I don't think a 2nd GET back to server A would succeed, since the successful login on B would not be communicated to A.

            I can't see any logging generated by single sign on, even with debug="2" and log4j.xml has org.jboss at debug level.


            Try turning on debug logging for org.apache.catalina.


            To get your use case to work, I think two things would need to be done:

            1) Session replication would need to replicate objects in the "notes" map.
            2) An SSO context would need to be created and replicated as soon as the login was done, not as part of the 1st request following authentication.


            • 3. Re: ClusteredSingleSignOn help
              groboclown

              I'm looking into this right now. I'm having a possible related issue where a custom login servlet that we use to handle the Form authentication is doing something really bad, and not following any standards (and will require some developer re-education). This might be the cause for the 400 error. However, the "notes" issue you report is probably also present.


              When you refresh, is the browser re-posting the login form, or is it resubmitting a GET for the original URL?


              The browser isn't asking if I'm sure that I want to re-POST my request, so it's doing a GET.


              To get your use case to work, I think two things would need to be done:


              I'm going to try another possible approach. From what I can tell about mod_jk and Tomcat, the Tomcat server.xml Host element needs the jvmRoute="node name" attribute to enable sticky sessions. Once we get that login servlet in a better state, I'll try enabling sticky sessions to see if this helps solve the "notes" replication issue.

              • 4. Re: ClusteredSingleSignOn help

                 

                I'm having a possible related issue where a custom login servlet that we use to handle the Form authentication is doing something really bad, and not following any standards


                I'd assumed from your mention of "j_security_check" that you were using container managed authentication. ClusteredSingleSignOn is based on Tomcat's SingleSignOn valve, and is tightly integrated with Tomcat's Authenticators (which provide container managed authentication). Unless your login servlet is somehow integrated with the Tomcat infrastructure, ClusteredSingleSignOn won't work; you'd need to use TC's form authentication configured through web.xml.

                I'm going to try another possible approach. From what I can tell about mod_jk and Tomcat, the Tomcat server.xml Host element needs the jvmRoute="node name" attribute to enable sticky sessions. Once we get that login servlet in a better state, I'll try enabling sticky sessions to see if this helps solve the "notes" replication issue.


                In my experience, sticky sessions are almost always the way to go for a web app that keeps any kind of server-side state. It should definitely prevent the "400 response from server B" scenario I described (but maybe not whatever's causing your login servlet to issue a 400). If using sticky sessions is possible in your app, and using container managed authentication is an option, ClusteredSingleSignOn will work.

                • 5. Re: ClusteredSingleSignOn help
                  kcoup

                  I am running into a similar problem trying to get clustered single sign-on to work.

                  Keep in mind that I am new to JBoss so there may be something I am doing (or not doing) which is very obviously wrong.

                  My setup is as follows:
                  - two JBoss 4.0.2 instances on different machines
                  - ClusteredSingleSignOn uncommented (SingleSignOn commented)
                  - clustering using default values (i.e. DefaultPartition)
                  - Tomcat's UseLocalCache set to false (also tried with true and had same result)
                  - Two simple web apps on each server which can redirect browser to other local app or to remote app (i.e. other JBoss server)
                  - web apps use Basic http authentication

                  Observations:
                  - cluster.log indicates there is communication between JBoss servers
                  - server.log indicates clustered single sign on enabled
                  - accessing a web app results in authentication challenge (as expected)
                  - from within web app, accessing redirect link to other local web app results in no additional authentication request (as expected)
                  - from within web app, accessing redirect link to remote web app results in authentication challenge from other JBoss server (expected to be able to access remote web app without re-authentication)

                  Does someone have an idea as to why I cannot access the remote web app without first re-authenticating?

                  • 6. Re: ClusteredSingleSignOn help

                    Do your webapps basically just issue a redirect to the other server as soon as authentication succeeds? That is, there is no delay, no going to another page or waiting for a user to click?

                    If so, it might be because the ClusteredSingleSignOn is by default configured to use asynchronous replication. With an immediate redirect the browser request to the 2nd server might be getting there before the SSO replicates.

                    If this immediate redirect is somehow important to your app, you can configure ClusteredSingleSignOn to use a non-default JBossCache. That cache should be configured to use REPL_SYNC instead of REPL_ASYNC. If immediate redirect is not important to your app but is just part of a test fixture, its probably easier to just find a way to add a delay (e.g. make user click a link to jump servers; add a pause before issuing redirect, etc.)

                    See http://wiki.jboss.org/wiki/Wiki.jsp?page=SingleSignOn for more on how to configure ClusteredSSO to use a non-default JBossCache. If you need help, post back and I'll try to help more this evening when I'm off work.

                    • 7. Re: ClusteredSingleSignOn help
                      kcoup

                      Brian - thanks for your reply.

                      In answer to your question - the redirect is not immediate. Following authentication the browser is directed to a page containing a link to the remote web app. Clicking on the link results in a pop-up to re-authenticate.

                      • 8. Re: ClusteredSingleSignOn help

                        Does the URL the user clicks on have a different server name?

                        • 9. Re: ClusteredSingleSignOn help
                          kcoup

                          Actually I am accessing it by IP address. Note that the host name in the server.xml file is set to localhost on both servers.

                          Also I have tried a couple of other things I found reference to at http://www.jboss.org/developers/projects/jboss/tc5-clustering.html- namely:

                          I nested

                          <distributable/>

                          within <web-app> of the web.xml file and

                          <replication-config>
                           <replication-trigger>SET_AND_NON_PRIMITIVE_GET</replication-trigger>
                           <replication-granularity>SESSION</replication-granularity>
                           </replication-config>

                          within <jboss-web> of the jboss-web.xml file.

                          • 10. Re: ClusteredSingleSignOn help

                            ClusteredSSO uses a cookie to track a user, and the cookie is scoped to a host. So, it won't work for URLs with different hostnames. I need to add this point to the wiki page.

                            When I'm manually testing ClusteredSSO I use a setup similar to what you describe, but I front it with Apache and mod_jk. I configure mod_jk to route requests for one app to one server and all requests for the other app to another server. The client sees everything as coming from one host.

                            • 11. Re: ClusteredSingleSignOn help
                              kcoup

                              Thanks Brian - that probably explains it.

                              If I don't front JBoss with Apache, do you know if JOSSO can provide single sign-on capability across servers?

                              • 12. Re: ClusteredSingleSignOn help
                                groboclown

                                I'll jump back into this discussion.

                                I finally got the developers to get rid of their silly login servlet, and now we're running with a proper FORM based authentication (setup via the web.xml) using JAAS in JBoss.

                                I think I may have discovered the reason for why the login isn't being clustered, but I can't explain why it's happening.

                                The setup as it stands right now:
                                * Apache w/ mod_jk on machine A, JBoss on machines B and C.
                                * Sticky sessions enabled.

                                Here's the two situations I've found. To me, it looks like either I have a setting wrong, or there's a bug somewhere.

                                Scenario 1:
                                - Machine B starts JBoss.
                                - User logs into the app through machine A.
                                - Everything's hunky-dory. The user can move about and see everything like it should be.
                                - Machine C starts JBoss. Log messages show that B and C are talking to each other.
                                - Machine B stops JBoss.
                                - User tries to do something else, and they get a login prompt.

                                In this scenario, the clustering logs show that the session that was created on B for the user was never replicated over to C. This one looks like I'm possibly not setting something that says to request all data on joining cluster.

                                Scenario 2:
                                - Machine B starts JBoss.
                                - User logs into the app through machine A, and everything's fine.
                                - Machine C starts JBoss. Logs say they talk to each other.
                                - User performs another action. Here, we see machine B (remember - sticky sessions) push the session information over to machine C, and we see machine C get the information:

                                2005-05-27 14:37:07,992 DEBUG [org.jgroups.blocks.RpcDispatcher] [sender=MachineB:2529], method_call: _replicate(prepare(<MachineB:2529>:6, [_put(<MachineB:2529>:6, /JSESSION/BzKYRcCq2UTMRNI8VUG3Yw**, BzKYRcCq2UTMRNI8VUG3Yw**, null, true)], MachineB:2529, false))

                                - Machine B stops JBoss.
                                - User tries to do something else, and gets a login message.

                                At this point, the logs in machine C are fishy:

                                2005-05-27 14:37:28,626 INFO [org.jboss.cache.TreeCache] viewAccepted(): new members: [MachineC:1799]

                                (comment: yup, machine C realized that machine B dropped out of the cluster)

                                2005-05-27 14:37:36,899 DEBUG [org.jboss.web.tomcat.tc5.session.JBossCacheManager] loadSession(): id= BzKYRcCq2UTMRNI8VUG3Yw**, session=null
                                2005-05-27 14:37:37,086 DEBUG [org.jboss.web.tomcat.tc5.session.JBossCacheManager] loadSession(): id= BzKYRcCq2UTMRNI8VUG3Yw**, session=null
                                2005-05-27 14:37:37,086 DEBUG [org.jboss.web.tomcat.tc5.session.JBossCacheManager] loadSession(): id= BzKYRcCq2UTMRNI8VUG3Yw**, session=null
                                2005-05-27 14:37:37,086 DEBUG [org.jboss.web.tomcat.tc5.session.JBossCacheManager] loadSession(): id= BzKYRcCq2UTMRNI8VUG3Yw**, session=null
                                2005-05-27 14:37:37,227 DEBUG [org.jboss.web.tomcat.tc5.session.ClusteredSession] initAfterLoad(): initialize the transient variables ...
                                2005-05-27 14:37:37,227 DEBUG [org.jboss.web.tomcat.tc5.session.SessionIDGenerator] getSessionId called: HG4R8B0iA5kATgL8tdl-tg**

                                It looks like Machine C properly received a request for the session with the correct ID (the one it was assigned to on machine B), but machine C either can't find the session or somehow loses the session, and assigns the user a new session.

                                Any clues as to why either of these scenarios are happening?

                                • 13. Re: ClusteredSingleSignOn help
                                  groboclown

                                   

                                  Any clues as to why either of these scenarios are happening?


                                  I just saw the clue: "session=null" A co-worker gave me the obvious suggestion to try a simple JSP site to see if we can cluster that in the scenarios I just outlined. Turns out JBoss works beautifully here, though the sample didn't use any login capabilities.

                                  I'm going to work with a developer to figure out why the session here is null, while our simple sample that only put an Integer into the session worked just fine.

                                  • 14. Re: ClusteredSingleSignOn help
                                    groboclown

                                    Looks like I figured out what was going on. There seems to be a bug in the Tomcat implementation where it attaches the ClusteredSingleSignOn to the wrong < Host >. I had:
                                    < Engine name="jboss.web" defaultHost="A" >
                                    ...
                                    < Host name="A" jvmRoute="node1" ... >
                                    < Alias >localhost< /Alias >
                                    ]]
                                    like the Tomcat documentation states. However, doing this caused all the valves defined in this to be attached to a Host w/ name="localhost" (which isn't defined anywhere in my server.xml file), and the Host w/ name=A" didn't have any valves attached to it.

                                    The clue was that I wasn't seeing a JSESSIONSSO cookie being set after login to the server.

                                    When I switched over to
                                    < Engine name="jboss.web" defaultHost="localhost" >
                                    ...
                                    < Host name="localhost" jvmRoute="node1" ... >
                                    < Alias >A< /Alias >
                                    it worked just fine, and the JSESSIONSSO became set.

                                    1 2 Previous Next