00001 <?php
00002
00020 require_once 'Auth/OpenID/CryptUtil.php';
00021
00025 require_once 'Auth/OpenID/KVForm.php';
00026
00030 require_once 'Auth/OpenID/HMAC.php';
00031
00044 class Auth_OpenID_Association {
00045
00051 var $SIG_LENGTH = 20;
00052
00058 var $assoc_keys = array(
00059 'version',
00060 'handle',
00061 'secret',
00062 'issued',
00063 'lifetime',
00064 'assoc_type'
00065 );
00066
00067 var $_macs = array(
00068 'HMAC-SHA1' => 'Auth_OpenID_HMACSHA1',
00069 'HMAC-SHA256' => 'Auth_OpenID_HMACSHA256'
00070 );
00071
00097 function fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
00098 {
00099 $issued = time();
00100 $lifetime = $expires_in;
00101 return new Auth_OpenID_Association($handle, $secret,
00102 $issued, $lifetime, $assoc_type);
00103 }
00104
00131 function Auth_OpenID_Association(
00132 $handle, $secret, $issued, $lifetime, $assoc_type)
00133 {
00134 if (!in_array($assoc_type,
00135 Auth_OpenID_getSupportedAssociationTypes())) {
00136 $fmt = 'Unsupported association type (%s)';
00137 trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR);
00138 }
00139
00140 $this->handle = $handle;
00141 $this->secret = $secret;
00142 $this->issued = $issued;
00143 $this->lifetime = $lifetime;
00144 $this->assoc_type = $assoc_type;
00145 }
00146
00154 function getExpiresIn($now = null)
00155 {
00156 if ($now == null) {
00157 $now = time();
00158 }
00159
00160 return max(0, $this->issued + $this->lifetime - $now);
00161 }
00162
00170 function equal($other)
00171 {
00172 return ((gettype($this) == gettype($other))
00173 && ($this->handle == $other->handle)
00174 && ($this->secret == $other->secret)
00175 && ($this->issued == $other->issued)
00176 && ($this->lifetime == $other->lifetime)
00177 && ($this->assoc_type == $other->assoc_type));
00178 }
00179
00186 function serialize()
00187 {
00188 $data = array(
00189 'version' => '2',
00190 'handle' => $this->handle,
00191 'secret' => base64_encode($this->secret),
00192 'issued' => strval(intval($this->issued)),
00193 'lifetime' => strval(intval($this->lifetime)),
00194 'assoc_type' => $this->assoc_type
00195 );
00196
00197 assert(array_keys($data) == $this->assoc_keys);
00198
00199 return Auth_OpenID_KVForm::fromArray($data, $strict = true);
00200 }
00201
00209 function deserialize($class_name, $assoc_s)
00210 {
00211 $pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true);
00212 $keys = array();
00213 $values = array();
00214 foreach ($pairs as $key => $value) {
00215 if (is_array($value)) {
00216 list($key, $value) = $value;
00217 }
00218 $keys[] = $key;
00219 $values[] = $value;
00220 }
00221
00222 $class_vars = get_class_vars($class_name);
00223 $class_assoc_keys = $class_vars['assoc_keys'];
00224
00225 sort($keys);
00226 sort($class_assoc_keys);
00227
00228 if ($keys != $class_assoc_keys) {
00229 trigger_error('Unexpected key values: ' . var_export($keys, true),
00230 E_USER_WARNING);
00231 return null;
00232 }
00233
00234 $version = $pairs['version'];
00235 $handle = $pairs['handle'];
00236 $secret = $pairs['secret'];
00237 $issued = $pairs['issued'];
00238 $lifetime = $pairs['lifetime'];
00239 $assoc_type = $pairs['assoc_type'];
00240
00241 if ($version != '2') {
00242 trigger_error('Unknown version: ' . $version, E_USER_WARNING);
00243 return null;
00244 }
00245
00246 $issued = intval($issued);
00247 $lifetime = intval($lifetime);
00248 $secret = base64_decode($secret);
00249
00250 return new $class_name(
00251 $handle, $secret, $issued, $lifetime, $assoc_type);
00252 }
00253
00263 function sign($pairs)
00264 {
00265 $kv = Auth_OpenID_KVForm::fromArray($pairs);
00266
00267
00268 $callback = $this->_macs[$this->assoc_type];
00269
00270 return call_user_func_array($callback, array($this->secret, $kv));
00271 }
00272
00283 function signMessage($message)
00284 {
00285 if ($message->hasKey(Auth_OpenID_OPENID_NS, 'sig') ||
00286 $message->hasKey(Auth_OpenID_OPENID_NS, 'signed')) {
00287
00288 return null;
00289 }
00290
00291 $extant_handle = $message->getArg(Auth_OpenID_OPENID_NS,
00292 'assoc_handle');
00293
00294 if ($extant_handle && ($extant_handle != $this->handle)) {
00295
00296 return null;
00297 }
00298
00299 $signed_message = $message;
00300 $signed_message->setArg(Auth_OpenID_OPENID_NS, 'assoc_handle',
00301 $this->handle);
00302
00303 $message_keys = array_keys($signed_message->toPostArgs());
00304 $signed_list = array();
00305 $signed_prefix = 'openid.';
00306
00307 foreach ($message_keys as $k) {
00308 if (strpos($k, $signed_prefix) === 0) {
00309 $signed_list[] = substr($k, strlen($signed_prefix));
00310 }
00311 }
00312
00313 $signed_list[] = 'signed';
00314 sort($signed_list);
00315
00316 $signed_message->setArg(Auth_OpenID_OPENID_NS, 'signed',
00317 implode(',', $signed_list));
00318 $sig = $this->getMessageSignature($signed_message);
00319 $signed_message->setArg(Auth_OpenID_OPENID_NS, 'sig', $sig);
00320 return $signed_message;
00321 }
00322
00330 function _makePairs(&$message)
00331 {
00332 $signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
00333 if (!$signed || Auth_OpenID::isFailure($signed)) {
00334
00335 return null;
00336 }
00337
00338 $signed_list = explode(',', $signed);
00339 $pairs = array();
00340 $data = $message->toPostArgs();
00341 foreach ($signed_list as $field) {
00342 $pairs[] = array($field, Auth_OpenID::arrayGet($data,
00343 'openid.' .
00344 $field, ''));
00345 }
00346 return $pairs;
00347 }
00348
00355 function getMessageSignature(&$message)
00356 {
00357 $pairs = $this->_makePairs($message);
00358 return base64_encode($this->sign($pairs));
00359 }
00360
00367 function checkMessageSignature(&$message)
00368 {
00369 $sig = $message->getArg(Auth_OpenID_OPENID_NS,
00370 'sig');
00371
00372 if (!$sig || Auth_OpenID::isFailure($sig)) {
00373 return false;
00374 }
00375
00376 $calculated_sig = $this->getMessageSignature($message);
00377 return $calculated_sig == $sig;
00378 }
00379 }
00380
00381 function Auth_OpenID_getSecretSize($assoc_type)
00382 {
00383 if ($assoc_type == 'HMAC-SHA1') {
00384 return 20;
00385 } else if ($assoc_type == 'HMAC-SHA256') {
00386 return 32;
00387 } else {
00388 return null;
00389 }
00390 }
00391
00392 function Auth_OpenID_getAllAssociationTypes()
00393 {
00394 return array('HMAC-SHA1', 'HMAC-SHA256');
00395 }
00396
00397 function Auth_OpenID_getSupportedAssociationTypes()
00398 {
00399 $a = array('HMAC-SHA1');
00400
00401 if (Auth_OpenID_HMACSHA256_SUPPORTED) {
00402 $a[] = 'HMAC-SHA256';
00403 }
00404
00405 return $a;
00406 }
00407
00408 function Auth_OpenID_getSessionTypes($assoc_type)
00409 {
00410 $assoc_to_session = array(
00411 'HMAC-SHA1' => array('DH-SHA1', 'no-encryption'));
00412
00413 if (Auth_OpenID_HMACSHA256_SUPPORTED) {
00414 $assoc_to_session['HMAC-SHA256'] =
00415 array('DH-SHA256', 'no-encryption');
00416 }
00417
00418 return Auth_OpenID::arrayGet($assoc_to_session, $assoc_type, array());
00419 }
00420
00421 function Auth_OpenID_checkSessionType($assoc_type, $session_type)
00422 {
00423 if (!in_array($session_type,
00424 Auth_OpenID_getSessionTypes($assoc_type))) {
00425 return false;
00426 }
00427
00428 return true;
00429 }
00430
00431 function Auth_OpenID_getDefaultAssociationOrder()
00432 {
00433 $order = array();
00434
00435 if (!Auth_OpenID_noMathSupport()) {
00436 $order[] = array('HMAC-SHA1', 'DH-SHA1');
00437
00438 if (Auth_OpenID_HMACSHA256_SUPPORTED) {
00439 $order[] = array('HMAC-SHA256', 'DH-SHA256');
00440 }
00441 }
00442
00443 $order[] = array('HMAC-SHA1', 'no-encryption');
00444
00445 if (Auth_OpenID_HMACSHA256_SUPPORTED) {
00446 $order[] = array('HMAC-SHA256', 'no-encryption');
00447 }
00448
00449 return $order;
00450 }
00451
00452 function Auth_OpenID_getOnlyEncryptedOrder()
00453 {
00454 $result = array();
00455
00456 foreach (Auth_OpenID_getDefaultAssociationOrder() as $pair) {
00457 list($assoc, $session) = $pair;
00458
00459 if ($session != 'no-encryption') {
00460 if (Auth_OpenID_HMACSHA256_SUPPORTED &&
00461 ($assoc == 'HMAC-SHA256')) {
00462 $result[] = $pair;
00463 } else if ($assoc != 'HMAC-SHA256') {
00464 $result[] = $pair;
00465 }
00466 }
00467 }
00468
00469 return $result;
00470 }
00471
00472 function &Auth_OpenID_getDefaultNegotiator()
00473 {
00474 $x = new Auth_OpenID_SessionNegotiator(
00475 Auth_OpenID_getDefaultAssociationOrder());
00476 return $x;
00477 }
00478
00479 function &Auth_OpenID_getEncryptedNegotiator()
00480 {
00481 $x = new Auth_OpenID_SessionNegotiator(
00482 Auth_OpenID_getOnlyEncryptedOrder());
00483 return $x;
00484 }
00485
00527 class Auth_OpenID_SessionNegotiator {
00528 function Auth_OpenID_SessionNegotiator($allowed_types)
00529 {
00530 $this->allowed_types = array();
00531 $this->setAllowedTypes($allowed_types);
00532 }
00533
00540 function setAllowedTypes($allowed_types)
00541 {
00542 foreach ($allowed_types as $pair) {
00543 list($assoc_type, $session_type) = $pair;
00544 if (!Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
00545 return false;
00546 }
00547 }
00548
00549 $this->allowed_types = $allowed_types;
00550 return true;
00551 }
00552
00560 function addAllowedType($assoc_type, $session_type = null)
00561 {
00562 if ($this->allowed_types === null) {
00563 $this->allowed_types = array();
00564 }
00565
00566 if ($session_type === null) {
00567 $available = Auth_OpenID_getSessionTypes($assoc_type);
00568
00569 if (!$available) {
00570 return false;
00571 }
00572
00573 foreach ($available as $session_type) {
00574 $this->addAllowedType($assoc_type, $session_type);
00575 }
00576 } else {
00577 if (Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
00578 $this->allowed_types[] = array($assoc_type, $session_type);
00579 } else {
00580 return false;
00581 }
00582 }
00583
00584 return true;
00585 }
00586
00587
00588 function isAllowed($assoc_type, $session_type)
00589 {
00590 $assoc_good = in_array(array($assoc_type, $session_type),
00591 $this->allowed_types);
00592
00593 $matches = in_array($session_type,
00594 Auth_OpenID_getSessionTypes($assoc_type));
00595
00596 return ($assoc_good && $matches);
00597 }
00598
00603 function getAllowedType()
00604 {
00605 if (!$this->allowed_types) {
00606 return array(null, null);
00607 }
00608
00609 return $this->allowed_types[0];
00610 }
00611 }
00612
00613 ?>