Matt RaibleMatt Raible is a Java Champion and Developer Advocate at Okta. developer.okta.com

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

Using Acegi Security for Remember Me and SSL Switching

I spent some time yesterday converting AppFuse's homegrown Remember Me and SSL Switching system to using Acegi Security. Thanks to Justin Spears, who provided the original motivation. It was much easier than I thought it would be, and resulted in the deleting of 7 classes in AppFuse. Not only that, but only one of them had a test for it, so the test coverage has naturally gone up as well. I'll trade 40 lines of XML for 1214 lines of Java any day - especially when I can get the support of an open-source framework. ;-)

If you're interested in using this code over 1.8.2, you can checkout the latest code from CVS (or download it from http://appfuse.org/nightly). The only other change currently in CVS is changing from "tomcat" to "user" as the default User role. Below is a list of classes that were removed as part of this move to Acegi:

  • src/dao/org/appfuse/model/UserCookie.java
  • src/service/org/appfuse/util/RandomGUID.java
  • src/web/org/appfuse/webapp/action/LoginServlet.java
  • src/web/org/appfuse/webapp/filter/LoginFilter.java
  • src/web/org/appfuse/webapp/taglib/SecureTag.java
  • src/web/org/appfuse/webapp/util/SslUtil.java
  • test/web/org/appfuse/webapp/action/LoginServletTest.java

I should also mention that I owe a big thanks to Virtuas - who pays me to work on AppFuse these days. :-D

Posted in Java at Aug 29 2005, 09:25:37 AM MDT 11 Comments
Comments:

Hi Matt,

I've done the same thing for my own app (http://tudu.sf.net), and of course I agree with you. However I have a slight problem with Acegi's remember-me implementation : the cookie stored in the user's computer contains the user password (in a md5 hash). So it's possible to find a user's password with this system, which was not possible with Appuse's home-made solution.
Of course, this is only for the paranoid, and once again I've chosen the same solution for my own app.

Julien Dubois.

Posted by Julien Dubois on August 29, 2005 at 10:26 AM MDT #

Yeah, I'm aware it's not as secure as the homegrown solution we had. However, it is documented better than AppFuse's (so I don't have to answer as many questions about it) and it's also pluggable. Hopefully those developers that are super-paranoid will contribute another implementation of RememberMeServices that we can all use. ;-)

The only hard things I found in this integration was detecting when RememberMe was being used, as well as when Password Encryption was turned on. My current logic detecting password encryption and remember me enabled is:

    ApplicationContext ctx =
        WebApplicationContextUtils.getRequiredWebApplicationContext(context);
    
    boolean encryptPassword = false;
    try {
        ProviderManager provider = (ProviderManager) ctx.getBean("authenticationManager");
        for (Iterator it = provider.getProviders().iterator(); it.hasNext();) {
            AuthenticationProvider p = (AuthenticationProvider) it.next();
            if (p instanceof RememberMeAuthenticationProvider) {
                config.put("rememberMeEnabled", Boolean.TRUE);
            }
        }
    
        if (ctx.containsBean("passwordEncoder")) {
            encryptPassword = true;
            config.put(Constants.ENCRYPT_PASSWORD, Boolean.TRUE);
            String algorithm = "SHA";
            if (ctx.getBean("passwordEncoder") instanceof Md5PasswordEncoder) {
                algorithm = "MD5";
            }
            config.put(Constants.ENC_ALGORITHM, algorithm);
        }
    } catch (NoSuchBeanDefinitionException n) {
        // ignore, should only happen when testing
    }

As far as detecting when Remember Me is used to login, I'm using:

    // if user logged in with remember me, display a warning that they can't change passwords
    log.debug("checking for remember me login...");

    AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
    SecureContext ctx = (SecureContext) ContextHolder.getContext();

    if (ctx != null) {
        Authentication auth = ctx.getAuthentication();

        if (resolver.isRememberMe(auth)) {
            request.getSession().setAttribute("cookieLogin", "true");
            
            // add warning message
            ActionMessages messages = new ActionMessages();
            messages.add(ActionMessages.GLOBAL_MESSAGE,  new ActionMessage("userProfile.cookieLogin"));
            saveMessages(request, messages);
        }
    }

Posted by Matt Raible on August 29, 2005 at 10:42 AM MDT #

So in other words, it's using md5 password in the cookie as a mechanism to implement remeber me? it this is true, then I would not use it in the this weird real world.

Posted by root on August 29, 2005 at 11:23 AM MDT #

It shouldn't be that bad if the password is MD5 hashed in a cookie if it was hashed using salt. But it would have to be user-configurable salt and not something that was hardcoded since everyone can see the source.

Posted by Ben C on August 30, 2005 at 06:39 AM MDT #

Ben - the password *is* MD5 hased in a cookie using salt. I encourage all AppFuse users to change the default "key" that's used for the salt. More information on the Remember Me logic is in TokenBasedRememberMeServices javadocs.

Posted by Matt Raible on August 30, 2005 at 08:03 AM MDT #

Matt - I was more replying to root saying that he wouldn't use this in the "weird real world" due to the md5 hashed pwd in a cookie. Although I hadn't seen the code until now, I knew that since you're a bright guy that that there would be salt involved in the algorithm.

Posted by Ben C on August 30, 2005 at 11:19 AM MDT #

'I should also mention that I owe a big thanks to Virtuas' Noticed that 'Virtuas is majority-owned by Alaskan Natives' Your co-workers there may be interested in that online station I like so much. Out of Talkeetna, Alaska. http://www.WholeWheatRadio.org They can say hi to me, I chat under the name Pretending to Work (not the truth but my goal in life!) Gotta say it again - your kids were the ultimate in cuteness at that Edeploy reunion!

Posted by Christina on August 30, 2005 at 01:13 PM MDT #

I don?t think that storing the password in the enrypted cookie is as scary as it looks at first. In fact, it solves a couple of problems inherent to RememberMe. The cookie comprises of a clear part and an MD5 hashed part. The clear part consists of username and expiry timestamp. The hashed part consists of username, password and expiry timestamp. If the password was salted when it was placed in the database, then it will be salted in the cookie as well. Since the password is hashed and its not possible to unscramble the hash (well, perhaps its not totally impossible, but its at least unfeasible. For added protection the password could be hashed twice ? ?hash the hash?). Its safe to say that its impossible to get the password out of the cookie. Even without the hash-the-hash, it would be hashed twice already because the cookie is hashed and the password is hashed. <p/> That begs the question, why have the password in the cookie? The reason is that cookies can be stolen from the machine and used by someone else on some other machine. That?s the inherent risk to RememberMe. If username was the only thing in the cookie, there would be no way to stop the cookie from providing access short of removing the user from the system. To mitigate this risk Acegi uses the username to access the password and expiry timestamp. It then hashes everything up and compares it to the hashed part of the cookie. If it matches, the user is considered authenticated. However, if the cookie is stolen, and you know its stolen, then you can just change the password in the backend and the cookie become worthless. <p/> The other problem this solves it defends agaist a RememberMe cookie attack. If a username was known, and the password was not stored in the cookie, then it would be possible to write a program that creates cookies for that username and a whole bunch of timestamps. Then write a program to hit the site with all those cookies until its breached. <p/> I suppose a token of some sort could be used instead of the password, but that really the same as a password and it forces the application that creates/manages the password to create and maintain a token for this purpose. In the end its no more safer than encrypting the password. I think the greatest risk is not in the fact that the password is encrypted in the cookie, but that someone can steal the cookie from a machine and use it until the password changes.

Posted by George Franciscus on September 01, 2005 at 11:32 AM MDT #

[schemaexport] alter table user_role
[schemaexport]     add index FK143BF46AEDF26C1C (username),
[schemaexport]     add constraint FK143BF46AEDF26C1C
[schemaexport]     foreign key (username)
[schemaexport]     references app_user (username);
[schemaexport] alter table user_role
[schemaexport]     add index FK143BF46A11CC04A5 (role_name),
[schemaexport]     add constraint FK143BF46A11CC04A5
[schemaexport]     foreign key (role_name)
[schemaexport]     references role (name);
[schemaexport] (hbm2ddl.SchemaExport                173 ) schema export complete

[schemaexport] (connection.DriverManagerConnectionProvider 147 ) cleaning up con
nection pool: jdbc:mysql://localhost/appfuse?autoReconnect=true&useUnicode=true&
characterEncoding=utf-8

db-load:
   [dbunit] Executing operation: CLEAN_INSERT
   [dbunit]           on   file: E:\eciplse\appfuse\metadata\sql\sample-data.xml

   [dbunit]           with format: xml
   [dbunit] WARNING - app_user.enabled data type (1111, ?bit?) not recognized
and will be ignored. See FAQ for more information.

BUILD FAILED

Posted by joe on September 13, 2005 at 02:54 AM MDT #

Joe, please subscribe to the AppFuse Mailing list for these types of questions. You could also google for the answer. ;-)

Posted by Matt Raible on September 13, 2005 at 06:41 AM MDT #

hahaha

Posted by 220.225.70.181 on November 09, 2006 at 10:20 AM MST #

Post a Comment:
  • HTML Syntax: Allowed