dolibarr  13.0.2
openid.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2013 Laurent Destailleur <eldy@users.sourceforge.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
28 {
29  public $openid_url_identity;
30  public $URLs = array();
31  public $error = array();
32  public $fields = array(
33  'required' => array(),
34  'optional' => array(),
35  );
36 
40  public function __construct()
41  {
42  if (!function_exists('curl_exec'))
43  {
44  die('Error: Class SimpleOpenID requires curl extension to work');
45  }
46  }
47 
48  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
55  public function SetOpenIDServer($a)
56  {
57  // phpcs:enable
58  $this->URLs['openid_server'] = $a;
59  }
60 
61  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
68  public function SetTrustRoot($a)
69  {
70  // phpcs:enable
71  $this->URLs['trust_root'] = $a;
72  }
73 
74  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
81  public function SetCancelURL($a)
82  {
83  // phpcs:enable
84  $this->URLs['cancel'] = $a;
85  }
86 
87  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
94  public function SetApprovedURL($a)
95  {
96  // phpcs:enable
97  $this->URLs['approved'] = $a;
98  }
99 
100  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
107  public function SetRequiredFields($a)
108  {
109  // phpcs:enable
110  if (is_array($a)) {
111  $this->fields['required'] = $a;
112  } else {
113  $this->fields['required'][] = $a;
114  }
115  }
116 
117  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
124  public function SetOptionalFields($a)
125  {
126  // phpcs:enable
127  if (is_array($a)) {
128  $this->fields['optional'] = $a;
129  } else {
130  $this->fields['optional'][] = $a;
131  }
132  }
133 
134  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
141  public function SetIdentity($a)
142  {
143  // phpcs:enable
144  // Set Identity URL
145  if ((stripos($a, 'http://') === false)
146  && (stripos($a, 'https://') === false)) {
147  $a = 'http://'.$a;
148  }
149  /*
150  $u = parse_url(trim($a));
151  if (!isset($u['path'])){
152  $u['path'] = '/';
153  }else if(substr($u['path'],-1,1) == '/'){
154  $u['path'] = substr($u['path'], 0, strlen($u['path'])-1);
155  }
156  if (isset($u['query'])){ // If there is a query string, then use identity as is
157  $identity = $a;
158  }else{
159  $identity = $u['scheme'] . '://' . $u['host'] . $u['path'];
160  }
161  */
162  $this->openid_url_identity = $a;
163  }
164 
165  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
171  public function GetIdentity()
172  {
173  // phpcs:enable
174  // Get Identity
175  return $this->openid_url_identity;
176  }
177 
178  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
184  public function GetError()
185  {
186  // phpcs:enable
187  $e = $this->error;
188  return array('code'=>$e[0], 'description'=>$e[1]);
189  }
190 
191  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
199  public function ErrorStore($code, $desc = null)
200  {
201  // phpcs:enable
202  $errs['OPENID_NOSERVERSFOUND'] = 'Cannot find OpenID Server TAG on Identity page.';
203  if ($desc == null) {
204  $desc = $errs[$code];
205  }
206  $this->error = array($code, $desc);
207  }
208 
209  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
215  public function IsError()
216  {
217  // phpcs:enable
218  if (count($this->error) > 0)
219  {
220  return true;
221  } else {
222  return false;
223  }
224  }
225 
232  public function splitResponse($response)
233  {
234  $r = array();
235  $response = explode("\n", $response);
236  foreach ($response as $line) {
237  $line = trim($line);
238  if ($line != "") {
239  list($key, $value) = explode(":", $line, 2);
240  $r[trim($key)] = trim($value);
241  }
242  }
243  return $r;
244  }
245 
246  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
253  public function OpenID_Standarize($openid_identity = null)
254  {
255  // phpcs:enable
256  if ($openid_identity === null)
257  $openid_identity = $this->openid_url_identity;
258 
259  $u = parse_url(strtolower(trim($openid_identity)));
260 
261  if (!isset($u['path']) || ($u['path'] == '/')) {
262  $u['path'] = '';
263  }
264  if (substr($u['path'], -1, 1) == '/') {
265  $u['path'] = substr($u['path'], 0, strlen($u['path']) - 1);
266  }
267  if (isset($u['query'])) { // If there is a query string, then use identity as is
268  return $u['host'].$u['path'].'?'.$u['query'];
269  } else {
270  return $u['host'].$u['path'];
271  }
272  }
273 
280  public function array2url($arr)
281  {
282  // converts associated array to URL Query String
283  if (!is_array($arr)) {
284  return false;
285  }
286  $query = '';
287  foreach ($arr as $key => $value) {
288  $query .= $key."=".$value."&";
289  }
290  return $query;
291  }
292 
293  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
302  public function FSOCK_Request($url, $method = "GET", $params = "")
303  {
304  // phpcs:enable
305  $fp = fsockopen("ssl://www.myopenid.com", 443, $errno, $errstr, 3); // Connection timeout is 3 seconds
306  if (!$fp) {
307  $this->ErrorStore('OPENID_SOCKETERROR', $errstr);
308  return false;
309  } else {
310  $request = $method." /server HTTP/1.0\r\n";
311  $request .= "User-Agent: Dolibarr\r\n";
312  $request .= "Connection: close\r\n\r\n";
313  fwrite($fp, $request);
314  stream_set_timeout($fp, 4); // Connection response timeout is 4 seconds
315  $res = fread($fp, 2000);
316  $info = stream_get_meta_data($fp);
317  fclose($fp);
318 
319  if ($info['timed_out']) {
320  $this->ErrorStore('OPENID_SOCKETTIMEOUT');
321  } else {
322  return $res;
323  }
324  }
325  }
326 
327  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
336  public function CURL_Request($url, $method = "GET", $params = "")
337  {
338  // phpcs:enable
339  // Remember, SSL MUST BE SUPPORTED
340  if (is_array($params)) $params = $this->array2url($params);
341 
342  $curl = curl_init($url.($method == "GET" && $params != "" ? "?".$params : ""));
343  @curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
344  curl_setopt($curl, CURLOPT_HEADER, false);
345  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
346  curl_setopt($curl, CURLOPT_HTTPGET, ($method == "GET"));
347  curl_setopt($curl, CURLOPT_POST, ($method == "POST"));
348  if ($method == "POST") curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
349  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
350  $response = curl_exec($curl);
351 
352  if (curl_errno($curl) == 0) {
353  $response;
354  } else {
355  $this->ErrorStore('OPENID_CURL', curl_error($curl));
356  }
357  return $response;
358  }
359 
360  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
367  public function HTML2OpenIDServer($content)
368  {
369  // phpcs:enable
370  $get = array();
371 
372  // Get details of their OpenID server and (optional) delegate
373  preg_match_all('/<link[^>]*rel=[\'"]openid.server[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
374  preg_match_all('/<link[^>]*href=\'"([^\'"]+)[\'"][^>]*rel=[\'"]openid.server[\'"][^>]*\/?>/i', $content, $matches2);
375  $servers = array_merge($matches1[1], $matches2[1]);
376 
377  preg_match_all('/<link[^>]*rel=[\'"]openid.delegate[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
378 
379  preg_match_all('/<link[^>]*href=[\'"]([^\'"]+)[\'"][^>]*rel=[\'"]openid.delegate[\'"][^>]*\/?>/i', $content, $matches2);
380 
381  $delegates = array_merge($matches1[1], $matches2[1]);
382 
383  $ret = array($servers, $delegates);
384  return $ret;
385  }
386 
387 
388  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
395  public function GetOpenIDServer($url = '')
396  {
397  // phpcs:enable
398  global $conf;
399 
400  include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
401  if (empty($url)) $url = $conf->global->MAIN_AUTHENTICATION_OPENID_URL;
402 
403  $response = getURLContent($url);
404 
405  list($servers, $delegates) = $this->HTML2OpenIDServer($response);
406  if (count($servers) == 0) {
407  $this->ErrorStore('OPENID_NOSERVERSFOUND');
408  return false;
409  }
410  if (isset($delegates[0])
411  && ($delegates[0] != "")) {
412  $this->SetIdentity($delegates[0]);
413  }
414  $this->SetOpenIDServer($servers[0]);
415  return $servers[0];
416  }
417 
418  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
424  public function GetRedirectURL()
425  {
426  // phpcs:enable
427  $params = array();
428  $params['openid.return_to'] = urlencode($this->URLs['approved']);
429  $params['openid.mode'] = 'checkid_setup';
430  $params['openid.identity'] = urlencode($this->openid_url_identity);
431  $params['openid.trust_root'] = urlencode($this->URLs['trust_root']);
432 
433  if (isset($this->fields['required'])
434  && (count($this->fields['required']) > 0)) {
435  $params['openid.sreg.required'] = implode(',', $this->fields['required']);
436  }
437  if (isset($this->fields['optional'])
438  && (count($this->fields['optional']) > 0)) {
439  $params['openid.sreg.optional'] = implode(',', $this->fields['optional']);
440  }
441  return $this->URLs['openid_server']."?".$this->array2url($params);
442  }
443 
444  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
450  public function Redirect()
451  {
452  // phpcs:enable
453  $redirect_to = $this->GetRedirectURL();
454  if (headers_sent())
455  { // Use JavaScript to redirect if content has been previously sent (not recommended, but safe)
456  echo '<script language="JavaScript" type="text/javascript">window.location=\'';
457  echo $redirect_to;
458  echo '\';</script>';
459  } else { // Default Header Redirect
460  header('Location: '.$redirect_to);
461  }
462  }
463 
464  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
470  public function ValidateWithServer()
471  {
472  // phpcs:enable
473  $params = array(
474  'openid.assoc_handle' => urlencode($_GET['openid_assoc_handle']),
475  'openid.signed' => urlencode($_GET['openid_signed']),
476  'openid.sig' => urlencode($_GET['openid_sig'])
477  );
478  // Send only required parameters to confirm validity
479  $arr_signed = explode(",", str_replace('sreg.', 'sreg_', $_GET['openid_signed']));
480  $num = count($arr_signed);
481  for ($i = 0; $i < $num; $i++)
482  {
483  $s = str_replace('sreg_', 'sreg.', $arr_signed[$i]);
484  $c = $_GET['openid_'.$arr_signed[$i]];
485  // if ($c != ""){
486  $params['openid.'.$s] = urlencode($c);
487  // }
488  }
489  $params['openid.mode'] = "check_authentication";
490 
491  $openid_server = $this->GetOpenIDServer();
492  if ($openid_server == false)
493  {
494  return false;
495  }
496  $response = $this->CURL_Request($openid_server, 'POST', $params);
497  $data = $this->splitResponse($response);
498  if ($data['is_valid'] == "true")
499  {
500  return true;
501  } else {
502  return false;
503  }
504  }
505 
506 
507 
508 
515  public function sendDiscoveryRequestToGetXRDS($url = '')
516  {
517  global $conf;
518 
519  include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
520  if (empty($url)) $url = $conf->global->MAIN_AUTHENTICATION_OPENID_URL;
521 
522  dol_syslog(get_class($this).'::sendDiscoveryRequestToGetXRDS get XRDS');
523 
524  $addheaders = array('Accept: application/xrds+xml');
525  $response = getURLContent($url, 'GET', '', 1, $addheaders);
526  /* response should like this:
527  <?xml version="1.0" encoding="UTF-8"?>
528  <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
529  <XRD>
530  <Service priority="0">
531  <Type>http://specs.openid.net/auth/2.0/server</Type>
532  <Type>http://openid.net/srv/ax/1.0</Type>
533  ...
534  <URI>https://www.google.com/accounts/o8/ud</URI>
535  </Service>
536  </XRD>
537  </xrds:XRDS>
538  */
539  $content = $response['content'];
540 
541  $server = '';
542  if (preg_match('/'.preg_quote('<URI>', '/').'(.*)'.preg_quote('</URI>', '/').'/is', $content, $reg))
543  {
544  $server = $reg[1];
545  }
546 
547  if (empty($server))
548  {
549  $this->ErrorStore('OPENID_NOSERVERSFOUND');
550  return false;
551  } else {
552  dol_syslog(get_class($this).'::sendDiscoveryRequestToGetXRDS found endpoint = '.$server);
553  $this->SetOpenIDServer($server);
554  return $server;
555  }
556  }
557 }
SetOptionalFields($a)
SetOptionalFields.
sendDiscoveryRequestToGetXRDS($url= '')
Get XRDS response and set possible servers.
GetOpenIDServer($url= '')
Get openid server.
SetApprovedURL($a)
SetApprovedURL.
SetOpenIDServer($a)
SetOpenIDServer.
GetIdentity()
GetIdentity.
HTML2OpenIDServer($content)
HTML2OpenIDServer.
foreach($object->fields as $key=> $val) if(is_array($extrafields->attributes[$object->table_element]['label'])&&count($extrafields->attributes[$object->table_element]['label']) > 0) $object fields
array2url($arr)
array2url
SetIdentity($a)
SetIdentity.
getURLContent($url, $postorget= 'GET', $param= '', $followlocation=1, $addheaders=array(), $allowedschemes=array('http', 'https'), $localurl=0)
Function to get a content from an URL (use proxy if proxy defined).
Definition: geturl.lib.php:38
GetRedirectURL()
GetRedirectURL.
IsError()
IsError.
ErrorStore($code, $desc=null)
ErrorStore.
SetRequiredFields($a)
SetRequiredFields.
SetCancelURL($a)
SetOpenIDServer.
SetTrustRoot($a)
SetOpenIDServer.
CURL_Request($url, $method="GET", $params="")
CURL_Request.
OpenID_Standarize($openid_identity=null)
OpenID_Standarize.
FSOCK_Request($url, $method="GET", $params="")
FSOCK_Request.
splitResponse($response)
splitResponse
GetError()
SetOpenIDServer.
__construct()
Constructor.
Redirect()
Redirect.
Class to manage OpenID.