danielebarchiesi@0
|
1 <?php
|
danielebarchiesi@0
|
2
|
danielebarchiesi@0
|
3 /**
|
danielebarchiesi@0
|
4 * @file
|
danielebarchiesi@0
|
5 * OpenID utility functions.
|
danielebarchiesi@0
|
6 */
|
danielebarchiesi@0
|
7
|
danielebarchiesi@0
|
8 /**
|
danielebarchiesi@0
|
9 * Diffie-Hellman Key Exchange Default Value.
|
danielebarchiesi@0
|
10 *
|
danielebarchiesi@0
|
11 * This is used to establish an association between the Relying Party and the
|
danielebarchiesi@0
|
12 * OpenID Provider.
|
danielebarchiesi@0
|
13 *
|
danielebarchiesi@0
|
14 * See RFC 2631: http://www.ietf.org/rfc/rfc2631.txt
|
danielebarchiesi@0
|
15 */
|
danielebarchiesi@0
|
16 define('OPENID_DH_DEFAULT_MOD', '155172898181473697471232257763715539915724801' .
|
danielebarchiesi@0
|
17 '966915404479707795314057629378541917580651227423698188993727816152646631' .
|
danielebarchiesi@0
|
18 '438561595825688188889951272158842675419950341258706556549803580104870537' .
|
danielebarchiesi@0
|
19 '681476726513255747040765857479291291572334510643245094715007229621094194' .
|
danielebarchiesi@0
|
20 '349783925984760375594985848253359305585439638443');
|
danielebarchiesi@0
|
21
|
danielebarchiesi@0
|
22 /**
|
danielebarchiesi@0
|
23 * Diffie-Hellman generator; used for Diffie-Hellman key exchange computations.
|
danielebarchiesi@0
|
24 */
|
danielebarchiesi@0
|
25 define('OPENID_DH_DEFAULT_GEN', '2');
|
danielebarchiesi@0
|
26
|
danielebarchiesi@0
|
27 /**
|
danielebarchiesi@0
|
28 * SHA-1 hash block size; used for Diffie-Hellman key exchange computations.
|
danielebarchiesi@0
|
29 */
|
danielebarchiesi@0
|
30 define('OPENID_SHA1_BLOCKSIZE', 64);
|
danielebarchiesi@0
|
31
|
danielebarchiesi@0
|
32 /**
|
danielebarchiesi@0
|
33 * Random number generator; used for Diffie-Hellman key exchange computations.
|
danielebarchiesi@0
|
34 */
|
danielebarchiesi@0
|
35 define('OPENID_RAND_SOURCE', '/dev/urandom');
|
danielebarchiesi@0
|
36
|
danielebarchiesi@0
|
37 /**
|
danielebarchiesi@0
|
38 * OpenID Authentication 2.0 namespace URL.
|
danielebarchiesi@0
|
39 */
|
danielebarchiesi@0
|
40 define('OPENID_NS_2_0', 'http://specs.openid.net/auth/2.0');
|
danielebarchiesi@0
|
41
|
danielebarchiesi@0
|
42 /**
|
danielebarchiesi@0
|
43 * OpenID Authentication 1.1 namespace URL; used for backwards-compatibility.
|
danielebarchiesi@0
|
44 */
|
danielebarchiesi@0
|
45 define('OPENID_NS_1_1', 'http://openid.net/signon/1.1');
|
danielebarchiesi@0
|
46
|
danielebarchiesi@0
|
47 /**
|
danielebarchiesi@0
|
48 * OpenID Authentication 1.0 namespace URL; used for backwards-compatibility.
|
danielebarchiesi@0
|
49 */
|
danielebarchiesi@0
|
50 define('OPENID_NS_1_0', 'http://openid.net/signon/1.0');
|
danielebarchiesi@0
|
51
|
danielebarchiesi@0
|
52 /**
|
danielebarchiesi@0
|
53 * OpenID namespace used in Yadis documents.
|
danielebarchiesi@0
|
54 */
|
danielebarchiesi@0
|
55 define('OPENID_NS_OPENID', 'http://openid.net/xmlns/1.0');
|
danielebarchiesi@0
|
56
|
danielebarchiesi@0
|
57 /**
|
danielebarchiesi@0
|
58 * OpenID Simple Registration extension.
|
danielebarchiesi@0
|
59 */
|
danielebarchiesi@0
|
60 define('OPENID_NS_SREG', 'http://openid.net/extensions/sreg/1.1');
|
danielebarchiesi@0
|
61
|
danielebarchiesi@0
|
62 /**
|
danielebarchiesi@0
|
63 * OpenID Attribute Exchange extension.
|
danielebarchiesi@0
|
64 */
|
danielebarchiesi@0
|
65 define('OPENID_NS_AX', 'http://openid.net/srv/ax/1.0');
|
danielebarchiesi@0
|
66
|
danielebarchiesi@0
|
67 /**
|
danielebarchiesi@0
|
68 * Extensible Resource Descriptor documents.
|
danielebarchiesi@0
|
69 */
|
danielebarchiesi@0
|
70 define('OPENID_NS_XRD', 'xri://$xrd*($v*2.0)');
|
danielebarchiesi@0
|
71
|
danielebarchiesi@0
|
72 /**
|
danielebarchiesi@0
|
73 * Performs an HTTP 302 redirect (for the 1.x protocol).
|
danielebarchiesi@0
|
74 */
|
danielebarchiesi@0
|
75 function openid_redirect_http($url, $message) {
|
danielebarchiesi@0
|
76 $query = array();
|
danielebarchiesi@0
|
77 foreach ($message as $key => $val) {
|
danielebarchiesi@0
|
78 $query[] = $key . '=' . urlencode($val);
|
danielebarchiesi@0
|
79 }
|
danielebarchiesi@0
|
80
|
danielebarchiesi@0
|
81 $sep = (strpos($url, '?') === FALSE) ? '?' : '&';
|
danielebarchiesi@0
|
82 header('Location: ' . $url . $sep . implode('&', $query), TRUE, 302);
|
danielebarchiesi@0
|
83
|
danielebarchiesi@0
|
84 drupal_exit();
|
danielebarchiesi@0
|
85 }
|
danielebarchiesi@0
|
86
|
danielebarchiesi@0
|
87 /**
|
danielebarchiesi@0
|
88 * Creates a js auto-submit redirect for (for the 2.x protocol)
|
danielebarchiesi@0
|
89 */
|
danielebarchiesi@0
|
90 function openid_redirect($url, $message) {
|
danielebarchiesi@0
|
91 global $language;
|
danielebarchiesi@0
|
92
|
danielebarchiesi@0
|
93 $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n";
|
danielebarchiesi@0
|
94 $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $language->language . '" lang="' . $language->language . '">' . "\n";
|
danielebarchiesi@0
|
95 $output .= "<head>\n";
|
danielebarchiesi@0
|
96 $output .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
danielebarchiesi@0
|
97 $output .= "<title>" . t('OpenID redirect') . "</title>\n";
|
danielebarchiesi@0
|
98 $output .= "</head>\n";
|
danielebarchiesi@0
|
99 $output .= "<body>\n";
|
danielebarchiesi@0
|
100 $elements = drupal_get_form('openid_redirect_form', $url, $message);
|
danielebarchiesi@0
|
101 $output .= drupal_render($elements);
|
danielebarchiesi@0
|
102 $output .= '<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>' . "\n";
|
danielebarchiesi@0
|
103 $output .= "</body>\n";
|
danielebarchiesi@0
|
104 $output .= "</html>\n";
|
danielebarchiesi@0
|
105 print $output;
|
danielebarchiesi@0
|
106
|
danielebarchiesi@0
|
107 drupal_exit();
|
danielebarchiesi@0
|
108 }
|
danielebarchiesi@0
|
109
|
danielebarchiesi@0
|
110 function openid_redirect_form($form, &$form_state, $url, $message) {
|
danielebarchiesi@0
|
111 $form['#action'] = $url;
|
danielebarchiesi@0
|
112 $form['#method'] = "post";
|
danielebarchiesi@0
|
113 foreach ($message as $key => $value) {
|
danielebarchiesi@0
|
114 $form[$key] = array(
|
danielebarchiesi@0
|
115 '#type' => 'hidden',
|
danielebarchiesi@0
|
116 '#name' => $key,
|
danielebarchiesi@0
|
117 '#value' => $value,
|
danielebarchiesi@0
|
118 );
|
danielebarchiesi@0
|
119 }
|
danielebarchiesi@0
|
120 $form['actions'] = array('#type' => 'actions');
|
danielebarchiesi@0
|
121 $form['actions']['submit'] = array(
|
danielebarchiesi@0
|
122 '#type' => 'submit',
|
danielebarchiesi@0
|
123 '#prefix' => '<noscript><div>',
|
danielebarchiesi@0
|
124 '#suffix' => '</div></noscript>',
|
danielebarchiesi@0
|
125 '#value' => t('Send'),
|
danielebarchiesi@0
|
126 );
|
danielebarchiesi@0
|
127
|
danielebarchiesi@0
|
128 return $form;
|
danielebarchiesi@0
|
129 }
|
danielebarchiesi@0
|
130
|
danielebarchiesi@0
|
131 /**
|
danielebarchiesi@0
|
132 * Parse an XRDS document.
|
danielebarchiesi@0
|
133 *
|
danielebarchiesi@0
|
134 * @param $raw_xml
|
danielebarchiesi@0
|
135 * A string containing the XRDS document.
|
danielebarchiesi@0
|
136 * @return
|
danielebarchiesi@0
|
137 * An array of service entries.
|
danielebarchiesi@0
|
138 */
|
danielebarchiesi@0
|
139 function _openid_xrds_parse($raw_xml) {
|
danielebarchiesi@0
|
140 $services = array();
|
danielebarchiesi@0
|
141
|
danielebarchiesi@0
|
142 // For PHP version >= 5.2.11, we can use this function to protect against
|
danielebarchiesi@0
|
143 // malicious doctype declarations and other unexpected entity loading.
|
danielebarchiesi@0
|
144 // However, we will not rely on it, and reject any XML with a DOCTYPE.
|
danielebarchiesi@0
|
145 $disable_entity_loader = function_exists('libxml_disable_entity_loader');
|
danielebarchiesi@0
|
146 if ($disable_entity_loader) {
|
danielebarchiesi@0
|
147 $load_entities = libxml_disable_entity_loader(TRUE);
|
danielebarchiesi@0
|
148 }
|
danielebarchiesi@0
|
149
|
danielebarchiesi@0
|
150 // Load the XML into a DOM document.
|
danielebarchiesi@0
|
151 $dom = new DOMDocument();
|
danielebarchiesi@0
|
152 @$dom->loadXML($raw_xml);
|
danielebarchiesi@0
|
153
|
danielebarchiesi@0
|
154 // Since DOCTYPE declarations from an untrusted source could be malicious, we
|
danielebarchiesi@0
|
155 // stop parsing here and treat the XML as invalid since XRDS documents do not
|
danielebarchiesi@0
|
156 // require, and are not expected to have, a DOCTYPE.
|
danielebarchiesi@0
|
157 if (isset($dom->doctype)) {
|
danielebarchiesi@0
|
158 return array();
|
danielebarchiesi@0
|
159 }
|
danielebarchiesi@0
|
160
|
danielebarchiesi@0
|
161 // Parse the DOM document for the information we need.
|
danielebarchiesi@0
|
162 if ($xml = simplexml_import_dom($dom)) {
|
danielebarchiesi@0
|
163 foreach ($xml->children(OPENID_NS_XRD)->XRD as $xrd) {
|
danielebarchiesi@0
|
164 foreach ($xrd->children(OPENID_NS_XRD)->Service as $service_element) {
|
danielebarchiesi@0
|
165 $service = array(
|
danielebarchiesi@0
|
166 'priority' => $service_element->attributes()->priority ? (int)$service_element->attributes()->priority : PHP_INT_MAX,
|
danielebarchiesi@0
|
167 'types' => array(),
|
danielebarchiesi@0
|
168 'uri' => (string)$service_element->children(OPENID_NS_XRD)->URI,
|
danielebarchiesi@0
|
169 'service' => $service_element,
|
danielebarchiesi@0
|
170 'xrd' => $xrd,
|
danielebarchiesi@0
|
171 );
|
danielebarchiesi@0
|
172 foreach ($service_element->Type as $type) {
|
danielebarchiesi@0
|
173 $service['types'][] = (string)$type;
|
danielebarchiesi@0
|
174 }
|
danielebarchiesi@0
|
175 if ($service_element->children(OPENID_NS_XRD)->LocalID) {
|
danielebarchiesi@0
|
176 $service['identity'] = (string)$service_element->children(OPENID_NS_XRD)->LocalID;
|
danielebarchiesi@0
|
177 }
|
danielebarchiesi@0
|
178 elseif ($service_element->children(OPENID_NS_OPENID)->Delegate) {
|
danielebarchiesi@0
|
179 $service['identity'] = (string)$service_element->children(OPENID_NS_OPENID)->Delegate;
|
danielebarchiesi@0
|
180 }
|
danielebarchiesi@0
|
181 else {
|
danielebarchiesi@0
|
182 $service['identity'] = FALSE;
|
danielebarchiesi@0
|
183 }
|
danielebarchiesi@0
|
184 $services[] = $service;
|
danielebarchiesi@0
|
185 }
|
danielebarchiesi@0
|
186 }
|
danielebarchiesi@0
|
187 }
|
danielebarchiesi@0
|
188
|
danielebarchiesi@0
|
189 // Return the LIBXML options to the previous state before returning.
|
danielebarchiesi@0
|
190 if ($disable_entity_loader) {
|
danielebarchiesi@0
|
191 libxml_disable_entity_loader($load_entities);
|
danielebarchiesi@0
|
192 }
|
danielebarchiesi@0
|
193
|
danielebarchiesi@0
|
194 return $services;
|
danielebarchiesi@0
|
195 }
|
danielebarchiesi@0
|
196
|
danielebarchiesi@0
|
197 /**
|
danielebarchiesi@0
|
198 * Select a service element.
|
danielebarchiesi@0
|
199 *
|
danielebarchiesi@0
|
200 * The procedure is described in OpenID Authentication 2.0, section 7.3.2.
|
danielebarchiesi@0
|
201 *
|
danielebarchiesi@0
|
202 * A new entry is added to the returned array with the key 'version' and the
|
danielebarchiesi@0
|
203 * value 1 or 2 specifying the protocol version used by the service.
|
danielebarchiesi@0
|
204 *
|
danielebarchiesi@0
|
205 * @param $services
|
danielebarchiesi@0
|
206 * An array of service arrays as returned by openid_discovery().
|
danielebarchiesi@0
|
207 * @return
|
danielebarchiesi@0
|
208 * The selected service array, or NULL if no valid services were found.
|
danielebarchiesi@0
|
209 */
|
danielebarchiesi@0
|
210 function _openid_select_service(array $services) {
|
danielebarchiesi@0
|
211 // Extensible Resource Identifier (XRI) Resolution Version 2.0, section 4.3.3:
|
danielebarchiesi@0
|
212 // Find the service with the highest priority (lowest integer value). If there
|
danielebarchiesi@0
|
213 // is a tie, select a random one, not just the first in the XML document.
|
danielebarchiesi@0
|
214 shuffle($services);
|
danielebarchiesi@0
|
215 $selected_service = NULL;
|
danielebarchiesi@0
|
216 $selected_type_priority = FALSE;
|
danielebarchiesi@0
|
217
|
danielebarchiesi@0
|
218 // Search for an OP Identifier Element.
|
danielebarchiesi@0
|
219 foreach ($services as $service) {
|
danielebarchiesi@0
|
220 if (!empty($service['uri'])) {
|
danielebarchiesi@0
|
221 $type_priority = FALSE;
|
danielebarchiesi@0
|
222 if (in_array('http://specs.openid.net/auth/2.0/server', $service['types'])) {
|
danielebarchiesi@0
|
223 $service['version'] = 2;
|
danielebarchiesi@0
|
224 $type_priority = 1;
|
danielebarchiesi@0
|
225 }
|
danielebarchiesi@0
|
226 elseif (in_array('http://specs.openid.net/auth/2.0/signon', $service['types'])) {
|
danielebarchiesi@0
|
227 $service['version'] = 2;
|
danielebarchiesi@0
|
228 $type_priority = 2;
|
danielebarchiesi@0
|
229 }
|
danielebarchiesi@0
|
230 elseif (in_array(OPENID_NS_1_0, $service['types']) || in_array(OPENID_NS_1_1, $service['types'])) {
|
danielebarchiesi@0
|
231 $service['version'] = 1;
|
danielebarchiesi@0
|
232 $type_priority = 3;
|
danielebarchiesi@0
|
233 }
|
danielebarchiesi@0
|
234
|
danielebarchiesi@0
|
235 if ($type_priority
|
danielebarchiesi@0
|
236 && (!$selected_service
|
danielebarchiesi@0
|
237 || $type_priority < $selected_type_priority
|
danielebarchiesi@0
|
238 || ($type_priority == $selected_type_priority && $service['priority'] < $selected_service['priority']))) {
|
danielebarchiesi@0
|
239 $selected_service = $service;
|
danielebarchiesi@0
|
240 $selected_type_priority = $type_priority;
|
danielebarchiesi@0
|
241 }
|
danielebarchiesi@0
|
242 }
|
danielebarchiesi@0
|
243 }
|
danielebarchiesi@0
|
244
|
danielebarchiesi@0
|
245 if ($selected_service) {
|
danielebarchiesi@0
|
246 // Unset SimpleXMLElement instances that cannot be saved in $_SESSION.
|
danielebarchiesi@0
|
247 unset($selected_service['xrd']);
|
danielebarchiesi@0
|
248 unset($selected_service['service']);
|
danielebarchiesi@0
|
249 }
|
danielebarchiesi@0
|
250
|
danielebarchiesi@0
|
251 return $selected_service;
|
danielebarchiesi@0
|
252 }
|
danielebarchiesi@0
|
253
|
danielebarchiesi@0
|
254 /**
|
danielebarchiesi@0
|
255 * Determine if the given identifier is an XRI ID.
|
danielebarchiesi@0
|
256 */
|
danielebarchiesi@0
|
257 function _openid_is_xri($identifier) {
|
danielebarchiesi@0
|
258 // Strip the xri:// scheme from the identifier if present.
|
danielebarchiesi@0
|
259 if (stripos($identifier, 'xri://') === 0) {
|
danielebarchiesi@0
|
260 $identifier = substr($identifier, 6);
|
danielebarchiesi@0
|
261 }
|
danielebarchiesi@0
|
262
|
danielebarchiesi@0
|
263 // Test whether the identifier starts with an XRI global context symbol or (.
|
danielebarchiesi@0
|
264 $firstchar = substr($identifier, 0, 1);
|
danielebarchiesi@0
|
265 if (strpos("=@+$!(", $firstchar) !== FALSE) {
|
danielebarchiesi@0
|
266 return TRUE;
|
danielebarchiesi@0
|
267 }
|
danielebarchiesi@0
|
268
|
danielebarchiesi@0
|
269 return FALSE;
|
danielebarchiesi@0
|
270 }
|
danielebarchiesi@0
|
271
|
danielebarchiesi@0
|
272 /**
|
danielebarchiesi@0
|
273 * Normalize the given identifier.
|
danielebarchiesi@0
|
274 *
|
danielebarchiesi@0
|
275 * The procedure is described in OpenID Authentication 2.0, section 7.2.
|
danielebarchiesi@0
|
276 */
|
danielebarchiesi@0
|
277 function openid_normalize($identifier) {
|
danielebarchiesi@0
|
278 $methods = module_invoke_all('openid_normalization_method_info');
|
danielebarchiesi@0
|
279 drupal_alter('openid_normalization_method_info', $methods);
|
danielebarchiesi@0
|
280
|
danielebarchiesi@0
|
281 // Execute each method in turn, stopping after the first method accepted
|
danielebarchiesi@0
|
282 // the identifier.
|
danielebarchiesi@0
|
283 foreach ($methods as $method) {
|
danielebarchiesi@0
|
284 $result = $method($identifier);
|
danielebarchiesi@0
|
285 if ($result !== NULL) {
|
danielebarchiesi@0
|
286 $identifier = $result;
|
danielebarchiesi@0
|
287 break;
|
danielebarchiesi@0
|
288 }
|
danielebarchiesi@0
|
289 }
|
danielebarchiesi@0
|
290
|
danielebarchiesi@0
|
291 return $identifier;
|
danielebarchiesi@0
|
292 }
|
danielebarchiesi@0
|
293
|
danielebarchiesi@0
|
294 /**
|
danielebarchiesi@0
|
295 * OpenID normalization method: normalize XRI identifiers.
|
danielebarchiesi@0
|
296 */
|
danielebarchiesi@0
|
297 function _openid_xri_normalize($identifier) {
|
danielebarchiesi@0
|
298 if (_openid_is_xri($identifier)) {
|
danielebarchiesi@0
|
299 if (stristr($identifier, 'xri://') !== FALSE) {
|
danielebarchiesi@0
|
300 $identifier = substr($identifier, 6);
|
danielebarchiesi@0
|
301 }
|
danielebarchiesi@0
|
302 return $identifier;
|
danielebarchiesi@0
|
303 }
|
danielebarchiesi@0
|
304 }
|
danielebarchiesi@0
|
305
|
danielebarchiesi@0
|
306 /**
|
danielebarchiesi@0
|
307 * OpenID normalization method: normalize URL identifiers.
|
danielebarchiesi@0
|
308 */
|
danielebarchiesi@0
|
309 function _openid_url_normalize($url) {
|
danielebarchiesi@0
|
310 $normalized_url = $url;
|
danielebarchiesi@0
|
311
|
danielebarchiesi@0
|
312 if (stristr($url, '://') === FALSE) {
|
danielebarchiesi@0
|
313 $normalized_url = 'http://' . $url;
|
danielebarchiesi@0
|
314 }
|
danielebarchiesi@0
|
315
|
danielebarchiesi@0
|
316 // Strip the fragment and fragment delimiter if present.
|
danielebarchiesi@0
|
317 $normalized_url = strtok($normalized_url, '#');
|
danielebarchiesi@0
|
318
|
danielebarchiesi@0
|
319 if (substr_count($normalized_url, '/') < 3) {
|
danielebarchiesi@0
|
320 $normalized_url .= '/';
|
danielebarchiesi@0
|
321 }
|
danielebarchiesi@0
|
322
|
danielebarchiesi@0
|
323 return $normalized_url;
|
danielebarchiesi@0
|
324 }
|
danielebarchiesi@0
|
325
|
danielebarchiesi@0
|
326 /**
|
danielebarchiesi@0
|
327 * Create a serialized message packet as per spec: $key:$value\n .
|
danielebarchiesi@0
|
328 */
|
danielebarchiesi@0
|
329 function _openid_create_message($data) {
|
danielebarchiesi@0
|
330 $serialized = '';
|
danielebarchiesi@0
|
331
|
danielebarchiesi@0
|
332 foreach ($data as $key => $value) {
|
danielebarchiesi@0
|
333 if ((strpos($key, ':') !== FALSE) || (strpos($key, "\n") !== FALSE) || (strpos($value, "\n") !== FALSE)) {
|
danielebarchiesi@0
|
334 return NULL;
|
danielebarchiesi@0
|
335 }
|
danielebarchiesi@0
|
336 $serialized .= "$key:$value\n";
|
danielebarchiesi@0
|
337 }
|
danielebarchiesi@0
|
338 return $serialized;
|
danielebarchiesi@0
|
339 }
|
danielebarchiesi@0
|
340
|
danielebarchiesi@0
|
341 /**
|
danielebarchiesi@0
|
342 * Encode a message from _openid_create_message for HTTP Post
|
danielebarchiesi@0
|
343 */
|
danielebarchiesi@0
|
344 function _openid_encode_message($message) {
|
danielebarchiesi@0
|
345 $encoded_message = '';
|
danielebarchiesi@0
|
346
|
danielebarchiesi@0
|
347 $items = explode("\n", $message);
|
danielebarchiesi@0
|
348 foreach ($items as $item) {
|
danielebarchiesi@0
|
349 $parts = explode(':', $item, 2);
|
danielebarchiesi@0
|
350
|
danielebarchiesi@0
|
351 if (count($parts) == 2) {
|
danielebarchiesi@0
|
352 if ($encoded_message != '') {
|
danielebarchiesi@0
|
353 $encoded_message .= '&';
|
danielebarchiesi@0
|
354 }
|
danielebarchiesi@0
|
355 $encoded_message .= rawurlencode(trim($parts[0])) . '=' . rawurlencode(trim($parts[1]));
|
danielebarchiesi@0
|
356 }
|
danielebarchiesi@0
|
357 }
|
danielebarchiesi@0
|
358
|
danielebarchiesi@0
|
359 return $encoded_message;
|
danielebarchiesi@0
|
360 }
|
danielebarchiesi@0
|
361
|
danielebarchiesi@0
|
362 /**
|
danielebarchiesi@0
|
363 * Convert a direct communication message
|
danielebarchiesi@0
|
364 * into an associative array.
|
danielebarchiesi@0
|
365 */
|
danielebarchiesi@0
|
366 function _openid_parse_message($message) {
|
danielebarchiesi@0
|
367 $parsed_message = array();
|
danielebarchiesi@0
|
368
|
danielebarchiesi@0
|
369 $items = explode("\n", $message);
|
danielebarchiesi@0
|
370 foreach ($items as $item) {
|
danielebarchiesi@0
|
371 $parts = explode(':', $item, 2);
|
danielebarchiesi@0
|
372
|
danielebarchiesi@0
|
373 if (count($parts) == 2) {
|
danielebarchiesi@0
|
374 $parsed_message[$parts[0]] = $parts[1];
|
danielebarchiesi@0
|
375 }
|
danielebarchiesi@0
|
376 }
|
danielebarchiesi@0
|
377
|
danielebarchiesi@0
|
378 return $parsed_message;
|
danielebarchiesi@0
|
379 }
|
danielebarchiesi@0
|
380
|
danielebarchiesi@0
|
381 /**
|
danielebarchiesi@0
|
382 * Return a nonce value - formatted per OpenID spec.
|
danielebarchiesi@0
|
383 */
|
danielebarchiesi@0
|
384 function _openid_nonce() {
|
danielebarchiesi@0
|
385 // YYYY-MM-DDThh:mm:ssZ, plus some optional extra unique characters.
|
danielebarchiesi@0
|
386 return gmdate('Y-m-d\TH:i:s\Z') .
|
danielebarchiesi@0
|
387 chr(mt_rand(0, 25) + 65) .
|
danielebarchiesi@0
|
388 chr(mt_rand(0, 25) + 65) .
|
danielebarchiesi@0
|
389 chr(mt_rand(0, 25) + 65) .
|
danielebarchiesi@0
|
390 chr(mt_rand(0, 25) + 65);
|
danielebarchiesi@0
|
391 }
|
danielebarchiesi@0
|
392
|
danielebarchiesi@0
|
393 /**
|
danielebarchiesi@0
|
394 * Pull the href attribute out of an html link element.
|
danielebarchiesi@0
|
395 */
|
danielebarchiesi@0
|
396 function _openid_link_href($rel, $html) {
|
danielebarchiesi@0
|
397 $rel = preg_quote($rel);
|
danielebarchiesi@0
|
398 preg_match('|<link\s+rel=["\'](.*)' . $rel . '(.*)["\'](.*)/?>|iUs', $html, $matches);
|
danielebarchiesi@0
|
399 if (isset($matches[3])) {
|
danielebarchiesi@0
|
400 preg_match('|href=["\']([^"]+)["\']|iU', $matches[3], $href);
|
danielebarchiesi@0
|
401 return trim($href[1]);
|
danielebarchiesi@0
|
402 }
|
danielebarchiesi@0
|
403 return FALSE;
|
danielebarchiesi@0
|
404 }
|
danielebarchiesi@0
|
405
|
danielebarchiesi@0
|
406 /**
|
danielebarchiesi@0
|
407 * Pull the http-equiv attribute out of an html meta element
|
danielebarchiesi@0
|
408 */
|
danielebarchiesi@0
|
409 function _openid_meta_httpequiv($equiv, $html) {
|
danielebarchiesi@0
|
410 preg_match('|<meta\s+http-equiv=["\']' . $equiv . '["\'](.*)/?>|iUs', $html, $matches);
|
danielebarchiesi@0
|
411 if (isset($matches[1])) {
|
danielebarchiesi@0
|
412 preg_match('|content=["\']([^"]+)["\']|iUs', $matches[1], $content);
|
danielebarchiesi@0
|
413 if (isset($content[1])) {
|
danielebarchiesi@0
|
414 return $content[1];
|
danielebarchiesi@0
|
415 }
|
danielebarchiesi@0
|
416 }
|
danielebarchiesi@0
|
417 return FALSE;
|
danielebarchiesi@0
|
418 }
|
danielebarchiesi@0
|
419
|
danielebarchiesi@0
|
420 /**
|
danielebarchiesi@0
|
421 * Sign certain keys in a message
|
danielebarchiesi@0
|
422 * @param $association - object loaded from openid_association or openid_server_association table
|
danielebarchiesi@0
|
423 * - important fields are ->assoc_type and ->mac_key
|
danielebarchiesi@0
|
424 * @param $message_array - array of entire message about to be sent
|
danielebarchiesi@0
|
425 * @param $keys_to_sign - keys in the message to include in signature (without
|
danielebarchiesi@0
|
426 * 'openid.' appended)
|
danielebarchiesi@0
|
427 */
|
danielebarchiesi@0
|
428 function _openid_signature($association, $message_array, $keys_to_sign) {
|
danielebarchiesi@0
|
429 $signature = '';
|
danielebarchiesi@0
|
430 $sign_data = array();
|
danielebarchiesi@0
|
431
|
danielebarchiesi@0
|
432 foreach ($keys_to_sign as $key) {
|
danielebarchiesi@0
|
433 if (isset($message_array['openid.' . $key])) {
|
danielebarchiesi@0
|
434 $sign_data[$key] = $message_array['openid.' . $key];
|
danielebarchiesi@0
|
435 }
|
danielebarchiesi@0
|
436 }
|
danielebarchiesi@0
|
437
|
danielebarchiesi@0
|
438 $message = _openid_create_message($sign_data);
|
danielebarchiesi@0
|
439 $secret = base64_decode($association->mac_key);
|
danielebarchiesi@0
|
440 $signature = _openid_hmac($secret, $message);
|
danielebarchiesi@0
|
441
|
danielebarchiesi@0
|
442 return base64_encode($signature);
|
danielebarchiesi@0
|
443 }
|
danielebarchiesi@0
|
444
|
danielebarchiesi@0
|
445 function _openid_hmac($key, $text) {
|
danielebarchiesi@0
|
446 if (strlen($key) > OPENID_SHA1_BLOCKSIZE) {
|
danielebarchiesi@0
|
447 $key = sha1($key, TRUE);
|
danielebarchiesi@0
|
448 }
|
danielebarchiesi@0
|
449
|
danielebarchiesi@0
|
450 $key = str_pad($key, OPENID_SHA1_BLOCKSIZE, chr(0x00));
|
danielebarchiesi@0
|
451 $ipad = str_repeat(chr(0x36), OPENID_SHA1_BLOCKSIZE);
|
danielebarchiesi@0
|
452 $opad = str_repeat(chr(0x5c), OPENID_SHA1_BLOCKSIZE);
|
danielebarchiesi@0
|
453 $hash1 = sha1(($key ^ $ipad) . $text, TRUE);
|
danielebarchiesi@0
|
454 $hmac = sha1(($key ^ $opad) . $hash1, TRUE);
|
danielebarchiesi@0
|
455
|
danielebarchiesi@0
|
456 return $hmac;
|
danielebarchiesi@0
|
457 }
|
danielebarchiesi@0
|
458
|
danielebarchiesi@0
|
459 function _openid_dh_base64_to_long($str) {
|
danielebarchiesi@0
|
460 $b64 = base64_decode($str);
|
danielebarchiesi@0
|
461
|
danielebarchiesi@0
|
462 return _openid_dh_binary_to_long($b64);
|
danielebarchiesi@0
|
463 }
|
danielebarchiesi@0
|
464
|
danielebarchiesi@0
|
465 function _openid_dh_long_to_base64($str) {
|
danielebarchiesi@0
|
466 return base64_encode(_openid_dh_long_to_binary($str));
|
danielebarchiesi@0
|
467 }
|
danielebarchiesi@0
|
468
|
danielebarchiesi@0
|
469 function _openid_dh_binary_to_long($str) {
|
danielebarchiesi@0
|
470 $bytes = array_merge(unpack('C*', $str));
|
danielebarchiesi@0
|
471
|
danielebarchiesi@0
|
472 $n = 0;
|
danielebarchiesi@0
|
473 foreach ($bytes as $byte) {
|
danielebarchiesi@0
|
474 $n = _openid_math_mul($n, pow(2, 8));
|
danielebarchiesi@0
|
475 $n = _openid_math_add($n, $byte);
|
danielebarchiesi@0
|
476 }
|
danielebarchiesi@0
|
477
|
danielebarchiesi@0
|
478 return $n;
|
danielebarchiesi@0
|
479 }
|
danielebarchiesi@0
|
480
|
danielebarchiesi@0
|
481 function _openid_dh_long_to_binary($long) {
|
danielebarchiesi@0
|
482 $cmp = _openid_math_cmp($long, 0);
|
danielebarchiesi@0
|
483 if ($cmp < 0) {
|
danielebarchiesi@0
|
484 return FALSE;
|
danielebarchiesi@0
|
485 }
|
danielebarchiesi@0
|
486
|
danielebarchiesi@0
|
487 if ($cmp == 0) {
|
danielebarchiesi@0
|
488 return "\x00";
|
danielebarchiesi@0
|
489 }
|
danielebarchiesi@0
|
490
|
danielebarchiesi@0
|
491 $bytes = array();
|
danielebarchiesi@0
|
492
|
danielebarchiesi@0
|
493 while (_openid_math_cmp($long, 0) > 0) {
|
danielebarchiesi@0
|
494 array_unshift($bytes, _openid_math_mod($long, 256));
|
danielebarchiesi@0
|
495 $long = _openid_math_div($long, pow(2, 8));
|
danielebarchiesi@0
|
496 }
|
danielebarchiesi@0
|
497
|
danielebarchiesi@0
|
498 if ($bytes && ($bytes[0] > 127)) {
|
danielebarchiesi@0
|
499 array_unshift($bytes, 0);
|
danielebarchiesi@0
|
500 }
|
danielebarchiesi@0
|
501
|
danielebarchiesi@0
|
502 $string = '';
|
danielebarchiesi@0
|
503 foreach ($bytes as $byte) {
|
danielebarchiesi@0
|
504 $string .= pack('C', $byte);
|
danielebarchiesi@0
|
505 }
|
danielebarchiesi@0
|
506
|
danielebarchiesi@0
|
507 return $string;
|
danielebarchiesi@0
|
508 }
|
danielebarchiesi@0
|
509
|
danielebarchiesi@0
|
510 function _openid_dh_xorsecret($shared, $secret) {
|
danielebarchiesi@0
|
511 $dh_shared_str = _openid_dh_long_to_binary($shared);
|
danielebarchiesi@0
|
512 $sha1_dh_shared = sha1($dh_shared_str, TRUE);
|
danielebarchiesi@0
|
513 $xsecret = "";
|
danielebarchiesi@0
|
514 for ($i = 0; $i < strlen($secret); $i++) {
|
danielebarchiesi@0
|
515 $xsecret .= chr(ord($secret[$i]) ^ ord($sha1_dh_shared[$i]));
|
danielebarchiesi@0
|
516 }
|
danielebarchiesi@0
|
517
|
danielebarchiesi@0
|
518 return $xsecret;
|
danielebarchiesi@0
|
519 }
|
danielebarchiesi@0
|
520
|
danielebarchiesi@0
|
521 function _openid_dh_rand($stop) {
|
danielebarchiesi@0
|
522 $duplicate_cache = &drupal_static(__FUNCTION__, array());
|
danielebarchiesi@0
|
523
|
danielebarchiesi@0
|
524 // Used as the key for the duplicate cache
|
danielebarchiesi@0
|
525 $rbytes = _openid_dh_long_to_binary($stop);
|
danielebarchiesi@0
|
526
|
danielebarchiesi@0
|
527 if (isset($duplicate_cache[$rbytes])) {
|
danielebarchiesi@0
|
528 list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
|
danielebarchiesi@0
|
529 }
|
danielebarchiesi@0
|
530 else {
|
danielebarchiesi@0
|
531 if ($rbytes[0] == "\x00") {
|
danielebarchiesi@0
|
532 $nbytes = strlen($rbytes) - 1;
|
danielebarchiesi@0
|
533 }
|
danielebarchiesi@0
|
534 else {
|
danielebarchiesi@0
|
535 $nbytes = strlen($rbytes);
|
danielebarchiesi@0
|
536 }
|
danielebarchiesi@0
|
537
|
danielebarchiesi@0
|
538 $mxrand = _openid_math_pow(256, $nbytes);
|
danielebarchiesi@0
|
539
|
danielebarchiesi@0
|
540 // If we get a number less than this, then it is in the
|
danielebarchiesi@0
|
541 // duplicated range.
|
danielebarchiesi@0
|
542 $duplicate = _openid_math_mod($mxrand, $stop);
|
danielebarchiesi@0
|
543
|
danielebarchiesi@0
|
544 if (count($duplicate_cache) > 10) {
|
danielebarchiesi@0
|
545 $duplicate_cache = array();
|
danielebarchiesi@0
|
546 }
|
danielebarchiesi@0
|
547
|
danielebarchiesi@0
|
548 $duplicate_cache[$rbytes] = array($duplicate, $nbytes);
|
danielebarchiesi@0
|
549 }
|
danielebarchiesi@0
|
550
|
danielebarchiesi@0
|
551 do {
|
danielebarchiesi@0
|
552 $bytes = "\x00" . _openid_get_bytes($nbytes);
|
danielebarchiesi@0
|
553 $n = _openid_dh_binary_to_long($bytes);
|
danielebarchiesi@0
|
554 // Keep looping if this value is in the low duplicated range.
|
danielebarchiesi@0
|
555 } while (_openid_math_cmp($n, $duplicate) < 0);
|
danielebarchiesi@0
|
556
|
danielebarchiesi@0
|
557 return _openid_math_mod($n, $stop);
|
danielebarchiesi@0
|
558 }
|
danielebarchiesi@0
|
559
|
danielebarchiesi@0
|
560 function _openid_get_bytes($num_bytes) {
|
danielebarchiesi@0
|
561 $f = &drupal_static(__FUNCTION__);
|
danielebarchiesi@0
|
562 $bytes = '';
|
danielebarchiesi@0
|
563 if (!isset($f)) {
|
danielebarchiesi@0
|
564 $f = @fopen(OPENID_RAND_SOURCE, "r");
|
danielebarchiesi@0
|
565 }
|
danielebarchiesi@0
|
566 if (!$f) {
|
danielebarchiesi@0
|
567 // pseudorandom used
|
danielebarchiesi@0
|
568 $bytes = '';
|
danielebarchiesi@0
|
569 for ($i = 0; $i < $num_bytes; $i += 4) {
|
danielebarchiesi@0
|
570 $bytes .= pack('L', mt_rand());
|
danielebarchiesi@0
|
571 }
|
danielebarchiesi@0
|
572 $bytes = substr($bytes, 0, $num_bytes);
|
danielebarchiesi@0
|
573 }
|
danielebarchiesi@0
|
574 else {
|
danielebarchiesi@0
|
575 $bytes = fread($f, $num_bytes);
|
danielebarchiesi@0
|
576 }
|
danielebarchiesi@0
|
577 return $bytes;
|
danielebarchiesi@0
|
578 }
|
danielebarchiesi@0
|
579
|
danielebarchiesi@0
|
580 function _openid_response($str = NULL) {
|
danielebarchiesi@0
|
581 $data = array();
|
danielebarchiesi@0
|
582
|
danielebarchiesi@0
|
583 if (isset($_SERVER['REQUEST_METHOD'])) {
|
danielebarchiesi@0
|
584 $data = _openid_get_params($_SERVER['QUERY_STRING']);
|
danielebarchiesi@0
|
585
|
danielebarchiesi@0
|
586 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
danielebarchiesi@0
|
587 $str = file_get_contents('php://input');
|
danielebarchiesi@0
|
588
|
danielebarchiesi@0
|
589 $post = array();
|
danielebarchiesi@0
|
590 if ($str !== FALSE) {
|
danielebarchiesi@0
|
591 $post = _openid_get_params($str);
|
danielebarchiesi@0
|
592 }
|
danielebarchiesi@0
|
593
|
danielebarchiesi@0
|
594 $data = array_merge($data, $post);
|
danielebarchiesi@0
|
595 }
|
danielebarchiesi@0
|
596 }
|
danielebarchiesi@0
|
597
|
danielebarchiesi@0
|
598 return $data;
|
danielebarchiesi@0
|
599 }
|
danielebarchiesi@0
|
600
|
danielebarchiesi@0
|
601 function _openid_get_params($str) {
|
danielebarchiesi@0
|
602 $chunks = explode("&", $str);
|
danielebarchiesi@0
|
603
|
danielebarchiesi@0
|
604 $data = array();
|
danielebarchiesi@0
|
605 foreach ($chunks as $chunk) {
|
danielebarchiesi@0
|
606 $parts = explode("=", $chunk, 2);
|
danielebarchiesi@0
|
607
|
danielebarchiesi@0
|
608 if (count($parts) == 2) {
|
danielebarchiesi@0
|
609 list($k, $v) = $parts;
|
danielebarchiesi@0
|
610 $data[$k] = urldecode($v);
|
danielebarchiesi@0
|
611 }
|
danielebarchiesi@0
|
612 }
|
danielebarchiesi@0
|
613 return $data;
|
danielebarchiesi@0
|
614 }
|
danielebarchiesi@0
|
615
|
danielebarchiesi@0
|
616 /**
|
danielebarchiesi@0
|
617 * Extract all the parameters belonging to an extension in a response message.
|
danielebarchiesi@0
|
618 *
|
danielebarchiesi@0
|
619 * OpenID 2.0 defines a simple extension mechanism, based on a namespace prefix.
|
danielebarchiesi@0
|
620 *
|
danielebarchiesi@0
|
621 * Each request or response can define a prefix using:
|
danielebarchiesi@0
|
622 * @code
|
danielebarchiesi@0
|
623 * openid.ns.[prefix] = [extension_namespace]
|
danielebarchiesi@0
|
624 * openid.[prefix].[key1] = [value1]
|
danielebarchiesi@0
|
625 * openid.[prefix].[key2] = [value2]
|
danielebarchiesi@0
|
626 * ...
|
danielebarchiesi@0
|
627 * @endcode
|
danielebarchiesi@0
|
628 *
|
danielebarchiesi@0
|
629 * This function extracts all the keys belonging to an extension namespace in a
|
danielebarchiesi@0
|
630 * response, optionally using a fallback prefix if none is provided in the response.
|
danielebarchiesi@0
|
631 *
|
danielebarchiesi@0
|
632 * Note that you cannot assume that a given extension namespace will use the same
|
danielebarchiesi@0
|
633 * prefix on the response and the request: each party may use a different prefix
|
danielebarchiesi@0
|
634 * to refer to the same namespace.
|
danielebarchiesi@0
|
635 *
|
danielebarchiesi@0
|
636 * @param $response
|
danielebarchiesi@0
|
637 * The response array.
|
danielebarchiesi@0
|
638 * @param $extension_namespace
|
danielebarchiesi@0
|
639 * The namespace of the extension.
|
danielebarchiesi@0
|
640 * @param $fallback_prefix
|
danielebarchiesi@0
|
641 * An optional prefix that will be used in case no prefix is found for the
|
danielebarchiesi@0
|
642 * target extension namespace.
|
danielebarchiesi@0
|
643 * @param $only_signed
|
danielebarchiesi@0
|
644 * Return only keys that are included in the message signature in openid.sig.
|
danielebarchiesi@0
|
645 * Unsigned fields may have been modified or added by other parties than the
|
danielebarchiesi@0
|
646 * OpenID Provider.
|
danielebarchiesi@0
|
647 *
|
danielebarchiesi@0
|
648 * @return
|
danielebarchiesi@0
|
649 * An associative array containing all the parameters in the response message
|
danielebarchiesi@0
|
650 * that belong to the extension. The keys are stripped from their namespace
|
danielebarchiesi@0
|
651 * prefix.
|
danielebarchiesi@0
|
652 *
|
danielebarchiesi@0
|
653 * @see http://openid.net/specs/openid-authentication-2_0.html#extensions
|
danielebarchiesi@0
|
654 */
|
danielebarchiesi@0
|
655 function openid_extract_namespace($response, $extension_namespace, $fallback_prefix = NULL, $only_signed = FALSE) {
|
danielebarchiesi@0
|
656 $signed_keys = explode(',', $response['openid.signed']);
|
danielebarchiesi@0
|
657
|
danielebarchiesi@0
|
658 // Find the namespace prefix.
|
danielebarchiesi@0
|
659 $prefix = $fallback_prefix;
|
danielebarchiesi@0
|
660 foreach ($response as $key => $value) {
|
danielebarchiesi@0
|
661 if ($value == $extension_namespace && preg_match('/^openid\.ns\.([^.]+)$/', $key, $matches)) {
|
danielebarchiesi@0
|
662 $prefix = $matches[1];
|
danielebarchiesi@0
|
663 if ($only_signed && !in_array('ns.' . $matches[1], $signed_keys)) {
|
danielebarchiesi@0
|
664 // The namespace was defined but was not signed as required. In this
|
danielebarchiesi@0
|
665 // case we do not fall back to $fallback_prefix.
|
danielebarchiesi@0
|
666 $prefix = NULL;
|
danielebarchiesi@0
|
667 }
|
danielebarchiesi@0
|
668 break;
|
danielebarchiesi@0
|
669 }
|
danielebarchiesi@0
|
670 }
|
danielebarchiesi@0
|
671
|
danielebarchiesi@0
|
672 // Now extract the namespace keys from the response.
|
danielebarchiesi@0
|
673 $output = array();
|
danielebarchiesi@0
|
674 if (!isset($prefix)) {
|
danielebarchiesi@0
|
675 return $output;
|
danielebarchiesi@0
|
676 }
|
danielebarchiesi@0
|
677 foreach ($response as $key => $value) {
|
danielebarchiesi@0
|
678 if (preg_match('/^openid\.' . $prefix . '\.(.+)$/', $key, $matches)) {
|
danielebarchiesi@0
|
679 $local_key = $matches[1];
|
danielebarchiesi@0
|
680 if (!$only_signed || in_array($prefix . '.' . $local_key, $signed_keys)) {
|
danielebarchiesi@0
|
681 $output[$local_key] = $value;
|
danielebarchiesi@0
|
682 }
|
danielebarchiesi@0
|
683 }
|
danielebarchiesi@0
|
684 }
|
danielebarchiesi@0
|
685
|
danielebarchiesi@0
|
686 return $output;
|
danielebarchiesi@0
|
687 }
|
danielebarchiesi@0
|
688
|
danielebarchiesi@0
|
689 /**
|
danielebarchiesi@0
|
690 * Extracts values from an OpenID AX Response.
|
danielebarchiesi@0
|
691 *
|
danielebarchiesi@0
|
692 * The values can be returned in two forms:
|
danielebarchiesi@0
|
693 * - only openid.ax.value.<alias> (for single-valued answers)
|
danielebarchiesi@0
|
694 * - both openid.ax.count.<alias> and openid.ax.value.<alias>.<count> (for both
|
danielebarchiesi@0
|
695 * single and multiple-valued answers)
|
danielebarchiesi@0
|
696 *
|
danielebarchiesi@0
|
697 * @param $values
|
danielebarchiesi@0
|
698 * An array as returned by openid_extract_namespace(..., OPENID_NS_AX).
|
danielebarchiesi@0
|
699 * @param $uris
|
danielebarchiesi@0
|
700 * An array of identifier URIs.
|
danielebarchiesi@0
|
701 * @return
|
danielebarchiesi@0
|
702 * An array of values.
|
danielebarchiesi@0
|
703 * @see http://openid.net/specs/openid-attribute-exchange-1_0.html#fetch_response
|
danielebarchiesi@0
|
704 */
|
danielebarchiesi@0
|
705 function openid_extract_ax_values($values, $uris) {
|
danielebarchiesi@0
|
706 $output = array();
|
danielebarchiesi@0
|
707 foreach ($values as $key => $value) {
|
danielebarchiesi@0
|
708 if (in_array($value, $uris) && preg_match('/^type\.([^.]+)$/', $key, $matches)) {
|
danielebarchiesi@0
|
709 $alias = $matches[1];
|
danielebarchiesi@0
|
710 if (isset($values['count.' . $alias])) {
|
danielebarchiesi@0
|
711 for ($i = 1; $i <= $values['count.' . $alias]; $i++) {
|
danielebarchiesi@0
|
712 $output[] = $values['value.' . $alias . '.' . $i];
|
danielebarchiesi@0
|
713 }
|
danielebarchiesi@0
|
714 }
|
danielebarchiesi@0
|
715 elseif (isset($values['value.' . $alias])) {
|
danielebarchiesi@0
|
716 $output[] = $values['value.' . $alias];
|
danielebarchiesi@0
|
717 }
|
danielebarchiesi@0
|
718 break;
|
danielebarchiesi@0
|
719 }
|
danielebarchiesi@0
|
720 }
|
danielebarchiesi@0
|
721 return $output;
|
danielebarchiesi@0
|
722 }
|
danielebarchiesi@0
|
723
|
danielebarchiesi@0
|
724 /**
|
danielebarchiesi@0
|
725 * Determine the available math library GMP vs. BCMath, favouring GMP for performance.
|
danielebarchiesi@0
|
726 */
|
danielebarchiesi@0
|
727 function _openid_get_math_library() {
|
danielebarchiesi@0
|
728 // Not drupal_static(), because a function is not going to disappear and
|
danielebarchiesi@0
|
729 // change the output of this under any circumstances.
|
danielebarchiesi@0
|
730 static $library;
|
danielebarchiesi@0
|
731
|
danielebarchiesi@0
|
732 if (empty($library)) {
|
danielebarchiesi@0
|
733 if (function_exists('gmp_add')) {
|
danielebarchiesi@0
|
734 $library = 'gmp';
|
danielebarchiesi@0
|
735 }
|
danielebarchiesi@0
|
736 elseif (function_exists('bcadd')) {
|
danielebarchiesi@0
|
737 $library = 'bcmath';
|
danielebarchiesi@0
|
738 }
|
danielebarchiesi@0
|
739 }
|
danielebarchiesi@0
|
740
|
danielebarchiesi@0
|
741 return $library;
|
danielebarchiesi@0
|
742 }
|
danielebarchiesi@0
|
743
|
danielebarchiesi@0
|
744 /**
|
danielebarchiesi@0
|
745 * Calls the add function from the available math library for OpenID.
|
danielebarchiesi@0
|
746 */
|
danielebarchiesi@0
|
747 function _openid_math_add($x, $y) {
|
danielebarchiesi@0
|
748 $library = _openid_get_math_library();
|
danielebarchiesi@0
|
749 switch ($library) {
|
danielebarchiesi@0
|
750 case 'gmp':
|
danielebarchiesi@0
|
751 return gmp_strval(gmp_add($x, $y));
|
danielebarchiesi@0
|
752 case 'bcmath':
|
danielebarchiesi@0
|
753 return bcadd($x, $y);
|
danielebarchiesi@0
|
754 }
|
danielebarchiesi@0
|
755 }
|
danielebarchiesi@0
|
756
|
danielebarchiesi@0
|
757 /**
|
danielebarchiesi@0
|
758 * Calls the mul function from the available math library for OpenID.
|
danielebarchiesi@0
|
759 */
|
danielebarchiesi@0
|
760 function _openid_math_mul($x, $y) {
|
danielebarchiesi@0
|
761 $library = _openid_get_math_library();
|
danielebarchiesi@0
|
762 switch ($library) {
|
danielebarchiesi@0
|
763 case 'gmp':
|
danielebarchiesi@0
|
764 return gmp_mul($x, $y);
|
danielebarchiesi@0
|
765 case 'bcmath':
|
danielebarchiesi@0
|
766 return bcmul($x, $y);
|
danielebarchiesi@0
|
767 }
|
danielebarchiesi@0
|
768 }
|
danielebarchiesi@0
|
769
|
danielebarchiesi@0
|
770 /**
|
danielebarchiesi@0
|
771 * Calls the div function from the available math library for OpenID.
|
danielebarchiesi@0
|
772 */
|
danielebarchiesi@0
|
773 function _openid_math_div($x, $y) {
|
danielebarchiesi@0
|
774 $library = _openid_get_math_library();
|
danielebarchiesi@0
|
775 switch ($library) {
|
danielebarchiesi@0
|
776 case 'gmp':
|
danielebarchiesi@0
|
777 return gmp_div($x, $y);
|
danielebarchiesi@0
|
778 case 'bcmath':
|
danielebarchiesi@0
|
779 return bcdiv($x, $y);
|
danielebarchiesi@0
|
780 }
|
danielebarchiesi@0
|
781 }
|
danielebarchiesi@0
|
782
|
danielebarchiesi@0
|
783 /**
|
danielebarchiesi@0
|
784 * Calls the cmp function from the available math library for OpenID.
|
danielebarchiesi@0
|
785 */
|
danielebarchiesi@0
|
786 function _openid_math_cmp($x, $y) {
|
danielebarchiesi@0
|
787 $library = _openid_get_math_library();
|
danielebarchiesi@0
|
788 switch ($library) {
|
danielebarchiesi@0
|
789 case 'gmp':
|
danielebarchiesi@0
|
790 return gmp_cmp($x, $y);
|
danielebarchiesi@0
|
791 case 'bcmath':
|
danielebarchiesi@0
|
792 return bccomp($x, $y);
|
danielebarchiesi@0
|
793 }
|
danielebarchiesi@0
|
794 }
|
danielebarchiesi@0
|
795
|
danielebarchiesi@0
|
796 /**
|
danielebarchiesi@0
|
797 * Calls the mod function from the available math library for OpenID.
|
danielebarchiesi@0
|
798 */
|
danielebarchiesi@0
|
799 function _openid_math_mod($x, $y) {
|
danielebarchiesi@0
|
800 $library = _openid_get_math_library();
|
danielebarchiesi@0
|
801 switch ($library) {
|
danielebarchiesi@0
|
802 case 'gmp':
|
danielebarchiesi@0
|
803 return gmp_mod($x, $y);
|
danielebarchiesi@0
|
804 case 'bcmath':
|
danielebarchiesi@0
|
805 return bcmod($x, $y);
|
danielebarchiesi@0
|
806 }
|
danielebarchiesi@0
|
807 }
|
danielebarchiesi@0
|
808
|
danielebarchiesi@0
|
809 /**
|
danielebarchiesi@0
|
810 * Calls the pow function from the available math library for OpenID.
|
danielebarchiesi@0
|
811 */
|
danielebarchiesi@0
|
812 function _openid_math_pow($x, $y) {
|
danielebarchiesi@0
|
813 $library = _openid_get_math_library();
|
danielebarchiesi@0
|
814 switch ($library) {
|
danielebarchiesi@0
|
815 case 'gmp':
|
danielebarchiesi@0
|
816 return gmp_pow($x, $y);
|
danielebarchiesi@0
|
817 case 'bcmath':
|
danielebarchiesi@0
|
818 return bcpow($x, $y);
|
danielebarchiesi@0
|
819 }
|
danielebarchiesi@0
|
820 }
|
danielebarchiesi@0
|
821
|
danielebarchiesi@0
|
822 /**
|
danielebarchiesi@0
|
823 * Calls the mul function from the available math library for OpenID.
|
danielebarchiesi@0
|
824 */
|
danielebarchiesi@0
|
825 function _openid_math_powmod($x, $y, $z) {
|
danielebarchiesi@0
|
826 $library = _openid_get_math_library();
|
danielebarchiesi@0
|
827 switch ($library) {
|
danielebarchiesi@0
|
828 case 'gmp':
|
danielebarchiesi@0
|
829 return gmp_powm($x, $y, $z);
|
danielebarchiesi@0
|
830 case 'bcmath':
|
danielebarchiesi@0
|
831 return bcpowmod($x, $y, $z);
|
danielebarchiesi@0
|
832 }
|
danielebarchiesi@0
|
833 }
|
danielebarchiesi@0
|
834
|
danielebarchiesi@0
|
835 /**
|
danielebarchiesi@0
|
836 * Provides transition for accounts with possibly invalid OpenID identifiers in authmap.
|
danielebarchiesi@0
|
837 *
|
danielebarchiesi@0
|
838 * This function provides a less safe but more unobtrusive procedure for users
|
danielebarchiesi@0
|
839 * who cannot login with their OpenID identifiers. OpenID identifiers in the
|
danielebarchiesi@0
|
840 * authmap could be incomplete due to invalid OpenID implementation in previous
|
danielebarchiesi@0
|
841 * versions of Drupal (e.g. fragment part of the identifier could be missing).
|
danielebarchiesi@0
|
842 * For more information see http://drupal.org/node/1120290.
|
danielebarchiesi@0
|
843 *
|
danielebarchiesi@0
|
844 * @param string $identity
|
danielebarchiesi@0
|
845 * The user's claimed OpenID identifier.
|
danielebarchiesi@0
|
846 *
|
danielebarchiesi@0
|
847 * @return
|
danielebarchiesi@0
|
848 * A fully-loaded user object if the user is found or FALSE if not found.
|
danielebarchiesi@0
|
849 */
|
danielebarchiesi@0
|
850 function _openid_invalid_openid_transition($identity, $response) {
|
danielebarchiesi@0
|
851 $account = FALSE;
|
danielebarchiesi@0
|
852 $fallback_account = NULL;
|
danielebarchiesi@0
|
853 $fallback_identity = $identity;
|
danielebarchiesi@0
|
854
|
danielebarchiesi@0
|
855 // Try to strip the fragment if it is present.
|
danielebarchiesi@0
|
856 if (strpos($fallback_identity, '#') !== FALSE) {
|
danielebarchiesi@0
|
857 $fallback_identity = preg_replace('/#.*/', '', $fallback_identity);
|
danielebarchiesi@0
|
858 $fallback_account = user_external_load($fallback_identity);
|
danielebarchiesi@0
|
859 }
|
danielebarchiesi@0
|
860
|
danielebarchiesi@0
|
861 // Try to replace HTTPS with HTTP. OpenID providers often redirect
|
danielebarchiesi@0
|
862 // from http to https, but Drupal didn't follow the redirect.
|
danielebarchiesi@0
|
863 if (!$fallback_account && strpos($fallback_identity, 'https://') !== FALSE) {
|
danielebarchiesi@0
|
864 $fallback_identity = str_replace('https://', 'http://', $fallback_identity);
|
danielebarchiesi@0
|
865 $fallback_account = user_external_load($fallback_identity);
|
danielebarchiesi@0
|
866 }
|
danielebarchiesi@0
|
867
|
danielebarchiesi@0
|
868 // Try to use original identifier.
|
danielebarchiesi@0
|
869 if (!$fallback_account && isset($_SESSION['openid']['user_login_values']['openid_identifier'])) {
|
danielebarchiesi@0
|
870 $fallback_identity = openid_normalize($_SESSION['openid']['user_login_values']['openid_identifier']);
|
danielebarchiesi@0
|
871 $fallback_account = user_external_load($fallback_identity);
|
danielebarchiesi@0
|
872 }
|
danielebarchiesi@0
|
873
|
danielebarchiesi@0
|
874 if ($fallback_account) {
|
danielebarchiesi@0
|
875 // Try to extract e-mail address from Simple Registration (SREG) or
|
danielebarchiesi@0
|
876 // Attribute Exchanges (AX) keys.
|
danielebarchiesi@0
|
877 $email = '';
|
danielebarchiesi@0
|
878 $sreg_values = openid_extract_namespace($response, OPENID_NS_SREG, 'sreg', TRUE);
|
danielebarchiesi@0
|
879 $ax_values = openid_extract_namespace($response, OPENID_NS_AX, 'ax', TRUE);
|
danielebarchiesi@0
|
880 if (!empty($sreg_values['email']) && valid_email_address($sreg_values['email'])) {
|
danielebarchiesi@0
|
881 $email = $sreg_values['email'];
|
danielebarchiesi@0
|
882 }
|
danielebarchiesi@0
|
883 elseif ($ax_mail_values = openid_extract_ax_values($ax_values, array('http://axschema.org/contact/email', 'http://schema.openid.net/contact/email'))) {
|
danielebarchiesi@0
|
884 $email = current($ax_mail_values);
|
danielebarchiesi@0
|
885 }
|
danielebarchiesi@0
|
886
|
danielebarchiesi@0
|
887 // If this e-mail address is the same as the e-mail address found in user
|
danielebarchiesi@0
|
888 // account, login the user and update the claimed identifier.
|
danielebarchiesi@0
|
889 if ($email && ($email == $fallback_account->mail || $email == $fallback_account->init)) {
|
danielebarchiesi@0
|
890 $query = db_insert('authmap')
|
danielebarchiesi@0
|
891 ->fields(array(
|
danielebarchiesi@0
|
892 'authname' => $identity,
|
danielebarchiesi@0
|
893 'uid' => $fallback_account->uid,
|
danielebarchiesi@0
|
894 'module' => 'openid',
|
danielebarchiesi@0
|
895 ))
|
danielebarchiesi@0
|
896 ->execute();
|
danielebarchiesi@0
|
897 drupal_set_message(t('New OpenID identifier %identity was added as a replacement for invalid identifier %invalid_identity. To finish the invalid OpenID transition process, please go to your <a href="@openid_url">OpenID identities page</a> and remove the old identifier %invalid_identity.', array('%invalid_identity' => $fallback_identity, '%identity' => $identity, '@openid_url' => 'user/' . $fallback_account->uid . '/openid')));
|
danielebarchiesi@0
|
898 // Set the account to the found one.
|
danielebarchiesi@0
|
899 $account = $fallback_account;
|
danielebarchiesi@0
|
900 }
|
danielebarchiesi@0
|
901 else {
|
danielebarchiesi@0
|
902 drupal_set_message(t('There is already an existing account associated with the OpenID identifier that you have provided. However, due to a bug in the previous version of the authentication system, we can\'t be sure that this account belongs to you. If you are new on this site, please continue registering the new user account. If you already have a registered account on this site associated with the provided OpenID identifier, please try to <a href="@url_password">reset the password</a> or contact the site administrator.', array('@url_password' => 'user/password')), 'warning');
|
danielebarchiesi@0
|
903 }
|
danielebarchiesi@0
|
904 }
|
danielebarchiesi@0
|
905
|
danielebarchiesi@0
|
906 return $account;
|
danielebarchiesi@0
|
907 }
|