Sunday, February 13, 2011

Spring Security 3 - OpenID with Javascript OpenID Selector

Introduction

In previous tutorials we've discussed how to add OpenID support to an existing Spring Security 3 application using various OpenID providers. We added each provider manually, including the images and specialized URLs. However that solution has introduced a couple of issues:

Problems

1. We're forced to manually add all OpenID providers in the JSP page. Developer A might implement it differently versus Developer B. This means users do not get a unified user experience.

2. Users are still required to know their full OpenID login. For example, to login using Blogspot, the user will type http://krams915.blogspot.com. Ideally the user should only type his username, i.e. krams915. Typing the full URL is error-prone, especially for non-technical users.

3. We could implement our own Javascript library that will parse and concatenate the default OpenID URLs. But that introduces extra work, and again, multiple developers may implement it differently. Also, are you expert enough to start your own Javascript framework?

Solution

Luckily for us there is a solution: the Javascript OpenID Selector

What is Javascript OpenID Selector?
This is a simple Javascript OpenID selector. It has been designed so that users do not even need to know what OpenID is to use it, they simply select their account by a recognisable logo.

Source: http://code.google.com/p/openid-selector/

You can find a live demo of this project at http://openid-selector.googlecode.com/svn/trunk/demo.html

Development

In this tutorial we'll add OpenID login support to an existing Spring Security 3 application. That means we'll be reusing existing configuration.

To fully appreciate this tutorial, it's required you know how to setup a simple Spring Security application using a simple user-service. If you need a review, please read my other guide Spring MVC 3 - Security - Using Simple User-Service.

You are also advised to read my other OpenID tutorials to understand the problem that we're trying to solve. You can check the following Spring Security 3 - OpenID Login with Google Provider and Spring Security 3 - OpenID Login with myOpenID Provider

We will based our application from the one we developed for Spring MVC 3 - Security - Using Simple User-Service tutorial. This is because the changes we need to implement are just a matter of configuration and placing Javascript snippets.

Preview

Before we add the Javascript OpenID Selector, our login page looks like the following:


After adding the Javascript OpenID Selector, our new login page should look like below:


Do you see the big improvement? We've just added multiple OpenID providers by just editing a JSP file which we'll show later.

Adding Javascript OpenID Selector

Since this is a third-party project, we must download it first and place the necessary files to the current Spring project. Here are the steps:

1. Visit the project's site at http://code.google.com/p/openid-selector/

2. Go to the Downloads section. Find the latest open-selector project:

3. Download and save the file.

4. Extract and open the extracted folder:


You should see a list of folders and files. We're only interested with the following:
js/jquery-1.2.6.min.js
js/openid-jquery.js
js/openid-en.js
images folder
css folder

5. Copy these files to the resources folder of the Spring project:

I suggest you create the following folders to logically contain these files.
css
images
js

Our next step is to edit the application's JSP login page to display the Javascript OpenID Selector.

6. Go back to the folder where you extracted the open-selector project.

7. Open the demo.html to see the following:


Right-click on this html file and view its source:

demo.html
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>JQuery Simple OpenID Selector Demo</title>
 <!-- Simple OpenID Selector -->
 <link type="text/css" rel="stylesheet" href="css/openid.css" />
 <script type="text/javascript" src="js/jquery-1.2.6.min.js"></script>
 <script type="text/javascript" src="js/openid-jquery.js"></script>
 <script type="text/javascript" src="js/openid-en.js"></script>
 <script type="text/javascript">
  $(document).ready(function() {
   openid.init('openid_identifier');
   openid.setDemoMode(true); //Stops form submission for client javascript-only test purposes
  });
 </script>
 <!-- /Simple OpenID Selector -->
 <style type="text/css">
  /* Basic page formatting */
  body {
   font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  }
 </style>
</head>

<body>
 <h2>JQuery Simple OpenID Selector Demo</h2>
 <p>This is a simple example to show how you can include the Javascript into your page.</p>
 <br/>
 <!-- Simple OpenID Selector -->
 <form action="examples/consumer/try_auth.php" method="get" id="openid_form">
  <input type="hidden" name="action" value="verify" />
  <fieldset>
   <legend>Sign-in or Create New Account</legend>
   <div id="openid_choice">
    <p>Please click your account provider:</p>
    <div id="openid_btns"></div>
   </div>
   <div id="openid_input_area">
    <input id="openid_identifier" name="openid_identifier" type="text" value="http://" />
    <input id="openid_submit" type="submit" value="Sign-In"/>
   </div>
   <noscript>
    <p>OpenID is service that allows you to log-on to many different websites using a single indentity.
    Find out <a href="http://openid.net/what/">more about OpenID</a> and <a href="http://openid.net/get/">how to get an OpenID enabled account</a>.</p>
   </noscript>
  </fieldset>
 </form>
 <!-- /Simple OpenID Selector -->
</body>
</html>

8. Copy the code inside head and body section. Paste the code in the corresponding sections of the JSP login page. Here's the final JSP page:

loginpage.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 
 <c:url var="rootUrl" value="/resources/" />
 
 <title>JQuery Simple OpenID Selector Demo</title>
 <!-- Simple OpenID Selector -->
 <link type="text/css" rel="stylesheet" href="${rootUrl}css/openid.css" />
 <script type="text/javascript" src="${rootUrl}js/jquery-1.2.6.min.js"></script>
 <script type="text/javascript" src="${rootUrl}js/openid-jquery.js"></script>
 <script type="text/javascript" src="${rootUrl}js/openid-en.js"></script>
 <script type="text/javascript">
  $(document).ready(function() {
   openid.init('openid_identifier');
   //openid.setDemoMode(true); //Stops form submission for client javascript-only test purposes
   });
 </script>
 <!-- /Simple OpenID Selector -->
 <style type="text/css">
 /* Basic page formatting */
 body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
 }
 </style>
</head>
<body>

<h1>Spring Security 3</h1>
<div id="login-error">${error}</div>

<c:url var="openIDLoginUrl" value="/j_spring_openid_security_check" />
<h2>JQuery Simple OpenID Selector Demo</h2> 
 <p>This is a simple example to show how you can include the Javascript into your page.</p> 
 <br/> 
 <!-- Simple OpenID Selector --> 
 <form action="${openIDLoginUrl}" method="post" id="openid_form"> 
  <input type="hidden" name="action" value="verify" /> 
  <fieldset> 
   <legend>Sign-in or Create New Account</legend> 
   <div id="openid_choice"> 
    <p>Please click your account provider:</p> 
    <div id="openid_btns"></div> 
   </div> 
   <div id="openid_input_area"> 
    <input id="openid_identifier" name="openid_identifier" type="text" value="http://" /> 
    <input id="openid_submit" type="submit" value="Sign-In"/> 
   </div> 
   <noscript> 
    <p>OpenID is service that allows you to log-on to many different websites using a single indentity.
    Find out <a href="http://openid.net/what/">more about OpenID</a> and <a href="http://openid.net/get/">how to get an OpenID enabled account</a>.</p>
   </noscript> 
  </fieldset> 
 </form> 
 <!-- /Simple OpenID Selector --> 

</body>
</html>

To make this code work, we have to correctly set the root URL by using a JSTL tag library:
<c:url var="rootUrl" value="/resources/" />
We've also commented out the following line which is responsible for activating the demo function:
//openid.setDemoMode(true); //Stops form submission for client 

Try running the application. You'll notice the images are missing. That's because we need to set the correct image path property inside the openid-jquery.js.

9. Go to the resources folder. Open the openid-jquery.js file.

10. Find the img_path property. Set the value as follows:
img_path : '../../resources/images/',

Run the Application

To run the application, use the following URL to display the login page:
http://localhost:8080/spring-security-openid-selector/krams/auth/login

Here's the final screenshot:

Try playing with all the various OpenID providers. Notice how user-friendly the interface is.

Reminder

Notice regardless whether you've entered the correct credentials the Spring application still throws out an error that the username or password is incorrect. That's because you need to add the correct OpenID identifier under the user-service tag. See the spring-security.xml

<security:user-service id="userDetailsService">
   <!-- user name is based on the returned open id identifier -->
   <!-- YOU MUST MANUALLY ADD THE RETURNED OPENID IDENTIFIER HERE -->
     <security:user name="http://krams915.blogspot.com/" password="" authorities="ROLE_USER, ROLE_ADMIN" />
  </security:user-service>

Conclusion

That's it. We've managed to add the Javascript OpenID Selector. Of course to make the whole project work, you need to add the corresponding returned OpenID identifiers in the Spring Security's in-memory user-service. If you're going to test these with Google, Yahoo, or any of your favorite providers, please log out first so that you can test the login functionality!

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-security-openid/

You can download the project as a Maven build. Look for the spring-security-openid-selector.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring Security 3 - OpenID with Javascript OpenID Selector ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

7 comments:

  1. Great Spring Security articles. They've helped me a lot. I'd like to implement ONLY OpenId for my site so I don't have to worry about managing accounts, password resets, etc.

    With that being the case, the first time someone successfully logs in I'll have to create an entry in the users table (and the acl_sid table in my case).

    The names returned are long and not very human friendly. I read somewhere that Google has another api to return extra fields such as username, email address, and other information. Do all OpenId sites do that?

    Could you write an article/example showing how to go about doing that or give me a quick reply if it's simple or a link to get some further information?

    ReplyDelete
    Replies
    1. paypal brokers is one of innovative platform by which you can make money from the Forex markets.

      Delete
  2. @scb, yes, Google does have a different format. Have you seen my article "Spring Security 3 - OpenID Login with Google Provider"? It's in the tutorials section. Yes, you can retrieve extra information from Google, and I know it also works for other OpenId provider as long as they have the information you're asking. Otherwise you may get an Exception.

    ReplyDelete
  3. I visited your blog for the first time and just been your fan. Keep posting as I am gonna come to read it everyday.

    ReplyDelete
  4. I have read your blog its very attractive and impressive. I like it your blog.

    Spring online training Spring online training Spring Hibernate online training Spring Hibernate online training Java online training

    spring training in chennai spring hibernate training in chennai

    ReplyDelete
  5. Have you been thinking about the power sources and the tiles whom use blocks I wanted to thank you for this great read!! I definitely enjoyed every little bit of it and I have you bookmarked to check out the new stuff you post. java training in jalandhar

    ReplyDelete