PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/main/classes/general/liveid.php

https://gitlab.com/alexprowars/bitrix
PHP | 1825 lines | 979 code | 202 blank | 644 comment | 135 complexity | 33bc4b8718c6880a0d5b4df7031f1d67 MD5 | raw file
  1. <?php
  2. /* TODO: Comments are out of date and incomplete. */
  3. /**
  4. * FILE: windowslivelogin.php
  5. *
  6. * DESCRIPTION: Sample implementation of Web Authentication and Delegated
  7. * Authentication protocol in PHP. Also includes trusted
  8. * sign-in and application verification sample
  9. * implementations.
  10. *
  11. * VERSION: 1.1
  12. *
  13. * Copyright (c) 2008 Microsoft Corporation. All Rights Reserved.
  14. */
  15. /**
  16. * Holds the user information after a successful sign-in.
  17. */
  18. class WLL_User
  19. {
  20. /**
  21. * Initialize the User with time stamp, userid, flags, context and token.
  22. */
  23. public function __construct($timestamp, $id, $flags, $context, $token)
  24. {
  25. $this->setTimestamp($timestamp);
  26. $this->setId($id);
  27. $this->setFlags($flags);
  28. $this->setContext($context);
  29. $this->setToken($token);
  30. }
  31. /*private*/
  32. var $_timestamp;
  33. /**
  34. * Returns the Unix timestamp as obtained from the SSO token.
  35. */
  36. /*public*/
  37. function getTimestamp()
  38. {
  39. return $this->_timestamp;
  40. }
  41. /**
  42. * Sets the Unix timestamp.
  43. */
  44. /*private*/
  45. function setTimestamp($timestamp)
  46. {
  47. if (!$timestamp) {
  48. //throw new Exception('Error: WLL_User: Null timestamp.');
  49. $this->setError('Error: WLL_User: Null timestamp.');
  50. return ;
  51. }
  52. if (!preg_match('/^\d+$/', $timestamp) || ($timestamp <= 0)) {
  53. //throw new Exception('Error: WLL_User: Invalid timestamp: ' . $timestamp);
  54. $this->setError('Error: WLL_User: Invalid timestamp: ' . $timestamp);
  55. return ;
  56. }
  57. $this->_timestamp = $timestamp;
  58. }
  59. /*private*/
  60. var $_id;
  61. /**
  62. * Returns the pairwise unique ID for the user.
  63. */
  64. /*public*/
  65. function getId()
  66. {
  67. return $this->_id;
  68. }
  69. /**
  70. * Sets the pairwise unique ID for the user.
  71. */
  72. /*private*/
  73. function setId($id)
  74. {
  75. if (!$id) {
  76. //throw new Exception('Error: WLL_User: Null id.');
  77. $this->setError('Error: WLL_User: Null id.');
  78. return ;
  79. }
  80. if (!preg_match('/^\w+$/', $id)) {
  81. //throw new Exception('Error: WLL_User: Invalid id: ' . $id);
  82. $this->setError('Error: WLL_User: Invalid id: ' . $id);
  83. return ;
  84. }
  85. $this->_id = $id;
  86. }
  87. /*private*/
  88. var $_usePersistentCookie;
  89. /**
  90. * Indicates whether the application is expected to store the
  91. * user token in a session or persistent cookie.
  92. */
  93. /*public*/
  94. function usePersistentCookie()
  95. {
  96. return $this->_usePersistentCookie;
  97. }
  98. /**
  99. * Sets the usePersistentCookie flag for the user.
  100. */
  101. /*private*/
  102. function setFlags($flags)
  103. {
  104. $this->_usePersistentCookie = false;
  105. if (preg_match('/^\d+$/', $flags)) {
  106. $this->_usePersistentCookie = (($flags % 2) == 1);
  107. }
  108. }
  109. /*private*/
  110. var $_context;
  111. /**
  112. * Returns the application context that was originally passed
  113. * to the sign-in request, if any.
  114. */
  115. /*public*/
  116. function getContext()
  117. {
  118. return $this->_context;
  119. }
  120. /**
  121. * Sets the the Application context.
  122. */
  123. /*private*/
  124. function setContext($context)
  125. {
  126. $this->_context = $context;
  127. }
  128. /*private*/
  129. var $_token;
  130. /**
  131. * Returns the encrypted Web Authentication token containing
  132. * the UID. This can be cached in a cookie and the UID can be
  133. * retrieved by calling the ProcessToken method.
  134. */
  135. /*public*/
  136. function getToken()
  137. {
  138. return $this->_token;
  139. }
  140. /**
  141. * Sets the the User token.
  142. */
  143. /*private*/
  144. function setToken($token)
  145. {
  146. $this->_token = $token;
  147. }
  148. var $_error = false;
  149. function setError($str)
  150. {
  151. $this->_error = $str;
  152. }
  153. function getError()
  154. {
  155. if ($this->_error !== false)
  156. {
  157. return $this->_error;
  158. }
  159. }
  160. }
  161. /**
  162. * Holds the Consent Token object corresponding to consent granted.
  163. */
  164. class WLL_ConsentToken
  165. {
  166. /**
  167. * Indicates whether the delegation token is set and has not expired.
  168. */
  169. /*public*/
  170. function isValid()
  171. {
  172. if (!$this->getDelegationToken()) {
  173. return false;
  174. }
  175. $now = time();
  176. return (($now-300) < $this->getExpiry());
  177. }
  178. /**
  179. * Refreshes the current token and replace it. If operation succeeds
  180. * true is returned to signify success.
  181. */
  182. /*public*/
  183. function refresh()
  184. {
  185. $wll = $this->_wll;
  186. $ct = $wll->refreshConsentToken($this);
  187. if (!$ct) {
  188. return false;
  189. }
  190. $this->copy($ct);
  191. return true;
  192. }
  193. /*private*/
  194. var $_wll;
  195. /**
  196. * Initialize the ConsentToken module with the WindowsLiveLogin,
  197. * delegation token, refresh token, session key, expiry, offers,
  198. * location ID, context, decoded token, and raw token.
  199. */
  200. public function __construct(
  201. $wll, $delegationtoken, $refreshtoken,
  202. $sessionkey, $expiry, $offers, $locationID, $context,
  203. $decodedtoken, $token
  204. )
  205. {
  206. $this->_wll = $wll;
  207. $this->setDelegationToken($delegationtoken);
  208. $this->setRefreshToken($refreshtoken);
  209. $this->setSessionKey($sessionkey);
  210. $this->setExpiry($expiry);
  211. $this->setOffers($offers);
  212. $this->setLocationID($locationID);
  213. $this->setContext($context);
  214. $this->setDecodedToken($decodedtoken);
  215. $this->setToken($token);
  216. }
  217. /*private*/
  218. var $_delegationtoken;
  219. /**
  220. * Gets the Delegation token.
  221. */
  222. /*public*/
  223. function getDelegationToken()
  224. {
  225. return $this->_delegationtoken;
  226. }
  227. /**
  228. * Sets the Delegation token.
  229. */
  230. /*private*/
  231. function setDelegationToken($delegationtoken)
  232. {
  233. if (!$delegationtoken) {
  234. //throw new Exception('Error: WLL_ConsentToken: Null delegation token.');
  235. $this->setError('Error: WLL_ConsentToken: Null delegation token.');
  236. return ;
  237. }
  238. $this->_delegationtoken = $delegationtoken;
  239. }
  240. /*private*/
  241. var $_refreshtoken;
  242. /**
  243. * Gets the refresh token.
  244. */
  245. /*public*/
  246. function getRefreshToken()
  247. {
  248. return $this->_refreshtoken;
  249. }
  250. /**
  251. * Sets the refresh token.
  252. */
  253. /*private*/
  254. function setRefreshToken($refreshtoken)
  255. {
  256. $this->_refreshtoken = $refreshtoken;
  257. }
  258. /*private*/
  259. var $_sessionkey;
  260. /**
  261. * Gets the session key.
  262. */
  263. /*public*/
  264. function getSessionKey()
  265. {
  266. return $this->_sessionkey;
  267. }
  268. /**
  269. * Sets the session key.
  270. */
  271. /*private*/
  272. function setSessionKey($sessionkey)
  273. {
  274. if (!$sessionkey) {
  275. //throw new Exception('Error: WLL_ConsentToken: Null session key.');
  276. $this->setError('Error: WLL_ConsentToken: Null session key.');
  277. return ;
  278. }
  279. $this->_sessionkey = base64_decode(urldecode($sessionkey));
  280. }
  281. /*private*/
  282. var $_expiry;
  283. /**
  284. * Gets the expiry time of delegation token.
  285. */
  286. /*public*/
  287. function getExpiry()
  288. {
  289. return $this->_expiry;
  290. }
  291. /**
  292. * Sets the expiry time of delegation token.
  293. */
  294. /*private*/
  295. function setExpiry($expiry)
  296. {
  297. if (!$expiry) {
  298. //throw new Exception('Error: WLL_ConsentToken: Null expiry time.');
  299. $this->setError('Error: WLL_ConsentToken: Null expiry time.');
  300. return ;
  301. }
  302. if (!preg_match('/^\d+$/', $expiry) || ($expiry <= 0)) {
  303. //throw new Exception('Error: WLL_ConsentToken: Invalid expiry time: ' . $expiry);
  304. $this->setError('Error: WLL_ConsentToken: Invalid expiry time: ' . $expiry);
  305. return ;
  306. }
  307. $this->_expiry = $expiry;
  308. }
  309. /*private*/
  310. var $_offers;
  311. /**
  312. * Gets the list of offers/actions for which the user granted consent.
  313. */
  314. /*public*/
  315. function getOffers()
  316. {
  317. return $this->_offers;
  318. }
  319. /*private*/
  320. var $_offers_string;
  321. /**
  322. * Gets the string representation of all the offers/actions for which
  323. * the user granted consent.
  324. */
  325. /*public*/
  326. function getOffersString()
  327. {
  328. return $this->_offers_string;
  329. }
  330. /**
  331. * Sets the offers/actions for which user granted consent.
  332. */
  333. /*private*/
  334. function setOffers($offers)
  335. {
  336. if (!$offers) {
  337. //throw new Exception('Error: WLL_ConsentToken: Null offers.');
  338. $this->setError('Error: WLL_ConsentToken: Null offers.');
  339. return ;
  340. }
  341. $offers = urldecode($offers);
  342. //Split $offers by ";" and then take only substring before first ":"
  343. if(preg_match_all("/(^|;)([^:;]*)/", $offers, $arMatch))
  344. {
  345. $this->_offers = $arMatch[2];
  346. $this->_offers_string = ltrim(implode(",", $arMatch[2]), ",");
  347. }
  348. else
  349. {
  350. $this->_offers = array();
  351. $this->_offers_string = "";
  352. }
  353. }
  354. /*private*/
  355. var $_locationID;
  356. /**
  357. * Gets the location ID.
  358. */
  359. /*public*/
  360. function getLocationID()
  361. {
  362. return $this->_locationID;
  363. }
  364. /**
  365. * Sets the location ID.
  366. */
  367. /*private*/
  368. function setLocationID($locationID)
  369. {
  370. if (!$locationID) {
  371. //throw new Exception('Error: WLL_ConsentToken: Null Location ID.');
  372. $this->setError('Error: WLL_ConsentToken: Null Location ID.');
  373. return ;
  374. }
  375. $this->_locationID = $locationID;
  376. }
  377. /*private*/
  378. var $_context;
  379. /**
  380. * Returns the application context that was originally passed
  381. * to the sign-in request, if any.
  382. */
  383. /*public*/
  384. function getContext()
  385. {
  386. return $this->_context;
  387. }
  388. /**
  389. * Sets the application context.
  390. */
  391. /*private*/
  392. function setContext($context)
  393. {
  394. $this->_context = $context;
  395. }
  396. /*private*/
  397. var $_decodedtoken;
  398. /**
  399. * Gets the decoded token.
  400. */
  401. /*public*/
  402. function getDecodedToken()
  403. {
  404. return $this->_decodedtoken;
  405. }
  406. /**
  407. * Sets the decoded token.
  408. */
  409. /*private*/
  410. function setDecodedToken($decodedtoken)
  411. {
  412. $this->_decodedtoken = $decodedtoken;
  413. }
  414. /*private*/
  415. var $_token;
  416. /**
  417. * Gets the raw token.
  418. */
  419. /*public*/
  420. function getToken()
  421. {
  422. return $this->_token;
  423. }
  424. /**
  425. * Sets the raw token.
  426. */
  427. /*private*/
  428. function setToken($token)
  429. {
  430. $this->_token = $token;
  431. }
  432. /**
  433. * Makes a copy of the ConsentToken object.
  434. */
  435. /*private*/
  436. function copy($ct)
  437. {
  438. $this->_delegationtoken = $ct->_delegationtoken;
  439. $this->_refreshtoken = $ct->_refreshtoken;
  440. $this->_sessionkey = $ct->_sessionkey;
  441. $this->_expiry = $ct->_expiry;
  442. $this->_offers = $ct->_offers;
  443. $this->_offers_string = $ct->_offers_string;
  444. $this->_locationID = $ct->_locationID;
  445. $this->_decodedtoken = $ct->_decodedtoken;
  446. $this->_token = $ct->_token;
  447. }
  448. var $_error = false;
  449. function setError($str)
  450. {
  451. $this->_error = $str;
  452. }
  453. function getError()
  454. {
  455. if ($this->_error !== false)
  456. {
  457. return $this->_error;
  458. }
  459. }
  460. }
  461. class WindowsLiveLogin
  462. {
  463. /* Implementation of basic methods for Web Authentication support. */
  464. /*private*/
  465. var $_debug = false;
  466. /**
  467. * Stub implementation for logging errors. If you want to enable
  468. * debugging output, set this to true. In this implementation
  469. * errors will be logged using the PHP error_log function.
  470. */
  471. /*public*/
  472. function setDebug($debug)
  473. {
  474. $this->_debug = $debug;
  475. }
  476. /**
  477. * Stub implementation for logging errors. By default, this
  478. * function does nothing if the debug flag has not been set with
  479. * setDebug. Otherwise, errors are logged using the PHP error_log
  480. * function.
  481. */
  482. /*private*/
  483. function debug($string)
  484. {
  485. if ($this->_debug) {
  486. echo "$string<br>";
  487. error_log($string);
  488. }
  489. }
  490. /**
  491. * Stub implementation for handling a fatal error.
  492. */
  493. /*private*/
  494. function fatal($string)
  495. {
  496. $this->debug($string);
  497. //throw new Exception($string);
  498. $this->setError($string);
  499. }
  500. /**
  501. * Initialize the WindowsLiveLogin module with the application ID,
  502. * secret key, and security algorithm.
  503. *
  504. * We recommend that you employ strong measures to protect the
  505. * secret key. The secret key should never be exposed to the Web
  506. * or other users.
  507. *
  508. * Be aware that if you do not supply these settings at
  509. * initialization time, you may need to set the corresponding
  510. * properties manually.
  511. *
  512. * For Delegated Authentication, you may optionally specify the
  513. * privacy policy URL and return URL. If you do not specify these
  514. * values here, the default values that you specified when you
  515. * registered your application will be used.
  516. *
  517. * The 'force_delauth_nonprovisioned' flag also indicates whether
  518. * your application is registered for Delegated Authentication
  519. * (that is, whether it uses an application ID and secret key). We
  520. * recommend that your Delegated Authentication application always
  521. * be registered for enhanced security and functionality.
  522. */
  523. public function __construct(
  524. $appid=null, $secret=null, $securityalgorithm=null,
  525. $force_delauth_nonprovisioned=null,
  526. $policyurl=null, $returnurl=null
  527. )
  528. {
  529. $this->setForceDelAuthNonProvisioned($force_delauth_nonprovisioned);
  530. if ($appid) {
  531. $this->setAppId($appid);
  532. }
  533. if ($secret) {
  534. $this->setSecret($secret);
  535. }
  536. if ($securityalgorithm) {
  537. $this->setSecurityAlgorithm($securityalgorithm);
  538. }
  539. if ($policyurl) {
  540. $this->setPolicyUrl($policyurl);
  541. }
  542. if ($returnurl) {
  543. $this->setReturnUrl($returnurl);
  544. }
  545. }
  546. /**
  547. * Initialize the WindowsLiveLogin module from a settings file.
  548. *
  549. * 'settingsFile' specifies the location of the XML settings file
  550. * that contains the application ID, secret key, and security
  551. * algorithm. The file is of the following format:
  552. *
  553. * <windowslivelogin>
  554. * <appid>APPID</appid>
  555. * <secret>SECRET</secret>
  556. * <securityalgorithm>wsignin1.0</securityalgorithm>
  557. * </windowslivelogin>
  558. *
  559. * In a Delegated Authentication scenario, you may also specify
  560. * 'returnurl' and 'policyurl' in the settings file, as shown in the
  561. * Delegated Authentication samples.
  562. *
  563. * We recommend that you store the WindowsLiveLogin settings file
  564. * in an area on your server that cannot be accessed through the
  565. * Internet. This file contains important confidential information.
  566. */
  567. /*public static*/
  568. function initFromXml($settingsFile)
  569. {
  570. $o = new WindowsLiveLogin();
  571. $settings = $o->parseSettings($settingsFile);
  572. if (@$settings['debug'] == 'true') {
  573. $o->setDebug(true);
  574. }
  575. else {
  576. $o->setDebug(false);
  577. }
  578. if (@$settings['force_delauth_nonprovisioned'] == 'true') {
  579. $o->setForceDelAuthNonProvisioned(true);
  580. }
  581. else {
  582. $o->setForceDelAuthNonProvisioned(false);
  583. }
  584. $o->setAppId(@$settings['appid']);
  585. $o->setSecret(@$settings['secret']);
  586. $o->setOldSecret(@$settings['oldsecret']);
  587. $o->setOldSecretExpiry(@$settings['oldsecretexpiry']);
  588. $o->setSecurityAlgorithm(@$settings['securityalgorithm']);
  589. $o->setPolicyUrl(@$settings['policyurl']);
  590. $o->setReturnUrl(@$settings['returnurl']);
  591. $o->setBaseUrl(@$settings['baseurl']);
  592. $o->setSecureUrl(@$settings['secureurl']);
  593. $o->setConsentBaseUrl(@$settings['consenturl']);
  594. return $o;
  595. }
  596. /*private*/
  597. var $_appid;
  598. /**
  599. * Sets the application ID. Use this method if you did not specify
  600. * an application ID at initialization.
  601. **/
  602. /*public*/
  603. function setAppId($appid)
  604. {
  605. $_force_delauth_nonprovisioned = $this->_force_delauth_nonprovisioned;
  606. if (!$appid) {
  607. if ($_force_delauth_nonprovisioned) {
  608. return;
  609. }
  610. $this->fatal('Error: setAppId: Null application ID.');
  611. }
  612. if (!preg_match('/^\w+$/', $appid)) {
  613. $this->fatal("Error: setAppId: Application ID must be alpha-numeric: $appid");
  614. }
  615. $this->_appid = $appid;
  616. }
  617. /**
  618. * Returns the application ID.
  619. */
  620. /*public*/
  621. function getAppId()
  622. {
  623. if (!$this->_appid) {
  624. $this->fatal('Error: getAppId: Application ID was not set. Aborting.');
  625. }
  626. return $this->_appid;
  627. }
  628. /*private*/
  629. var $_signkey;
  630. /*private*/
  631. var $_cryptkey;
  632. /**
  633. * Sets your secret key. Use this method if you did not specify
  634. * a secret key at initialization.
  635. */
  636. /*public*/
  637. function setSecret($secret)
  638. {
  639. $_force_delauth_nonprovisioned = $this->_force_delauth_nonprovisioned;
  640. if (!$secret || (strlen($secret) < 16)) {
  641. if ($_force_delauth_nonprovisioned) {
  642. return;
  643. }
  644. $this->fatal("Error: setSecret: Secret key is expected to be non-null and longer than 16 characters.");
  645. }
  646. $this->_signkey = $this->derive($secret, "SIGNATURE");
  647. $this->_cryptkey = $this->derive($secret, "ENCRYPTION");
  648. }
  649. /*private*/
  650. var $_oldsignkey;
  651. /*private*/
  652. var $_oldcryptkey;
  653. /**
  654. * Sets your old secret key.
  655. *
  656. * Use this property to set your old secret key if you are in the
  657. * process of transitioning to a new secret key. You may need this
  658. * property because the Windows Live ID servers can take up to
  659. * 24 hours to propagate a new secret key after you have updated
  660. * your application settings.
  661. *
  662. * If an old secret key is specified here and has not expired
  663. * (as determined by the oldsecretexpiry setting), it will be used
  664. * as a fallback if token decryption fails with the new secret
  665. * key.
  666. */
  667. /*public*/
  668. function setOldSecret($secret)
  669. {
  670. if (!$secret) {
  671. return;
  672. }
  673. if (strlen($secret) < 16) {
  674. $this->fatal("Error: setOldSecret: Secret key is expected to be non-null and longer than 16 characters.");
  675. }
  676. $this->_oldsignkey = $this->derive($secret, "SIGNATURE");
  677. $this->_oldcryptkey = $this->derive($secret, "ENCRYPTION");
  678. }
  679. /*private*/
  680. var $_oldsecretexpiry;
  681. /**
  682. * Sets the expiry time for your old secret key.
  683. *
  684. * After this time has passed, the old secret key will no longer be
  685. * used even if token decryption fails with the new secret key.
  686. *
  687. * The old secret expiry time is represented as the number of seconds
  688. * elapsed since January 1, 1970.
  689. */
  690. /*public*/
  691. function setOldSecretExpiry($timestamp)
  692. {
  693. if (!$timestamp) {
  694. return;
  695. }
  696. if (!preg_match('/^\d+$/', $timestamp) || ($timestamp <= 0)) {
  697. $this->fatal('Error: setOldSecretExpiry Invalid timestamp: '
  698. . $timestamp);
  699. }
  700. $this->_oldsecretexpiry = $timestamp;
  701. }
  702. /**
  703. * Gets the old secret key expiry time.
  704. */
  705. /*public*/
  706. function getOldSecretExpiry()
  707. {
  708. return $this->_oldsecretexpiry;
  709. }
  710. /*private*/
  711. var $_securityalgorithm;
  712. /**
  713. * Sets the version of the security algorithm being used.
  714. */
  715. /*public*/
  716. function setSecurityAlgorithm($securityalgorithm)
  717. {
  718. $this->_securityalgorithm = $securityalgorithm;
  719. }
  720. /**
  721. * Gets the version of the security algorithm being used.
  722. */
  723. /*public*/
  724. function getSecurityAlgorithm()
  725. {
  726. $securityalgorithm = $this->_securityalgorithm;
  727. if (!$securityalgorithm) {
  728. return 'wsignin1.0';
  729. }
  730. return $securityalgorithm;
  731. }
  732. /*private*/
  733. var $_force_delauth_nonprovisioned;
  734. /**
  735. * Sets a flag that indicates whether Delegated Authentication
  736. * is non-provisioned (i.e. does not use an application ID or secret
  737. * key).
  738. */
  739. /*public*/
  740. function setForceDelAuthNonProvisioned($force_delauth_nonprovisioned)
  741. {
  742. $this->_force_delauth_nonprovisioned = $force_delauth_nonprovisioned;
  743. }
  744. /*private*/
  745. var $_policyurl;
  746. /**
  747. * Sets the privacy policy URL if you did not provide one at initialization time.
  748. */
  749. /*public*/
  750. function setPolicyUrl($policyurl)
  751. {
  752. $_force_delauth_nonprovisioned = $this->_force_delauth_nonprovisioned;
  753. if (!$policyurl) {
  754. if ($_force_delauth_nonprovisioned) {
  755. $this->fatal("Error: setPolicyUrl: Null policy URL given.");
  756. }
  757. }
  758. $this->_policyurl = $policyurl;
  759. }
  760. /**
  761. * Gets the privacy policy URL for your site.
  762. */
  763. /*public*/
  764. function getPolicyUrl()
  765. {
  766. $policyurl = $this->_policyurl;
  767. $_force_delauth_nonprovisioned = $this->_force_delauth_nonprovisioned;
  768. if (!$policyurl) {
  769. $this->debug("Warning: In the initial release of Delegated Auth, a Policy URL must be configured in the SDK for both provisioned and non-provisioned scenarios.");
  770. if ($_force_delauth_nonprovisioned) {
  771. $this->fatal("Error: getPolicyUrl: Policy URL must be set in a Del Auth non-provisioned scenario. Aborting.");
  772. }
  773. }
  774. return $policyurl;
  775. }
  776. /*private*/
  777. var $_returnurl;
  778. /**
  779. * Sets the return URL--the URL on your site to which the consent
  780. * service redirects users (along with the action, consent token,
  781. * and application context) after they have successfully provided
  782. * consent information for Delegated Authentication. This value will
  783. * override the return URL specified during registration.
  784. */
  785. /*public*/
  786. function setReturnUrl($returnurl)
  787. {
  788. $_force_delauth_nonprovisioned = $this->_force_delauth_nonprovisioned;
  789. if (!$returnurl) {
  790. if ($_force_delauth_nonprovisioned) {
  791. $this->fatal("Error: setReturnUrl: Null return URL given.");
  792. }
  793. }
  794. $this->_returnurl = $returnurl;
  795. }
  796. /**
  797. * Returns the return URL of your site.
  798. */
  799. /*public*/
  800. function getReturnUrl()
  801. {
  802. $_force_delauth_nonprovisioned = $this->_force_delauth_nonprovisioned;
  803. $returnurl = $this->_returnurl;
  804. if (!$returnurl) {
  805. if ($_force_delauth_nonprovisioned) {
  806. $this->fatal("Error: getReturnUrl: Return URL must be set in a Del Auth non-provisioned scenario. Aborting.");
  807. }
  808. }
  809. return $returnurl;
  810. }
  811. /*private*/
  812. var $_baseurl;
  813. /**
  814. * Sets the base URL to use for the Windows Live Login server.
  815. * You should not have to change this property. Furthermore, we recommend
  816. * that you use the Sign In control instead of the URL methods
  817. * provided here.
  818. */
  819. /*public*/
  820. function setBaseUrl($baseurl)
  821. {
  822. $this->_baseurl = $baseurl;
  823. }
  824. /**
  825. * Gets the base URL to use for the Windows Live Login server.
  826. * You should not have to use this property. Furthermore, we recommend
  827. * that you use the Sign In control instead of the URL methods
  828. * provided here.
  829. */
  830. /*public*/
  831. function getBaseUrl()
  832. {
  833. $baseurl = $this->_baseurl;
  834. if (!$baseurl) {
  835. return "http://login.live.com/";
  836. }
  837. return $baseurl;
  838. }
  839. /*private*/
  840. var $_secureurl;
  841. /**
  842. * Sets the secure (HTTPS) URL to use for the Windows Live Login
  843. * server. You should not have to change this property.
  844. */
  845. /*public*/
  846. function setSecureUrl($secureurl)
  847. {
  848. $this->_secureurl = $secureurl;
  849. }
  850. /**
  851. * Gets the secure (HTTPS) URL to use for the Windows Live Login
  852. * server. You should not have to use this functon directly.
  853. */
  854. /*public*/
  855. function getSecureUrl()
  856. {
  857. $secureurl = $this->_secureurl;
  858. if (!$secureurl) {
  859. return "https://login.live.com/";
  860. }
  861. return $secureurl;
  862. }
  863. /*private*/
  864. var $_consenturl;
  865. /**
  866. * Sets the Consent Base URL to use for the Windows Live Consent
  867. * server. You should not have to use or change this property directly.
  868. */
  869. /*public*/
  870. function setConsentBaseUrl($consenturl)
  871. {
  872. $this->_consenturl = $consenturl;
  873. }
  874. /**
  875. * Gets the URL to use for the Windows Live Consent server. You
  876. * should not have to use or change this directly.
  877. */
  878. /*public*/
  879. function getConsentBaseUrl()
  880. {
  881. $consenturl = $this->_consenturl;
  882. if (!$consenturl) {
  883. return "https://consent.live.com/";
  884. }
  885. return $consenturl;
  886. }
  887. /* Methods for Web Authentication support. */
  888. /**
  889. * Returns the sign-in URL to use for the Windows Live Login server.
  890. * We recommend that you use the Sign In control instead.
  891. *
  892. * If you specify it, 'context' will be returned as-is in the sign-in
  893. * response for site-specific use.
  894. */
  895. /*public*/
  896. function getLoginUrl($context=null, $market=null)
  897. {
  898. $url = $this->getBaseUrl();
  899. $url .= 'wlogin.srf?appid=' . $this->getAppId();
  900. $url .= '&alg=' . $this->getSecurityAlgorithm();
  901. $url .= ($context ? '&appctx=' . urlencode($context) : '');
  902. $url .= ($market ? '&mkt=' . urlencode($market) : '');
  903. return $url;
  904. }
  905. /**
  906. * Returns the sign-out URL to use for the Windows Live Login server.
  907. * We recommend that you use the Sign In control instead.
  908. */
  909. /*public*/
  910. function getLogoutUrl($market=null)
  911. {
  912. $url = $this->getBaseUrl();
  913. $url .= "logout.srf?appid=" . $this->getAppId();
  914. $url .= ($market ? '&mkt=' . urlencode($market) : '');
  915. return $url;
  916. }
  917. /**
  918. * Processes the sign-in response from Windows Live Login server.
  919. *
  920. * @param query contains the preprocessed POST query, a map of
  921. * Strings to an an array of Strings, such as that
  922. * returned by ServletRequest.getParameterMap().
  923. * @return a User object on successful sign-in; otherwise null.
  924. */
  925. /*public*/
  926. function processLogin($query)
  927. {
  928. $action = @$query['action'];
  929. if ($action != 'login') {
  930. $this->debug("Warning: processLogin: query action ignored: $action");
  931. return;
  932. }
  933. $token = @$query['stoken'];
  934. $context = urldecode(@$query['appctx']);
  935. return $this->processToken($token, $context);
  936. }
  937. /**
  938. * Decodes and validates a Web Authentication token. Returns a User
  939. * object on success. If a context is passed in, it will be returned
  940. * as the context field in the User object.
  941. */
  942. /*public*/
  943. function processToken($token, $context=null)
  944. {
  945. if (!$token) {
  946. $this->debug('Error: processToken: Invalid token specified.');
  947. return;
  948. }
  949. $decodedToken = $this->decodeAndValidateToken($token);
  950. if (!$decodedToken) {
  951. $this->debug("Error: processToken: Failed to decode/validate token: $token");
  952. return;
  953. }
  954. $parsedToken = $this->parse($decodedToken);
  955. if (!$parsedToken) {
  956. $this->debug("Error: processToken: Failed to parse token after decoding: $token");
  957. return;
  958. }
  959. $appid = $this->getAppId();
  960. $tokenappid = @$parsedToken['appid'];
  961. if ($appid != $tokenappid) {
  962. $this->debug("Error: processToken: Application ID in token did not match ours: $tokenappid, $appid");
  963. return;
  964. }
  965. $user = null;
  966. //try {
  967. $user = new WLL_User(@$parsedToken['ts'],
  968. @$parsedToken['uid'],
  969. @$parsedToken['flags'],
  970. $context, $token);
  971. //} catch (Exception $e) {
  972. if ($user->getError() !== false)
  973. $this->debug("Error: processToken: Contents of token considered invalid: " + $user->getError());
  974. //}
  975. return $user;
  976. }
  977. /**
  978. * Returns an appropriate content type and body response that the
  979. * application handler can return to signify a successful sign-out
  980. * from the application.
  981. *
  982. * When a user signs out of Windows Live or a Windows Live
  983. * application, a best-effort attempt is made at signing the user out
  984. * from all other Windows Live applications the user might be signed
  985. * in to. This is done by calling the handler page for each
  986. * application with 'action' set to 'clearcookie' in the query
  987. * string. The application handler is then responsible for clearing
  988. * any cookies or data associated with the sign-in. After successfully
  989. * signing the user out, the handler should return a GIF (any GIF)
  990. * image as response to the 'action=clearcookie' query.
  991. */
  992. /*public*/
  993. function getClearCookieResponse()
  994. {
  995. $type = "image/gif";
  996. $content = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7";
  997. $content = base64_decode($content);
  998. return array($type, $content);
  999. }
  1000. /* Methods for Delegated Authentication. */
  1001. /*
  1002. * Returns the consent URL to use for Delegated Authentication for
  1003. * the given comma-delimited list of offers.
  1004. *
  1005. * If you specify it, 'context' will be returned as-is in the consent
  1006. * response for site-specific use.
  1007. *
  1008. * The registered/configured return URL can also be overridden by
  1009. * specifying 'ru' here.
  1010. *
  1011. * You can change the language in which the consent page is displayed
  1012. * by specifying a culture ID (For example, 'fr-fr' or 'en-us') in the
  1013. * 'market' parameter.
  1014. */
  1015. /*public*/
  1016. function getConsentUrl($offers, $context=null, $ru=null, $market=null)
  1017. {
  1018. if (!$offers) {
  1019. //throw new Exception('Error: getConsentUrl: Invalid offers list.');
  1020. $this->setError('Error: getConsentUrl: Invalid offers list.');
  1021. return false;
  1022. }
  1023. $url = $this->getConsentBaseUrl();
  1024. $url .= 'Delegation.aspx?ps=' . urlencode($offers);
  1025. $ru = ($ru ? $ru : $this->getReturnUrl());
  1026. $url .= ($ru ? '&ru=' . urlencode($ru) : '');
  1027. $pl = $this->getPolicyUrl();
  1028. $url .= ($pl ? '&pl=' . urlencode($pl) : '');
  1029. $url .= ($market ? '&mkt=' . urlencode($market) : '');
  1030. if (!$this->_force_delauth_nonprovisioned) {
  1031. $url .= '&app=' . $this->getAppVerifier();
  1032. }
  1033. $url .= ($context ? '&appctx=' . urlencode($context) : '');
  1034. return $url;
  1035. }
  1036. /*
  1037. * Returns the URL to use to download a new consent token, given the
  1038. * offers and refresh token.
  1039. *
  1040. * The registered/configured return URL can also be overridden by
  1041. * specifying 'ru' here.
  1042. */
  1043. /*public*/
  1044. function getRefreshConsentTokenUrl($offers, $refreshtoken, $ru=null)
  1045. {
  1046. $_force_delauth_nonprovisioned = $this->_force_delauth_nonprovisioned;
  1047. if (!$offers) {
  1048. //throw new Exception('Error: getRefreshConsentTokenUrl: Invalid offers list.');
  1049. $this->setError('Error: getRefreshConsentTokenUrl: Invalid offers list.');
  1050. return false;
  1051. }
  1052. if (!$refreshtoken) {
  1053. //throw new Exception('Error: getRefreshConsentTokenUrl: Invalid refresh token.');
  1054. $this->setError('Error: getRefreshConsentTokenUrl: Invalid refresh token.');
  1055. return false;
  1056. }
  1057. $url = $this->getConsentBaseUrl();
  1058. $url .= 'RefreshToken.aspx?ps=' . urlencode($offers);
  1059. $url .= '&reft=' . $refreshtoken;
  1060. $ru = ($ru ? $ru : $this->getReturnUrl());
  1061. $url .= ($ru ? '&ru=' . urlencode($ru) : '');
  1062. if (!$this->_force_delauth_nonprovisioned) {
  1063. $url .= '&app=' . $this->getAppVerifier();
  1064. }
  1065. return $url;
  1066. }
  1067. /*
  1068. * Returns the URL for the consent-management user interface.
  1069. *
  1070. * You can change the language in which the consent page is displayed
  1071. * by specifying a culture ID (For example, 'fr-fr' or 'en-us') in the
  1072. * 'market' parameter.
  1073. */
  1074. /*public*/
  1075. function getManageConsentUrl($market=null)
  1076. {
  1077. $url = $this->getConsentBaseUrl();
  1078. $url .= 'ManageConsent.aspx';
  1079. $url .= ($market ? '?mkt=' . urlencode($market) : '');
  1080. return $url;
  1081. }
  1082. /*
  1083. * Processes the POST response from the Delegated Authentication
  1084. * service after a user has granted consent. The processConsent
  1085. * function extracts the consent token string and returns the result
  1086. * of invoking the processConsentToken method.
  1087. */
  1088. /*public*/
  1089. function processConsent($query)
  1090. {
  1091. $action = @$query['action'];
  1092. if ($action != 'delauth') {
  1093. $this->debug("Warning: processConsent: query action ignored: $action");
  1094. return;
  1095. }
  1096. $responsecode = @$query['ResponseCode'];
  1097. if ($responsecode != 'RequestApproved') {
  1098. $this->debug("Warning: processConsent: consent was not successfully granted: $responsecode");
  1099. return;
  1100. }
  1101. $token = @$query['ConsentToken'];
  1102. $context = urldecode(@$query['appctx']);
  1103. return $this->processConsentToken($token, $context);
  1104. }
  1105. /*
  1106. * Processes the consent token string that is returned in the POST
  1107. * response by the Delegated Authentication service after a
  1108. * user has granted consent.
  1109. */
  1110. /*public*/
  1111. function processConsentToken($token, $context=null)
  1112. {
  1113. if (!$token) {
  1114. $this->debug('Error: processConsentToken: Null token.');
  1115. return;
  1116. }
  1117. $decodedToken = $token;
  1118. $parsedToken = $this->parse(urldecode($decodedToken));
  1119. if (!$parsedToken) {
  1120. $this->debug("Error: processConsentToken: Failed to parse token: $token");
  1121. return;
  1122. }
  1123. $eact = @$parsedToken['eact'];
  1124. if ($eact) {
  1125. $decodedToken = $this->decodeAndValidateToken($eact);
  1126. if (!$decodedToken) {
  1127. $this->debug("Error: processConsentToken: Failed to decode/validate token: $token");
  1128. return;
  1129. }
  1130. $parsedToken = $this->parse($decodedToken);
  1131. if (!$parsedToken) {
  1132. $this->debug("Error: processConsentToken: Failed to parse token after decoding: $token");
  1133. return;
  1134. }
  1135. $decodedToken = urlencode($decodedToken);
  1136. }
  1137. $consenttoken = null;
  1138. //try {
  1139. $consenttoken = new WLL_ConsentToken($this,
  1140. @$parsedToken['delt'],
  1141. @$parsedToken['reft'],
  1142. @$parsedToken['skey'],
  1143. @$parsedToken['exp'],
  1144. @$parsedToken['offer'],
  1145. @$parsedToken['lid'],
  1146. $context, $decodedToken, $token);
  1147. //} catch (Exception $e) {
  1148. if($consenttoken->getError() !== false)
  1149. $this->debug("Error: processConsentToken: Contents of token considered invalid: " + $consenttoken->getError());
  1150. //}
  1151. return $consenttoken;
  1152. }
  1153. /*
  1154. * Attempts to obtain a new, refreshed token and return it. The
  1155. * original token is not modified.
  1156. */
  1157. /*public*/
  1158. function refreshConsentToken($token, $ru=null)
  1159. {
  1160. if (!$token) {
  1161. $this->debug("Error: refreshConsentToken: Null consent token.");
  1162. return;
  1163. }
  1164. $this->refreshConsentToken2($token->getOffersString(), $token->getRefreshToken(), $ru);
  1165. }
  1166. /*
  1167. * Helper function to obtain a new, refreshed token and return it.
  1168. * The original token is not modified.
  1169. */
  1170. /*public*/
  1171. function refreshConsentToken2($offers_string, $refreshtoken, $ru=null)
  1172. {
  1173. $body = $this->fetch($this->getRefreshConsentTokenUrl($offers_string, $refreshtoken, $ru));
  1174. if (!$body) {
  1175. $this->debug("Error: refreshConsentToken2: Failed to obtain a new token.");
  1176. return;
  1177. }
  1178. preg_match('/\{"ConsentToken":"(.*)"\}/', $body, $matches);
  1179. if(count($matches) == 2) {
  1180. return $matches[1];
  1181. }
  1182. else {
  1183. $this->debug("Error: refreshConsentToken2: Failed to extract token: $body");
  1184. return;
  1185. }
  1186. }
  1187. /* Common methods. */
  1188. /*
  1189. * Decodes and validates the token.
  1190. */
  1191. /*public*/
  1192. function decodeAndValidateToken($token, $cryptkey=null, $signkey=null,
  1193. $internal_allow_recursion=true)
  1194. {
  1195. if (!$cryptkey) {
  1196. $cryptkey = $this->_cryptkey;
  1197. }
  1198. if (!$signkey) {
  1199. $signkey = $this->_signkey;
  1200. }
  1201. $haveoldsecret = false;
  1202. $oldsecretexpiry = $this->getOldSecretExpiry();
  1203. $oldcryptkey = $this->_oldcryptkey;
  1204. $oldsignkey = $this->_oldsignkey;
  1205. if ($oldsecretexpiry and (time() < $oldsecretexpiry)) {
  1206. if ($oldcryptkey and $oldsignkey) {
  1207. $haveoldsecret = true;
  1208. }
  1209. }
  1210. $haveoldsecret = ($haveoldsecret and $internal_allow_recursion);
  1211. $stoken = $this->decodeToken($token, $cryptkey);
  1212. if ($stoken) {
  1213. $stoken = $this->validateToken($stoken, $signkey);
  1214. }
  1215. if (!$stoken and $haveoldsecret) {
  1216. $this->debug("Warning: Failed to validate token with current secret, attempting old secret.");
  1217. $stoken =
  1218. $this->decodeAndValidateToken($token, $oldcryptkey, $oldsignkey, false);
  1219. }
  1220. return $stoken;
  1221. }
  1222. /**
  1223. * Decodes the given token string; returns undef on failure.
  1224. *
  1225. * First, the string is URL-unescaped and base64 decoded.
  1226. * Second, the IV is extracted from the first 16 bytes of the string.
  1227. * Finally, the string is decrypted using the encryption key.
  1228. */
  1229. /*public*/
  1230. function decodeToken($token, $cryptkey=null)
  1231. {
  1232. if (!$cryptkey) {
  1233. $cryptkey = $this->_cryptkey;
  1234. }
  1235. if (!$cryptkey) {
  1236. $this->fatal("Error: decodeToken: Secret key was not set. Aborting.");
  1237. }
  1238. $ivLen = 16;
  1239. $token = $this->u64($token);
  1240. $len = strlen($token);
  1241. if (!$token || ($len <= $ivLen) || (($len % $ivLen) != 0)) {
  1242. $this->debug("Error: decodeToken: Attempted to decode invalid token.");
  1243. return;
  1244. }
  1245. $iv = substr($token, 0, 16);
  1246. $crypted = substr($token, 16);
  1247. return openssl_decrypt($crypted, "AES-128-CBC", $cryptkey, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
  1248. }
  1249. /**
  1250. * Creates a signature for the given string by using the signature
  1251. * key.
  1252. */
  1253. /*public*/
  1254. function signToken($token, $signkey=null)
  1255. {
  1256. if (!$signkey) {
  1257. $signkey = $this->_signkey;
  1258. }
  1259. if (!$signkey) {
  1260. $this->fatal("Error: signToken: Secret key was not set. Aborting.");
  1261. }
  1262. if (!$token) {
  1263. $this->debug("Attempted to sign null token.");
  1264. return;
  1265. }
  1266. return hash_hmac("sha256", $token, $signkey, true);
  1267. }
  1268. /**
  1269. * Extracts the signature from the token and validates it.
  1270. */
  1271. /*public*/
  1272. function validateToken($token, $signkey=null)
  1273. {
  1274. if (!$signkey) {
  1275. $signkey = $this->_signkey;
  1276. }
  1277. if (!$token) {
  1278. $this->debug("Error: validateToken: Invalid token.");
  1279. return;
  1280. }
  1281. $split = explode("&sig=", $token);
  1282. if (count($split) != 2) {
  1283. $this->debug("ERROR: validateToken: Invalid token: $token");
  1284. return;
  1285. }
  1286. list($body, $sig) = $split;
  1287. $sig = $this->u64($sig);
  1288. if (!$sig) {
  1289. $this->debug("Error: validateToken: Could not extract signature from token.");
  1290. return;
  1291. }
  1292. $sig2 = $this->signToken($body, $signkey);
  1293. if (!$sig2) {
  1294. $this->debug("Error: validateToken: Could not generate signature for the token.");
  1295. return;
  1296. }
  1297. if ($sig == $sig2) {
  1298. return $token;
  1299. }
  1300. $this->debug("Error: validateToken: Signature did not match.");
  1301. return;
  1302. }
  1303. /* Implementation of the methods needed to perform Windows Live
  1304. application verification as well as trusted sign-in. */
  1305. /**
  1306. * Generates an application verifier token. An IP address can
  1307. * optionally be included in the token.
  1308. */
  1309. /*public*/
  1310. function getAppVerifier($ip=null)
  1311. {
  1312. $token = 'appid=' . $this->getAppId() . '&ts=' . $this->getTimestamp();
  1313. $token .= ($ip ? "&ip={$ip}" : '');
  1314. $token .= '&sig=' . $this->e64($this->signToken($token));
  1315. return urlencode($token);
  1316. }
  1317. /**
  1318. * Returns the URL that is required to retrieve the application
  1319. * security token.
  1320. *
  1321. * By default, the application security token is generated for
  1322. * the Windows Live site; a specific Site ID can optionally be
  1323. * specified in 'siteid'. The IP address can also optionally be
  1324. * included in 'ip'.
  1325. *
  1326. * If 'js' is nil, a JavaScript Output Notation (JSON) response is
  1327. * returned in the following format:
  1328. *
  1329. * {"token":"<value>"}
  1330. *
  1331. * Otherwise, a JavaScript response is returned. It is assumed that
  1332. * WLIDResultCallback is a custom function implemented to handle the
  1333. * token value:
  1334. *
  1335. * WLIDResultCallback("<tokenvalue>");
  1336. */
  1337. /*public*/
  1338. function getAppLoginUrl($siteid=null, $ip=null, $js=null)
  1339. {
  1340. $url = $this->getSecureUrl();
  1341. $url .= 'wapplogin.srf?app=' . $this->getAppVerifier($ip);
  1342. $url .= '&alg=' . $this->getSecurityAlgorithm();
  1343. $url .= ($siteid ? "&id=$siteid" : '');
  1344. $url .= ($js ? '&js=1' : '');
  1345. return $url;
  1346. }
  1347. /**
  1348. * Retrieves the application security token for application
  1349. * verification from the application sign-in URL.
  1350. *
  1351. * By default, the application security token will be generated for
  1352. * the Windows Live site; a specific Site ID can optionally be
  1353. * specified in 'siteid'. The IP address can also optionally be
  1354. * included in 'ip'.
  1355. *
  1356. * Implementation note: The application security token is downloaded
  1357. * from the application sign-in URL in JSON format:
  1358. *
  1359. * {"token":"<value>"}
  1360. *
  1361. * Therefore we must extract <value> from the string and return it as
  1362. * seen here.
  1363. */
  1364. /*public*/
  1365. function getAppSecurityToken($siteid=null, $ip=null)
  1366. {
  1367. $body = $this->fetch($this->getAppLoginUrl($siteid, $ip));
  1368. if (!$body) {
  1369. $this->debug("Error: getAppSecurityToken: Could not fetch the application security token.");
  1370. return;
  1371. }
  1372. preg_match('/\{"token":"(.*)"\}/', $body, $matches);
  1373. if(count($matches) == 2) {
  1374. return $matches[1];
  1375. }
  1376. else {
  1377. $this->debug("Error: getAppSecurityToken: Failed to extract token: $body");
  1378. return;
  1379. }
  1380. }
  1381. /**
  1382. * Returns a string that can be passed to the getTrustedParams
  1383. * function as the 'retcode' parameter. If this is specified as the
  1384. * 'retcode', the application will be used as return URL after it
  1385. * finishes trusted sign-in.
  1386. */
  1387. /*public*/
  1388. function getAppRetCode()
  1389. {
  1390. return 'appid=' . $this->getAppId();
  1391. }
  1392. /**
  1393. * Returns a table of key-value pairs that must be posted to the
  1394. * sign-in URL for trusted sign-in. Use HTTP POST to do this. Be aware
  1395. * that the values in the table are neither URL nor HTML escaped and
  1396. * may have to be escaped if you are inserting them in code such as
  1397. * an HTML form.
  1398. *
  1399. * The user to be trusted on the local site is passed in as string
  1400. * 'user'.
  1401. *
  1402. * Optionally, 'retcode' specifies the resource to which successful
  1403. * sign-in is redirected, such as Windows Live Mail, and is typically
  1404. * a string in the format 'id=2000'. If you pass in the value from
  1405. * getAppRetCode instead, sign-in will be redirected to the
  1406. * application. Otherwise, an HTTP 200 response is returned.
  1407. */
  1408. /*public*/
  1409. function getTrustedParams($user, $retcode=null)
  1410. {
  1411. $token = $this->getTrustedToken($user);
  1412. if (!$token) {
  1413. return;
  1414. }
  1415. $token = "<wst:RequestSecurityTokenResponse xmlns:wst=\"http://schemas.xmlsoap.org/ws/2005/02/trust\"><wst:RequestedSecurityToken><wsse:BinarySecurityToken xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">$token</wsse:BinarySecurityToken></wst:RequestedSecurityToken><wsp:AppliesTo xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\"><wsa:EndpointReference xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\"><wsa:Address>uri:WindowsLiveID</wsa:Address></wsa:EndpointReference></wsp:AppliesTo></wst:RequestSecurityTokenResponse>";
  1416. $params = array();
  1417. $params['wa'] = $this->getSecurityAlgorithm();
  1418. $params['wresult'] = $token;
  1419. if ($retcode) {
  1420. $params['wctx'] = $retcode;
  1421. }
  1422. return $params;
  1423. }
  1424. /**
  1425. * Returns the trusted sign-in token in the format that is needed by a
  1426. * control doing trusted sign-in.
  1427. *
  1428. * The user to be trusted on the local site is passed in as string
  1429. * 'user'.
  1430. */
  1431. /*public*/
  1432. function getTrustedToken($user)
  1433. {
  1434. if (!$user) {
  1435. $this->debug('Error: getTrustedToken: Null user specified.');
  1436. return;
  1437. }
  1438. $token = "appid=" . $this->getAppId() . "&uid=" . urlencode($user)
  1439. . "&ts=". $this->getTimestamp();
  1440. $token .= "&sig=" . $this->e64($this->signToken($token));
  1441. return urlencode($token);
  1442. }
  1443. /**
  1444. * Returns the trusted sign-in URL to use for Windows Live Login server.
  1445. */
  1446. /*public*/
  1447. function getTrustedLoginUrl()
  1448. {
  1449. return $this->getSecureUrl() . 'wlogin.srf';
  1450. }
  1451. /**
  1452. * Returns the trusted sign-in URL to use for Windows Live
  1453. * Login server.
  1454. */
  1455. /*public*/
  1456. function getTrustedLogoutUrl()
  1457. {
  1458. return $this->getSecureUrl() . "logout.srf?appid=" + $this->getAppId();
  1459. }
  1460. /* Helper methods */
  1461. /**
  1462. * Function to parse the settings file.
  1463. */
  1464. /*private*/
  1465. function parseSettings($settingsFile)
  1466. {
  1467. $settings = array(
  1468. 'appid' => '00163FFF8000E2C5',
  1469. 'secret' => '12345678901234567890',
  1470. 'securityalgorithm' => 'wsignin1.0',
  1471. );
  1472. return $settings;
  1473. $doc = new DOMDocument();
  1474. if (!$doc->load($settingsFile)) {
  1475. $this->fatal("Error: parseSettings: Error while reading $settingsFile");
  1476. }
  1477. $nl = $doc->getElementsByTagName('windowslivelogin');
  1478. if($nl->length != 1) {
  1479. $this->fatal("error: parseSettings: Failed to parse settings file:"
  1480. . $settingsFile);
  1481. }
  1482. $topnode = $nl->item(0);
  1483. foreach ($topnode->childNodes as $node) {
  1484. if ($node->nodeType == XML_ELEMENT_NODE) {
  1485. $firstChild = $node->firstChild;
  1486. if (!$firstChild) {
  1487. $this->fatal("error: parseSettings: Failed to parse settings file:"
  1488. . $settingsFile);
  1489. }
  1490. $settings[$node->nodeName] = $firstChild->nodeValue;
  1491. }
  1492. }
  1493. return $settings;
  1494. }
  1495. /**
  1496. * Derives the key, given the secret key and prefix as described in the
  1497. * Web Authentication SDK documentation.
  1498. */
  1499. /*private*/
  1500. function derive($secret, $prefix)
  1501. {
  1502. if (!$secret || !$prefix) {
  1503. $this->fatal("Error: derive: secret or prefix is null.");
  1504. }
  1505. $keyLen = 16;
  1506. $key = $prefix . $secret;
  1507. $key = hash("sha256", $key, true);
  1508. if (!$key || (strlen($key) < $keyLen)) {
  1509. $this->debug("Error: derive: Unable to derive key.");
  1510. return;
  1511. }
  1512. return substr($key, 0, $keyLen);
  1513. }
  1514. /**
  1515. * Parses query string and returns a hash.
  1516. *
  1517. * If a hash ref is passed in from CGI->Var, it is dereferenced and
  1518. * returned.
  1519. */
  1520. /*private*/
  1521. function parse($input)
  1522. {
  1523. if (!$input) {
  1524. $this->debug("Error: parse: Null input.");
  1525. return;
  1526. }
  1527. $input = explode('&', $input);
  1528. $pairs = array();
  1529. foreach ($input as $pair) {
  1530. $kv = explode('=', $pair);
  1531. if (count($kv) != 2) {
  1532. $this->debug("Error: parse: Bad input to parse: " . $pair);
  1533. return;
  1534. }
  1535. $pairs[$kv[0]] = $kv[1];
  1536. }
  1537. return $pairs;
  1538. }
  1539. /**
  1540. * Generates a time stamp suitable for the application verifier
  1541. * token.
  1542. */
  1543. /*private*/
  1544. function getTimestamp()
  1545. {
  1546. return time();
  1547. }
  1548. /**
  1549. * Base64-encodes and URL-escapes a string.
  1550. */
  1551. /*private*/
  1552. function e64($input)
  1553. {
  1554. if (is_null($input)) {
  1555. return;
  1556. }
  1557. return urlencode(base64_encode($input));
  1558. }
  1559. /**
  1560. * URL-unescapes and Base64-decodes a string.
  1561. */
  1562. /*private*/
  1563. function u64($input)
  1564. {
  1565. if(is_null($input))
  1566. return;
  1567. return base64_decode(urldecode($input));
  1568. }
  1569. /**
  1570. * Fetches the contents given a URL.
  1571. */
  1572. /*private*/
  1573. function fetch($url)
  1574. {
  1575. /*
  1576. if (!($handle = fopen($url, "rb"))) {
  1577. WindowsLiveLogin::debug("error: fetch: Could not open url: $url");
  1578. return;
  1579. }
  1580. if (!($contents = stream_get_contents($handle))) {
  1581. WindowsLiveLogin::debug("Error: fetch: Could not read from url: $url");
  1582. }
  1583. fclose($handle);
  1584. */
  1585. //$str = $url."\n\n".$contents."\n\n\n";
  1586. //file_put_contents(__FILE__ . '.ftech.log', $str, FILE_APPEND);
  1587. $contents = CHTTP::sGet($url, false);
  1588. return $contents;
  1589. }
  1590. var $_error = false;
  1591. function setError($str)
  1592. {
  1593. $this->_error = $str;
  1594. }
  1595. function getError()
  1596. {
  1597. if ($this->_error !== false)
  1598. {
  1599. return $this->_error;
  1600. }
  1601. }
  1602. function OnExternalAuthList()
  1603. {
  1604. $arResult = Array();
  1605. if (
  1606. COption::GetOptionString('main', 'new_user_registration', 'Y') == 'Y' &&
  1607. COption::GetOptionString('main', 'auth_liveid', 'N') == 'Y'
  1608. )
  1609. {
  1610. $arResult[] = Array(
  1611. 'ID' => 'LIVEID',
  1612. 'NAME' => 'LiveID',
  1613. );
  1614. }
  1615. return $arResult;
  1616. }
  1617. public static function IsAvailable()
  1618. {
  1619. return function_exists('hash');
  1620. }
  1621. }