Преглед изворни кода

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

Luke Taylor пре 15 година
родитељ
комит
def5f88c8c
26 измењених фајлова са 686 додато и 25 уклоњено
  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
             authentication providers configured in this application. </para>
     </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">
         <title>CAS Sample</title>
         <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);
             }
 
+            if (attribute.getName().equals("lastname")) {
+                lastName = attribute.getValues().get(0);
+            }
+
             if (attribute.getName().equals("fullname")) {
                 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>
-        <intercept-url pattern="/**" access="ROLE_USER"/>
         <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/>
         <openid-login login-page="/openidlogin.jsp" user-service-ref="registeringUserService"
                 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="fullname" type="http://axschema.org/namePerson" required="true" />
             </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>
         <remember-me token-repository-ref="tokenRepo"/>
     </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


Разлика између датотеке није приказан због своје велике величине
+ 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' %>
+<?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>

Неке датотеке нису приказане због велике количине промена