00001 <?php
00026
00027
00028
00029
00030
00031
00032 require_once 'Services/Yadis/Yadis.php';
00033
00034
00035 class Dope_OpenID
00036 {
00037 public $fields = array('required' => array(),'optional' => array());
00038
00039 public $arr_userinfo = array();
00040
00041
00042 private $arr_ax_types = array(
00043 'nickname' => 'http://axschema.org/namePerson/friendly',
00044 'email' => 'http://axschema.org/contact/email',
00045 'fullname' => 'http://axschema.org/namePerson',
00046 'dob' => 'http://axschema.org/birthDate',
00047 'gender' => 'http://axschema.org/person/gender',
00048 'postcode' => 'http://axschema.org/contact/postalCode/home',
00049 'country' => 'http://axschema.org/contact/country/home',
00050 'language' => 'http://axschema.org/pref/language',
00051 'timezone' => 'http://axschema.org/pref/timezone',
00052 'prefix' => 'http://axschema.org/namePerson/prefix',
00053 'firstname' => 'http://axschema.org/namePerson/first',
00054 'lastname' => 'http://axschema.org/namePerson/last',
00055 'suffix' => 'http://axschema.org/namePerson/suffix'
00056 );
00057
00058 private $openid_url_identity;
00059 private $openid_ns;
00060 private $openid_version;
00061
00062 private $error = array();
00063 private $URLs = array();
00064
00065
00066 public function Dope_OpenID($identity)
00067 {
00068 $this->__construct($identity);
00069 }
00070
00071
00072 public function __construct($identity)
00073 {
00074 if ( ! $identity) {
00075 $this->errorStore('OPENID_NOIDENTITY','No identity passed to Dope OpenID constructor.');
00076 return FALSE;
00077 }
00078
00079
00080 if ( ! function_exists('curl_exec')) {
00081 die('Error: Dope OpenID requires the PHP cURL extension.');
00082 }
00083
00084
00085 $this->setIdentity($identity);
00086 }
00087
00088 public function setReturnURL($url)
00089 {
00090 $this->URLs['return'] = $url;
00091 }
00092
00093 public function setTrustRoot($url)
00094 {
00095 $this->URLs['trust_root'] = $url;
00096 }
00097
00098 public function setCancelURL($url)
00099 {
00100 $this->URLs['cancel'] = $url;
00101 }
00102
00103 public function setRequiredInfo($fields)
00104 {
00105 if (is_array($fields)){
00106 $this->fields['required'] = $fields;
00107 }
00108 else {
00109 $this->fields['required'][] = $fields;
00110 }
00111 }
00112
00113 public function setOptionalInfo($fields)
00114 {
00115 if (is_array($fields)) {
00116 $this->fields['optional'] = $fields;
00117 }
00118 else {
00119 $this->fields['optional'][] = $fields;
00120 }
00121 }
00122
00123 public function setPapePolicies($policies)
00124 {
00125 if (is_array($policies)) {
00126 $this->fields['pape_policies'] = $policies;
00127 }
00128 else {
00129 $this->fields['pape_policies'][] = $policies;
00130 }
00131 }
00132
00133 public function setPapeMaxAuthAge($seconds){
00134
00135
00136 if(preg_match("/^[1-9]+[0-9]*$/",$seconds)){
00137 $this->fields['pape_max_auth_age'] = $seconds;
00138 }
00139 else {
00140 $this->errorStore('OPENID_MAXAUTHAGE','Max Auth Age must be a numeric value greater than or equal to zero in seconds.');
00141 return FALSE;
00142 }
00143 }
00144
00145 public function isError()
00146 {
00147 if ( ! empty($this->error)) {
00148 return TRUE;
00149 }
00150 else{
00151 return FALSE;
00152 }
00153 }
00154
00155 public function getError()
00156 {
00157 $the_error = $this->error;
00158 return array('code'=>$the_error[0],'description'=>$the_error[1]);
00159 }
00160
00161
00162
00163
00164 public function getOpenIDEndpoint()
00165 {
00166
00167 $http_response = array();
00168 $fetcher = Services_Yadis_Yadis::getHTTPFetcher();
00169 $yadis_object = Services_Yadis_Yadis::discover($this->openid_url_identity, $http_response, $fetcher);
00170
00171
00172 if($yadis_object != NULL) {
00173
00174 $service_list = $yadis_object->services();
00175 $service_types = $service_list[0]->getTypes();
00176
00177 $servers = $service_list[0]->getURIs();
00178 $delegates = $service_list[0]->getElements('openid:Delegate');
00179
00180 }
00181
00182 else {
00183 $response = $this->makeCURLRequest($this->openid_url_identity);
00184 list($servers, $delegates) = $this->parseHTML($response);
00185 }
00186
00187
00188 if (empty($servers)){
00189 $this->errorStore('OPENID_NOSERVERSFOUND');
00190 return FALSE;
00191 }
00192
00193
00194 if (isset($service_types[0]) && ($service_types[0] != "")) {
00195 $this->setServiceType($service_types[0]);
00196 }
00197
00198
00199 if (isset($delegates[0]) && ($delegates[0] != "")) {
00200 $this->setIdentity($delegates[0]);
00201 }
00202
00203 $this->setOpenIDEndpoint($servers[0]);
00204
00205 return $servers[0];
00206 }
00207
00208
00209
00210
00211 public function redirect()
00212 {
00213 $redirect_to = $this->getRedirectURL();
00214
00215 if (headers_sent()) {
00216
00217
00218 echo '<script language="JavaScript" type="text/javascript">window.location=\'';
00219 echo $redirect_to;
00220 echo '\';</script>';
00221 }
00222 // Else we can use PHP header() redirect
00223 else {
00224 header('Location: ' . $redirect_to);
00225 }
00226 }
00227
00228 /*
00229 * Method to validate information with the OpenID Provider
00230 */
00231 public function validateWithServer()
00232 {
00233
00234 $params = array();
00235
00236 // Find keys that include dots and store them in an array
00237 preg_match_all("/([\w]+[\.])/",$_GET['openid_signed'],$arr_periods);
00238 $arr_periods = array_unique(array_shift($arr_periods));
00239
00240 // Duplicate the dot keys array, but replace the dot with an underscore
00241 $arr_underscores = preg_replace("/\./","_",$arr_periods);
00242
00243 // The OpenID Provider returns a list of signed keys we need to validate
00244 $arr_get_signed_keys = explode(",",str_replace($arr_periods, $arr_underscores, $_GET['openid_signed']));
00245
00246 // Send back only the signed keys to confirm validity
00247 foreach($arr_get_signed_keys as $key) {
00248 $paramKey = str_replace($arr_underscores, $arr_periods, $key);
00249 $params["openid.$paramKey"] = urlencode($_GET["openid_$key"]);
00250 }
00251
00252 // If we're using OpenID 2.0 specs, we must include these values also
00253 if($this->openid_version != "2.0"){
00254 $params['openid.assoc_handle'] = urlencode($_GET['openid_assoc_handle']);
00255 $params['openid.signed'] = urlencode($_GET['openid_signed']);
00256 }
00257
00258 $params['openid.sig'] = urlencode($_GET['openid_sig']);
00259 $params['openid.mode'] = "check_authentication";
00260
00261 $endpoint_url = $this->getOpenIDEndpoint();
00262
00263 if ($endpoint_url == FALSE) {
00264 return FALSE;
00265 }
00266
00267
00268 $response = $this->makeCURLRequest($endpoint_url,'POST',$params);
00269 $data = $this->splitResponse($response);
00270
00271
00272 if ($data['is_valid'] == "true") {
00273 return TRUE;
00274 }else{
00275 return FALSE;
00276 }
00277 }
00278
00279
00280
00281
00282
00283 public function filterUserInfo($arr_get)
00284 {
00285 foreach($arr_get as $key => $value){
00286 $trimmed_key = substr($key,strrpos($key,"_")+1);
00287 if(stristr($key, 'openid_ext1_value') && isset($value[1])) {
00288 $this->arr_userinfo[$trimmed_key] = $value;
00289 }
00290 if( (stristr($key, 'sreg_') || stristr($key, 'ax_value_')) &&
00291 array_key_exists($trimmed_key, $this->arr_ax_types)) {
00292 $this->arr_userinfo[$trimmed_key] = $value;
00293 }
00294 }
00295 return $this->arr_userinfo;
00296 }
00297
00298
00299
00300
00301
00302
00303 private function setIdentity($identity)
00304 {
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 if ((stripos($identity, 'http://') === FALSE) &&
00328 (stripos($identity, 'https://') === FALSE)) {
00329 $identity = 'http://'.$identity;
00330 }
00331
00332
00333
00334 if (stripos($identity, 'gmail') OR stripos($identity, 'google')) {
00335 $identity = "https://www.google.com/accounts/o8/id";
00336 }
00337 $this->openid_url_identity = $identity;
00338 }
00339
00340 private function getIdentity()
00341 {
00342 return $this->openid_url_identity;
00343 }
00344
00345
00346
00347
00348 private function makeCURLRequest($url, $method="GET", $params = "")
00349 {
00350 if (is_array($params)) {
00351 $params = $this->createQueryString($params);
00352 }
00353
00354 $curl = curl_init($url . ($method == "GET" && $params != "" ? "?" . $params : ""));
00355
00356
00357 curl_setopt($curl, CURLOPT_HEADER, FALSE);
00358 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
00359 curl_setopt($curl, CURLOPT_HTTPGET, ($method == "GET"));
00360 curl_setopt($curl, CURLOPT_POST, ($method == "POST"));
00361 curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
00362 curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
00363 if ($method == "POST") {
00364 curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
00365 }
00366
00367 $response = curl_exec($curl);
00368
00369 if (curl_errno($curl) == 0) {
00370 $response;
00371 }
00372 else {
00373 $this->errorStore('OPENID_CURL', curl_error($curl));
00374 }
00375
00376 return $response;
00377 }
00378
00379 private function parseHTML($content)
00380 {
00381 $ret = array();
00382
00383
00384 preg_match_all('/<link[^>]*rel=[\'"]openid.server[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
00385 preg_match_all('/<link[^>]*rel=[\'"]openid2.provider[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches2);
00386 preg_match_all('/<link[^>]*href=\'"([^\'"]+)[\'"][^>]*rel=[\'"]openid.server[\'"][^>]*\/?>/i', $content, $matches3);
00387 preg_match_all('/<link[^>]*href=\'"([^\'"]+)[\'"][^>]*rel=[\'"]openid2.provider[\'"][^>]*\/?>/i', $content, $matches4);
00388
00389 $servers = array_merge($matches1[1], $matches2[1], $matches3[1], $matches4[1]);
00390
00391 preg_match_all('/<link[^>]*rel=[\'"]openid.delegate[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
00392 preg_match_all('/<link[^>]*rel=[\'"]openid2.local_id[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches2);
00393 preg_match_all('/<link[^>]*href=[\'"]([^\'"]+)[\'"][^>]*rel=[\'"]openid.delegate[\'"][^>]*\/?>/i', $content, $matches3);
00394 preg_match_all('/<link[^>]*href=[\'"]([^\'"]+)[\'"][^>]*rel=[\'"]openid2.local_id[\'"][^>]*\/?>/i', $content, $matches4);
00395
00396 $delegates = array_merge($matches1[1], $matches2[1], $matches3[1], $matches4[1]);
00397
00398 $ret = array($servers, $delegates);
00399 return $ret;
00400 }
00401
00402 private function splitResponse($response)
00403 {
00404 $r = array();
00405 $response = explode("\n", $response);
00406 foreach($response as $line) {
00407 $line = trim($line);
00408 if ($line != "") {
00409 list($key, $value) = explode(":", $line, 2);
00410 $r[trim($key)] = trim($value);
00411 }
00412 }
00413 return $r;
00414 }
00415
00416 private function createQueryString($array_params)
00417 {
00418 if ( ! is_array($array_params)) {
00419 return FALSE;
00420 }
00421
00422 $query = "";
00423
00424 foreach($array_params as $key => $value){
00425 $query .= $key . "=" . $value . "&";
00426 }
00427
00428 return $query;
00429 }
00430
00431 private function setOpenIDEndpoint($url)
00432 {
00433 $this->URLs['openid_server'] = $url;
00434 }
00435
00436 private function setServiceType($url)
00437 {
00438
00439
00440
00441
00442
00443 if (stristr($url, "2.0")) {
00444 $ns = "http://specs.openid.net/auth/2.0";
00445 $version = "2.0";
00446 }
00447 else if (stristr($url, "1.1")) {
00448 $ns = "http://openid.net/signon/1.1";
00449 $version = "1.1";
00450 }
00451 else {
00452 $ns = "http://openid.net/signon/1.0";
00453 $version = "1.0";
00454 }
00455 $this->openid_ns = $ns;
00456 $this->openid_version = $version;
00457 }
00458
00459 function getRedirectURL()
00460 {
00461 $params = array();
00462
00463 $params['openid.return_to'] = urlencode($this->URLs['return']);
00464 $params['openid.identity'] = urlencode($this->openid_url_identity);
00465
00466 if($this->openid_version == "2.0"){
00467 $params['openid.ns'] = urlencode($this->openid_ns);
00468 $params['openid.claimed_id'] = urlencode("http://specs.openid.net/auth/2.0/identifier_select");
00469 $params['openid.identity'] = urlencode("http://specs.openid.net/auth/2.0/identifier_select");
00470 $params['openid.realm'] = urlencode($this->URLs['trust_root']);
00471 }
00472 else {
00473 $params['openid.trust_root'] = urlencode($this->URLs['trust_root']);
00474 }
00475
00476 $params['openid.mode'] = 'checkid_setup';
00477
00481 $info_request = FALSE;
00482
00483
00484 if (isset($this->fields['required']) OR isset($this->fields['optional'])) {
00485 $params['openid.ns.ax'] = "http://openid.net/srv/ax/1.0";
00486 $params['openid.ax.mode'] = "fetch_request";
00487 $params['openid.ns.sreg'] = "http://openid.net/extensions/sreg/1.1";
00488
00489 $info_request = TRUE;
00490 }
00491
00492
00493 if (stristr($this->URLs['openid_server'], 'myopenid.com') && $info_request == TRUE) {
00494 $this->arr_ax_types = preg_replace("/axschema.org/","schema.openid.net",$this->arr_ax_types);
00495 }
00496
00497
00498
00499 if (stristr($this->URLs['openid_server'], 'google.com') && $info_request == TRUE) {
00500 $this->fields['required'] = array_unique(array_merge($this->fields['optional'], $this->fields['required']));
00501 $this->fields['optional'] = array();
00502 }
00503
00504
00505 if (isset($this->fields['required']) && ( ! empty($this->fields['required']))) {
00506
00507
00508 $params['openid.ax.required'] = implode(',',$this->fields['required']);
00509
00510 foreach($this->fields['required'] as $field) {
00511 if(array_key_exists($field,$this->arr_ax_types)) {
00512 $params["openid.ax.type.$field"] = urlencode($this->arr_ax_types[$field]);
00513 }
00514 }
00515
00516
00517 $params['openid.sreg.required'] = implode(',',$this->fields['required']);
00518 }
00519
00520
00521 if (isset($this->fields['optional']) && ( ! empty($this->fields['optional']))) {
00522
00523 $params['openid.ax.if_available'] = implode(',',$this->fields['optional']);
00524
00525 foreach($this->fields['optional'] as $field) {
00526 if(array_key_exists($field,$this->arr_ax_types)) {
00527 $params["openid.ax.type.$field"] = urlencode($this->arr_ax_types[$field]);
00528 }
00529 }
00530
00531 $params['openid.sreg.optional'] = implode(',',$this->fields['optional']);
00532 }
00533
00534
00535 if (isset($this->fields['pape_policies']) && ( ! empty($this->fields['pape_policies']))) {
00536 $params['openid.ns.pape'] = "http://specs.openid.net/extensions/pape/1.0";
00537 $params['openid.pape.preferred_auth_policies'] = urlencode(implode(' ',$this->fields['pape_policies']));
00538
00539 if($this->fields['pape_max_auth_age']) {
00540 $params['openid.pape.max_auth_age'] = $this->fields['pape_max_auth_age'];
00541 }
00542 }
00543
00544 $urlJoiner = (strstr($this->URLs['openid_server'], "?")) ? "&" : "?";
00545
00546 return $this->URLs['openid_server'] . $urlJoiner . $this->createQueryString($params);
00547
00548 }
00549
00550 private function errorStore($code, $desc = NULL)
00551 {
00552 $errs['OPENID_NOSERVERSFOUND'] = 'Cannot find OpenID Server TAG on Identity page.';
00553
00554 if ($desc == NULL){
00555 $desc = $errs[$code];
00556 }
00557
00558 $this->error = array($code,$desc);
00559 }
00560 }
00561
00562 ?>