My favorites | Sign in
Project Logo
                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


// PopupManager is a library to facilitate integration with OpenID
// identity providers (OP)s that support a pop-up authentication interface.
// To create a popup window, you first construct a popupOpener customized
// for your site and a particular identity provider, E.g.:
//
// var googleOpener = popupManager.createOpener(openidParams);
//
// where 'openidParams' are customized for Google in this instance.
// (typically you just change the openidpoint, the version number
// (the openid.ns parameter) and the extensions based on what
// the OP supports.
// OpenID libraries can often discover these properties
// automatically from the location of an XRD document.
//
// Then, you can either directly call
// googleOpener.popup(width, height), where 'width' and 'height' are your choices
// for popup size, or you can display a button 'Sign in with Google' and set the
//..'onclick' handler of the button to googleOpener.popup()

var popupManager = {};

// Library constants

popupManager.constants = {
'darkCover' : 'popupManager_darkCover_div',
'darkCoverStyle' : ['position:absolute;',
'top:0px;',
'left:0px;',
'padding-right:0px;',
'padding-bottom:0px;',
'background-color:#000000;',
'opacity:0.5;', //standard-compliant browsers
'-moz-opacity:0.5;', // old Mozilla
'filter:alpha(opacity=0.5);', // IE
'z-index:10000;',
'width:100%;',
'height:100%;'
].join(''),
'openidSpec' : {
'identifier_select' : 'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select',
'namespace2' : 'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0'
} };

// Computes the size of the window contents. Returns a pair of
// coordinates [width, height] which can be [0, 0] if it was not possible
// to compute the values.
popupManager.getWindowInnerSize = function() {
var width = 0;
var height = 0;
var elem = null;
if ('innerWidth' in window) {
// For non-IE
width = window.innerWidth;
height = window.innerHeight;
} else {
// For IE,
if (('BackCompat' === window.document.compatMode)
&& ('body' in window.document)) {
elem = window.document.body;
} else if ('documentElement' in window.document) {
elem = window.document.documentElement;
}
if (elem !== null) {
width = elem.offsetWidth;
height = elem.offsetHeight;
}
}
return [width, height];
};

// Computes the coordinates of the parent window.
// Gets the coordinates of the parent frame
popupManager.getParentCoords = function() {
var width = 0;
var height = 0;
if ('screenLeft' in window) {
// IE-compatible variants
width = window.screenLeft;
height = window.screenTop;
} else if ('screenX' in window) {
// Firefox-compatible
width = window.screenX;
height = window.screenY;
}
return [width, height];
};

// Computes the coordinates of the new window, so as to center it
// over the parent frame
popupManager.getCenteredCoords = function(width, height) {
var parentSize = this.getWindowInnerSize();
var parentPos = this.getParentCoords();
var xPos = parentPos[0] +
Math.max(0, Math.floor((parentSize[0] - width) / 2));
var yPos = parentPos[1] +
Math.max(0, Math.floor((parentSize[1] - height) / 2));
return [xPos, yPos];
};

// A utility class, implements an onOpenHandler that darkens the screen
// by overlaying it with a semi-transparent black layer. To use, ensure that
// no screen element has a z-index at or above 10000.
// This layer will be suppressed automatically after the screen closes.
//
// Note: If you want to perform other operations before opening the popup, but
// also would like the screen to darken, you can define a custom handler
// as such:
// var myOnOpenHandler = function(inputs) {
// .. do something
// popupManager.darkenScreen();
// .. something else
// };
// Then you pass myOnOpenHandler as input to the opener, as in:
// var openidParams = {};
// openidParams.onOpenHandler = myOnOpenHandler;
// ... other customizations
// var myOpener = popupManager.createOpener(openidParams);
popupManager.darkenScreen = function() {
var darkCover = window.document.getElementById(window.popupManager.constants['darkCover']);
if (!darkCover) {
darkCover = window.document.createElement('div');
darkCover['id'] = window.popupManager.constants['darkCover'];
darkCover.setAttribute('style', window.popupManager.constants['darkCoverStyle']);
window.document.body.appendChild(darkCover);
}
darkCover.style.visibility = 'visible';
};

// Returns a an object that can open a popup window customized for an OP & RP.
// to use you call var opener = popupManager.cretePopupOpener(openidParams);
// and then you can assign the 'onclick' handler of a button to
// opener.popup(width, height), where width and height are the values of the popup size;
//
// To use it, you would typically have code such as:
// var myLoginCheckFunction = ... some AJAXy call or page refresh operation
// that will cause the user to see the logged-in experience in the current page.
// var openidParams = { realm : 'openid.realm', returnToUrl : 'openid.return_to',
// opEndpoint : 'openid.op_endpoint', onCloseHandler : myLoginCheckFunction,
// shouldEncodeUrls : 'true' (default) or 'false', extensions : myOpenIDExtensions };
//
// Here extensions include any OpenID extensions that you support. For instance,
// if you support Attribute Exchange v.1.0, you can say:
// (Example for attribute exchange request for email and name,
// assuming that shouldEncodeUrls = 'true':)
// var myOpenIDExtensions = {
// 'openid.ax.ns' : 'http://openid.net/srv/ax/1.0',
// 'openid.ax.type.email' : 'http://axschema.org/contact/email',
// 'openid.ax.type.name1' : 'http://axschema.org/namePerson/first',
// 'openid.ax.type.name2' : 'http://axschema.org/namePerson/last',
// 'openid.ax.required' : 'email,name1,name2' };
// Note that the 'ui' namespace is reserved by this library for the OpenID
// UI extension, and that the mode 'popup' is automatically applied.
// If you wish to make use of the 'language' feature of the OpenID UI extension
// simply add the following entry (example assumes the language requested
// is Swiss French:
// var my OpenIDExtensions = {
// ... // other extension parameters
// 'openid.ui.language' : 'fr_CH',
// ... };
popupManager.createPopupOpener = (function(openidParams) {
var interval_ = null;
var popupWindow_ = null;
var that = this;
var shouldEscape_ = ('shouldEncodeUrls' in openidParams) ? openidParams.shouldEncodeUrls : true;
var encodeIfRequested_ = function(url) {
return (shouldEscape_ ? encodeURIComponent(url) : url);
};
var identifier_ = ('identifier' in openidParams) ? encodeIfRequested_(openidParams.identifier) :
this.constants.openidSpec.identifier_select;
var identity_ = ('identity' in openidParams) ? encodeIfRequested_(openidParams.identity) :
this.constants.openidSpec.identifier_select;
var openidNs_ = ('namespace' in openidParams) ? encodeIfRequested_(openidParams.namespace) :
this.constants.openidSpec.namespace2;
var onOpenHandler_ = (('onOpenHandler' in openidParams) &&
('function' === typeof(openidParams.onOpenHandler))) ?
openidParams.onOpenHandler : this.darkenScreen;
var onCloseHandler_ = (('onCloseHandler' in openidParams) &&
('function' === typeof(openidParams.onCloseHandler))) ?
openidParams.onCloseHandler : null;
var returnToUrl_ = ('returnToUrl' in openidParams) ? openidParams.returnToUrl : null;
var realm_ = ('realm' in openidParams) ? openidParams.realm : null;
var endpoint_ = ('opEndpoint' in openidParams) ? openidParams.opEndpoint : null;
var extensions_ = ('extensions' in openidParams) ? openidParams.extensions : null;

// processes key value pairs, escaping any input;
var keyValueConcat_ = function(keyValuePairs) {
var result = "";
for (key in keyValuePairs) {
result += ['&', key, '=', encodeIfRequested_(keyValuePairs[key])].join('');
}
return result;
};

//Assembles the OpenID request from customizable parameters
var buildUrlToOpen_ = function() {
var connector = '&';
var encodedUrl = null;
var urlToOpen = null;
if ((null === endpoint_) || (null === returnToUrl_)) {
return;
}
if (endpoint_.indexOf('?') === -1) {
connector = '?';
}
encodedUrl = encodeIfRequested_(returnToUrl_);
urlToOpen = [ endpoint_, connector,
'openid.ns=', openidNs_,
'&openid.mode=checkid_setup',
'&openid.claimed_id=', identifier_,
'&openid.identity=', identity_,
'&openid.return_to=', encodedUrl ].join('');
if (realm_ !== null) {
urlToOpen += "&openid.realm=" + encodeIfRequested_(realm_);
}
if (extensions_ !== null) {
urlToOpen += keyValueConcat_(extensions_);
}
urlToOpen += '&openid.ns.ui=' + encodeURIComponent(
'http://specs.openid.net/extensions/ui/1.0');
urlToOpen += '&openid.ui.mode=popup';
return urlToOpen;
};

// Tests that the popup window has closed
var isPopupClosed_ = function() {
return (!popupWindow_ || popupWindow_.closed);
};

// Check to perform at each execution of the timed loop. It also triggers
// the action that follows the closing of the popup
var waitForPopupClose_ = function() {
if (isPopupClosed_()) {
popupWindow_ = null;
var darkCover = window.document.getElementById(window.popupManager.constants['darkCover']);
if (darkCover) {
darkCover.style.visibility = 'hidden';
}
if (onCloseHandler_ !== null) {
onCloseHandler_();
}
if ((null !== interval_)) {
window.clearInterval(interval_);
interval_ = null;
}
}
};

return {
// Function that opens the window.
popup: function(width, height) {
var urlToOpen = buildUrlToOpen_();
if (onOpenHandler_ !== null) {
onOpenHandler_();
}
var coordinates = that.getCenteredCoords(width, height);
popupWindow_ = window.open(urlToOpen, "",
"width=" + width + ",height=" + height +
",status=1,location=1,resizable=yes" +
",left=" + coordinates[0] +",top=" + coordinates[1]);
interval_ = window.setInterval(waitForPopupClose_, 80);
return true;
}
};
});
Show details Hide details

Change log

r373 by breno.demedeiros on Mar 06, 2009   Diff
-Added support for non-identifier select
(untested at this point)
-Added support for configuring version of
OpenID (untested at this point)
-Added support for the UI extension (hard-
coded in since this library makes little
sense for non-popup applications). Tested
locally, but no interoperability tests
performed.
Go to: 
Project members, sign in to write a code review

Older revisions

r364 by breno.demedeiros on Feb 12, 2009   Diff
Clarifying comments on the library
r350 by breno.demedeiros on Feb 09, 2009   Diff
adds the onOpenHandler that darkens
the screen
r339 by breno.demedeiros on Feb 06, 2009   Diff
Adds a javascript library and an
example consumer servlet for OpenID
login using a popup UI.
All revisions of this file

File info

Size: 11241 bytes, 279 lines
Hosted by Google Code