summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenId/RelyingParty/OpenIdAjaxTextBox.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenId/RelyingParty/OpenIdAjaxTextBox.js')
-rw-r--r--src/DotNetOpenId/RelyingParty/OpenIdAjaxTextBox.js455
1 files changed, 455 insertions, 0 deletions
diff --git a/src/DotNetOpenId/RelyingParty/OpenIdAjaxTextBox.js b/src/DotNetOpenId/RelyingParty/OpenIdAjaxTextBox.js
new file mode 100644
index 0000000..e2ef0a0
--- /dev/null
+++ b/src/DotNetOpenId/RelyingParty/OpenIdAjaxTextBox.js
@@ -0,0 +1,455 @@
+// Options that can be set on the host page:
+// window.openid_visible_iframe = true; // causes the hidden iframe to show up
+// window.openid_trace = true; // causes lots of alert boxes
+
+function trace(msg) {
+ if (window.openid_trace) {
+ alert(msg);
+ }
+}
+
+function initAjaxOpenId(box, openid_logo_url, dotnetopenid_logo_url, spinner_url, success_icon_url, failure_icon_url,
+ timeout, assertionReceivedCode,
+ loginButtonText, loginButtonToolTip, retryButtonText, retryButtonToolTip, busyToolTip,
+ identifierRequiredMessage, loginInProgressMessage,
+ authenticationSucceededToolTip, authenticationFailedToolTip) {
+ box.dnoi_internal = new Object();
+ if (assertionReceivedCode) {
+ box.dnoi_internal.onauthenticated = function(sender, e) { eval(assertionReceivedCode); }
+ }
+
+ box.dnoi_internal.originalBackground = box.style.background;
+ box.timeout = timeout;
+
+ box.dnoi_internal.constructButton = function(text, tooltip, onclick) {
+ var button = document.createElement('button');
+ button.textContent = text; // Mozilla
+ button.value = text; // IE
+ button.title = tooltip;
+ button.onclick = onclick;
+ button.style.visibility = 'hidden';
+ button.style.position = 'absolute';
+ button.style.padding = "0px";
+ button.style.fontSize = '8px';
+ button.style.top = "1px";
+ button.style.bottom = "1px";
+ button.style.right = "2px";
+ box.parentNode.appendChild(button);
+ return button;
+ }
+
+ box.dnoi_internal.constructIcon = function(imageUrl, tooltip, rightSide, visible, height) {
+ var icon = document.createElement('img');
+ icon.src = imageUrl;
+ icon.title = tooltip != null ? tooltip : '';
+ if (!visible) {
+ icon.style.visibility = 'hidden';
+ }
+ icon.style.position = 'absolute';
+ icon.style.top = "2px";
+ icon.style.bottom = "2px"; // for FireFox (and IE7, I think)
+ if (height) {
+ icon.style.height = height; // for Chrome and IE8
+ }
+ if (rightSide) {
+ icon.style.right = "2px";
+ } else {
+ icon.style.left = "2px";
+ }
+ box.parentNode.appendChild(icon);
+ return icon;
+ }
+
+ box.dnoi_internal.prefetchImage = function(imageUrl) {
+ var img = document.createElement('img');
+ img.src = imageUrl;
+ img.style.display = 'none';
+ box.parentNode.appendChild(img);
+ return img;
+ }
+
+ box.dnoi_internal.loginButton = box.dnoi_internal.constructButton(loginButtonText, loginButtonToolTip, function() {
+ box.dnoi_internal.popup = window.open(box.dnoi_internal.getAuthenticationUrl(), 'opLogin', 'status=0,toolbar=0,location=1,resizable=1,scrollbars=1,width=800,height=600');
+ self.waiting_openidBox = box;
+ return false;
+ });
+ box.dnoi_internal.retryButton = box.dnoi_internal.constructButton(retryButtonText, retryButtonToolTip, function() {
+ box.timeout += 5000; // give the retry attempt 5s longer than the last attempt
+ box.dnoi_internal.performDiscovery();
+ return false;
+ });
+ box.dnoi_internal.openid_logo = box.dnoi_internal.constructIcon(openid_logo_url, null, false, true);
+ box.dnoi_internal.op_logo = box.dnoi_internal.constructIcon('', null, false, false, "16px");
+ box.dnoi_internal.spinner = box.dnoi_internal.constructIcon(spinner_url, busyToolTip, true);
+ box.dnoi_internal.success_icon = box.dnoi_internal.constructIcon(success_icon_url, authenticationSucceededToolTip, true);
+ //box.dnoi_internal.failure_icon = box.dnoi_internal.constructIcon(failure_icon_url, authenticationFailedToolTip, true);
+
+ // Disable the display of the DotNetOpenId logo
+ //box.dnoi_internal.dnoi_logo = box.dnoi_internal.constructIcon(dotnetopenid_logo_url);
+ box.dnoi_internal.dnoi_logo = box.dnoi_internal.openid_logo;
+
+ box.dnoi_internal.setVisualCue = function(state) {
+ box.dnoi_internal.openid_logo.style.visibility = 'hidden';
+ box.dnoi_internal.dnoi_logo.style.visibility = 'hidden';
+ box.dnoi_internal.op_logo.style.visibility = 'hidden';
+ box.dnoi_internal.spinner.style.visibility = 'hidden';
+ box.dnoi_internal.success_icon.style.visibility = 'hidden';
+// box.dnoi_internal.failure_icon.style.visibility = 'hidden';
+ box.dnoi_internal.loginButton.style.visibility = 'hidden';
+ box.dnoi_internal.retryButton.style.visibility = 'hidden';
+ box.title = null;
+ if (state == "discovering") {
+ box.dnoi_internal.dnoi_logo.style.visibility = 'visible';
+ box.dnoi_internal.spinner.style.visibility = 'visible';
+ box.dnoi_internal.claimedIdentifier = null;
+ box.title = null;
+ window.status = "Discovering OpenID Identifier '" + box.value + "'...";
+ } else if (state == "authenticated") {
+ var opLogo = box.dnoi_internal.deriveOPFavIcon();
+ if (opLogo) {
+ box.dnoi_internal.op_logo.src = opLogo;
+ box.dnoi_internal.op_logo.style.visibility = 'visible';
+ } else {
+ box.dnoi_internal.openid_logo.style.visibility = 'visible';
+ }
+ box.dnoi_internal.success_icon.style.visibility = 'visible';
+ box.title = box.dnoi_internal.claimedIdentifier;
+ window.status = "Authenticated as " + box.value;
+ } else if (state == "setup") {
+ var opLogo = box.dnoi_internal.deriveOPFavIcon();
+ if (opLogo) {
+ box.dnoi_internal.op_logo.src = opLogo;
+ box.dnoi_internal.op_logo.style.visibility = 'visible';
+ } else {
+ box.dnoi_internal.openid_logo.style.visibility = 'visible';
+ }
+ box.dnoi_internal.loginButton.style.visibility = 'visible';
+ box.dnoi_internal.claimedIdentifier = null;
+ window.status = "Authentication requires setup.";
+ } else if (state == "failed") {
+ box.dnoi_internal.openid_logo.style.visibility = 'visible';
+ //box.dnoi_internal.failure_icon.style.visibility = 'visible';
+ box.dnoi_internal.retryButton.style.visibility = 'visible';
+ box.dnoi_internal.claimedIdentifier = null;
+ window.status = authenticationFailedToolTip;
+ box.title = authenticationFailedToolTip;
+ } else if (state = '' || state == null) {
+ box.dnoi_internal.openid_logo.style.visibility = 'visible';
+ box.title = null;
+ box.dnoi_internal.claimedIdentifier = null;
+ window.status = null;
+ } else {
+ box.dnoi_internal.claimedIdentifier = null;
+ trace('unrecognized state ' + state);
+ }
+ }
+
+ box.dnoi_internal.isBusy = function() {
+ return box.discoveryIFrame != null;
+ };
+
+ box.dnoi_internal.onSubmit = function() {
+ if (box.lastAuthenticationResult != 'authenticated') {
+ if (box.dnoi_internal.isBusy()) {
+ alert(loginInProgressMessage);
+ } else {
+ if (box.value.length > 0) {
+ // submitPending will be true if we've already tried deferring submit for a login,
+ // in which case we just want to display a box to the user.
+ if (box.dnoi_internal.submitPending) {
+ alert(identifierRequiredMessage);
+ } else {
+ // The user hasn't clicked "Login" yet. We'll click login for him,
+ // after leaving a note for ourselves to automatically click submit
+ // when login is complete.
+ box.dnoi_internal.submitPending = box.dnoi_internal.submitButtonJustClicked;
+ if (box.dnoi_internal.submitPending == null) {
+ box.dnoi_internal.submitPending = true;
+ }
+ box.dnoi_internal.loginButton.onclick();
+ return false; // abort submit for now
+ }
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+ };
+
+ box.dnoi_internal.setLastSubmitButtonClicked = function(evt) {
+ var button;
+ if (evt.target) {
+ button = evt.target;
+ } else {
+ button = evt.srcElement;
+ }
+
+ box.dnoi_internal.submitButtonJustClicked = button;
+ };
+
+ // box.hookAllSubmitElements = function(searchNode) {
+ var inputs = document.getElementsByTagName('input');
+ for (var i = 0; i < inputs.length; i++) {
+ var el = inputs[i];
+ if (el.type == 'submit') {
+ if (el.attachEvent) {
+ el.attachEvent("onclick", box.dnoi_internal.setLastSubmitButtonClicked);
+ } else {
+ el.addEventListener("click", box.dnoi_internal.setLastSubmitButtonClicked, true);
+ }
+ }
+ }
+ //};
+
+ box.dnoi_internal.getAuthenticationUrl = function(immediateMode) {
+ var frameLocation = new Uri(document.location.href);
+ var discoveryUri = frameLocation.trimFragment();
+ discoveryUri.appendQueryVariable('dotnetopenid.userSuppliedIdentifier', box.value);
+ if (immediateMode) {
+ discoveryUri.appendQueryVariable('dotnetopenid.immediate', 'true');
+ }
+ return discoveryUri;
+ };
+
+ box.dnoi_internal.performDiscovery = function() {
+ box.dnoi_internal.closeDiscoveryIFrame();
+ box.dnoi_internal.setVisualCue('discovering');
+ box.lastDiscoveredIdentifier = box.value;
+ box.lastAuthenticationResult = null;
+ var discoveryUri = box.dnoi_internal.getAuthenticationUrl(true);
+ if (box.discoveryIFrame) {
+ box.discoveryIFrame.parentNode.removeChild(box.discoveryIFrame);
+ box.discoveryIFrame = null;
+ }
+ trace('Performing discovery using url: ' + discoveryUri);
+ box.discoveryIFrame = createHiddenFrame(discoveryUri);
+ };
+
+ function findParentForm(element) {
+ if (element == null || element.nodeName == "FORM") {
+ return element;
+ }
+
+ return findParentForm(element.parentNode);
+ };
+
+ function findOrCreateHiddenField(form, name) {
+ if (box.hiddenField) {
+ return box.hiddenField;
+ }
+
+ box.hiddenField = document.createElement('input');
+ box.hiddenField.setAttribute("name", name);
+ box.hiddenField.setAttribute("type", "hidden");
+ form.appendChild(box.hiddenField);
+ return box.hiddenField;
+ };
+
+ box.dnoi_internal.deriveOPFavIcon = function() {
+ if (!box.hiddenField) return;
+ var authResult = new Uri(box.hiddenField.value);
+ var opUri;
+ if (authResult.getQueryArgValue("openid.op_endpoint")) {
+ opUri = new Uri(authResult.getQueryArgValue("openid.op_endpoint"));
+ } else if (authResult.getQueryArgValue("openid.user_setup_url")) {
+ opUri = new Uri(authResult.getQueryArgValue("openid.user_setup_url"));
+ } else return null;
+ var favicon = opUri.getAuthority() + "/favicon.ico";
+ return favicon;
+ };
+
+ function createHiddenFrame(url) {
+ var iframe = document.createElement("iframe");
+ if (!window.openid_visible_iframe) {
+ iframe.setAttribute("width", 0);
+ iframe.setAttribute("height", 0);
+ iframe.setAttribute("style", "display: none");
+ }
+ iframe.setAttribute("src", url);
+ iframe.openidBox = box;
+ box.parentNode.insertBefore(iframe, box);
+ box.discoveryTimeout = setTimeout(function() { trace("timeout"); box.dnoi_internal.openidDiscoveryFailure("Timed out"); }, box.timeout);
+ return iframe;
+ };
+
+ box.parentForm = findParentForm(box);
+
+ box.dnoi_internal.openidDiscoveryFailure = function(msg) {
+ box.dnoi_internal.closeDiscoveryIFrame();
+ trace('Discovery failure: ' + msg);
+ box.lastAuthenticationResult = 'failed';
+ box.dnoi_internal.setVisualCue('failed');
+ box.title = msg;
+ };
+
+ box.dnoi_internal.closeDiscoveryIFrame = function() {
+ if (box.discoveryTimeout) {
+ clearTimeout(box.discoveryTimeout);
+ }
+ if (box.discoveryIFrame) {
+ box.discoveryIFrame.parentNode.removeChild(box.discoveryIFrame);
+ box.discoveryIFrame = null;
+ }
+ };
+
+ box.dnoi_internal.openidAuthResult = function(resultUrl) {
+ self.waiting_openidBox = null;
+ trace('openidAuthResult ' + resultUrl);
+ if (box.discoveryIFrame) {
+ box.dnoi_internal.closeDiscoveryIFrame();
+ } else if (box.dnoi_internal.popup) {
+ box.dnoi_internal.popup.close();
+ box.dnoi_internal.popup = null;
+ }
+ var resultUri = new Uri(resultUrl);
+
+ // stick the result in a hidden field so the RP can verify it (positive or negative)
+ var form = findParentForm(box);
+ var hiddenField = findOrCreateHiddenField(form, "openidAuthData");
+ hiddenField.setAttribute("value", resultUri.toString());
+ trace("set openidAuthData = " + resultUri.queryString);
+ if (hiddenField.parentNode == null) {
+ form.appendChild(hiddenField);
+ }
+ trace("review: " + box.hiddenField.value);
+
+ if (isAuthSuccessful(resultUri)) {
+ // visual cue that auth was successful
+ box.dnoi_internal.claimedIdentifier = isOpenID2Response(resultUri) ? resultUri.getQueryArgValue("openid.claimed_id") : resultUri.getQueryArgValue("openid.identity");
+ box.dnoi_internal.setVisualCue('authenticated');
+ box.lastAuthenticationResult = 'authenticated';
+ if (box.dnoi_internal.onauthenticated) {
+ box.dnoi_internal.onauthenticated(box);
+ }
+ if (box.dnoi_internal.submitPending) {
+ // We submit the form BEFORE resetting the submitPending so
+ // the submit handler knows we've already tried this route.
+ if (box.dnoi_internal.submitPending == true) {
+ box.parentForm.submit();
+ } else {
+ box.dnoi_internal.submitPending.click();
+ }
+ }
+ } else {
+ // visual cue that auth failed
+ box.dnoi_internal.setVisualCue('setup');
+ box.lastAuthenticationResult = 'setup';
+ }
+
+ box.dnoi_internal.submitPending = null;
+ };
+
+ function isAuthSuccessful(resultUri) {
+ if (isOpenID2Response(resultUri)) {
+ return resultUri.getQueryArgValue("openid.mode") == "id_res";
+ } else {
+ return resultUri.getQueryArgValue("openid.mode") == "id_res" && !resultUri.containsQueryArg("openid.user_setup_url");
+ }
+ };
+
+ function isOpenID2Response(resultUri) {
+ return resultUri.containsQueryArg("openid.ns");
+ };
+
+ box.onblur = function(event) {
+ if (box.lastDiscoveredIdentifier != box.value) {
+ if (box.value.length > 0) {
+ box.dnoi_internal.performDiscovery();
+ } else {
+ box.dnoi_internal.setVisualCue();
+ }
+ box.oldvalue = box.value;
+ }
+ return true;
+ };
+ box.onkeyup = function(event) {
+ if (box.lastDiscoveredIdentifier != box.value) {
+ box.dnoi_internal.setVisualCue();
+ } else {
+ box.dnoi_internal.setVisualCue(box.lastAuthenticationResult);
+ }
+ return true;
+ };
+ box.getClaimedIdentifier = function() { return box.dnoi_internal.claimedIdentifier; };
+}
+
+function Uri(url) {
+ this.originalUri = url;
+
+ this.toString = function() {
+ return this.originalUri;
+ };
+
+ this.getAuthority = function() {
+ var authority = this.getScheme() + "://" + this.getHost();
+ return authority;
+ }
+
+ this.getHost = function() {
+ var hostStartIdx = this.originalUri.indexOf("://") + 3;
+ var hostEndIndex = this.originalUri.indexOf("/", hostStartIdx);
+ if (hostEndIndex < 0) hostEndIndex = this.originalUri.length;
+ var host = this.originalUri.substr(hostStartIdx, hostEndIndex - hostStartIdx);
+ return host;
+ }
+
+ this.getScheme = function() {
+ var schemeStartIdx = this.indexOf("://");
+ return this.originalUri.substr(this.originalUri, schemeStartIdx);
+ }
+
+ this.trimFragment = function() {
+ var hashmark = this.originalUri.indexOf('#');
+ if (hashmark >= 0) {
+ return new Uri(this.originalUri.substr(0, hashmark));
+ }
+ return this;
+ };
+
+ this.appendQueryVariable = function(name, value) {
+ var pair = encodeURI(name) + "=" + encodeURI(value);
+ if (this.originalUri.indexOf('?') >= 0) {
+ this.originalUri = this.originalUri + "&" + pair;
+ } else {
+ this.originalUri = this.originalUri + "?" + pair;
+ }
+ };
+
+ function KeyValuePair(key, value) {
+ this.key = key;
+ this.value = value;
+ };
+
+ this.Pairs = Array();
+
+ var queryBeginsAt = this.originalUri.indexOf('?');
+ if (queryBeginsAt >= 0) {
+ this.queryString = url.substr(queryBeginsAt + 1);
+ var queryStringPairs = this.queryString.split('&');
+
+ for (var i = 0; i < queryStringPairs.length; i++) {
+ var pair = queryStringPairs[i].split('=');
+ this.Pairs.push(new KeyValuePair(unescape(pair[0]), unescape(pair[1])))
+ }
+ };
+
+ this.getQueryArgValue = function(key) {
+ for (var i = 0; i < this.Pairs.length; i++) {
+ if (this.Pairs[i].key == key) {
+ return this.Pairs[i].value;
+ }
+ }
+ };
+
+ this.containsQueryArg = function(key) {
+ return this.getQueryArgValue(key);
+ };
+
+ this.indexOf = function(args) {
+ return this.originalUri.indexOf(args);
+ };
+
+ return this;
+};