Results 1 to 8 of 8

Thread: Spring 1.0 Observations when integrating into AppFuse

  1. #1
    Join Date
    Aug 2004
    Location
    Denver
    Posts
    249

    Default Acegi 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 at 02:33 PM. Reason: Changed title from Spring to Acegi

  2. #2
    Join Date
    Oct 2004
    Posts
    207

    Default

    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 at 04:09 PM.

  3. #3
    Join Date
    Aug 2004
    Location
    Denver
    Posts
    249

    Default

    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

  4. #4
    Join Date
    Oct 2004
    Posts
    207

    Default

    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...

  5. #5
    Join Date
    Aug 2004
    Location
    Denver
    Posts
    249

    Default

    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);
                }
            }
        }

  6. #6
    Join Date
    Oct 2004
    Posts
    207

    Default

    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

  7. #7
    Join Date
    Aug 2004
    Location
    Denver
    Posts
    249

  8. #8
    Join Date
    Aug 2004
    Location
    Luxembourg
    Posts
    1

    Default

    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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •