PageRenderTime 38ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Molinos/OpenID/Handlers/Generic.php

https://code.google.com/p/molinos-cms/
PHP | 321 lines | 212 code | 42 blank | 67 comment | 25 complexity | 823b86d4cdf6b157c2ced4a2f5339cd6 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * ???? ? ??????? OpenID.
  4. *
  5. * @package Molinos_CMS
  6. * @subpackage OpenID
  7. * @author Justin Forest <justin.forest@gmail.com>
  8. * @copyright 2006-2011 molinos.ru
  9. * @license http://www.gnu.org/copyleft/gpl.html GPL
  10. */
  11. class Molinos_OpenID_Handlers_Generic extends Molinos_Auth_RequestHandler
  12. {
  13. public function get()
  14. {
  15. if ('return' != $this->arg('action'))
  16. return parent::get();
  17. try {
  18. $t = new Molinos_Database_Transaction();
  19. $user = $this->getUser();
  20. Molinos_Hook_Dispatcher::getInstance()
  21. ->call('ru_molinos_cms_hook_login', array($user));
  22. $this->ctx->session->login = array(
  23. 'id' => $user->id,
  24. 'groups' => $user->getGroups(),
  25. );
  26. $t->commit();
  27. return new Molinos_HTTP_Responses_Redirect($this->arg('destination'));
  28. } catch (Molinos_Base_Exceptions_NotFound $e) {
  29. throw new Molinos_HTTP_Exceptions_Forbidden(t('You were successfully authenticated, but the administrator of this web site had turned off creation of new accounts. Condolences.'));
  30. }
  31. return new Molinos_HTTP_Responses_Redirect('admin?openid=failed');
  32. }
  33. protected function getForm()
  34. {
  35. $form = Molinos_Core_API::getInstance('form')->createForm(array(
  36. 'title' => t('Log in using OpenID'),
  37. 'class' => 'autofocus',
  38. ));
  39. $form->addControl("TextLine", array(
  40. 'value' => 'id',
  41. 'label' => t('Your OpenID'),
  42. ));
  43. $form->addControl("Submit", array(
  44. 'text' => t('Log in'),
  45. ));
  46. return $form;
  47. }
  48. /**
  49. * ?????? ??????????? ?? OpenID.
  50. *
  51. * ???????? ?????????? ? ???? id ???????? ? {@link verify()}.
  52. */
  53. public function post()
  54. {
  55. return $this->verify($this->rarg('id'));
  56. }
  57. /**
  58. * ???????? ??????????????.
  59. *
  60. * @param string $id OpenID.
  61. */
  62. protected function verify($openid)
  63. {
  64. $this->include_openid();
  65. $consumer = $this->getConsumer();
  66. // Begin the OpenID authentication process.
  67. // No auth request means we can't begin OpenID.
  68. if (!($auth_request = $consumer->begin($openid))) {
  69. throw new RuntimeException(t('Could not reach your OpenID provider, please try again later.'));
  70. return new Molinos_HTTP_Responses_Redirect('user/logout');
  71. }
  72. $sreg_request = Auth_OpenID_SRegRequest::build(
  73. array('nickname'), // Required
  74. array('fullname', 'email') // Optional
  75. );
  76. if ($sreg_request)
  77. $auth_request->addExtension($sreg_request);
  78. $policy_uris = $this->arg('policies');
  79. $pape_request = new Auth_OpenID_PAPE_Request($policy_uris);
  80. if ($pape_request)
  81. $auth_request->addExtension($pape_request);
  82. $ax = new Auth_OpenID_AX_FetchRequest();
  83. $ax->add(Auth_OpenID_AX_AttrInfo::make('http://axschema.org/contact/email', 2, 1, 'email'));
  84. $ax->add(Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson/first', 1, 1, 'firstname'));
  85. $ax->add(Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson/last', 1, 1, 'lastname'));
  86. $ax->add(Auth_OpenID_AX_AttrInfo::make('http://axschema.org/pref/language', 1, 1, 'language'));
  87. $auth_request->addExtension($ax);
  88. $logger = Molinos_Core_Logger::getInstance();
  89. // Redirect the user to the OpenID server for authentication.
  90. // Store the token for this authentication so we can verify the
  91. // response.
  92. // For OpenID 1, send a redirect. For OpenID 2, use a Javascript
  93. // form to send a POST request to the server.
  94. if ($auth_request->shouldSendRedirect()) {
  95. $redirect_url = $auth_request->redirectURL($this->getTrustRoot(), $this->getReturnTo($openid));
  96. if (Auth_OpenID::isFailure($redirect_url)) {
  97. // If the redirect URL can't be built, display an error message.
  98. $logger->warning("Could not redirect to server: " . $redirect_url->message, 'openid');
  99. } else {
  100. return new Molinos_HTTP_Responses_Redirect($redirect_url);
  101. }
  102. } else {
  103. // Generate form markup and render it.
  104. $form_id = 'openid_message';
  105. $form_html = $auth_request->formMarkup($this->getTrustRoot(), $this->getReturnTo($openid), false, array('id' => $form_id));
  106. $logger->debug($form_html);
  107. // Display an error if the form markup couldn't be generated;
  108. // otherwise, render the HTML.
  109. if (Auth_OpenID::isFailure($form_html)) {
  110. $logger->warning("Could not redirect to server: " . $form_html->message, 'openid');
  111. } else {
  112. $page_contents = "<html><head><title>"
  113. . "OpenID transaction in progress"
  114. . "</title></head>"
  115. . "<body onload='document.getElementById(\"".$form_id."\").submit()'>"
  116. . $form_html
  117. . "</body></html>";
  118. return new Molinos_HTTP_Responses_Simple($page_contents);
  119. }
  120. }
  121. }
  122. protected function include_openid()
  123. {
  124. $path_extra = dirname(dirname(__FILE__));
  125. $path = ini_get('include_path');
  126. $path = $path_extra . PATH_SEPARATOR . $path;
  127. ini_set('include_path', $path);
  128. require_once "Auth/OpenID/Consumer.php";
  129. require_once "Auth/OpenID/FileStore.php";
  130. require_once "Auth/OpenID/AX.php";
  131. require_once "Auth/OpenID/SReg.php";
  132. require_once "Auth/OpenID/PAPE.php";
  133. }
  134. protected function getConsumer()
  135. {
  136. $store = $this->getStore();
  137. return new Auth_OpenID_Consumer($store, new Molinos_OpenID_Session($this->ctx->session));
  138. }
  139. protected function getStore()
  140. {
  141. $store_path = Molinos_Core_Utils::mkdir($path = Molinos_Core_Utils::path(Molinos_Core_Utils::tmpdir(), 'openid'), 'Could not create the FileStore directory (%path), please check the effective permissions.', array(
  142. '%path' => $path,
  143. ));
  144. return new Auth_OpenID_FileStore($store_path);
  145. }
  146. protected function getTrustRoot()
  147. {
  148. return $this->request->base_url;
  149. }
  150. protected function getScheme()
  151. {
  152. return 'http';
  153. }
  154. /**
  155. * ?????????? ???????? ?????.
  156. *
  157. * @param string $id OpenID.
  158. * @return string ?????, ?? ??????? ?????????? ??????? ??????? ????????????.
  159. */
  160. protected function getReturnTo($id)
  161. {
  162. $url = $this->ctx->request->base_url
  163. . $this->ctx->lp
  164. . $this->path
  165. . '?action=return&id=' . urlencode($id)
  166. . '&sid=' . $this->ctx->session->id
  167. . '&destination=' . urlencode($this->arg('destination'));
  168. Molinos_Core_Logger::getInstance()->debug($url, 'openid');
  169. return $url;
  170. }
  171. /**
  172. * ????? ????????????? ????????????.
  173. *
  174. * ????????? ??????? ????????????????? ????????????. ???? ???????
  175. * ?? ??????, ???????? ??????? ????? (???? ??? ?? ????????? ? ??????????).
  176. *
  177. * @return Molinos_Auth_Nodes_User ??????? ????????????.
  178. * @uses getAttributes() ??? ?????? ?? ????????? ?????????? OpenID.
  179. * @uses authExistingUser() ??? ??????????? ????????????? ????????????.
  180. * @uses registerNewUser() ??? ??????????? ?????? ????????????.
  181. */
  182. protected function getUser()
  183. {
  184. $logger = Molinos_Core_Logger::getInstance();
  185. if ('id_res' != $this->arg('openid_mode')) {
  186. $logger->debug('login cancelled ?!');
  187. throw new Molinos_Core_Exceptions_Response(new Molinos_HTTP_Responses_Redirect('user/logout'));
  188. }
  189. $data = $this->getAttributes();
  190. // ??????? ?????? ??? ??????? ???????? ????????????.
  191. $filter = array(
  192. 'class' => 'user',
  193. 'deleted' => 0,
  194. 'published' => 1,
  195. '#sort' => 'id',
  196. 'lang' => Molinos_I18n_Utils::getEnabledLanguages(),
  197. );
  198. // ????????? ?????????????.
  199. if (!empty($data['url']))
  200. $filter['url'] = $data['url'];
  201. elseif (!empty($data['email']))
  202. $filter['email'] = $data['email'];
  203. else {
  204. $logger->error(t('OpenID response has neither an URL nor an email.'));
  205. throw new Molinos_HTTP_Exceptions_BadRequest();
  206. }
  207. if (!count($nodes = Molinos_Core_API::getInstance('node')->find($filter)))
  208. $user = $this->registerNewUser($data);
  209. else
  210. $user = $this->authExistingUser(array_shift($nodes), $data);
  211. return new Molinos_Auth_User($user->id, $user->getLinkedTo('group', true));
  212. }
  213. /**
  214. * ??????????? ?????? ????????????.
  215. *
  216. * @param array $data ???????? ????????????, ?????????? ?? ??????????.
  217. * @return Molinos_Auth_Nodes_User ??????? ???????????? (???????????).
  218. */
  219. protected function registerNewUser(array $data)
  220. {
  221. $node = Molinos_Core_API::getInstance('node')->create(array_merge($data, array(
  222. 'class' => 'user',
  223. 'published' => true,
  224. )));
  225. if (!$node->checkPermission(Molinos_Auth_ACL::CREATE))
  226. throw new Molinos_HTTP_Exceptions_Forbidden(t('You were successfully authenticated, but the administrator of this web site had turned off creation of new accounts. Condolences.'));
  227. return $node->save();
  228. }
  229. /**
  230. * ???????? ??????? ????????????? ????????????.
  231. *
  232. * ???? ??????? ?????, ????????? ?????? 403.
  233. * @return Molinos_Auth_Nodes_User ??????? ????????????.
  234. */
  235. protected function authExistingUser(Molinos_Auth_Nodes_User $node, array $data)
  236. {
  237. if (!empty($data['url']) and $node->url == $data['url'])
  238. ;
  239. elseif (!empty($data['email']) and $node->email == $data['email'])
  240. ;
  241. else {
  242. Molinos_Core_Logger::getInstance()->error("OpenID auth failed: user id mismatch. Node: {$node}, data:" . var_export($data, true));
  243. throw new Molinos_HTTP_Exceptions_ServiceUnavailable();
  244. }
  245. if (!$node->published)
  246. throw new Molinos_HTTP_Exceptions_Forbidden(t('Your user profile was suspended.'));
  247. return $node;
  248. }
  249. /**
  250. * ???????? ?? ?????? ???????????? ????????.
  251. *
  252. * @return array ????????????? ?????? ?????????.
  253. */
  254. protected function getAttributes()
  255. {
  256. $map = array(
  257. 'openid1_claimed_id' => 'url',
  258. 'openid_claimed_id' => 'url',
  259. 'openid_identity' => 'url',
  260. 'sreg_email' => 'email',
  261. 'sreg_fullname' => 'name',
  262. 'sreg_nickname' => 'nickname',
  263. 'openid_ext1_value_firstname' => 'firstname',
  264. 'openid_ext1_value_email' => 'email',
  265. 'openid_ext1_value_lastname' => 'lastname',
  266. 'openid_ext1_value_language' => 'lang',
  267. );
  268. $result = array();
  269. foreach ($map as $k => $v)
  270. if (empty($result[$v]) and ($tmp = $this->arg($k)))
  271. $result[$v] = $tmp;
  272. // ????????? ????????? ???????.
  273. if (empty($result['lang']) or !in_array($result['lang'], Molinos_I18n_Utils::getEnabledLanguages()))
  274. $result['lang'] = Molinos_I18n_Utils::getDefaultLanguage();
  275. if (empty($result['name']) and !empty($result['firstname']) and !empty($result['lastname']))
  276. $result['lname'] = $result['firstname'] . ' ' . $result['lastname'];
  277. return $result;
  278. }
  279. }