AX.php

Go to the documentation of this file.
00001 <?php
00002 
00013 require_once "Auth/OpenID/Extension.php";
00014 require_once "Auth/OpenID/Message.php";
00015 require_once "Auth/OpenID/TrustRoot.php";
00016 
00017 define('Auth_OpenID_AX_NS_URI',
00018        'http://openid.net/srv/ax/1.0');
00019 
00020 // Use this as the 'count' value for an attribute in a FetchRequest to
00021 // ask for as many values as the OP can provide.
00022 define('Auth_OpenID_AX_UNLIMITED_VALUES', 'unlimited');
00023 
00024 // Minimum supported alias length in characters.  Here for
00025 // completeness.
00026 define('Auth_OpenID_AX_MINIMUM_SUPPORTED_ALIAS_LENGTH', 32);
00027 
00033 class Auth_OpenID_AX {
00041     function isError($thing)
00042     {
00043         return is_a($thing, 'Auth_OpenID_AX_Error');
00044     }
00045 }
00046 
00051 function Auth_OpenID_AX_checkAlias($alias)
00052 {
00053   if (strpos($alias, ',') !== false) {
00054       return new Auth_OpenID_AX_Error(sprintf(
00055                    "Alias %s must not contain comma", $alias));
00056   }
00057   if (strpos($alias, '.') !== false) {
00058       return new Auth_OpenID_AX_Error(sprintf(
00059                    "Alias %s must not contain period", $alias));
00060   }
00061 
00062   return true;
00063 }
00064 
00071 class Auth_OpenID_AX_Error {
00072     function Auth_OpenID_AX_Error($message=null)
00073     {
00074         $this->message = $message;
00075     }
00076 }
00077 
00084 class Auth_OpenID_AX_Message extends Auth_OpenID_Extension {
00089     var $ns_alias = 'ax';
00090 
00095     var $mode = null;
00096 
00097     var $ns_uri = Auth_OpenID_AX_NS_URI;
00098 
00106     function _checkMode($ax_args)
00107     {
00108         $mode = Auth_OpenID::arrayGet($ax_args, 'mode');
00109         if ($mode != $this->mode) {
00110             return new Auth_OpenID_AX_Error(
00111                             sprintf(
00112                                     "Expected mode '%s'; got '%s'",
00113                                     $this->mode, $mode));
00114         }
00115 
00116         return true;
00117     }
00118 
00126     function _newArgs()
00127     {
00128         return array('mode' => $this->mode);
00129     }
00130 }
00131 
00139 class Auth_OpenID_AX_AttrInfo {
00154     function Auth_OpenID_AX_AttrInfo($type_uri, $count, $required,
00155                                      $alias)
00156     {
00162         $this->required = $required;
00163 
00168         $this->count = $count;
00169 
00177         $this->type_uri = $type_uri;
00178 
00187         $this->alias = $alias;
00188     }
00189 
00194     function make($type_uri, $count=1, $required=false,
00195                   $alias=null)
00196     {
00197         if ($alias !== null) {
00198             $result = Auth_OpenID_AX_checkAlias($alias);
00199 
00200             if (Auth_OpenID_AX::isError($result)) {
00201                 return $result;
00202             }
00203         }
00204 
00205         return new Auth_OpenID_AX_AttrInfo($type_uri, $count, $required,
00206                                            $alias);
00207     }
00208 
00216     function wantsUnlimitedValues()
00217     {
00218         return $this->count === Auth_OpenID_AX_UNLIMITED_VALUES;
00219     }
00220 }
00221 
00238 function Auth_OpenID_AX_toTypeURIs(&$namespace_map, $alias_list_s)
00239 {
00240     $uris = array();
00241 
00242     if ($alias_list_s) {
00243         foreach (explode(',', $alias_list_s) as $alias) {
00244             $type_uri = $namespace_map->getNamespaceURI($alias);
00245             if ($type_uri === null) {
00246                 // raise KeyError(
00247                 // 'No type is defined for attribute name %r' % (alias,))
00248                 return new Auth_OpenID_AX_Error(
00249                   sprintf('No type is defined for attribute name %s',
00250                           $alias)
00251                   );
00252             } else {
00253                 $uris[] = $type_uri;
00254             }
00255         }
00256     }
00257 
00258     return $uris;
00259 }
00260 
00268 class Auth_OpenID_AX_FetchRequest extends Auth_OpenID_AX_Message {
00269 
00270     var $mode = 'fetch_request';
00271 
00272     function Auth_OpenID_AX_FetchRequest($update_url=null)
00273     {
00278         $this->requested_attributes = array();
00279 
00285         $this->update_url = $update_url;
00286     }
00287 
00295     function add($attribute)
00296     {
00297         if ($this->contains($attribute->type_uri)) {
00298             return new Auth_OpenID_AX_Error(
00299               sprintf("The attribute %s has already been requested",
00300                       $attribute->type_uri));
00301         }
00302 
00303         $this->requested_attributes[$attribute->type_uri] = $attribute;
00304 
00305         return true;
00306     }
00307 
00313     function getExtensionArgs()
00314     {
00315         $aliases = new Auth_OpenID_NamespaceMap();
00316 
00317         $required = array();
00318         $if_available = array();
00319 
00320         $ax_args = $this->_newArgs();
00321 
00322         foreach ($this->requested_attributes as $type_uri => $attribute) {
00323             if ($attribute->alias === null) {
00324                 $alias = $aliases->add($type_uri);
00325             } else {
00326                 $alias = $aliases->addAlias($type_uri, $attribute->alias);
00327 
00328                 if ($alias === null) {
00329                     return new Auth_OpenID_AX_Error(
00330                       sprintf("Could not add alias %s for URI %s",
00331                               $attribute->alias, $type_uri
00332                       ));
00333                 }
00334             }
00335 
00336             if ($attribute->required) {
00337                 $required[] = $alias;
00338             } else {
00339                 $if_available[] = $alias;
00340             }
00341 
00342             if ($attribute->count != 1) {
00343                 $ax_args['count.' . $alias] = strval($attribute->count);
00344             }
00345 
00346             $ax_args['type.' . $alias] = $type_uri;
00347         }
00348 
00349         if ($required) {
00350             $ax_args['required'] = implode(',', $required);
00351         }
00352 
00353         if ($if_available) {
00354             $ax_args['if_available'] = implode(',', $if_available);
00355         }
00356 
00357         return $ax_args;
00358     }
00359 
00367     function getRequiredAttrs()
00368     {
00369         $required = array();
00370         foreach ($this->requested_attributes as $type_uri => $attribute) {
00371             if ($attribute->required) {
00372                 $required[] = $type_uri;
00373             }
00374         }
00375 
00376         return $required;
00377     }
00378 
00389     function &fromOpenIDRequest($request)
00390     {
00391         $m = $request->message;
00392         $obj = new Auth_OpenID_AX_FetchRequest();
00393         $ax_args = $m->getArgs($obj->ns_uri);
00394 
00395         $result = $obj->parseExtensionArgs($ax_args);
00396 
00397         if (Auth_OpenID_AX::isError($result)) {
00398             return $result;
00399         }
00400 
00401         if ($obj->update_url) {
00402             // Update URL must match the openid.realm of the
00403             // underlying OpenID 2 message.
00404             $realm = $m->getArg(Auth_OpenID_OPENID_NS, 'realm',
00405                         $m->getArg(
00406                                   Auth_OpenID_OPENID_NS,
00407                                   'return_to'));
00408 
00409             if (!$realm) {
00410                 $obj = new Auth_OpenID_AX_Error(
00411                   sprintf("Cannot validate update_url %s " .
00412                           "against absent realm", $obj->update_url));
00413             } else if (!Auth_OpenID_TrustRoot::match($realm,
00414                                                      $obj->update_url)) {
00415                 $obj = new Auth_OpenID_AX_Error(
00416                   sprintf("Update URL %s failed validation against realm %s",
00417                           $obj->update_url, $realm));
00418             }
00419         }
00420 
00421         return $obj;
00422     }
00423 
00432     function parseExtensionArgs($ax_args)
00433     {
00434         $result = $this->_checkMode($ax_args);
00435         if (Auth_OpenID_AX::isError($result)) {
00436             return $result;
00437         }
00438 
00439         $aliases = new Auth_OpenID_NamespaceMap();
00440 
00441         foreach ($ax_args as $key => $value) {
00442             if (strpos($key, 'type.') === 0) {
00443                 $alias = substr($key, 5);
00444                 $type_uri = $value;
00445 
00446                 $alias = $aliases->addAlias($type_uri, $alias);
00447 
00448                 if ($alias === null) {
00449                     return new Auth_OpenID_AX_Error(
00450                       sprintf("Could not add alias %s for URI %s",
00451                               $alias, $type_uri)
00452                       );
00453                 }
00454 
00455                 $count_s = Auth_OpenID::arrayGet($ax_args, 'count.' . $alias);
00456                 if ($count_s) {
00457                     $count = Auth_OpenID::intval($count_s);
00458                     if (($count === false) &&
00459                         ($count_s === Auth_OpenID_AX_UNLIMITED_VALUES)) {
00460                         $count = $count_s;
00461                     }
00462                 } else {
00463                     $count = 1;
00464                 }
00465 
00466                 if ($count === false) {
00467                     return new Auth_OpenID_AX_Error(
00468                       sprintf("Integer value expected for %s, got %s",
00469                               'count.' . $alias, $count_s));
00470                 }
00471 
00472                 $attrinfo = Auth_OpenID_AX_AttrInfo::make($type_uri, $count,
00473                                                           false, $alias);
00474 
00475                 if (Auth_OpenID_AX::isError($attrinfo)) {
00476                     return $attrinfo;
00477                 }
00478 
00479                 $this->add($attrinfo);
00480             }
00481         }
00482 
00483         $required = Auth_OpenID_AX_toTypeURIs($aliases,
00484                          Auth_OpenID::arrayGet($ax_args, 'required'));
00485 
00486         foreach ($required as $type_uri) {
00487             $attrib =& $this->requested_attributes[$type_uri];
00488             $attrib->required = true;
00489         }
00490 
00491         $if_available = Auth_OpenID_AX_toTypeURIs($aliases,
00492                              Auth_OpenID::arrayGet($ax_args, 'if_available'));
00493 
00494         $all_type_uris = array_merge($required, $if_available);
00495 
00496         foreach ($aliases->iterNamespaceURIs() as $type_uri) {
00497             if (!in_array($type_uri, $all_type_uris)) {
00498                 return new Auth_OpenID_AX_Error(
00499                   sprintf('Type URI %s was in the request but not ' .
00500                           'present in "required" or "if_available"',
00501                           $type_uri));
00502 
00503             }
00504         }
00505 
00506         $this->update_url = Auth_OpenID::arrayGet($ax_args, 'update_url');
00507 
00508         return true;
00509     }
00510 
00515     function iterAttrs()
00516     {
00517         return array_values($this->requested_attributes);
00518     }
00519 
00520     function iterTypes()
00521     {
00522         return array_keys($this->requested_attributes);
00523     }
00524 
00528     function contains($type_uri)
00529     {
00530         return in_array($type_uri, $this->iterTypes());
00531     }
00532 }
00533 
00541 class Auth_OpenID_AX_KeyValueMessage extends Auth_OpenID_AX_Message {
00542 
00543     function Auth_OpenID_AX_KeyValueMessage()
00544     {
00545         $this->data = array();
00546     }
00547 
00559     function addValue($type_uri, $value)
00560     {
00561         if (!array_key_exists($type_uri, $this->data)) {
00562             $this->data[$type_uri] = array();
00563         }
00564 
00565         $values =& $this->data[$type_uri];
00566         $values[] = $value;
00567     }
00568 
00576     function setValues($type_uri, &$values)
00577     {
00578         $this->data[$type_uri] =& $values;
00579     }
00580 
00590     function _getExtensionKVArgs(&$aliases)
00591     {
00592         if ($aliases === null) {
00593             $aliases = new Auth_OpenID_NamespaceMap();
00594         }
00595 
00596         $ax_args = array();
00597 
00598         foreach ($this->data as $type_uri => $values) {
00599             $alias = $aliases->add($type_uri);
00600 
00601             $ax_args['type.' . $alias] = $type_uri;
00602             $ax_args['count.' . $alias] = strval(count($values));
00603 
00604             foreach ($values as $i => $value) {
00605               $key = sprintf('value.%s.%d', $alias, $i + 1);
00606               $ax_args[$key] = $value;
00607             }
00608         }
00609 
00610         return $ax_args;
00611     }
00612 
00621     function parseExtensionArgs($ax_args)
00622     {
00623         $result = $this->_checkMode($ax_args);
00624         if (Auth_OpenID_AX::isError($result)) {
00625             return $result;
00626         }
00627 
00628         $aliases = new Auth_OpenID_NamespaceMap();
00629 
00630         foreach ($ax_args as $key => $value) {
00631             if (strpos($key, 'type.') === 0) {
00632                 $type_uri = $value;
00633                 $alias = substr($key, 5);
00634 
00635                 $result = Auth_OpenID_AX_checkAlias($alias);
00636 
00637                 if (Auth_OpenID_AX::isError($result)) {
00638                     return $result;
00639                 }
00640 
00641                 $alias = $aliases->addAlias($type_uri, $alias);
00642 
00643                 if ($alias === null) {
00644                     return new Auth_OpenID_AX_Error(
00645                       sprintf("Could not add alias %s for URI %s",
00646                               $alias, $type_uri)
00647                       );
00648                 }
00649             }
00650         }
00651 
00652         foreach ($aliases->iteritems() as $pair) {
00653             list($type_uri, $alias) = $pair;
00654 
00655             if (array_key_exists('count.' . $alias, $ax_args)) {
00656 
00657                 $count_key = 'count.' . $alias;
00658                 $count_s = $ax_args[$count_key];
00659 
00660                 $count = Auth_OpenID::intval($count_s);
00661 
00662                 if ($count === false) {
00663                     return new Auth_OpenID_AX_Error(
00664                       sprintf("Integer value expected for %s, got %s",
00665                               'count. %s' . $alias, $count_s,
00666                               Auth_OpenID_AX_UNLIMITED_VALUES)
00667                                                     );
00668                 }
00669 
00670                 $values = array();
00671                 for ($i = 1; $i < $count + 1; $i++) {
00672                     $value_key = sprintf('value.%s.%d', $alias, $i);
00673 
00674                     if (!array_key_exists($value_key, $ax_args)) {
00675                       return new Auth_OpenID_AX_Error(
00676                         sprintf(
00677                                 "No value found for key %s",
00678                                 $value_key));
00679                     }
00680 
00681                     $value = $ax_args[$value_key];
00682                     $values[] = $value;
00683                 }
00684             } else {
00685                 $key = 'value.' . $alias;
00686 
00687                 if (!array_key_exists($key, $ax_args)) {
00688                   return new Auth_OpenID_AX_Error(
00689                     sprintf(
00690                             "No value found for key %s",
00691                             $key));
00692                 }
00693 
00694                 $value = $ax_args['value.' . $alias];
00695 
00696                 if ($value == '') {
00697                     $values = array();
00698                 } else {
00699                     $values = array($value);
00700                 }
00701             }
00702 
00703             $this->data[$type_uri] = $values;
00704         }
00705 
00706         return true;
00707     }
00708 
00722     function getSingle($type_uri, $default=null)
00723     {
00724         $values = Auth_OpenID::arrayGet($this->data, $type_uri);
00725         if (!$values) {
00726             return $default;
00727         } else if (count($values) == 1) {
00728             return $values[0];
00729         } else {
00730             return new Auth_OpenID_AX_Error(
00731               sprintf('More than one value present for %s',
00732                       $type_uri)
00733               );
00734         }
00735     }
00736 
00753     function get($type_uri)
00754     {
00755         if (array_key_exists($type_uri, $this->data)) {
00756             return $this->data[$type_uri];
00757         } else {
00758             return new Auth_OpenID_AX_Error(
00759               sprintf("Type URI %s not found in response",
00760                       $type_uri)
00761               );
00762         }
00763     }
00764 
00775     function count($type_uri)
00776     {
00777         if (array_key_exists($type_uri, $this->data)) {
00778             return count($this->get($type_uri));
00779         } else {
00780             return new Auth_OpenID_AX_Error(
00781               sprintf("Type URI %s not found in response",
00782                       $type_uri)
00783               );
00784         }
00785     }
00786 }
00787 
00793 class Auth_OpenID_AX_FetchResponse extends Auth_OpenID_AX_KeyValueMessage {
00794     var $mode = 'fetch_response';
00795 
00796     function Auth_OpenID_AX_FetchResponse($update_url=null)
00797     {
00798         $this->Auth_OpenID_AX_KeyValueMessage();
00799         $this->update_url = $update_url;
00800     }
00801 
00810     function getExtensionArgs($request=null)
00811     {
00812         $aliases = new Auth_OpenID_NamespaceMap();
00813 
00814         $zero_value_types = array();
00815 
00816         if ($request !== null) {
00817             // Validate the data in the context of the request (the
00818             // same attributes should be present in each, and the
00819             // counts in the response must be no more than the counts
00820             // in the request)
00821 
00822             foreach ($this->data as $type_uri => $unused) {
00823                 if (!$request->contains($type_uri)) {
00824                     return new Auth_OpenID_AX_Error(
00825                       sprintf("Response attribute not present in request: %s",
00826                               $type_uri)
00827                       );
00828                 }
00829             }
00830 
00831             foreach ($request->iterAttrs() as $attr_info) {
00832                 // Copy the aliases from the request so that reading
00833                 // the response in light of the request is easier
00834                 if ($attr_info->alias === null) {
00835                     $aliases->add($attr_info->type_uri);
00836                 } else {
00837                     $alias = $aliases->addAlias($attr_info->type_uri,
00838                                                 $attr_info->alias);
00839 
00840                     if ($alias === null) {
00841                         return new Auth_OpenID_AX_Error(
00842                           sprintf("Could not add alias %s for URI %s",
00843                                   $attr_info->alias, $attr_info->type_uri)
00844                           );
00845                     }
00846                 }
00847 
00848                 if (array_key_exists($attr_info->type_uri, $this->data)) {
00849                     $values = $this->data[$attr_info->type_uri];
00850                 } else {
00851                     $values = array();
00852                     $zero_value_types[] = $attr_info;
00853                 }
00854 
00855                 if (($attr_info->count != Auth_OpenID_AX_UNLIMITED_VALUES) &&
00856                     ($attr_info->count < count($values))) {
00857                     return new Auth_OpenID_AX_Error(
00858                       sprintf("More than the number of requested values " .
00859                               "were specified for %s",
00860                               $attr_info->type_uri)
00861                       );
00862                 }
00863             }
00864         }
00865 
00866         $kv_args = $this->_getExtensionKVArgs($aliases);
00867 
00868         // Add the KV args into the response with the args that are
00869         // unique to the fetch_response
00870         $ax_args = $this->_newArgs();
00871 
00872         // For each requested attribute, put its type/alias and count
00873         // into the response even if no data were returned.
00874         foreach ($zero_value_types as $attr_info) {
00875             $alias = $aliases->getAlias($attr_info->type_uri);
00876             $kv_args['type.' . $alias] = $attr_info->type_uri;
00877             $kv_args['count.' . $alias] = '0';
00878         }
00879 
00880         $update_url = null;
00881         if ($request) {
00882             $update_url = $request->update_url;
00883         } else {
00884             $update_url = $this->update_url;
00885         }
00886 
00887         if ($update_url) {
00888             $ax_args['update_url'] = $update_url;
00889         }
00890 
00891         Auth_OpenID::update(&$ax_args, $kv_args);
00892 
00893         return $ax_args;
00894     }
00895 
00900     function parseExtensionArgs($ax_args)
00901     {
00902         $result = parent::parseExtensionArgs($ax_args);
00903 
00904         if (Auth_OpenID_AX::isError($result)) {
00905             return $result;
00906         }
00907 
00908         $this->update_url = Auth_OpenID::arrayGet($ax_args, 'update_url');
00909 
00910         return true;
00911     }
00912 
00925     function fromSuccessResponse($success_response, $signed=true)
00926     {
00927         $obj = new Auth_OpenID_AX_FetchResponse();
00928         if ($signed) {
00929             $ax_args = $success_response->getSignedNS($obj->ns_uri);
00930         } else {
00931             $ax_args = $success_response->message->getArgs($obj->ns_uri);
00932         }
00933         if ($ax_args === null || Auth_OpenID::isFailure($ax_args) ||
00934               sizeof($ax_args) == 0) {
00935             return null;
00936         }
00937 
00938         $result = $obj->parseExtensionArgs($ax_args);
00939         if (Auth_OpenID_AX::isError($result)) {
00940             #XXX log me
00941             return null;
00942         }
00943         return $obj;
00944     }
00945 }
00946 
00952 class Auth_OpenID_AX_StoreRequest extends Auth_OpenID_AX_KeyValueMessage {
00953     var $mode = 'store_request';
00954 
00959     function getExtensionArgs($aliases=null)
00960     {
00961         $ax_args = $this->_newArgs();
00962         $kv_args = $this->_getExtensionKVArgs($aliases);
00963         Auth_OpenID::update(&$ax_args, $kv_args);
00964         return $ax_args;
00965     }
00966 }
00967 
00975 class Auth_OpenID_AX_StoreResponse extends Auth_OpenID_AX_Message {
00976     var $SUCCESS_MODE = 'store_response_success';
00977     var $FAILURE_MODE = 'store_response_failure';
00978 
00983     function &make($succeeded=true, $error_message=null)
00984     {
00985         if (($succeeded) && ($error_message !== null)) {
00986             return new Auth_OpenID_AX_Error('An error message may only be '.
00987                                     'included in a failing fetch response');
00988         }
00989 
00990         return new Auth_OpenID_AX_StoreResponse($succeeded, $error_message);
00991     }
00992 
00993     function Auth_OpenID_AX_StoreResponse($succeeded=true, $error_message=null)
00994     {
00995         if ($succeeded) {
00996             $this->mode = $this->SUCCESS_MODE;
00997         } else {
00998             $this->mode = $this->FAILURE_MODE;
00999         }
01000 
01001         $this->error_message = $error_message;
01002     }
01003 
01007     function succeeded()
01008     {
01009         return $this->mode == $this->SUCCESS_MODE;
01010     }
01011 
01012     function getExtensionArgs()
01013     {
01014         $ax_args = $this->_newArgs();
01015         if ((!$this->succeeded()) && $this->error_message) {
01016             $ax_args['error'] = $this->error_message;
01017         }
01018 
01019         return $ax_args;
01020     }
01021 }
01022 
01023 ?>

Generated on Thu Feb 19 15:02:21 2009 for OXID eShop CE by  doxygen 1.5.5