163 require_once
"Auth/OpenID.php";
164 require_once
"Auth/OpenID/Message.php";
165 require_once
"Auth/OpenID/HMAC.php";
166 require_once
"Auth/OpenID/Association.php";
167 require_once
"Auth/OpenID/CryptUtil.php";
168 require_once
"Auth/OpenID/DiffieHellman.php";
169 require_once
"Auth/OpenID/KVForm.php";
170 require_once
"Auth/OpenID/Nonce.php";
171 require_once
"Auth/OpenID/Discover.php";
172 require_once
"Auth/OpenID/URINorm.php";
173 require_once
"Auth/Yadis/Manager.php";
174 require_once
"Auth/Yadis/XRI.php";
180 define(
'Auth_OpenID_SUCCESS',
'success');
185 define(
'Auth_OpenID_CANCEL',
'cancel');
191 define(
'Auth_OpenID_FAILURE',
'failure');
199 define(
'Auth_OpenID_SETUP_NEEDED',
'setup needed');
206 define(
'Auth_OpenID_PARSE_ERROR',
'parse error');
262 $consumer_cls = null)
264 if ($session === null) {
268 $this->session = $session;
270 if ($consumer_cls !== null) {
271 $this->consumer =
new $consumer_cls($store);
313 function begin($user_url, $anonymous=
false)
315 $openid_url = $user_url;
319 $this->session_key_prefix);
325 $m = $disco->getManager();
330 $disco->destroyManager();
333 $disco->session->set($disco->session_key,
334 serialize(
$loader->toSession($m)));
338 $endpoint = $disco->getNextService($this->discoverMethod,
339 $this->consumer->fetcher);
342 $m = $disco->getManager();
345 $disco->session->set($disco->session_key,
346 serialize(
$loader->toSession($m)));
349 if ($endpoint === null) {
376 $auth_req = $this->consumer->begin($endpoint);
377 $this->session->set($this->_token_key,
378 $loader->toSession($auth_req->endpoint));
379 if (!$auth_req->setAnonymous($anonymous)) {
381 "OpenID 1 requests MUST include the identifier " .
412 if ($current_url && !is_string($current_url)) {
415 trigger_error(
"current_url must be a string; see NEWS file " .
416 "for upgrading notes.",
425 $endpoint_data = $this->session->get($this->_token_key);
427 $loader->fromSession($endpoint_data);
430 $response = $this->consumer->complete($message, $endpoint,
432 $this->session->del($this->_token_key);
436 if ($response->identity_url !== null) {
438 $response->identity_url,
439 $this->session_key_prefix);
440 $disco->cleanup(
true);
472 $cpub = $math->longToBase64($this->dh->public);
474 $args = array(
'dh_consumer_public' => $cpub);
476 if (!$this->dh->usingDefaultValues()) {
477 $args = array_merge($args, array(
479 $math->longToBase64($this->dh->mod),
481 $math->longToBase64($this->dh->gen)));
490 'dh_server_public')) {
502 'dh_server_public'));
506 return $this->dh->xorSecret($spub, $enc_mac_key, $this->hash_func);
554 'no-encryption' =>
'Auth_OpenID_PlainTextConsumerSession',
555 'DH-SHA1' =>
'Auth_OpenID_DiffieHellmanSHA1ConsumerSession',
556 'DH-SHA256' =>
'Auth_OpenID_DiffieHellmanSHA256ConsumerSession');
618 $this->_use_assocs = (is_null($this->store) ?
false :
true);
638 if ($r->message->isOpenID1()) {
640 $r->endpoint->claimed_id;
658 $mode_methods = array(
659 'cancel' =>
'_complete_cancel',
660 'error' =>
'_complete_error',
661 'setup_needed' =>
'_complete_setup_needed',
662 'id_res' =>
'_complete_id_res',
668 return call_user_func_array(array($this, $method),
669 array($message, &$endpoint, $return_to));
681 sprintf(
"Invalid openid.mode '%s'", $mode));
702 $contact, $reference);
710 if (!$message->isOpenID2()) {
729 $endpoint, $user_setup_url);
731 return $this->
_doIdRes($message, $endpoint, $return_to);
743 if ($message->isOpenID1()) {
746 if ($user_setup_url !== null) {
769 sprintf(
"return_to does not match return URL. Expected %s, got %s",
784 $endpoint->server_url);
799 return $signed_list_str;
801 $signed_list = explode(
',', $signed_list_str);
822 $message->toPostArgs());
841 if ((!array_key_exists(
'port', $return_to_parts)) &&
842 (!array_key_exists(
'port', $msg_return_to_parts))) {
843 $return_to_parts[
'port'] = null;
844 $msg_return_to_parts[
'port'] = null;
849 if ((!array_key_exists(
'path', $return_to_parts)) &&
850 (!array_key_exists(
'path', $msg_return_to_parts))) {
851 $return_to_parts[
'path'] = null;
852 $msg_return_to_parts[
'path'] = null;
857 foreach (array(
'scheme',
'host',
'port',
'path') as $component) {
860 if (!array_key_exists($component, $return_to_parts)) {
864 if (!array_key_exists($component, $msg_return_to_parts)) {
894 "Response has no return_to");
897 $parsed_url = parse_url($return_to);
900 if (array_key_exists(
'query', $parsed_url)) {
901 $rt_query = $parsed_url[
'query'];
905 foreach ($q as $rt_key => $rt_value) {
906 if (!array_key_exists($rt_key,
$query)) {
908 sprintf(
"return_to parameter %s absent from query", $rt_key));
911 if ($rt_value != $value) {
913 sprintf(
"parameter %s value %s does not match " .
914 "return_to value %s", $rt_key,
923 foreach ($bare_args as $key => $value) {
926 sprintf(
"Parameter %s = %s not in return_to URL",
942 return $assoc_handle;
945 $assoc = $this->store->getAssociation($server_url, $assoc_handle);
948 if ($assoc->getExpiresIn() <= 0) {
956 'Association with ' . $server_url .
' expired');
959 if (!$assoc->checkMessageSignature($message)) {
968 if (!$this->
_checkAuth($message, $server_url)) {
970 "Server denied check_authentication");
997 $this->openid1_return_to_identifier_name);
999 if (($endpoint === null) && ($claimed_id === null)) {
1001 'When using OpenID 1, the claimed ID must be supplied, ' .
1002 'either by passing it through as a return_to parameter ' .
1003 'or by using a session, and supplied to the GenericConsumer ' .
1004 'as the argument to complete()');
1005 }
else if (($endpoint !== null) && ($claimed_id === null)) {
1006 $claimed_id = $endpoint->claimed_id;
1015 $to_match->claimed_id = $claimed_id;
1017 if ($to_match->local_id === null) {
1019 "Missing required field openid.identity");
1022 $to_match_1_0 = $to_match->copy();
1025 if ($endpoint !== null) {
1028 if (is_a($result,
'Auth_OpenID_TypeURIMismatch')) {
1045 array($to_match, $to_match_1_0));
1055 foreach ($to_match->type_uris as $type_uri) {
1056 if (!$endpoint->usesExtension($type_uri)) {
1058 "Required type ".$type_uri.
" not present");
1065 list($defragged_claimed_id, $_) =
1068 if ($defragged_claimed_id != $endpoint->claimed_id) {
1070 sprintf(
'Claimed ID does not match (different subjects!), ' .
1071 'Expected %s, got %s', $defragged_claimed_id,
1072 $endpoint->claimed_id));
1075 if ($to_match->getLocalID() != $endpoint->getLocalID()) {
1077 sprintf(
'local_id mismatch. Expected %s, got %s',
1078 $to_match->getLocalID(), $endpoint->getLocalID()));
1086 if ($to_match->server_url === null) {
1089 "Preferred namespace mismatch (bug)");
1091 }
else if ($to_match->server_url != $endpoint->server_url) {
1093 sprintf(
'OP Endpoint mismatch. Expected %s, got %s',
1094 $to_match->server_url, $endpoint->server_url));
1116 if ($to_match->server_url === null) {
1118 "OP Endpoint URL missing");
1123 if (($to_match->claimed_id === null) &&
1124 ($to_match->local_id !== null)) {
1126 'openid.identity is present without openid.claimed_id');
1129 if (($to_match->claimed_id !== null) &&
1130 ($to_match->local_id === null)) {
1132 'openid.claimed_id is present without openid.identity');
1135 if ($to_match->claimed_id === null) {
1140 $to_match->server_url);
1169 if ($endpoint->claimed_id != $to_match->claimed_id) {
1170 $endpoint->claimed_id = $to_match->claimed_id;
1182 list($unused, $services) = call_user_func($this->discoverMethod,
1188 sprintf(
"No OpenID information found at %s",
1193 $to_match_endpoints);
1200 $services, $to_match_endpoints)
1205 foreach ($services as $endpoint) {
1206 foreach ($to_match_endpoints as $to_match_endpoint) {
1208 $to_match_endpoint);
1219 sprintf(
'No matching endpoint found after discovering %s: %s',
1220 $claimed_id, $result->message));
1237 $this->openid1_nonce_query_arg_name);
1245 if ($message->isOpenID1()) {
1253 $server_url = $endpoint->server_url;
1256 if ($nonce === null) {
1258 "Nonce missing from response");
1263 if ($parts === null) {
1265 "Malformed nonce in response");
1270 if (!$this->store->useNonce($server_url,
$timestamp, $salt)) {
1272 "Nonce already used or out of range");
1283 $basic_fields = array(
'return_to',
'assoc_handle',
'sig',
'signed');
1284 $basic_sig_fields = array(
'return_to',
'identity');
1286 $require_fields = array(
1288 array(
'op_endpoint')),
1294 $require_sigs = array(
1296 array(
'response_nonce',
1304 foreach ($require_fields[$message->getOpenIDNamespace()] as $field) {
1307 "Missing required field '".$field.
"'");
1315 return $signed_list_str;
1317 $signed_list = explode(
',', $signed_list_str);
1319 foreach ($require_sigs[$message->getOpenIDNamespace()] as $field) {
1322 (!in_array($field, $signed_list))) {
1324 "'".$field.
"' not signed");
1337 if ($request === null) {
1341 $resp_message = $this->
_makeKVPost($request, $server_url);
1342 if (($resp_message === null) ||
1343 (is_a($resp_message,
'Auth_OpenID_ServerErrorContainer'))) {
1357 foreach (explode(
',', $signed) as $k) {
1358 $value = $message->getAliasedArg($k);
1359 if ($value === null) {
1364 $ca_message = $message->copy();
1366 'check_authentication');
1379 'invalidate_handle');
1381 if ($invalidate_handle !== null) {
1382 $this->store->removeAssociation($server_url,
1383 $invalidate_handle);
1386 if ($is_valid ==
'true') {
1405 if ($response->status == 400) {
1408 }
else if ($response->status != 200 and $response->status != 206) {
1412 return $response_message;
1420 $body = $message->toURLEncoded();
1421 $resp = $this->fetcher->post($server_url, $body);
1423 if ($resp === null) {
1435 if (!$this->_use_assocs) {
1439 $assoc = $this->store->getAssociation($endpoint->server_url);
1441 if (($assoc === null) ||
1442 ($assoc->getExpiresIn() <= 0)) {
1446 if ($assoc !== null) {
1447 $this->store->storeAssociation($endpoint->server_url,
1469 if (($server_error->error_code !=
'unsupported-type') ||
1470 ($server_error->message->isOpenID1())) {
1486 if (($assoc_type === null) || ($session_type === null)) {
1488 }
else if (!$this->negotiator->isAllowed($assoc_type,
1492 return array($assoc_type, $session_type);
1502 list($assoc_type, $session_type) = $this->negotiator->getAllowedType();
1505 $endpoint, $assoc_type, $session_type);
1511 if (is_a($assoc,
'Auth_OpenID_ServerErrorContainer')) {
1515 $why, $endpoint, $assoc_type);
1517 if ($supportedTypes !== null) {
1518 list($assoc_type, $session_type) = $supportedTypes;
1524 $endpoint, $assoc_type, $session_type);
1526 if (is_a($assoc,
'Auth_OpenID_ServerErrorContainer')) {
1551 $endpoint, $assoc_type, $session_type);
1553 $response_message = $this->
_makeKVPost($args, $endpoint->server_url);
1555 if ($response_message === null) {
1558 }
else if (is_a($response_message,
1559 'Auth_OpenID_ServerErrorContainer')) {
1560 return $response_message;
1573 $assoc_type = $assoc_response->getArg(
1581 $assoc_handle = $assoc_response->getArg(
1586 return $assoc_handle;
1593 $expires_in_str = $assoc_response->getArg(
1598 return $expires_in_str;
1602 if ($expires_in ===
false) {
1604 $err = sprintf(
"Could not parse expires_in from association ".
1605 "response %s", print_r($assoc_response,
true));
1610 if ($assoc_response->isOpenID1()) {
1613 $session_type = $assoc_response->getArg(
1618 return $session_type;
1623 if ($assoc_session->session_type != $session_type) {
1624 if ($assoc_response->isOpenID1() &&
1625 ($session_type ==
'no-encryption')) {
1641 if (!in_array($assoc_type, $assoc_session->allowed_assoc_types)) {
1648 $secret = $assoc_session->extractSecret($assoc_response);
1650 if ($secret === null) {
1655 $expires_in, $assoc_handle, $secret, $assoc_type);
1663 if (array_key_exists($session_type, $this->session_types)) {
1664 $session_type_class = $this->session_types[$session_type];
1666 if (is_callable($session_type_class)) {
1667 $assoc_session = $session_type_class();
1669 $assoc_session =
new $session_type_class();
1676 'mode' =>
'associate',
1677 'assoc_type' => $assoc_type);
1679 if (!$endpoint->compatibilityMode()) {
1685 if ((!$endpoint->compatibilityMode()) ||
1686 ($assoc_session->session_type !=
'no-encryption')) {
1687 $args[
'session_type'] = $assoc_session->session_type;
1690 $args = array_merge($args, $assoc_session->getRequest());
1692 return array($assoc_session, $message);
1720 if ($session_type ==
'no-encryption') {
1723 }
else if (($session_type ==
'') || ($session_type === null)) {
1728 $session_type =
'no-encryption';
1731 return $session_type;
1753 $this->assoc = $assoc;
1754 $this->endpoint = $endpoint;
1755 $this->return_to_args = array();
1757 $endpoint->preferredNamespace());
1758 $this->_anonymous =
false;
1769 $extension_request->toMessage($this->message);
1793 return $this->message->setArg(
$namespace, $key, $value);
1807 if ($is_anonymous && $this->message->isOpenID1()) {
1810 $this->_anonymous = $is_anonymous;
1839 $this->return_to_args);
1840 }
else if ($immediate) {
1845 "'return_to' is mandatory when using checkid_immediate");
1846 }
else if ($this->message->isOpenID1()) {
1850 "'return_to' is mandatory for OpenID 1 requests");
1851 }
else if ($this->return_to_args) {
1855 "extra 'return_to' arguments where specified, " .
1856 "but no return_to was specified");
1860 $mode =
'checkid_immediate';
1862 $mode =
'checkid_setup';
1865 $message = $this->message->copy();
1866 if ($message->isOpenID1()) {
1867 $realm_key =
'trust_root';
1869 $realm_key =
'realm';
1874 $realm_key => $realm,
1876 'return_to' => $return_to));
1878 if (!$this->_anonymous) {
1879 if ($this->endpoint->isOPIdentifier()) {
1883 $claimed_id = $request_identity =
1886 $request_identity = $this->endpoint->getLocalID();
1887 $claimed_id = $this->endpoint->claimed_id;
1894 if ($message->isOpenID2()) {
1902 $this->assoc->handle);
1911 $message = $this->
getMessage($realm, $return_to, $immediate);
1917 return $message->toURL($this->endpoint->server_url);
1929 $form_tag_attrs=null)
1931 $message = $this->
getMessage($realm, $return_to, $immediate);
1937 return $message->toFormMarkup($this->endpoint->server_url,
1948 $form_tag_attrs=null)
1950 $form = $this->
formMarkup($realm, $return_to, $immediate,
1961 return $this->endpoint->compatibilityMode();
1975 $this->endpoint = $endpoint;
1976 if ($endpoint === null) {
1977 $this->identity_url = null;
1979 $this->identity_url = $endpoint->claimed_id;
2002 if ($this->endpoint !== null) {
2003 return $this->endpoint->getDisplayIdentifier();
2032 $this->endpoint = $endpoint;
2033 $this->identity_url = $endpoint->claimed_id;
2034 $this->signed_args = $signed_args;
2035 $this->message = $message;
2037 if ($this->signed_args === null) {
2038 $this->signed_args = array();
2050 if ($require_signed) {
2053 return $this->message->getArgs($namespace_uri);
2059 return $this->message->isOpenID1();
2066 return in_array($this->message->getKey($ns_uri, $ns_key),
2067 $this->signed_args);
2074 if ($this->
isSigned($ns_uri, $ns_key)) {
2075 return $this->message->getArg($ns_uri, $ns_key, $default);
2085 $msg_args = $this->message->getArgs($ns_uri);
2090 foreach ($msg_args as $key => $value) {
2091 if (!$this->
isSigned($ns_uri, $key)) {
2092 unset($msg_args[$key]);
2134 $contact = null, $reference = null)
2137 $this->message = $message;
2138 $this->contact = $contact;
2139 $this->reference = $reference;
2162 $this->error_text = $error_text;
2163 $this->error_code = $error_code;
2164 $this->message = $message;
2172 $error_text = $message->getArg(
2226 $this->setup_url = $setup_url;