1 2 Previous Next 19 Replies Latest reply on Dec 20, 2012 2:52 PM by pgarner Go to original post
      • 15. Re: LoginModule defined with cached=true, but called between web and ejb container
        pgarner

        Where should the wiki article go?  Community >  Picketbox?

        • 16. Re: LoginModule defined with cached=true, but called between web and ejb container
          anil.saldhana

          Patrick Garner wrote:

           

          Where should the wiki article go?  Community >  Picketbox?

          You can put it anywhere you want.  Like AS7 or PicketBox user areas. We can link from other places.

           

          I absolutely love the community participation. We (users, JBoss devs) b$tch and complain when things don't work. Then we solve it. Then we create wiki articles or quickstarts. And the world is a better place.

           

          (Anil shuts up his philosophy now).

          • 17. Re: LoginModule defined with cached=true, but called between web and ejb container
            pgarner

            Okay I've put together a quickstart app, but I'm still confused about something. 

             

            If a method of a managed bean invokes HttpServletRequest#logout and HttpSession#invalidate and attempts to invoke a method on a secure EJB, this should be forbidden by JBoss security.  Is this true? 

             

            Because what I'm observing is that JBoss security only forbids such method invocation if the user's password has been changed in the underlying data source during the user's session.  As long as the user's password has not been changed the secure method can be invoked after the principal has been removed and after the session has been destroyed.

             

            Check out the attached application.

             

            1.  Make a browser request against localhost/Foobar.  You will be redirected to index.xhtml.

             

            2.  Login

             

            3.  If login is successful, you will be served loggedIn.xhtml, a facelet that allows you to change the password or log out.  If you change the password loggedIn.xhtml is reloaded.

             

            4.  Re-enter the password that you logged in with and click Submit New Password.

             

            5.  Click Logout Failure, which programmatically logs you out and ends the session prior to looking up LoginHistoryService and invoking LoginHistoryService#create.

             

            6.  Notice that no error occurred.  LoginHistoryService EJB, which is protected by @RolesAllowed("SYSTEM_ADMINISTRATOR"), was looked up and LoginHistoryService#create was invoked after programmatic logout.

             

            7.  Repeat steps 2 - 5 except on step 4 enter a different password.  Notice that in step 6 an error occurs, EJBAccessException: JBAS013323: Invalid User.  In the stack trace note the following:

             

            PBOX000206: Login failure: javax.security.auth.login.FailedLoginException: PBOX000070: Password invalid/Password required
            

             

            In both scenarios, above, the password was changed in the underlying database during the user's session.  Only difference being that in one case the password was identical to the login password and in the other case the password was changed to a different password.  In both cases HttpServletRequest#logout and HttpSession#invalidate were invoked prior to invoking LoginHistoryService#create.

             

            8.  Repeat steps 2 - 7 except on step 5 click Logout Success instead of Logout Failure.  The only difference between Logout Failure and Logout Success is that LoginHistory#create is invoked prior to HttpServletRequest#logout and HttpSession#invalidate.  What step 8 demonstrates is that JBoss Security behaves as expected when LoginHistoryService#create is invoked prior to removing the principal and destroying the session.

             

            It seems that in the above scenarios JBoss Security should not attempt to authenticate the user after HttpServletRequest#logout is invoked.  Instead of attempting to authenticate it should be attempting to authorize, and if the principal has been removed the error should come back as follows:

             

            javax.ejb.EJBAccessException: JBAS014502: Invocation on method: public void com.foobar.service.LoginHistoryService.create(com.foobar.model.LoginHistory) of bean: LoginHistoryService is not allowed
            

             

            instead of the FailedLoginException.

             

            I will finish my wiki article and post it with the quickstart after this confusion is resolved.

            • 18. Re: LoginModule defined with cached=true, but called between web and ejb container
              sguilhen

              I believe the problem here is that you need to programmatically login with the new credentials so that the underlying security context can be updated. When you login (step 2) a security context is established in the web layer. This context contains the authenticated principal/password and is propagated to the EJB container when calling EJBs. It is established once the call is served by a thread and is cleaned up after the thread returns.

               

              In your example, you are invalidating the session and calling the EJB as part of the same method, so this is what happens:

               

              1- context is established using the principal/password associated with the session, lets say userA/passA.

               

              2- session.invalidate() is called, causing the security cache to purge the entry that corresponds to userA.

               

              3- you call the LoginHistoryService EJB. The WEB layer will use the established security context to propagate the identity/password to the EJB container. As there is no cache entry for userA, a new authentication will take place and the DBLoginModule will be called.

                3a - if you changed the DB password to the same password (passA), then the authentication will succeed as the exisiting context will propagate the userA/passA pair and this will match the values found in the DB.

                3b - if you changed the password to a different password, then the authentication will fail because the existing context will propagate the userA/passA pair and the DB will have a different value for the password.

               

              This is why you see no error in the first case and a login failure in the second.

               

              When you call loginSuccess, you successfully invoke the EJB because the security cache is still active and the security context that was established in the web layer still reflect the correct username and password pair that exists in the DB. So when the invocation reaches the EJB container, the security cache is hit and the user is authenticated. Note that there's no way to escape authentication in the EJB container as all EJB calls are required to be authenticated by the EJB specification. Finally, you invalidate the session and return, so the existing security context is removed and when the client (browser) attempts to call a protected resource he should be redirected to the login page as the session has been terminated.

               

              I believe you can get around the error in the first scenario by calling request.login(username, newPass) after invoking logout (and before invoking the EJB) so that the web container updates the existing security context. This would cause the new username/password pair to be propagated to the EJB container in subsequent calls and you should get no errors from the EJB security layer.

              • 19. Re: LoginModule defined with cached=true, but called between web and ejb container
                pgarner

                Correct me if I'm wrong but it was a bug or at least bad programming practice on my part to invoke HttpServletRequest#logout and HttpSession#invalidate prior to LoginHistory#create.  I didn't notice the bug until I implemented Change Password workflow, which was when the FailedLoginException was thrown.  The problem was resolved by simply reversing the order e.g. invoking LoginHistory#create before logout.  However, it was troubling to learn that the EJB container was re-authenticating the user every time during the logout process after I explicitly invoked HttpServletRequest#logout and HttpSession.invalidate.

                2- session.invalidate() is called, causing the security cache to purge the entry that corresponds to userA.

                 

                3- you call the LoginHistoryService EJB. The WEB layer will use the established security context to propagate the identity/password to the EJB container. As there is no cache entry for userA ...

                 

                So, if I understand you correctly, the security context remains established and userA (I'm assuming this means the principal) remains intact?  Wow.  Until now, I assumed that immediately upon invocation of logout and/or invalidate the security context was removed.  Perhaps it's not removed until the thread returns because of some requirement in the EJB spec, such as being able to pass principals across a chain of EJB calls?  Well... it was certainly confusing to receive a FailedLoginException when logging out    and it was troubling that the application didn't receive an error except during logout under the unique circumstance when the user's password was changed during the session -- all because the EJB container was re-authenticating behind the scenes after logout was invoked.

                When you call loginSuccess, you successfully invoke the EJB because the security cache is still active and the security context that was established in the web layer still reflect the correct username and password pair that exists in the DB. So when the invocation reaches the EJB container, the security cache is hit and the user is authenticated. Note that there's no way to escape authentication in the EJB container as all EJB calls are required to be authenticated by the EJB specification. Finally, you invalidate the session and return, so the existing security context is removed and when the client (browser) attempts to call a protected resource he should be redirected to the login page as the session has been terminated.

                Just when I thought I was catching on, I'm confused again    I don't understand when you say that the EJB spec requires all EJB calls to be 'authenticated.'  It is my understanding that principals are authenticated -- not EJB calls -- and that EJB calls require access authorization -- not authentication.  If this is the case then referring back to my web application, since the security context (I'm assuming this means the principal) remains intact after invoking HttpServletRequest#logout and HttpSession#invalidate (and until the thread returns) there should be no reason to re-authenticate the principal before the thread returns.  In other words, if the principal is authenticated at login and logout is invoked but does not remove the security context, and during logout (e.g. before the thread returns) a secure EJB method is invoked, the EJB container should perform access authorization, checking that the user has the proper role, and not authentication, and, hence, the FailedLoginException should never be thrown after invoking logout and before the thread returns.

                1 2 Previous Next