Monday, December 13, 2010

OpenID + Spring MVC 3 + Spring Security 3 + OpenID Selector

We decided to move our authentication into openID. Meanwhile, we upgrade our security from Spring Security 2 to 3. Adding OpenID to spring security is straightforward, add the following tag into "<http>" tag of security.xml
<openid-login login-page="/login.jsp" login-processing-url="/openlogin" user-service-ref="userDao"
                 authentication-failure-handler-ref="openIdAuthFailureHandler"/>

And OpenID will take over the authentication.

However, there are more to change for openID.

First and most obviously, we need a new login page takes user to openid provider instead of our own user/password checker. We chose openid-selector (1.2 currently) as the spring security choose it for demo. It is a fairly nice package. It allows one to choose from several openid providers (Google, Yahoo, AOL, OpenID, blogger, flicker, ...) Several things need to be done to use it:


  • However, it uses jQuery and has lots of conflict with prototype we are using. Fortunately, the conflict originates mostly from "$". I modify the two js file, replace all "$" with "jQuery" and add jQuery.noConflict(); in the beginning and firebug stops to complain.


  • There are several options in openid-jquery.js to play with. I use default mostly, except "no_sprite" to true as I have uncomment flickr and its not in the big sprite picture.


  • In the login page, add following into "<head"> tag (notice that openid-jquery.js should be add before openid-jquery-en.js)
    <script type="text/javascript" src="<c:url value="/scripts/jquery/openid-selector/js/openid-jquery.js" />"></script>
         <script type="text/javascript" src="<c:url value="/scripts/jquery/openid-selector/js/openid-jquery-en.js" />"></script>

    and add following into "<body">
    <script type="text/javascript">
            jQuery.noConflict();
            jQuery(document).ready(function(){
                openid.img_path="<c:url value='/scripts/jquery/openid-selector/images/'/>";
                openid.init("openid_identifier");
                jQuery("#openid_identifier").focus();
            });
        </script>

    Notice the openid.img_path has to be set outside if the openid-selector files are not put under the root.

These pretty much take care of login. But now we also need to modify signup process. Originally, you click signup and then put a new username/password. Now with openid, you first login with an openid from one of the providers, system found that you are not a user, and provide you a signup sheet. That is why in above <openid-login"> tag, we need a special "openIdAuthFailureHandler" for "authentication-failure-handler".

We can extend a spring handler for this purpose.
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.imirsel.nema.webapp.security;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.openid.OpenIDAuthenticationStatus;
import org.springframework.security.openid.OpenIDAuthenticationToken;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

/**
 *  Customized {@link AuthenticationFailureHandler} that redirect to sign-up page
 * if the OpenID authentication succeeds, but the user name is not yet in local DB of the container
 * @author gzhu1
 */
public class OpenIDAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    static private Log logger = LogFactory.getLog(OpenIDAuthenticationFailureHandler.class);

    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
            HttpServletResponse response, AuthenticationException exception)
            throws IOException, ServletException {
        logger.error(exception, exception);
        if (exception instanceof UsernameNotFoundException
                && exception.getAuthentication() instanceof OpenIDAuthenticationToken
                && ((OpenIDAuthenticationToken) exception.getAuthentication()).getStatus().equals(OpenIDAuthenticationStatus.SUCCESS)) {
            DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
            request.getSession(true).setAttribute("USER_OPENID_CREDENTIAL", exception.getAuthentication().getPrincipal());
            // redirect to create account page

            logger.info("user (" + exception.getAuthentication().getPrincipal() + "," + exception.getExtraInformation() + ") is not found and redirect to signup.");
            redirectStrategy.sendRedirect(request, response, "/signup.html");

        } else {
            super.onAuthenticationFailure(request, response, exception);
        }
    }
}

and declare the bean in applicationContext.xml.
<bean id="openIdAuthFailureHandler" class="org.imirsel.nema.webapp.security.OpenIDAuthenticationFailureHandler">
        <property name="defaultFailureUrl" value="/login.jsp"/>
    </bean>

Of course, now I do not really have a password, so I generate a random string for password, because a password is needed somewhere else.

That is it. Now your user can sign-in with their Google, Yahoo, AOL, open-id account directly.

Tuesday, December 7, 2010

My Review of HP G62-340US 15.6" Laptop

Originally submitted at Staples

Now you can do more and have more fun without spending more. The HP G62 notebook PC features the latest technology and enhanced security right out of the box for the perfect balance of performance, connectivity, and worry-free computing. With its cl ean design and textured HP Imprint finish in char...


Solid buy

By zggame from urbana, IL on 12/7/2010

 

5out of 5

Pros: Quiet, Quality Display

Best Uses: Web Browsing, Video, Word Processing

Describe Yourself: Tech Savvy

Primary use: Personal

I bought at the sale for $379-$50 coupon for my parents. It has HDMI and webcam. They mostly just use skype, web browsing and watch online streaming TV/movie. It is perfect for their usage. The thrown in office starter is not bad. HDMI is easy for them to connect TV to watch video, better than VGA+audio port. Webcam works fairly well during skype. Overall, it is plenty for them. Great buy. Not too many bloatware. Norton is annoying for the trial. I uninstalled it and put a free Avast Personal. Office starter should be more than enough for some basic use.

(legalese)