Announcement Announcement Module
Collapse
No announcement yet.
Spring 1.0 Observations when integrating into AppFuse Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring 1.0 Observations when integrating into AppFuse

    I'm having a few issues when upgrading AppFuse to use Acegi Security 1.0. I've documented some of these issues in other posts, but I figured it would be best to write a detailed step-by-step log of issues I encountered while upgrading.

    The first thing I did to upgrade was to simply replace acegi-security-1.0.0-RC2.jar with acegi-security-1.0.0.jar. I'm using Spring 1.2.8. My applicationContext-security.xml file is located at:

    http://fisheye5.cenqua.com/browse/~r...t-security.xml

    1. The first issue I see is a ClassCastException in an HttpSessionAttributeListener that counts the number of logged in users.

    Code:
    User user = (User) securityContext.getAuthentication().getPrincipal();
    The above line throws an exception because securityContext.getAuthentication().getPrincipal() returns a String instead of a User. This happens before I even login. I'm guessing Acegi is stuffing an anonymous object into the session with the HttpSessionContextIntegrationFilter.ACEGI_SECURITY _CONTEXT_KEY key.

    I have my securityFilter mapped to /j_security_check, *.html and *.jsp. My welcome-file is index.jsp, which redirects to mainMenu.html. Since mainMenu.html is protected, Acegi forwards to login.jsp. Below is my objectDefinitionSource from filterInvocationInterceptor:

    Code:
            <property name="objectDefinitionSource">
                <value>
                    PATTERN_TYPE_APACHE_ANT
                    /signup.html=ROLE_ANONYMOUS,admin,user
                    /passwordHint.html*=ROLE_ANONYMOUS,admin,user
                    /**/*.html*=admin,user
                    /clickstreams.jsp=admin
                </value>
    Even after logging in, my HttpSessionAttributeListener doesn't get fired again. However, if I logout and log back in, it *will* get fired and the cast will work properly. If I clear all my cookies and hit my application again, I can reproduce the ClassCastException.

    Is there something that changed in the anonymous user processing logic (or in filterInvocationInterceptor) between RC2 and 1.0? It seems like RC2 did not stuff anonymous users into the session, whereas 1.0 does.

    2. Reloading my application results in the following error:

    Code:
    [appfuse-webwork] WARN [http-8080-Processor24] [/appfuse-webwork].writeObject(1461) | Cannot serialize session attribute ACEGI_SAVED_REQUEST_KEY for session 31C8785E3615152E56FED21AC9795A92
    java.io.NotSerializableException: javax.servlet.http.Cookie
            at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1075)        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:291)
            at java.util.ArrayList.writeObject(ArrayList.java:569)
    I'm guessing this has something to do with the new "save the request parameters" logic introduced in 1.0.0? The strange thing is this happens when I'm not even doing anything, so Acegi is putting something into my session (a cookie?) that's not serializable.

    For these reasons, I believe I'm probably better off backing down to RC2.

    Thanks,

    Matt
    Last edited by mraible; Jun 1st, 2006, 02:33 PM. Reason: Changed title from Spring to Acegi

  • #2
    Matt, for issue #1, the occasional String you're getting is due to the AnonymousAuthenticationProvider.

    It stores the AnonymousAuthenticationFilter. It stores an AnonymousAuthenticationToken in the SecurityContext. The principal on that object is the password you provided to the userAttribute property on the AnonymousProcessingFilter.

    You can use the AuthenticationTrustResolver to determine if the authentication is anonymous, or you can use...

    AnonymousAuthenticationToken.isAssignableFrom(auth entication.getClass()) for example.

    There might be a better answer, I don't know what it is yet.
    Last edited by RayKrueger; Jun 1st, 2006, 04:09 PM.

    Comment


    • #3
      Thanks for the clarification Ray. The main issue seems to be that Acegi 1.0 puts an ACEGI_SECURITY_CONTEXT object into the session even for anonymous users. In RC2, it only added a ACEGI_SECURITY_CONTEXT object when a "real" (non-anonymous) user logged in.

      To illustrate, I have the following method in my HttpSessionAttributeListener. You'll notice I added an !isAnonymous() call that prevents the ClassCastException from happening with anonymous users.

      Code:
          public void attributeAdded(HttpSessionBindingEvent event) {
              log.debug("event.name: " + event.getName());
              if (event.getName().equals(EVENT_KEY) && !isAnonymous()) {
                  SecurityContext securityContext = (SecurityContext) event.getValue();
                  User user = (User) securityContext.getAuthentication().getPrincipal();
                  addUsername(user);
              }
          }
      
          private boolean isAnonymous() {
              AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
              SecurityContext ctx = SecurityContextHolder.getContext();
              if (ctx != null) {
                  Authentication auth = ctx.getAuthentication();
                  return resolver.isAnonymous(auth);
              }
              return true;
          }
      With 1.0, attributeAdded() is called when I first hit the application - before I login. And it's never called again, even after I login. I suppose I could change my attributeReplaced() method to handle this (b/c it's likely called after I login). With RC2, attributeAdded() was never called until the user logged in.

      As long as this is "desired behavior", I suppose I can deal with it accordingly.

      Thanks,

      Matt

      Comment


      • #4
        It might feel like so much work if you did...

        Code:
            public void attributeAdded(HttpSessionBindingEvent event) {
                log.debug("event.name: " + event.getName());
                if (event.getName().equals(EVENT_KEY)) {
                    SecurityContext securityContext = (SecurityContext) event.getValue();
                    Object principal = securityContext.getAuthentication().getPrincipal();
                    if (principal instanceof User) {
                        User user = (User) principal;
                        addUsername(user);
                    }
                }
            }

        And maybe even use UserDetails instead of User for flexibility. Unless that "User" object is your own thing and not the Acegi "User" class...

        Comment


        • #5
          User is my own class. Also, the attribute gets added for anonymous users in 1.0, whereas it didn't in previous releases. I believe I first integrated Acegi 0.8 into AppFuse.

          Here's my solution, which works for 1.0, as well as previous releases:

          Code:
              /**
              * This method is designed to catch when user's login and record their name
               * @see javax.servlet.http.HttpSessionAttributeListener#attributeAdded(javax.servlet.http.HttpSessionBindingEvent)
               */
              public void attributeAdded(HttpSessionBindingEvent event) {
                  log.debug("event.name: " + event.getName());
                  if (event.getName().equals(EVENT_KEY) && !isAnonymous()) {
                      SecurityContext securityContext = (SecurityContext) event.getValue();
                      User user = (User) securityContext.getAuthentication().getPrincipal();
                      addUsername(user);
                  }
              }
          
              private boolean isAnonymous() {
                  AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
                  SecurityContext ctx = SecurityContextHolder.getContext();
                  if (ctx != null) {
                      Authentication auth = ctx.getAuthentication();
                      return resolver.isAnonymous(auth);
                  }
                  return true;
              }
          
              /**
              * When user's logout, remove their name from the hashMap
               * @see javax.servlet.http.HttpSessionAttributeListener#attributeRemoved(javax.servlet.http.HttpSessionBindingEvent)
               */
              public void attributeRemoved(HttpSessionBindingEvent event) {
                  if (event.getName().equals(EVENT_KEY) && !isAnonymous()) {
                      SecurityContext securityContext = (SecurityContext) event.getValue();
                      User user = (User) securityContext.getAuthentication().getPrincipal();
                      removeUsername(user);
                  }
              }
          
              /**
               * Needed for Acegi Security 1.0, as it adds an anonymous user to the session and
               * then replaces it after authentication. http://forum.springframework.org/showthread.php?p=63593
               * @see javax.servlet.http.HttpSessionAttributeListener#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent)
               */
              public void attributeReplaced(HttpSessionBindingEvent event) {
                  if (event.getName().equals(EVENT_KEY) && !isAnonymous()) {
                      SecurityContext securityContext = (SecurityContext) event.getValue();
                      if (securityContext.getAuthentication() != null) {
                          User user = (User) securityContext.getAuthentication().getPrincipal();
                          addUsername(user);
                      }
                  }
              }

          Comment


          • #6
            I forgot to reply to NotSerializableException...

            You are correct, the class org.acegisecurity.ui.savedrequest.SavedRequest saves a collection of Cookies. SavedRequest is put in the Session, and Cookies are not serializable.

            Would you mind opening a Jira on this?
            http://opensource2.atlassian.com/projects/spring

            Comment


            • #7
              Done.

              http://opensource.atlassian.com/proj...browse/SEC-294

              Thanks,

              Matt

              Comment


              • #8
                I think the jira SEC-294 is a duplicate of the jira-289.

                I posted a new version of SavedRequest on SEC-289 page that seems to solve the problem.

                Comment

                Working...
                X