PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/src/Authentication/AuthenticationType.php

http://github.com/concrete5/concrete5
PHP | 528 lines | 384 code | 38 blank | 106 comment | 25 complexity | 06ef4129cea5851e6032530f4563be5c MD5 | raw file
Possible License(s): MIT, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. <?php
  2. namespace Concrete\Core\Authentication;
  3. use Concrete\Authentication\Concrete\Controller;
  4. use Concrete\Core\Foundation\ConcreteObject;
  5. use Concrete\Core\Package\PackageList;
  6. use Core;
  7. use Environment;
  8. use Exception;
  9. use Loader;
  10. use Package;
  11. class AuthenticationType extends ConcreteObject
  12. {
  13. /** @var Controller */
  14. public $controller;
  15. protected $authTypeID;
  16. protected $authTypeName;
  17. protected $authTypeHandle;
  18. protected $authTypeDisplayOrder;
  19. protected $authTypeIsEnabled;
  20. protected $pkgID;
  21. public static function getListSorted()
  22. {
  23. return self::getList(true);
  24. }
  25. /**
  26. * Return a raw list of authentication types.
  27. *
  28. * @param bool $sorted true: Sort by display order, false: sort by install order
  29. * @param bool $activeOnly true: include only active types, false: include active and inactive types
  30. *
  31. * @return AuthenticationType[]
  32. */
  33. public static function getList($sorted = false, $activeOnly = false)
  34. {
  35. $list = [];
  36. $db = Loader::db();
  37. $q = $db->query('SELECT * FROM AuthenticationTypes'
  38. . ($activeOnly ? ' WHERE authTypeIsEnabled=1 ' : '')
  39. . ' ORDER BY ' . ($sorted ? 'authTypeDisplayOrder' : 'authTypeID'));
  40. while ($row = $q->fetchRow()) {
  41. $list[] = self::load($row);
  42. }
  43. return $list;
  44. }
  45. /**
  46. * Load an AuthenticationType from an array.
  47. *
  48. * @param array $arr should be an array of the following key/value pairs to create an object from:
  49. * <pre>
  50. * array(
  51. * 'authTypeID' => int,
  52. * 'authTypeHandle' => string,
  53. * 'authTypeName' => string,
  54. * 'authTypeDisplayOrder' => int,
  55. * 'authTypeIsEnabled' => tinyint,
  56. * 'pkgID' => int
  57. * )
  58. * </pre>
  59. *
  60. * @return bool|\Concrete\Core\Authentication\AuthenticationType
  61. */
  62. public static function load($arr)
  63. {
  64. $extract = [
  65. 'authTypeID',
  66. 'authTypeName',
  67. 'authTypeHandle',
  68. 'authTypeDisplayOrder',
  69. 'authTypeIsEnabled',
  70. 'pkgID',
  71. ];
  72. $obj = new self();
  73. foreach ($extract as $key) {
  74. if (!isset($arr[$key])) {
  75. return false;
  76. }
  77. $obj->{$key} = $arr[$key];
  78. }
  79. $obj->loadController();
  80. return $obj;
  81. }
  82. /**
  83. * Load the AuthenticationTypeController into the AuthenticationType.
  84. */
  85. protected function loadController()
  86. {
  87. $env = Environment::get();
  88. $r = $env->getRecord(DIRNAME_AUTHENTICATION . '/' . $this->authTypeHandle . '/' . FILENAME_CONTROLLER);
  89. $prefix = $r->override ? true : $this->getPackageHandle();
  90. $authTypeHandle = Core::make('helper/text')->camelcase($this->authTypeHandle);
  91. $class = core_class('Authentication\\' . $authTypeHandle . '\\Controller', $prefix);
  92. $this->controller = Core::make($class, [$this]);
  93. }
  94. /**
  95. * AuthenticationType::getPackageHandle
  96. * Return the package handle.
  97. */
  98. public function getPackageHandle()
  99. {
  100. return PackageList::getHandle($this->pkgID);
  101. }
  102. /**
  103. * Return an array of AuthenticationTypes that are associated with a specific package.
  104. *
  105. * @param Package $pkg
  106. *
  107. * @return AuthenticationType[]
  108. */
  109. public static function getListByPackage($pkg)
  110. {
  111. $db = Loader::db();
  112. $list = [];
  113. $q = $db->query('SELECT * FROM AuthenticationTypes WHERE pkgID=?', [$pkg->getPackageID()]);
  114. while ($row = $q->FetchRow()) {
  115. $list[] = self::load($row);
  116. }
  117. return $list;
  118. }
  119. /**
  120. * @param string $atHandle New AuthenticationType handle
  121. * @param string $atName New AuthenticationType name, expect this to be presented with "%s Authentication Type"
  122. * @param int $order Order int, used to order the display of AuthenticationTypes
  123. * @param bool|\Package $pkg package object to which this AuthenticationType is associated
  124. *
  125. * @throws \Exception
  126. *
  127. * @return AuthenticationType returns a loaded authentication type
  128. */
  129. public static function add($atHandle, $atName, $order = 0, $pkg = false)
  130. {
  131. $die = true;
  132. try {
  133. self::getByHandle($atHandle);
  134. } catch (exception $e) {
  135. $die = false;
  136. }
  137. if ($die) {
  138. throw new Exception(t('Authentication type with handle %s already exists!', $atHandle));
  139. }
  140. $pkgID = 0;
  141. if (is_object($pkg)) {
  142. $pkgID = $pkg->getPackageID();
  143. }
  144. $db = Loader::db();
  145. $db->Execute(
  146. 'INSERT INTO AuthenticationTypes (authTypeHandle, authTypeName, authTypeIsEnabled, authTypeDisplayOrder, pkgID) values (?, ?, ?, ?, ?)',
  147. [$atHandle, $atName, 1, intval($order), $pkgID]);
  148. $est = self::getByHandle($atHandle);
  149. $r = $est->mapAuthenticationTypeFilePath(FILENAME_AUTHENTICATION_DB);
  150. if ($r->exists()) {
  151. Package::installDB($r->file);
  152. }
  153. return $est;
  154. }
  155. /**
  156. * Return loaded AuthenticationType with the given handle.
  157. *
  158. * @param string $atHandle authenticationType handle
  159. *
  160. * @throws \Exception when an invalid handle is provided
  161. *
  162. * @return AuthenticationType
  163. */
  164. public static function getByHandle($atHandle)
  165. {
  166. $db = Loader::db();
  167. $row = $db->GetRow('SELECT * FROM AuthenticationTypes WHERE authTypeHandle=?', [$atHandle]);
  168. if (!$row) {
  169. throw new Exception(t('Invalid Authentication Type Handle'));
  170. }
  171. $at = self::load($row);
  172. return $at;
  173. }
  174. /**
  175. * Return loaded AuthenticationType with the given ID.
  176. *
  177. * @param int $authTypeID
  178. *
  179. * @throws \Exception
  180. *
  181. * @return AuthenticationType
  182. */
  183. public static function getByID($authTypeID)
  184. {
  185. $db = Loader::db();
  186. $row = $db->GetRow('SELECT * FROM AuthenticationTypes where authTypeID=?', [$authTypeID]);
  187. if (!$row) {
  188. throw new Exception(t('Invalid Authentication Type ID'));
  189. }
  190. $at = self::load($row);
  191. $at->loadController();
  192. return $at;
  193. }
  194. public function getAuthenticationTypeName()
  195. {
  196. return $this->authTypeName;
  197. }
  198. /**
  199. * Returns the display name for this instance (localized and escaped accordingly to $format)
  200. *
  201. * @param string $format = 'html' Escape the result in html format (if $format is 'html'). If $format is 'text' or any other value, the display name won't be escaped.
  202. *
  203. * @return string
  204. */
  205. public function getAuthenticationTypeDisplayName($format = 'html')
  206. {
  207. $value = tc('AuthenticationType', $this->getAuthenticationTypeName());
  208. switch ($format) {
  209. case 'html':
  210. return h($value);
  211. case 'text':
  212. default:
  213. return $value;
  214. }
  215. }
  216. public function getAuthenticationTypeDisplayOrder()
  217. {
  218. return $this->authTypeDisplayOrder;
  219. }
  220. public function getAuthenticationTypePackageID()
  221. {
  222. return $this->pkgID;
  223. }
  224. public function getController()
  225. {
  226. return $this->controller;
  227. }
  228. public function getAuthenticationTypeIconHTML()
  229. {
  230. return $this->controller->getAuthenticationTypeIconHTML();
  231. }
  232. /**
  233. * Update the name.
  234. *
  235. * @param string $authTypeName
  236. */
  237. public function setAuthenticationTypeName($authTypeName)
  238. {
  239. $db = Loader::db();
  240. $db->Execute(
  241. 'UPDATE AuthenticationTypes SET authTypeName=? WHERE authTypeID=?',
  242. [$authTypeName, $this->getAuthenticationTypeID()]);
  243. }
  244. /**
  245. * AuthenticationType::setAuthenticationTypeDisplayOrder
  246. * Update the order for display.
  247. *
  248. * @param int $order value from 0-n to signify order
  249. */
  250. public function setAuthenticationTypeDisplayOrder($order)
  251. {
  252. $db = Loader::db();
  253. $db->Execute(
  254. 'UPDATE AuthenticationTypes SET authTypeDisplayOrder=? WHERE authTypeID=?',
  255. [$order, $this->getAuthenticationTypeID()]);
  256. }
  257. public function getAuthenticationTypeID()
  258. {
  259. return $this->authTypeID;
  260. }
  261. /**
  262. * AuthenticationType::toggle
  263. * Toggle the active state of an AuthenticationType.
  264. */
  265. public function toggle()
  266. {
  267. return $this->isEnabled() ? $this->disable() : $this->enable();
  268. }
  269. public function isEnabled()
  270. {
  271. return (bool) $this->getAuthenticationTypeStatus();
  272. }
  273. public function getAuthenticationTypeStatus()
  274. {
  275. return $this->authTypeIsEnabled;
  276. }
  277. /**
  278. * AuthenticationType::disable
  279. * Disable an authentication type.
  280. */
  281. public function disable()
  282. {
  283. if ($this->getAuthenticationTypeID() == 1) {
  284. throw new Exception(t('The core concrete5 authentication cannot be disabled.'));
  285. }
  286. $db = Loader::db();
  287. $db->Execute(
  288. 'UPDATE AuthenticationTypes SET authTypeIsEnabled=0 WHERE AuthTypeID=?',
  289. [$this->getAuthenticationTypeID()]);
  290. }
  291. /**
  292. * AuthenticationType::enable
  293. * Enable an authentication type.
  294. */
  295. public function enable()
  296. {
  297. $db = Loader::db();
  298. $db->Execute(
  299. 'UPDATE AuthenticationTypes SET authTypeIsEnabled=1 WHERE AuthTypeID=?',
  300. [$this->getAuthenticationTypeID()]);
  301. }
  302. /**
  303. * AuthenticationType::delete
  304. * Remove an AuthenticationType, this should be used sparingly.
  305. */
  306. public function delete()
  307. {
  308. $db = Loader::db();
  309. if (method_exists($this->controller, 'deleteType')) {
  310. $this->controller->deleteType();
  311. }
  312. $db->Execute('DELETE FROM AuthenticationTypes WHERE authTypeID=?', [$this->authTypeID]);
  313. }
  314. /**
  315. * Return the path to a file.
  316. *
  317. * @param string $_file the relative path to the file
  318. *
  319. * @return bool|string
  320. */
  321. public function getAuthenticationTypeFilePath($_file)
  322. {
  323. $f = $this->mapAuthenticationTypeFilePath($_file);
  324. if ($f->exists()) {
  325. return $f->url;
  326. }
  327. return false;
  328. }
  329. /**
  330. * Return the first existing file path in this order:
  331. * - /models/authentication/types/HANDLE
  332. * - /packages/PKGHANDLE/authentication/types/HANDLE
  333. * - /concrete/models/authentication/types/HANDLE
  334. * - /concrete/core/models/authentication/types/HANDLE.
  335. *
  336. * @param string $_file the filename you want
  337. *
  338. * @return string this will return false if the file is not found
  339. */
  340. protected function mapAuthenticationTypeFilePath($_file)
  341. {
  342. $atHandle = $this->getAuthenticationTypeHandle();
  343. $env = Environment::get();
  344. $pkgHandle = PackageList::getHandle($this->pkgID);
  345. $r = $env->getRecord(implode('/', [DIRNAME_AUTHENTICATION, $atHandle, $_file]), $pkgHandle);
  346. return $r;
  347. }
  348. public function getAuthenticationTypeHandle()
  349. {
  350. return $this->authTypeHandle;
  351. }
  352. /**
  353. * Render the settings form for this type.
  354. * Settings forms are expected to handle their own submissions and redirect to the appropriate page.
  355. * Otherwise, if the method exists, all $_REQUEST variables with the arrangement: HANDLE[]
  356. * in an array to the AuthenticationTypeController::saveTypeForm.
  357. */
  358. public function renderTypeForm()
  359. {
  360. $type_form = $this->mapAuthenticationTypeFilePath('type_form.php');
  361. if ($type_form->exists()) {
  362. ob_start();
  363. $this->controller->edit();
  364. extract($this->controller->getSets());
  365. require_once $type_form->file; // We use the $this method to prevent extract overwrite.
  366. $out = ob_get_contents();
  367. ob_end_clean();
  368. echo $out;
  369. } else {
  370. echo '<p>' . t('This authentication type does not require any customization.') . '</p>';
  371. }
  372. }
  373. /**
  374. * Render the login form for this authentication type.
  375. *
  376. * @param string $element
  377. * @param array $params
  378. */
  379. public function renderForm($element = 'form', $params = [])
  380. {
  381. $this->controller->requireAsset('javascript', 'backstretch');
  382. $form_element = $this->mapAuthenticationTypeFilePath($element . '.php');
  383. if (!$form_element->exists()) {
  384. $form_element = $this->mapAuthenticationTypeFilePath('form.php');
  385. if (method_exists($this->controller, 'form')) {
  386. call_user_func_array([$this->controller, 'form'], $params);
  387. }
  388. }
  389. ob_start();
  390. if (method_exists($this->controller, $element)) {
  391. call_user_func_array([$this->controller, $element], $params);
  392. } else {
  393. $this->controller->view();
  394. }
  395. extract(array_merge($params, $this->controller->getSets()));
  396. require $form_element->file;
  397. $out = ob_get_contents();
  398. ob_end_clean();
  399. echo $out;
  400. }
  401. /**
  402. * Render the hook form for saving the profile settings.
  403. * All settings are expected to be saved by each individual authentication type.
  404. */
  405. public function renderHook()
  406. {
  407. $form_hook = $this->mapAuthenticationTypeFilePath('hook.php');
  408. if (method_exists($this->controller, 'hook') || $form_hook->exists()) {
  409. ob_start();
  410. if (method_exists($this->controller, 'hook')) {
  411. $this->controller->hook();
  412. }
  413. if ($form_hook->exists()) {
  414. $controller = $this->controller;
  415. extract($this->controller->getSets());
  416. require_once $form_hook->file;
  417. }
  418. $out = ob_get_contents();
  419. ob_end_clean();
  420. echo $out;
  421. }
  422. }
  423. public function hasHook()
  424. {
  425. $form_hook = $this->mapAuthenticationTypeFilePath('hook.php');
  426. return method_exists($this->controller, 'hook') || $form_hook->exists();
  427. }
  428. /**
  429. * Render the a form to be displayed when the authentication type is already hooked.
  430. * All settings are expected to be saved by each individual authentication type.
  431. */
  432. public function renderHooked()
  433. {
  434. $form_hooked = $this->mapAuthenticationTypeFilePath('hooked.php');
  435. if (method_exists($this->controller, 'hooked') || $form_hooked->exists()) {
  436. ob_start();
  437. if (method_exists($this->controller, 'hooked')) {
  438. $this->controller->hooked();
  439. }
  440. if ($form_hooked->exists()) {
  441. $controller = $this->controller;
  442. extract($this->controller->getSets());
  443. require_once $form_hooked->file;
  444. }
  445. $out = ob_get_contents();
  446. ob_end_clean();
  447. echo $out;
  448. }
  449. }
  450. /**
  451. * Does this authentication type support rendering a form when it has already been hooked?
  452. *
  453. * @return bool
  454. */
  455. public function hasHooked()
  456. {
  457. $form_hooked = $this->mapAuthenticationTypeFilePath('hooked.php');
  458. return method_exists($this->controller, 'hooked') || $form_hooked->exists();
  459. }
  460. /**
  461. * Is this authentication type already hooked for a specific user?
  462. *
  463. * @param \Concrete\Core\User\User|\Concrete\Core\User\UserInfo|\Concrete\Core\Entity\User\User|int $user
  464. *
  465. * @return bool|null returns null if the controller does not implement a way to determine if a user is already hooked or not
  466. */
  467. public function isHooked($user)
  468. {
  469. $result = null;
  470. if (is_callable([$this->controller, 'getBindingForUser'])) {
  471. $result = $this->controller->getBindingForUser($user) !== null;
  472. } else {
  473. $result = null;
  474. }
  475. return $result;
  476. }
  477. }