PageRenderTime 116ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/skyviewpartners.com/auth_openid/code/Auth/OpenID/Discover.php

https://github.com/ramziammar/websites
PHP | 469 lines | 323 code | 87 blank | 59 comment | 44 complexity | 657d3b703ffbdbce8bd85d6772a967e0 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * The OpenID and Yadis discovery implementation for OpenID 1.2.
  4. * @package OpenID
  5. */
  6. require_once "Auth/OpenID.php";
  7. require_once "Auth/OpenID/Parse.php";
  8. require_once "Auth/OpenID/Message.php";
  9. require_once "Auth/Yadis/XRIRes.php";
  10. require_once "Auth/Yadis/Yadis.php";
  11. // XML namespace value
  12. define('Auth_OpenID_XMLNS_1_0', 'http://openid.net/xmlns/1.0');
  13. // Yadis service types
  14. define('Auth_OpenID_TYPE_1_2', 'http://openid.net/signon/1.2');
  15. define('Auth_OpenID_TYPE_1_1', 'http://openid.net/signon/1.1');
  16. define('Auth_OpenID_TYPE_1_0', 'http://openid.net/signon/1.0');
  17. define('Auth_OpenID_TYPE_2_0_IDP', 'http://specs.openid.net/auth/2.0/server');
  18. define('Auth_OpenID_TYPE_2_0', 'http://specs.openid.net/auth/2.0/signon');
  19. function Auth_OpenID_getOpenIDTypeURIs()
  20. {
  21. return array(Auth_OpenID_TYPE_2_0_IDP,
  22. Auth_OpenID_TYPE_2_0,
  23. Auth_OpenID_TYPE_1_2,
  24. Auth_OpenID_TYPE_1_1,
  25. Auth_OpenID_TYPE_1_0);
  26. }
  27. /**
  28. * Object representing an OpenID service endpoint.
  29. */
  30. class Auth_OpenID_ServiceEndpoint {
  31. function Auth_OpenID_ServiceEndpoint()
  32. {
  33. $this->claimed_id = null;
  34. $this->server_url = null;
  35. $this->type_uris = array();
  36. $this->local_id = null;
  37. $this->canonicalID = null;
  38. $this->used_yadis = false; // whether this came from an XRDS
  39. }
  40. function usesExtension($extension_uri)
  41. {
  42. return in_array($extension_uri, $this->type_uris);
  43. }
  44. function preferredNamespace()
  45. {
  46. if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) ||
  47. in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) {
  48. return Auth_OpenID_OPENID2_NS;
  49. } else {
  50. return Auth_OpenID_OPENID1_NS;
  51. }
  52. }
  53. function supportsType($type_uri)
  54. {
  55. // Does this endpoint support this type?
  56. return ((in_array($type_uri, $this->type_uris)) ||
  57. (($type_uri == Auth_OpenID_TYPE_2_0) &&
  58. $this->isOPIdentifier()));
  59. }
  60. function compatibilityMode()
  61. {
  62. return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS;
  63. }
  64. function isOPIdentifier()
  65. {
  66. return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
  67. }
  68. function fromOPEndpointURL($op_endpoint_url)
  69. {
  70. // Construct an OP-Identifier OpenIDServiceEndpoint object for
  71. // a given OP Endpoint URL
  72. $obj = new Auth_OpenID_ServiceEndpoint();
  73. $obj->server_url = $op_endpoint_url;
  74. $obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP);
  75. return $obj;
  76. }
  77. function parseService($yadis_url, $uri, $type_uris, $service_element)
  78. {
  79. // Set the state of this object based on the contents of the
  80. // service element. Return true if successful, false if not
  81. // (if findOPLocalIdentifier returns false).
  82. $this->type_uris = $type_uris;
  83. $this->server_url = $uri;
  84. $this->used_yadis = true;
  85. if (!$this->isOPIdentifier()) {
  86. $this->claimed_id = $yadis_url;
  87. $this->local_id = Auth_OpenID_findOPLocalIdentifier(
  88. $service_element,
  89. $this->type_uris);
  90. if ($this->local_id === false) {
  91. return false;
  92. }
  93. }
  94. return true;
  95. }
  96. function getLocalID()
  97. {
  98. // Return the identifier that should be sent as the
  99. // openid.identity_url parameter to the server.
  100. if ($this->local_id === null && $this->canonicalID === null) {
  101. return $this->claimed_id;
  102. } else {
  103. if ($this->local_id) {
  104. return $this->local_id;
  105. } else {
  106. return $this->canonicalID;
  107. }
  108. }
  109. }
  110. function fromHTML($uri, $html)
  111. {
  112. $discovery_types = array(
  113. array(Auth_OpenID_TYPE_2_0,
  114. 'openid2.provider', 'openid2.local_id'),
  115. array(Auth_OpenID_TYPE_1_1,
  116. 'openid.server', 'openid.delegate')
  117. );
  118. $services = array();
  119. foreach ($discovery_types as $triple) {
  120. list($type_uri, $server_rel, $delegate_rel) = $triple;
  121. $urls = Auth_OpenID_legacy_discover($html, $server_rel,
  122. $delegate_rel);
  123. if ($urls === false) {
  124. continue;
  125. }
  126. list($delegate_url, $server_url) = $urls;
  127. $service = new Auth_OpenID_ServiceEndpoint();
  128. $service->claimed_id = $uri;
  129. $service->local_id = $delegate_url;
  130. $service->server_url = $server_url;
  131. $service->type_uris = array($type_uri);
  132. $services[] = $service;
  133. }
  134. return $services;
  135. }
  136. function copy()
  137. {
  138. $x = new Auth_OpenID_ServiceEndpoint();
  139. $x->claimed_id = $this->claimed_id;
  140. $x->server_url = $this->server_url;
  141. $x->type_uris = $this->type_uris;
  142. $x->local_id = $this->local_id;
  143. $x->canonicalID = $this->canonicalID;
  144. $x->used_yadis = $this->used_yadis;
  145. return $x;
  146. }
  147. }
  148. function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
  149. {
  150. // Extract a openid:Delegate value from a Yadis Service element.
  151. // If no delegate is found, returns null. Returns false on
  152. // discovery failure (when multiple delegate/localID tags have
  153. // different values).
  154. $service->parser->registerNamespace('openid',
  155. Auth_OpenID_XMLNS_1_0);
  156. $service->parser->registerNamespace('xrd',
  157. Auth_Yadis_XMLNS_XRD_2_0);
  158. $parser =& $service->parser;
  159. $permitted_tags = array();
  160. if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) ||
  161. in_array(Auth_OpenID_TYPE_1_0, $type_uris)) {
  162. $permitted_tags[] = 'openid:Delegate';
  163. }
  164. if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) {
  165. $permitted_tags[] = 'xrd:LocalID';
  166. }
  167. $local_id = null;
  168. foreach ($permitted_tags as $tag_name) {
  169. $tags = $service->getElements($tag_name);
  170. foreach ($tags as $tag) {
  171. $content = $parser->content($tag);
  172. if ($local_id === null) {
  173. $local_id = $content;
  174. } else if ($local_id != $content) {
  175. return false;
  176. }
  177. }
  178. }
  179. return $local_id;
  180. }
  181. function filter_MatchesAnyOpenIDType(&$service)
  182. {
  183. $uris = $service->getTypes();
  184. foreach ($uris as $uri) {
  185. if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) {
  186. return true;
  187. }
  188. }
  189. return false;
  190. }
  191. function Auth_OpenID_bestMatchingService($service, $preferred_types)
  192. {
  193. // Return the index of the first matching type, or something
  194. // higher if no type matches.
  195. //
  196. // This provides an ordering in which service elements that
  197. // contain a type that comes earlier in the preferred types list
  198. // come before service elements that come later. If a service
  199. // element has more than one type, the most preferred one wins.
  200. foreach ($preferred_types as $index => $typ) {
  201. if (in_array($typ, $service->type_uris)) {
  202. return $index;
  203. }
  204. }
  205. return count($preferred_types);
  206. }
  207. function Auth_OpenID_arrangeByType($service_list, $preferred_types)
  208. {
  209. // Rearrange service_list in a new list so services are ordered by
  210. // types listed in preferred_types. Return the new list.
  211. // Build a list with the service elements in tuples whose
  212. // comparison will prefer the one with the best matching service
  213. $prio_services = array();
  214. foreach ($service_list as $index => $service) {
  215. $prio_services[] = array(Auth_OpenID_bestMatchingService($service,
  216. $preferred_types),
  217. $index, $service);
  218. }
  219. sort($prio_services);
  220. // Now that the services are sorted by priority, remove the sort
  221. // keys from the list.
  222. foreach ($prio_services as $index => $s) {
  223. $prio_services[$index] = $prio_services[$index][2];
  224. }
  225. return $prio_services;
  226. }
  227. // Extract OP Identifier services. If none found, return the rest,
  228. // sorted with most preferred first according to
  229. // OpenIDServiceEndpoint.openid_type_uris.
  230. //
  231. // openid_services is a list of OpenIDServiceEndpoint objects.
  232. //
  233. // Returns a list of OpenIDServiceEndpoint objects."""
  234. function Auth_OpenID_getOPOrUserServices($openid_services)
  235. {
  236. $op_services = Auth_OpenID_arrangeByType($openid_services,
  237. array(Auth_OpenID_TYPE_2_0_IDP));
  238. $openid_services = Auth_OpenID_arrangeByType($openid_services,
  239. Auth_OpenID_getOpenIDTypeURIs());
  240. if ($op_services) {
  241. return $op_services;
  242. } else {
  243. return $openid_services;
  244. }
  245. }
  246. function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services)
  247. {
  248. $s = array();
  249. if (!$yadis_services) {
  250. return $s;
  251. }
  252. foreach ($yadis_services as $service) {
  253. $type_uris = $service->getTypes();
  254. $uris = $service->getURIs();
  255. // If any Type URIs match and there is an endpoint URI
  256. // specified, then this is an OpenID endpoint
  257. if ($type_uris &&
  258. $uris) {
  259. foreach ($uris as $service_uri) {
  260. $openid_endpoint = new Auth_OpenID_ServiceEndpoint();
  261. if ($openid_endpoint->parseService($uri,
  262. $service_uri,
  263. $type_uris,
  264. $service)) {
  265. $s[] = $openid_endpoint;
  266. }
  267. }
  268. }
  269. }
  270. return $s;
  271. }
  272. function Auth_OpenID_discoverWithYadis($uri, &$fetcher)
  273. {
  274. // Discover OpenID services for a URI. Tries Yadis and falls back
  275. // on old-style <link rel='...'> discovery if Yadis fails.
  276. // Might raise a yadis.discover.DiscoveryFailure if no document
  277. // came back for that URI at all. I don't think falling back to
  278. // OpenID 1.0 discovery on the same URL will help, so don't bother
  279. // to catch it.
  280. $openid_services = array();
  281. $response = Auth_Yadis_Yadis::discover($uri, $fetcher);
  282. $yadis_url = $response->normalized_uri;
  283. $yadis_services = array();
  284. if ($response->isFailure()) {
  285. return array($uri, array());
  286. }
  287. $xrds =& Auth_Yadis_XRDS::parseXRDS($response->response_text);
  288. if ($xrds) {
  289. $yadis_services =
  290. $xrds->services(array('filter_MatchesAnyOpenIDType'));
  291. }
  292. if (!$yadis_services) {
  293. if ($response->isXRDS()) {
  294. return Auth_OpenID_discoverWithoutYadis($uri,
  295. $fetcher);
  296. }
  297. // Try to parse the response as HTML to get OpenID 1.0/1.1
  298. // <link rel="...">
  299. $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
  300. $yadis_url,
  301. $response->response_text);
  302. } else {
  303. $openid_services = Auth_OpenID_makeOpenIDEndpoints($yadis_url,
  304. $yadis_services);
  305. }
  306. $openid_services = Auth_OpenID_getOPOrUserServices($openid_services);
  307. return array($yadis_url, $openid_services);
  308. }
  309. function Auth_OpenID_discoverURI($uri, &$fetcher)
  310. {
  311. $parsed = parse_url($uri);
  312. if ($parsed && isset($parsed['scheme']) &&
  313. isset($parsed['host'])) {
  314. if (!in_array($parsed['scheme'], array('http', 'https'))) {
  315. // raise DiscoveryFailure('URI scheme is not HTTP or HTTPS', None)
  316. return array($uri, array());
  317. }
  318. } else {
  319. $uri = 'http://' . $uri;
  320. }
  321. $uri = Auth_OpenID::normalizeUrl($uri);
  322. return Auth_OpenID_discoverWithYadis($uri,
  323. $fetcher);
  324. }
  325. function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher)
  326. {
  327. $http_resp = @$fetcher->get($uri);
  328. if ($http_resp->status != 200) {
  329. return array($uri, array());
  330. }
  331. $identity_url = $http_resp->final_url;
  332. // Try to parse the response as HTML to get OpenID 1.0/1.1 <link
  333. // rel="...">
  334. $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
  335. $identity_url,
  336. $http_resp->body);
  337. return array($identity_url, $openid_services);
  338. }
  339. function Auth_OpenID_discoverXRI($iname, &$fetcher)
  340. {
  341. $resolver = new Auth_Yadis_ProxyResolver($fetcher);
  342. list($canonicalID, $yadis_services) =
  343. $resolver->query($iname,
  344. Auth_OpenID_getOpenIDTypeURIs(),
  345. array('filter_MatchesAnyOpenIDType'));
  346. $openid_services = Auth_OpenID_makeOpenIDEndpoints($iname,
  347. $yadis_services);
  348. $openid_services = Auth_OpenID_getOPOrUserServices($openid_services);
  349. for ($i = 0; $i < count($openid_services); $i++) {
  350. $openid_services[$i]->canonicalID = $canonicalID;
  351. $openid_services[$i]->claimed_id = $canonicalID;
  352. }
  353. // FIXME: returned xri should probably be in some normal form
  354. return array($iname, $openid_services);
  355. }
  356. function Auth_OpenID_discover($uri, &$fetcher)
  357. {
  358. // If the fetcher (i.e., PHP) doesn't support SSL, we can't do
  359. // discovery on an HTTPS URL.
  360. if ($fetcher->isHTTPS($uri) && !$fetcher->supportsSSL()) {
  361. return array($uri, array());
  362. }
  363. if (Auth_Yadis_identifierScheme($uri) == 'XRI') {
  364. $result = Auth_OpenID_discoverXRI($uri, $fetcher);
  365. } else {
  366. $result = Auth_OpenID_discoverURI($uri, $fetcher);
  367. }
  368. // If the fetcher doesn't support SSL, we can't interact with
  369. // HTTPS server URLs; remove those endpoints from the list.
  370. if (!$fetcher->supportsSSL()) {
  371. $http_endpoints = array();
  372. list($new_uri, $endpoints) = $result;
  373. foreach ($endpoints as $e) {
  374. if (!$fetcher->isHTTPS($e->server_url)) {
  375. $http_endpoints[] = $e;
  376. }
  377. }
  378. $result = array($new_uri, $http_endpoints);
  379. }
  380. return $result;
  381. }
  382. ?>