Browse Source

SEC-1431: Added openid-selector to openid sample, plus AX configuration for myopenid.com.

Luke Taylor 15 years ago
parent
commit
def5f88c8c
26 changed files with 686 additions and 25 deletions
  1. 20 0
      docs/manual/src/docbook/samples.xml
  2. 4 0
      samples/openid/src/main/java/org/springframework/security/samples/openid/CustomUserDetailsService.java
  3. 8 1
      samples/openid/src/main/webapp/WEB-INF/applicationContext-security.xml
  4. 45 0
      samples/openid/src/main/webapp/css/openid.css
  5. BIN
      samples/openid/src/main/webapp/images/aol.gif
  6. BIN
      samples/openid/src/main/webapp/images/blogger.ico
  7. BIN
      samples/openid/src/main/webapp/images/claimid.ico
  8. BIN
      samples/openid/src/main/webapp/images/facebook.gif
  9. BIN
      samples/openid/src/main/webapp/images/flickr.ico
  10. BIN
      samples/openid/src/main/webapp/images/google.gif
  11. BIN
      samples/openid/src/main/webapp/images/livejournal.ico
  12. BIN
      samples/openid/src/main/webapp/images/myopenid.ico
  13. BIN
      samples/openid/src/main/webapp/images/openid-inputicon.gif
  14. BIN
      samples/openid/src/main/webapp/images/openid.gif
  15. BIN
      samples/openid/src/main/webapp/images/technorati.ico
  16. BIN
      samples/openid/src/main/webapp/images/verisign.gif
  17. BIN
      samples/openid/src/main/webapp/images/verisign.ico
  18. BIN
      samples/openid/src/main/webapp/images/vidoop.ico
  19. BIN
      samples/openid/src/main/webapp/images/wordpress.ico
  20. BIN
      samples/openid/src/main/webapp/images/yahoo.gif
  21. 11 0
      samples/openid/src/main/webapp/js/jquery-1.2.6.min.js
  22. 220 0
      samples/openid/src/main/webapp/js/openid-client/jquery.query-2.1.3.js
  23. 20 0
      samples/openid/src/main/webapp/js/openid-client/openid-client-config.js
  24. 63 0
      samples/openid/src/main/webapp/js/openid-client/openid-client.js
  25. 240 0
      samples/openid/src/main/webapp/js/openid-jquery.js
  26. 55 24
      samples/openid/src/main/webapp/openidlogin.jsp

+ 20 - 0
docs/manual/src/docbook/samples.xml

@@ -99,6 +99,26 @@ Success! Your web filters appear to be properly configured!
             the same application context file. This means there are actually two identical
             the same application context file. This means there are actually two identical
             authentication providers configured in this application. </para>
             authentication providers configured in this application. </para>
     </section>
     </section>
+    <section xml:id="openid-sample">
+        <title>OpenID Sample</title>
+        <para>
+            The OpenID sample demonstrates how to use the namespace to configure OpenID and how to set up
+            <link xlink:href="http://openid.net/specs/openid-attribute-exchange-1_0.html">attribute exchange</link>
+            configurations for Google, Yahoo and MyOpenID identity providers (you can experiment with adding others
+            if you wish). It uses the JQuery-based <link xlink:href="http://code.google.com/p/openid-selector/">openid-selector</link>
+            project to provide a user-friendly login page which allows the user to easily select a provider, rather than
+            typing in the full OpenID identifier.
+        </para>
+        <para>
+            The application differs from normal authentication scenarios in that it allows any user to access the site (provided
+            their OpenID authentication is successful). The first time you login, you will get a <quote>Welcome [your name]"</quote>
+            message. If you logout and log back in (with the same OpenID identity) then this should change to <quote>Welcome Back</quote>.
+            This is achieved by using a custom <interfacename>UserDetailsService</interfacename> which assigns a standard role
+            to any user and stores the identities internally in a map. Obviously a real application would use a database instead.
+            Have a look at the source form more information. This class also takes into account the fact that different attributes may be returned
+            from different providers and builds the name with which it addresses the user accordingly.
+        </para>
+    </section>
     <section xml:id="cas-sample">
     <section xml:id="cas-sample">
         <title>CAS Sample</title>
         <title>CAS Sample</title>
         <para> The CAS sample requires that you run both a CAS server and CAS client. It isn't
         <para> The CAS sample requires that you run both a CAS server and CAS client. It isn't

+ 4 - 0
samples/openid/src/main/java/org/springframework/security/samples/openid/CustomUserDetailsService.java

@@ -69,6 +69,10 @@ public class CustomUserDetailsService implements UserDetailsService, Authenticat
                 firstName = attribute.getValues().get(0);
                 firstName = attribute.getValues().get(0);
             }
             }
 
 
+            if (attribute.getName().equals("lastname")) {
+                lastName = attribute.getValues().get(0);
+            }
+
             if (attribute.getName().equals("fullname")) {
             if (attribute.getName().equals("fullname")) {
                 fullName = attribute.getValues().get(0);
                 fullName = attribute.getValues().get(0);
             }
             }

+ 8 - 1
samples/openid/src/main/webapp/WEB-INF/applicationContext-security.xml

@@ -11,8 +11,11 @@
                         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
                         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
 
 
     <http>
     <http>
-        <intercept-url pattern="/**" access="ROLE_USER"/>
         <intercept-url pattern="/openidlogin.jsp*" filters="none"/>
         <intercept-url pattern="/openidlogin.jsp*" filters="none"/>
+        <intercept-url pattern="/images/*" filters="none"/>
+        <intercept-url pattern="/css/*" filters="none"/>
+        <intercept-url pattern="/js/*" filters="none"/>
+        <intercept-url pattern="/**" access="ROLE_USER"/>
         <logout/>
         <logout/>
         <openid-login login-page="/openidlogin.jsp" user-service-ref="registeringUserService"
         <openid-login login-page="/openidlogin.jsp" user-service-ref="registeringUserService"
                 authentication-failure-url="/openidlogin.jsp?login_error=true">
                 authentication-failure-url="/openidlogin.jsp?login_error=true">
@@ -25,6 +28,10 @@
                 <openid-attribute name="email" type="http://axschema.org/contact/email" required="true"/>
                 <openid-attribute name="email" type="http://axschema.org/contact/email" required="true"/>
                 <openid-attribute name="fullname" type="http://axschema.org/namePerson" required="true" />
                 <openid-attribute name="fullname" type="http://axschema.org/namePerson" required="true" />
             </attribute-exchange>
             </attribute-exchange>
+            <attribute-exchange identifier-match=".*myopenid.com.*">
+                <openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true"/>
+                <openid-attribute name="fullname" type="http://schema.openid.net/namePerson" required="true" />
+            </attribute-exchange>
         </openid-login>
         </openid-login>
         <remember-me token-repository-ref="tokenRepo"/>
         <remember-me token-repository-ref="tokenRepo"/>
     </http>
     </http>

+ 45 - 0
samples/openid/src/main/webapp/css/openid.css

@@ -0,0 +1,45 @@
+#openid_form {
+	width: 580px;	
+}
+	#openid_form legend {
+		font-weight: bold;
+	}
+#openid_choice {
+	display: none;
+}
+#openid_input_area {
+	clear: both;
+	padding: 10px;
+}
+#openid_btns, #openid_btns br {
+	clear: both;
+}
+	#openid_highlight {
+		padding: 3px;
+		background-color: #FFFCC9;
+		float: left;
+	}
+	.openid_large_btn {
+		width: 100px;
+		height: 60px;
+		border: 1px solid #DDD;
+		margin: 3px;
+		float: left;
+	}
+	.openid_small_btn {
+		width: 24px;
+		height: 24px;
+		border: 1px solid #DDD;
+		margin: 3px;
+		float: left;
+	}	
+	a.openid_large_btn:focus {
+		outline: none;
+	}
+	a.openid_large_btn:focus
+	{
+	-moz-outline-style: none;
+	}
+	.openid_selected {
+		border: 4px solid #DDD;
+	}	

BIN
samples/openid/src/main/webapp/images/aol.gif


BIN
samples/openid/src/main/webapp/images/blogger.ico


BIN
samples/openid/src/main/webapp/images/claimid.ico


BIN
samples/openid/src/main/webapp/images/facebook.gif


BIN
samples/openid/src/main/webapp/images/flickr.ico


BIN
samples/openid/src/main/webapp/images/google.gif


BIN
samples/openid/src/main/webapp/images/livejournal.ico


BIN
samples/openid/src/main/webapp/images/myopenid.ico


BIN
samples/openid/src/main/webapp/images/openid-inputicon.gif


BIN
samples/openid/src/main/webapp/images/openid.gif


BIN
samples/openid/src/main/webapp/images/technorati.ico


BIN
samples/openid/src/main/webapp/images/verisign.gif


BIN
samples/openid/src/main/webapp/images/verisign.ico


BIN
samples/openid/src/main/webapp/images/vidoop.ico


BIN
samples/openid/src/main/webapp/images/wordpress.ico


BIN
samples/openid/src/main/webapp/images/yahoo.gif


File diff suppressed because it is too large
+ 11 - 0
samples/openid/src/main/webapp/js/jquery-1.2.6.min.js


+ 220 - 0
samples/openid/src/main/webapp/js/openid-client/jquery.query-2.1.3.js

@@ -0,0 +1,220 @@
+/**
+ * jQuery.query - Query String Modification and Creation for jQuery
+ * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
+ * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
+ * Date: 2009/02/08
+ *
+ * @author Blair Mitchelmore
+ * @version 2.1.3
+ *
+ **/
+new function(settings) { 
+  // Various Settings
+  var $separator = settings.separator || '&';
+  var $spaces = settings.spaces === false ? false : true;
+  var $suffix = settings.suffix === false ? '' : '[]';
+  var $prefix = settings.prefix === false ? false : true;
+  var $hash = $prefix ? settings.hash === true ? "#" : "?" : "";
+  var $numbers = settings.numbers === false ? false : true;
+  
+  jQuery.query = new function() {
+    var is = function(o, t) {
+      return o != undefined && o !== null && (!!t ? o.constructor == t : true);
+    };
+    var parse = function(path) {
+      var m, rx = /\[([^[]*)\]/g, match = /^(\S+?)(\[\S*\])?$/.exec(path), base = match[1], tokens = [];
+      while (m = rx.exec(match[2])) tokens.push(m[1]);
+      return [base, tokens];
+    };
+    var set = function(target, tokens, value) {
+      var o, token = tokens.shift();
+      if (typeof target != 'object') target = null;
+      if (token === "") {
+        if (!target) target = [];
+        if (is(target, Array)) {
+          target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value));
+        } else if (is(target, Object)) {
+          var i = 0;
+          while (target[i++] != null);
+          target[--i] = tokens.length == 0 ? value : set(target[i], tokens.slice(0), value);
+        } else {
+          target = [];
+          target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value));
+        }
+      } else if (token && token.match(/^\s*[0-9]+\s*$/)) {
+        var index = parseInt(token, 10);
+        if (!target) target = [];
+        target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value);
+      } else if (token) {
+        var index = token.replace(/^\s*|\s*$/g, "");
+        if (!target) target = {};
+        if (is(target, Array)) {
+          var temp = {};
+          for (var i = 0; i < target.length; ++i) {
+            temp[i] = target[i];
+          }
+          target = temp;
+        }
+        target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value);
+      } else {
+        return value;
+      }
+      return target;
+    };
+    
+    var queryObject = function(a) {
+      var self = this;
+      self.keys = {};
+      
+      if (a.queryObject) {
+        jQuery.each(a.get(), function(key, val) {
+          self.SET(key, val);
+        });
+      } else {
+        jQuery.each(arguments, function() {
+          var q = "" + this;
+					q = decodeURIComponent(q);
+          q = q.replace(/^[?#]/,''); // remove any leading ? || #
+          q = q.replace(/[;&]$/,''); // remove any trailing & || ;
+          if ($spaces) q = q.replace(/[+]/g,' '); // replace +'s with spaces
+          
+          jQuery.each(q.split(/[&;]/), function(){
+            var key = this.split('=')[0];
+            var val = this.split('=')[1];
+            
+            if (!key) return;
+            
+            if ($numbers) {
+              if (/^[+-]?[0-9]+\.[0-9]*$/.test(val)) // simple float regex
+                val = parseFloat(val);
+              else if (/^[+-]?[0-9]+$/.test(val)) // simple int regex
+                val = parseInt(val, 10);
+            }
+            
+            val = (!val && val !== 0) ? true : val;
+            
+            if (val !== false && val !== true && typeof val != 'number')
+              val = val;
+            
+            self.SET(key, val);
+          });
+        });
+      }
+      return self;
+    };
+    
+    queryObject.prototype = {
+      queryObject: true,
+      has: function(key, type) {
+        var value = this.get(key);
+        return is(value, type);
+      },
+      GET: function(key) {
+        if (!is(key)) return this.keys;
+        var parsed = parse(key), base = parsed[0], tokens = parsed[1];
+        var target = this.keys[base];
+        while (target != null && tokens.length != 0) {
+          target = target[tokens.shift()];
+        }
+        return typeof target == 'number' ? target : target || "";
+      },
+      get: function(key) {
+        var target = this.GET(key);
+        if (is(target, Object))
+          return jQuery.extend(true, {}, target);
+        else if (is(target, Array))
+          return target.slice(0);
+        return target;
+      },
+      SET: function(key, val) {
+        var value = !is(val) ? null : val;
+        var parsed = parse(key), base = parsed[0], tokens = parsed[1];
+        var target = this.keys[base];
+        this.keys[base] = set(target, tokens.slice(0), value);
+        return this;
+      },
+      set: function(key, val) {
+        return this.copy().SET(key, val);
+      },
+      REMOVE: function(key) {
+        return this.SET(key, null).COMPACT();
+      },
+      remove: function(key) {
+        return this.copy().REMOVE(key);
+      },
+      EMPTY: function() {
+        var self = this;
+        jQuery.each(self.keys, function(key, value) {
+          delete self.keys[key];
+        });
+        return self;
+      },
+      load: function(url) {
+        var hash = url.replace(/^.*?[#](.+?)(?:\?.+)?$/, "$1");
+        var search = url.replace(/^.*?[?](.+?)(?:#.+)?$/, "$1");
+        return new queryObject(url.length == search.length ? '' : search, url.length == hash.length ? '' : hash);
+      },
+      empty: function() {
+        return this.copy().EMPTY();
+      },
+      copy: function() {
+        return new queryObject(this);
+      },
+      COMPACT: function() {
+        function build(orig) {
+          var obj = typeof orig == "object" ? is(orig, Array) ? [] : {} : orig;
+          if (typeof orig == 'object') {
+            function add(o, key, value) {
+              if (is(o, Array))
+                o.push(value);
+              else
+                o[key] = value;
+            }
+            jQuery.each(orig, function(key, value) {
+              if (!is(value)) return true;
+              add(obj, key, build(value));
+            });
+          }
+          return obj;
+        }
+        this.keys = build(this.keys);
+        return this;
+      },
+      compact: function() {
+        return this.copy().COMPACT();
+      },
+      toString: function() {
+        var i = 0, queryString = [], chunks = [], self = this;
+        var addFields = function(arr, key, value) {
+          if (!is(value) || value === false) return;
+          var o = [encodeURIComponent(key)];
+          if (value !== true) {
+            o.push("=");
+            o.push(encodeURIComponent(value));
+          }
+          arr.push(o.join(""));
+        };
+        var build = function(obj, base) {
+          var newKey = function(key) {
+            return !base || base == "" ? [key].join("") : [base, "[", key, "]"].join("");
+          };
+          jQuery.each(obj, function(key, value) {
+            if (typeof value == 'object') 
+              build(value, newKey(key));
+            else
+              addFields(chunks, newKey(key), value);
+          });
+        };
+        
+        build(this.keys);
+        
+        if (chunks.length > 0) queryString.push($hash);
+        queryString.push(chunks.join($separator));
+        
+        return queryString.join("");
+      }
+    };
+    
+    return new queryObject(location.search, location.hash);
+  };
+}(jQuery.query || {}); // Pass in jQuery.query as settings object

+ 20 - 0
samples/openid/src/main/webapp/js/openid-client/openid-client-config.js

@@ -0,0 +1,20 @@
+/*
+Defines the base of where the OpenID Provider redirects its response to.
+ */
+var server_root = "http://openid-selector.googlecode.com/svn/trunk/"
+
+/*
+On the server-side you'd accept an OpenID URL and perform discovery
+on it to find out the actual OpenID endpoint to send the authentication
+request to. On the client side it isn't possible to lookup the endpoint
+from the target server due to XSS restrictions. The endpoint for each
+provider is therefore cached in this static file. If an endpoint isn't 
+specified for a provider then authentication on the client side cannot
+proceed.
+*/
+var providers_endpoint = {
+	google: 'https://www.google.com/accounts/o8/ud',
+	yahoo: 'https://open.login.yahooapis.com/openid/op/auth',
+	aol: 'https://api.screenname.aol.com/auth/openidServer',
+	verisign: 'http://pip.verisignlabs.com/server'
+}

+ 63 - 0
samples/openid/src/main/webapp/js/openid-client/openid-client.js

@@ -0,0 +1,63 @@
+var claimedID;
+var providerID;
+var openIDPopup;
+
+function OpenID_iframe_then_popup_handler(provider, claimed) {
+    providerID = provider;
+    claimedID = claimed;
+    var immediateiframe = document.getElementById("openid_immediate_iframe");
+
+    var iframeurl = getBaseOpenIDProviderURL(providerID, claimedID, true);
+    
+    immediateiframe.innerHTML = "<iframe frameborder='1' src='" + iframeurl + "'></iframe>";
+}
+
+function processOpenIDImmediateResponse(responseURL) {
+	var immediateiframe = document.getElementById("openid_immediate_iframe");
+	immediateiframe.innerHTML = responseURL;
+
+	var failure = new RegExp("openid.mode=setup_needed");
+	if(failure.test(responseURL)) {
+		var popupurl = getBaseOpenIDProviderURL(providerID, claimedID, false);
+        openIDPopup = window.open(popupurl, "OpenIDPopup");
+	} else {
+	    alert("Success without popup!");
+	}
+}
+
+function processOpenIDSetupResponse(responseURL) {
+	openIDPopup.close();
+
+	var results = "";
+	var responseQuery = $.query.load(responseURL);
+    $.each(responseQuery.get(), function(key, value) {
+         results += "<br/>" + key + "=" + value;
+    });
+
+    document.getElementById("openid_status").innerHTML = "<br/>Result of authentication is: " + results;
+}
+
+function getBaseOpenIDProviderURL(provider, claimed, immediate) {
+	var providerEndpoint = providers_endpoint[provider];
+    var providerURL = providerEndpoint; //From previous discovery
+    providerURL += "?";
+    providerURL += "openid.ns=" + encodeURIComponent("http://specs.openid.net/auth/2.0");
+    if(providers[provider].label) {
+        providerURL += "&openid.claimed_id=" + encodeURIComponent(claimed);
+        providerURL += "&openid.identity=" + encodeURIComponent(claimed);    	
+    }
+    else {
+        providerURL += "&openid.claimed_id=" + encodeURIComponent("http://specs.openid.net/auth/2.0/identifier_select");
+        providerURL += "&openid.identity=" + encodeURIComponent("http://specs.openid.net/auth/2.0/identifier_select");
+    }
+    if(immediate) {
+        providerURL += "&openid.return_to=" + encodeURIComponent(server_root + "openid-client/checkid_immediate_response.html");
+        providerURL += "&openid.realm=" + encodeURIComponent(server_root + "openid-client/checkid_immediate_response.html");
+        providerURL += "&openid.mode=checkid_immediate";
+    } else {
+        providerURL += "&openid.return_to=" + encodeURIComponent(server_root + "openid-client/checkid_setup_response.html");
+        providerURL += "&openid.realm=" + encodeURIComponent(server_root + "openid-client/checkid_setup_response.html");
+        providerURL += "&openid.mode=checkid_setup";
+    }
+    return providerURL;
+}

+ 240 - 0
samples/openid/src/main/webapp/js/openid-jquery.js

@@ -0,0 +1,240 @@
+/*
+Simple OpenID Plugin
+http://code.google.com/p/openid-selector/
+
+This code is licenced under the New BSD License.
+*/
+
+var providers_large = {
+    google: {
+        name: 'Google',
+        url: 'https://www.google.com/accounts/o8/id'
+    },
+    yahoo: {
+        name: 'Yahoo',      
+        url: 'http://yahoo.com/'
+    },    
+    aol: {
+        name: 'AOL',     
+        label: 'Enter your AOL screenname.',
+        url: 'http://openid.aol.com/{username}'
+    },
+    verisign: {
+        name: 'Verisign',
+        label: 'Your Verisign username',
+        url: 'http://{username}.pip.verisignlabs.com/'
+    },
+    openid: {
+        name: 'OpenID',     
+        label: 'Enter your OpenID.',
+        url: null
+    }
+};
+var providers_small = {
+    myopenid: {
+        name: 'MyOpenID',
+        label: 'Enter your MyOpenID username.',
+        url: 'http://{username}.myopenid.com/'
+    },
+    livejournal: {
+        name: 'LiveJournal',
+        label: 'Enter your Livejournal username.',
+        url: 'http://{username}.livejournal.com/'
+    },
+    flickr: {
+        name: 'Flickr',        
+        label: 'Enter your Flickr username.',
+        url: 'http://flickr.com/{username}/'
+    },
+    technorati: {
+        name: 'Technorati',
+        label: 'Enter your Technorati username.',
+        url: 'http://technorati.com/people/technorati/{username}/'
+    },
+    wordpress: {
+        name: 'Wordpress',
+        label: 'Enter your Wordpress.com username.',
+        url: 'http://{username}.wordpress.com/'
+    },
+    blogger: {
+        name: 'Blogger',
+        label: 'Your Blogger account',
+        url: 'http://{username}.blogspot.com/'
+    },
+    vidoop: {
+        name: 'Vidoop',
+        label: 'Your Vidoop username',
+        url: 'http://{username}.myvidoop.com/'
+    },
+    claimid: {
+        name: 'ClaimID',
+        label: 'Your ClaimID username',
+        url: 'http://claimid.com/{username}'
+    }
+};
+var providers = $.extend({}, providers_large, providers_small);
+
+var openid = {
+
+	demo: false,
+	ajaxHandler: null,
+	cookie_expires: 6*30,	// 6 months.
+	cookie_name: 'openid_provider',
+	cookie_path: '/',
+	
+	img_path: 'images/',
+	
+	input_id: null,
+	provider_url: null,
+	provider_id: null,
+	
+    init: function(input_id) {
+        
+        var openid_btns = $('#openid_btns');
+        
+        this.input_id = input_id;
+        
+        $('#openid_choice').show();
+        $('#openid_input_area').empty();
+        
+        // add box for each provider
+        for (id in providers_large) {
+        
+           	openid_btns.append(this.getBoxHTML(providers_large[id], 'large', '.gif'));
+        }
+        if (providers_small) {
+        	openid_btns.append('<br/>');
+        	
+	        for (id in providers_small) {
+	        
+	           	openid_btns.append(this.getBoxHTML(providers_small[id], 'small', '.ico'));
+	        }
+        }
+        
+        $('#openid_form').submit(this.submit);
+        
+        var box_id = this.readCookie();
+        if (box_id) {
+        	this.signin(box_id, true);
+        }  
+    },
+    getBoxHTML: function(provider, box_size, image_ext) {
+            
+        var box_id = provider["name"].toLowerCase();
+        return '<a title="'+provider["name"]+'" href="javascript: openid.signin(\''+ box_id +'\');"' +
+        		' style="background: #FFF url(' + this.img_path + box_id + image_ext+') no-repeat center center" ' + 
+        		'class="' + box_id + ' openid_' + box_size + '_btn"></a>';    
+    
+    },
+    /* Provider image click */
+    signin: function(box_id, onload) {
+    
+    	var provider = providers[box_id];
+  		if (! provider) {
+  			return;
+  		}
+		
+		this.highlight(box_id);
+		this.setCookie(box_id);
+		
+		this.provider_id = box_id;
+		this.provider_url = provider['url'];
+		
+		// prompt user for input?
+		if (provider['label']) {
+			this.useInputBox(provider);
+		} else {
+			$('#openid_input_area').empty();
+			if (! onload) {
+				$('#openid_form').submit();
+			}
+		}
+    },
+    /* Sign-in button click */
+    submit: function() {
+        
+    	var url = openid.provider_url; 
+    	if (url) {
+    		url = url.replace('{username}', $('#openid_username').val());
+    		openid.setOpenIdUrl(url);
+    	}
+    	if(openid.ajaxHandler) {
+    		openid.ajaxHandler(openid.provider_id, document.getElementById(openid.input_id).value);
+    		return false;
+    	}
+    	if(openid.demo) {
+    		alert("In client demo mode. Normally would have submitted OpenID:\r\n" + document.getElementById(openid.input_id).value);
+    		return false;
+    	}
+    	return true;
+    },
+    setOpenIdUrl: function (url) {
+    
+    	var hidden = document.getElementById(this.input_id);
+    	if (hidden != null) {
+    		hidden.value = url;
+    	} else {
+    		$('#openid_form').append('<input type="hidden" id="' + this.input_id + '" name="' + this.input_id + '" value="'+url+'"/>');
+    	}
+    },
+    highlight: function (box_id) {
+    	
+    	// remove previous highlight.
+    	var highlight = $('#openid_highlight');
+    	if (highlight) {
+    		highlight.replaceWith($('#openid_highlight a')[0]);
+    	}
+    	// add new highlight.
+    	$('.'+box_id).wrap('<div id="openid_highlight"></div>');
+    },
+    setCookie: function (value) {
+    
+		var date = new Date();
+		date.setTime(date.getTime()+(this.cookie_expires*24*60*60*1000));
+		var expires = "; expires="+date.toGMTString();
+		
+		document.cookie = this.cookie_name+"="+value+expires+"; path=" + this.cookie_path;
+    },
+    readCookie: function () {
+		var nameEQ = this.cookie_name + "=";
+		var ca = document.cookie.split(';');
+		for(var i=0;i < ca.length;i++) {
+			var c = ca[i];
+			while (c.charAt(0)==' ') c = c.substring(1,c.length);
+			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
+		}
+		return null;
+    },
+    useInputBox: function (provider) {
+   	
+		var input_area = $('#openid_input_area');
+		
+		var html = '';
+		var id = 'openid_username';
+		var value = '';
+		var label = provider['label'];
+		var style = '';
+		
+		if (label) {
+			html = '<p>' + label + '</p>';
+		}
+		if (provider['name'] == 'OpenID') {
+			id = this.input_id;
+			value = 'http://';
+			style = 'background:#FFF url('+this.img_path+'openid-inputicon.gif) no-repeat scroll 0 50%; padding-left:18px;';
+		}
+		html += '<input id="'+id+'" type="text" style="'+style+'" name="'+id+'" value="'+value+'" />' + 
+					'<input id="openid_submit" type="submit" value="Sign-In"/>';
+		
+		input_area.empty();
+		input_area.append(html);
+
+		$('#'+id).focus();
+    },
+    setDemoMode: function (demoMode) {
+    	this.demo = demoMode;
+    },
+    setAjaxHandler: function (ajaxFunction) {
+    	this.ajaxHandler = ajaxFunction;
+    }
+};

+ 55 - 24
samples/openid/src/main/webapp/openidlogin.jsp

@@ -1,33 +1,64 @@
 <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt' %>
 <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt' %>
+<?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>
+    <title>OpenID Login</title>
 
 
-<html>
-  <head>
-    <title>Open ID Login</title>
-  </head>
+    <!-- Simple OpenID Selector -->
+    <link rel="stylesheet" href="<c:url value='/css/openid.css'/>" />
+    <script type="text/javascript" src="<c:url value='/js/jquery-1.2.6.min.js'/>"></script>
+    <script type="text/javascript" src="<c:url value='/js/openid-jquery.js'/>"></script>
 
 
-  <body onload="document.f.j_username.focus();">
-    <h3>Please Enter Your OpenID Identity</h3>
+    <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 -->
 
 
-    <%-- this form-login-page form is also used as the
-         form-error-page to ask for a login again.
-         --%>
-    <c:if test="${not empty param.login_error}">
-      <font color="red">
-        Your login attempt was not successful, try again.<br/><br/>
-        Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>.
-      </font>
-    </c:if>
+    <style type="text/css">
+        /* Basic page formatting. */
+        body {
+            font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
+        }
+    </style>
+</head>
 
 
+<body>
 
 
-    <form name="f" action="<c:url value='j_spring_openid_security_check'/>" method="POST">
-      <table>
-        <tr><td>OpenID Identity:</td><td><input type='text' name='openid_identifier' value='<c:if test="${not empty param.login_error}"><c:out value="${SPRING_SECURITY_LAST_USERNAME}"/></c:if>'/></td></tr>
-        <tr><td><input type="checkbox" name="_spring_security_remember_me"></td><td>Remember me on this computer.</td></tr>
-        <tr><td colspan='2'><input name="submit" type="submit"></td></tr>
-        <tr><td colspan='2'><input name="reset" type="reset"></td></tr>
-      </table>
+<c:if test="${not empty param.login_error}">
+  <font color="red">
+    Your login attempt was not successful, try again.<br/><br/>
+    Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>.
+  </font>
+</c:if>
 
 
-    </form>
+<!-- Simple OpenID Selector -->
+<form action="<c:url value='j_spring_openid_security_check'/>" method="post" id="openid_form">
+    <input type="hidden" name="action" value="verify" />
 
 
-  </body>
+    <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 a 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>
 </html>

Some files were not shown because too many files changed in this diff