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

/phocoa/framework/WFAuthorization.php

https://github.com/SwissalpS/phocoa
PHP | 838 lines | 350 code | 100 blank | 388 comment | 60 complexity | 5714f319618204b7cc40034075bc1ca3 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. /**
  4. * @package framework-base
  5. * @subpackage Authorization
  6. * @copyright Copyright (c) 2005 Alan Pinstein. All Rights Reserved.
  7. * @version $Id: kvcoding.php,v 1.3 2004/12/12 02:44:09 alanpinstein Exp $
  8. * @author Alan Pinstein <apinstein@mac.com>
  9. * @todo Remember Me - Add to default login module now that there's support for it in core.
  10. * @todo Remember Me - Use HMAC or something to sign the cookie on the remote end. Read a "private" salt/passphrase from OPTIONS.
  11. * @todo Remember Me - Encrypt the cookie on the client end so that the userid isn't in cleartext.
  12. */
  13. /**
  14. * Informal delegate protocol for your web application to handle authentication.
  15. *
  16. * The WFAuthorizationManager will call your delegate methods to attempt logins.
  17. */
  18. class WFAuthorizationDelegate extends WFObject
  19. {
  20. /**
  21. * Provide the login authentication.
  22. *
  23. * Your WFAuthorizationDelegate can provide its own login capability. Maybe your app will authenticate against LDAP, a Database, etc.
  24. *
  25. * @param string The username to use for the authentication.
  26. * @param string The password to use for the authentication.
  27. * @param boolean TRUE if the password is in "token" form; ie, not the clear-text password. Useful for remember-me logins or single-sign-on (SSO) setups.
  28. * @return object WFAuthorizationInfo Return an WFAuthorizationInfo with any additional security profile. This of course can be a subclass. Return NULL if login failed.
  29. */
  30. function login($username, $password, $passIsToken) {}
  31. /**
  32. * Provide the invocationPath for handling login.
  33. *
  34. * By default, this will be "login/promptLogin". Applications can override this behavior by writing their own login modules, or even simply "wrapping" the built-in one.
  35. *
  36. * @return string The invocationPath to the login. Remember the page handling login *should* accept a first parameter of "continueURL" (the url will be encoded with {@link WFWebApplication::serializeURL()})
  37. */
  38. function loginInvocationPath() {}
  39. /**
  40. * The URL to continue to if the user logs in but there is no "continue to url" set.
  41. *
  42. * If NULL, no redirect will be performed, and just a message saying "Login successful" will be seen.
  43. *
  44. * @return string A URL to redirect to (will be done via {@link WFRedirectRequestException}). DEFAULT: NULL.
  45. */
  46. function defaultLoginContinueURL() {}
  47. /**
  48. * The URL to continue to if the user logs out.
  49. *
  50. * If NULL, no redirect will be performed, and just a message saying "Logout successful" will be seen.
  51. *
  52. * @return string A URL to redirect to (will be done via {@link WFRedirectRequestException}). DEFAULT: NULL.
  53. */
  54. function defaultLogoutContinueURL() {}
  55. /**
  56. * Should there be an interstitial "You have logged out successfully, click here to continue", or should logout immediately redirect to {@link WFAuthorizationDelegate::defaultLogoutContinueURL() defaultLogoutContinueURL()}?
  57. *
  58. * @return boolean TRUE to show a logout interstitial. DEFAULT: true.
  59. */
  60. function shouldShowLogoutConfirmation() {}
  61. /**
  62. * Should the login interface have a "remember me" checkbox?
  63. *
  64. * @return boolean TRUE to enable "remember me" functionality. DEFAULT: false.
  65. */
  66. function shouldEnableRememberMe() {}
  67. /**
  68. * The label for the sign-up link.
  69. *
  70. * @return string The label for the sign-up link. Default: Sign Up
  71. */
  72. function signUpLabel() {}
  73. /**
  74. * The URL for the sign-up link.
  75. *
  76. * If NULL, the sign-up link will not be shown.
  77. *
  78. * @return string The url for the sign-up link. Default: NULL
  79. */
  80. function signUpUrl() {}
  81. /**
  82. * Delegate should return the "token" to persist via a long-term cookie. This exact token will be passed back in when trying to do a rememberMe login.
  83. *
  84. * SECURITY RECOMMENDATION:
  85. * Your token should be something like md5("app-salt+userid").
  86. *
  87. * Clients should get the userid from the current WFAuthorizationInfo.
  88. *
  89. * @return string The token to persist on the client.
  90. */
  91. function rememberMeToken() {}
  92. /**
  93. * Delegate should implement and return this method if they want to override the default rememberme settings.
  94. *
  95. * @return array OPTIONS hash. See WFAuthorizationManager::REMEMBER_ME_OPT_*.
  96. */
  97. function rememberMeOptions() {}
  98. /**
  99. * If "remember me" is enabled with {@link WFAuthorizationDelegate::shouldEnableRememberMe() shouldEnableRememberMe}, should "remember me"
  100. * be checked by default?
  101. *
  102. * @return boolean TRUE if the "remember me" checkbox should be checked by default. DEFAULT: false.
  103. */
  104. function shouldRememberMeByDefault() {}
  105. /**
  106. * The login help message that should be displayed above the login box.
  107. *
  108. * @return string The login message to display above the login box. DEFAULT: "You must log in to access the requested page."
  109. */
  110. function loginMessage() {}
  111. /**
  112. * The label to use for the "username" field.
  113. *
  114. * @return string The label for the username field. DEFAULT: "Username".
  115. */
  116. function usernameLabel() {}
  117. /**
  118. * The message to display to a use on unsuccessful login.
  119. *
  120. * @param string The username that the attempted login was for.
  121. * @return mixed string: The message to display on failed login. array of strings; Multiple messages to display (as list items). DEFAULT: string:"Login username or password is not valid."
  122. */
  123. function loginFailedMessage($username) {}
  124. /**
  125. * Should a "forgot your password" link be shown?
  126. *
  127. * @return boolean TRUE to enable forgotten password reset feature.
  128. */
  129. function shouldEnableForgottenPasswordReset() {}
  130. /**
  131. * Reset the password for the given user.
  132. *
  133. * @param string The username that the attempted login was for.
  134. * @return string The message to show the user on successful password reset. DEFAULT: "The password for <usernameLabel> <username> been reset. Your new password information has been emailed to the email address on file for your account."
  135. * @throws object WFException If the password cannot be reset, throw an error with the message to be displayed as the string.<br>
  136. * object WFRedirectRequestException If your reset password system is more complicated than can be handled by PHOCOA, feel free to redirect to another page to handle this.
  137. */
  138. function resetPassword($username) {}
  139. }
  140. /**
  141. * The WFAuthorizationInfo object stores all access control information for the logged-in user.
  142. *
  143. * The base class provides the ability to tell if someone is logged in, if they logged in recently, and their userid. For many applications, this is all that's needed.
  144. *
  145. * For applications requiring more complicated access control, they should subclass WFAuthorizationInfo and provide further access control information and methods to query it.
  146. *
  147. * NOTE: The WFAuthorizationInfo class is stored in the SESSION at the time of login. The WFAuthorizationInfo is immutable once stored in the session; whatever rights are given
  148. * to the user at login remain with him until he logs in again (this includes REMEMBER-ME login).
  149. * The WFAuthorizationInfo MUST be easily serializable! No circular references, etc... subclasses be careful!
  150. *
  151. * NOTE: If you are using a subclass of WFAuthorizationInfo, please note that the authorizationInfo managed by WFAuthorizationManager will only be of your subclass' type if
  152. * someone is logged in. Until then, it's always WFAuthorizationInfo. So, always test isLoggedIn() before accessing authorizationInfo as your subclass.
  153. */
  154. class WFAuthorizationInfo extends WFObject
  155. {
  156. /**
  157. * @var string The userid of the logged in user.
  158. */
  159. protected $userid;
  160. /**
  161. * @var boolean TRUE is the user is a super-user. FALSE otherwise.
  162. */
  163. protected $isSuperUser;
  164. /**
  165. * @const Flag for no user logged in.
  166. */
  167. const NO_USER = -1;
  168. function __construct()
  169. {
  170. $this->userid = WFAuthorizationInfo::NO_USER;
  171. $this->isSuperUser = false;
  172. }
  173. /**
  174. * Is the current user a superuser?
  175. *
  176. * @return boolean TRUE if superuser, false otherwise.
  177. */
  178. function isSuperUser()
  179. {
  180. return $this->isSuperUser;
  181. }
  182. /**
  183. * Set the superuser status.
  184. *
  185. * @param boolean TRUE if the user is a superuser, false otherwise.
  186. */
  187. function setIsSuperUser($isSuperUser)
  188. {
  189. $this->isSuperUser = $isSuperUser;
  190. }
  191. /**
  192. * Set the user id of the authorized user.
  193. * @param string The user id.
  194. */
  195. function setUserid($uid)
  196. {
  197. $this->userid = $uid;
  198. }
  199. /**
  200. * Is there a user logged in?
  201. *
  202. * @return boolean TRUE if a user is logged in, false otherwise.
  203. */
  204. final function isLoggedIn()
  205. {
  206. return ($_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_LOGGED_IN] === true);
  207. }
  208. /**
  209. * What is the userid of the currently logged in user?
  210. *
  211. * @return string The userid of the currently logged in user, or WFAuthorizationInfo::NO_USER if no one is logged in.
  212. */
  213. final function userid()
  214. {
  215. return $this->userid;
  216. }
  217. /**
  218. * Has the user authenticated recently?
  219. *
  220. * Some sites may wish to keep a user logged in forever, even with "remember me", but then restrict access to extremely sensitive data by requiring that a user is in a "recent" session. That is, they have recently authenticated with username/password and have not been "idle" in that session for more than a short period of time.
  221. *
  222. * @return boolean TRUE if a user has authenticated recently and not been idle for more than WFAuthorizationManager::RECENT_LOGIN_SECS seconds.
  223. */
  224. final function isRecentLogin()
  225. {
  226. return ( (time() - $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_RECENT_LOGIN_TIME]) < WFAuthorizationManager::RECENT_LOGIN_SECS );
  227. }
  228. }
  229. /**
  230. * A specialized exception class for authorization exceptions. Used by the Module subsystem to handle access control.
  231. */
  232. class WFAuthorizationException extends Exception
  233. {
  234. /**
  235. * @const Set the exception's CODE to this if access is denied based on the user's WFAuthorizationInfo.
  236. */
  237. const DENY = 1;
  238. /**
  239. * @const Set the exception's CODE to this if access is denied because no one is logged in. System will bounced to login and return.
  240. */
  241. const TRY_LOGIN = 2;
  242. }
  243. /**
  244. * The WFAuthorizationManager helps the application manage user authentication, login, and access control.
  245. *
  246. * By default, a web application has no login capabilities and thus all users are unprivileged.
  247. *
  248. * WFAuthorizationManager works in conjuction with the bundled "login" module. The following is the public interface of the login module (via invocationPath redirects)
  249. * - promptLogin/<continueURL:base64>
  250. * - doLogout
  251. * - notAuthorized
  252. *
  253. * You can reliably link to the above listed invocationPaths from your application.
  254. *
  255. * @todo captcha option
  256. * @todo Decouple the default WFAuthorizationInfo class from the manager; let applications define this so that if there's no one logged in at least they get back the correct instance type.
  257. * @todo Make VERSION accessible externally (maybe through Delegate interface?) so that applications can have phocoa invalidate/re-login automatically when session structures change.
  258. */
  259. class WFAuthorizationManager extends WFObject
  260. {
  261. const SESSION_NAMESPACE = 'WFAuthorizationManager';
  262. const SESSION_KEY_VERSION = 'version';
  263. const SESSION_KEY_LOGGED_IN = 'isLoggedIn';
  264. const SESSION_KEY_AUTHORIZATION_INFO = 'authorizationInfo';
  265. const SESSION_KEY_RECENT_LOGIN_TIME = 'recentLoginTime';
  266. const VERSION = 1.1;
  267. const RECENT_LOGIN_SECS = 900; // 15 minutes
  268. const ALLOW = 1;
  269. const DENY = 2;
  270. /**
  271. * @var object WFAuthorizationInfo The authorization info for the current session.
  272. */
  273. protected $authorizationInfo;
  274. /**
  275. * @var object WFAuthorizationDelegate The delegate object for handling authorization-related things.
  276. */
  277. protected $authorizationDelegate;
  278. /**
  279. * @var string The class name to use as the {@link WFAuthorizationManager::$authorizationInfo}. Defaults to {@link WFAuthorizationInfo}.
  280. */
  281. protected $authorizationInfoClass;
  282. function __construct()
  283. {
  284. parent::__construct();
  285. $this->authorizationInfoClass = WFWebApplication::sharedWebApplication()->authorizationInfoClass();
  286. $this->authorizationInfo = NULL;
  287. $this->authorizationDelegate = NULL;
  288. // is session authorization info initialized?
  289. if (empty($_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_VERSION]) or $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_VERSION] < WFAuthorizationManager::VERSION)
  290. {
  291. // SESSION authorization info doesn't exist; initialize to least-privileged state
  292. // initialize
  293. $this->init();
  294. }
  295. else
  296. {
  297. // SESSION authorization does exist; restore from session
  298. $this->authorizationInfo = $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_AUTHORIZATION_INFO];
  299. // update recent-auth time if it's within the window
  300. if ( (time() - $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_RECENT_LOGIN_TIME]) < WFAuthorizationManager::RECENT_LOGIN_SECS )
  301. {
  302. $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_RECENT_LOGIN_TIME] = time();
  303. }
  304. }
  305. }
  306. const REMEMBER_ME_OPT_NAME = 'name';
  307. const REMEMBER_ME_OPT_DURATION = 'duration';
  308. const REMEMBER_ME_OPT_DOMAIN = 'domain';
  309. const REMEMBER_ME_OPT_PATH = 'path';
  310. const REMEMBER_ME_SEPARATOR = ':';
  311. /**
  312. * Set a long-term remember me cookie.
  313. * @param array OPTIONS hash. See WFAuthorizationManager::REMEMBER_ME_OPT_*.
  314. */
  315. function rememberMe()
  316. {
  317. $options = $this->rememberMeOptions();
  318. $userid = $this->authorizationInfo->userid();
  319. $userToken = $this->rememberMeToken($userid);
  320. $rememberMeData = "{$userid}" . self::REMEMBER_ME_SEPARATOR . "{$userToken}";
  321. setcookie($options[self::REMEMBER_ME_OPT_NAME], $rememberMeData, strtotime($options[self::REMEMBER_ME_OPT_DURATION]), $options[self::REMEMBER_ME_OPT_PATH], $options[self::REMEMBER_ME_OPT_DOMAIN]);
  322. }
  323. function rememberMeToken($username)
  324. {
  325. if (!$this->authorizationInfo->isLoggedIn()) throw new WFException("Cannot call rememberMeToken if not logged in.");
  326. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for rememberMeToken.") );
  327. $rememberMeToken = NULL;
  328. if (method_exists($this->authorizationDelegate, 'rememberMeToken'))
  329. {
  330. $rememberMeToken = $this->authorizationDelegate->rememberMeToken($username);
  331. }
  332. return $rememberMeToken;
  333. }
  334. function rememberMeOptions()
  335. {
  336. $options = array(
  337. self::REMEMBER_ME_OPT_NAME => 'PHOCOA_REMEMBER_ME',
  338. self::REMEMBER_ME_OPT_DURATION => '+10 years',
  339. self::REMEMBER_ME_OPT_DOMAIN => NULL,
  340. self::REMEMBER_ME_OPT_PATH => '/',
  341. );
  342. if ($this->authorizationDelegate && method_exists($this->authorizationDelegate, 'rememberMeOptions'))
  343. {
  344. $delegateOptions = $this->authorizationDelegate->rememberMeOptions();
  345. if (is_array($delegateOptions)) $options = array_merge($options, $delegateOptions);
  346. }
  347. return $options;
  348. }
  349. /**
  350. * Initialize the auth manager to the default state.
  351. */
  352. function init()
  353. {
  354. $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_VERSION] = WFAuthorizationManager::VERSION;
  355. $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_LOGGED_IN] = false;
  356. $this->authorizationInfo = $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_AUTHORIZATION_INFO] = new $this->authorizationInfoClass();
  357. $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_RECENT_LOGIN_TIME] = 0;
  358. }
  359. /**
  360. * Get a reference to the shared WFAuthorizationManager object.
  361. * @static
  362. * @return object The WFAuthorizationManager object.
  363. */
  364. public static function sharedAuthorizationManager()
  365. {
  366. static $singleton = NULL;
  367. if (!$singleton) {
  368. $singleton = new WFAuthorizationManager();
  369. }
  370. return $singleton;
  371. }
  372. /**
  373. * Get the current auth info.
  374. *
  375. * @return object WFAuthorizationInfo The active WFAuthorizationInfo info.
  376. */
  377. function authorizationInfo()
  378. {
  379. return $this->authorizationInfo;
  380. }
  381. /**
  382. * Set the WFAuthorizationDelegate to use.
  383. *
  384. * The WFWebApplication will usually do this for you.
  385. *
  386. * @param object An object that implements WFAuthorizationDelegate.
  387. */
  388. function setDelegate($d)
  389. {
  390. $this->authorizationDelegate = $d;
  391. if (!$this->authorizationInfo->isLoggedIn())
  392. {
  393. $options = $this->rememberMeOptions();
  394. // try to load from remember me
  395. if (isset($_COOKIE[$options[self::REMEMBER_ME_OPT_NAME]]))
  396. {
  397. list($username, $token) = explode(self::REMEMBER_ME_SEPARATOR, $_COOKIE[$options[self::REMEMBER_ME_OPT_NAME]], 2);
  398. $ok = $this->login($username, $token, true);
  399. }
  400. }
  401. }
  402. /**
  403. * Get the WFAuthorizationDelegate set for the WFAuthorizationManager.
  404. *
  405. * @return object An object that implements WFAuthorizationDelegate.
  406. */
  407. function delegate()
  408. {
  409. return $this->authorizationDelegate;
  410. }
  411. /**
  412. * Logout the current session.
  413. */
  414. function logout()
  415. {
  416. $this->init();
  417. // clear remember me cookie
  418. $options = $this->rememberMeOptions();
  419. setcookie($options[self::REMEMBER_ME_OPT_NAME], '', strtotime('-1 year'), $options[self::REMEMBER_ME_OPT_PATH], $options[self::REMEMBER_ME_OPT_DOMAIN]);
  420. }
  421. /**
  422. * Attempt to authorize the user with the given name/password.
  423. *
  424. * This will call the delegate's login function to authenticate and get the authorizationInfo.
  425. *
  426. * @param string The username to use for the authentication.
  427. * @param string The password to use for the authentication.
  428. * @param boolean TRUE if the password is in "token" form; ie, not the clear-text password. Useful for remember-me logins or single-sign-on (SSO) setups.
  429. * @return boolean TRUE if login was successful, FALSE otherwise.
  430. * @see WFAuthorizationDelegate::login()
  431. */
  432. function login($username, $password, $passIsToken = false)
  433. {
  434. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required to attempt login.") );
  435. if (!method_exists($this->authorizationDelegate, 'login')) throw( new Exception("WFAuthorizationDelegate is missing login() function.") );
  436. // get delegate to attempt authorization
  437. $result = $this->authorizationDelegate->login($username, $password, $passIsToken);
  438. if ($result instanceof WFAuthorizationInfo)
  439. {
  440. $this->loginAsAuthorizationInfo($result);
  441. return true;
  442. }
  443. else
  444. {
  445. // means login failed - kill all current login info!
  446. $this->init();
  447. return false;
  448. }
  449. }
  450. /**
  451. * Change the current session authorization info to the specified WFAuthorizationInfo object.
  452. *
  453. * This is useful for SSO or other internal user-switching capabilities.
  454. *
  455. * @param object WFAuthorizationInfo The new authorization info to set for the current session.
  456. */
  457. function loginAsAuthorizationInfo($authInfo)
  458. {
  459. if (!$authInfo instanceof WFAuthorizationInfo) throw new WFException("WFAuthorizationInfo or subclass required.");
  460. $this->authorizationInfo = $authInfo;
  461. $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_LOGGED_IN] = true;
  462. $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_AUTHORIZATION_INFO] = $this->authorizationInfo;
  463. $_SESSION[WFAuthorizationManager::SESSION_NAMESPACE][WFAuthorizationManager::SESSION_KEY_RECENT_LOGIN_TIME] = time();
  464. }
  465. /**
  466. * Cause the visitor to be re-directed to the login page.
  467. *
  468. * OPTIONAL: "continueURL" support.
  469. *
  470. * This will issue a 302 redirect and exit the current request execution.
  471. *
  472. * @param string The URL of the page to go to after successful login. Note that this should be a PLAIN URL, but it WILL BE base64-encoded before being passed to the login module.
  473. */
  474. function doLoginRedirect($continueURL)
  475. {
  476. $loginInvocationPath = $this->loginInvocationPath();
  477. if (WFRequestController::sharedRequestController()->isAjax())
  478. {
  479. header("HTTP/1.0 401 Login Required");
  480. print WWW_ROOT . "/{$loginInvocationPath}/" . WFWebApplication::serializeURL($continueURL);
  481. }
  482. else
  483. {
  484. header("Location: " . WWW_ROOT . "/{$loginInvocationPath}/" . WFWebApplication::serializeURL($continueURL));
  485. }
  486. exit;
  487. }
  488. /**
  489. * Get the login modulePath to use.
  490. *
  491. * @return string The modulePath for the login module. The module at the given path must implement promptLogin/doLogout/notAuthorized
  492. */
  493. function loginInvocationPath()
  494. {
  495. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for defaultLoginContinueURL.") );
  496. $loginInvocationPath = 'login/promptLogin';
  497. if (method_exists($this->authorizationDelegate, 'loginInvocationPath'))
  498. {
  499. $dLoginInvocationPath = $this->authorizationDelegate->loginInvocationPath();
  500. if ($dLoginInvocationPath)
  501. {
  502. $loginInvocationPath = $dLoginInvocationPath;
  503. }
  504. }
  505. return $loginInvocationPath;
  506. }
  507. /**
  508. * The URL to continue to if the user logs in but there is no "continue to url" set.
  509. *
  510. * Will call the login delegate method to get info as well.
  511. *
  512. * @return string A URL to redirect to (will be done via {@link WFRedirectRequestException}). DEFAULT: NULL.
  513. * @see WFAuthorizationDelegate::defaultLoginContinueURL()
  514. */
  515. function defaultLoginContinueURL()
  516. {
  517. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for defaultLoginContinueURL.") );
  518. $continueURL = WFRequestController::WFURL('login', 'showLoginSuccess');
  519. if (method_exists($this->authorizationDelegate, 'defaultLoginContinueURL'))
  520. {
  521. $dContinueURL = $this->authorizationDelegate->defaultLoginContinueURL();
  522. if ($dContinueURL)
  523. {
  524. $continueURL = $dContinueURL;
  525. }
  526. }
  527. return $continueURL;
  528. }
  529. /**
  530. * The URL to continue to if the user logs out.
  531. *
  532. * Will call the login delegate method.
  533. *
  534. * If NULL, no redirect will be performed, and just a message saying "Logout successful" will be seen.
  535. *
  536. * @return string A URL to redirect to (will be done via {@link WFRedirectRequestException}). DEFAULT: NULL.
  537. * @see WFAuthorizationDelegate::defaultLogoutContinueURL()
  538. */
  539. function defaultLogoutContinueURL()
  540. {
  541. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for defaultLogoutContinueURL.") );
  542. $continueURL = NULL;
  543. if (method_exists($this->authorizationDelegate, 'defaultLogoutContinueURL'))
  544. {
  545. $continueURL = $this->authorizationDelegate->defaultLogoutContinueURL();
  546. }
  547. return $continueURL;
  548. }
  549. /**
  550. * Should there be an interstitial "You have logged out successfully, click here to continue", or should logout immediately redirect to {@link WFAuthorizationDelegate::defaultLogoutContinueURL() defaultLogoutContinueURL()}?
  551. *
  552. * Will call login delegate.
  553. *
  554. * @return boolean TRUE to show a logout interstitial. DEFAULT: true.
  555. * @see WFAuthorizationDelegate::defaultLoginContinueURL()
  556. */
  557. function shouldShowLogoutConfirmation()
  558. {
  559. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for shouldShowLogoutConfirmation.") );
  560. $shouldShowLogoutConfirmation = true;
  561. if (method_exists($this->authorizationDelegate, 'shouldShowLogoutConfirmation'))
  562. {
  563. $shouldShowLogoutConfirmation = $this->authorizationDelegate->shouldShowLogoutConfirmation();
  564. }
  565. return $shouldShowLogoutConfirmation;
  566. }
  567. /**
  568. * Should the login interface have a "remember me" checkbox?
  569. *
  570. * Will call the login delegate method.
  571. *
  572. * @return boolean TRUE to enable "remember me" functionality. DEFAULT: false.
  573. * @see WFAuthorizationDelegate::shouldEnableRememberMe()
  574. */
  575. function shouldEnableRememberMe()
  576. {
  577. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for shouldEnableRememberMe.") );
  578. $shouldEnableRememberMe = false;
  579. if (method_exists($this->authorizationDelegate, 'shouldEnableRememberMe'))
  580. {
  581. $shouldEnableRememberMe = $this->authorizationDelegate->shouldEnableRememberMe();
  582. }
  583. return $shouldEnableRememberMe;
  584. }
  585. /**
  586. * If "remember me" is enabled with {@link WFAuthorizationDelegate::shouldEnableRememberMe() shouldEnableRememberMe}, should "remember me"
  587. * be checked by default?
  588. *
  589. * Will call the login delegate method.
  590. *
  591. * @return boolean TRUE if the "remember me" checkbox should be checked by default. DEFAULT: false.
  592. * @see WFAuthorizationDelegate::shouldRememberMeByDefault()
  593. */
  594. function shouldRememberMeByDefault()
  595. {
  596. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for shouldRememberMeByDefault.") );
  597. $shouldRememberMeByDefault = false;
  598. if (method_exists($this->authorizationDelegate, 'shouldRememberMeByDefault'))
  599. {
  600. $shouldRememberMeByDefault = $this->authorizationDelegate->shouldRememberMeByDefault();
  601. }
  602. return $shouldRememberMeByDefault;
  603. }
  604. /**
  605. * The login help message that should be displayed above the login box.
  606. *
  607. * Will call the login delegate method.
  608. *
  609. * @return string The login message to display above the login box. DEFAULT: "You must log in to access the requested page."
  610. * @see WFAuthorizationDelegate::loginMessage()
  611. */
  612. function loginMessage()
  613. {
  614. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for loginMessage.") );
  615. $loginMessage = 'You must log in to access the requested page.';
  616. if (method_exists($this->authorizationDelegate, 'loginMessage'))
  617. {
  618. $loginMessage = $this->authorizationDelegate->loginMessage();
  619. }
  620. return $loginMessage;
  621. }
  622. /**
  623. * The label to use for the "username" field.
  624. *
  625. * Will call the login delegate method.
  626. *
  627. * @return string The label for the username field. DEFAULT: "Username".
  628. * @see WFAuthorizationDelegate::usernameLabel()
  629. */
  630. function usernameLabel()
  631. {
  632. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for usernameLabel.") );
  633. $usernameLabel = 'Username';
  634. if (method_exists($this->authorizationDelegate, 'usernameLabel'))
  635. {
  636. $usernameLabel = $this->authorizationDelegate->usernameLabel();
  637. }
  638. return $usernameLabel;
  639. }
  640. /**
  641. * The label for the sign up link on the login form.
  642. *
  643. * Will call the login delegate method.
  644. *
  645. * @return string The label for the sign up link. DEFAULT: 'Sign Up'.
  646. * @see WFAuthorizationDelegate::signUpLabel()
  647. */
  648. function signUpLabel()
  649. {
  650. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for signUpLabel.") );
  651. if (method_exists($this->authorizationDelegate, 'signUpLabel'))
  652. {
  653. return $this->authorizationDelegate->signUpLabel();
  654. }
  655. return 'Sign Up';
  656. }
  657. /**
  658. * The URL for the sign up link on the login form.
  659. *
  660. * Will call the login delegate method.
  661. *
  662. * @return string The URL for the sign up link. DEFAULT: NULL.
  663. * @see WFAuthorizationDelegate::signUpUrl()
  664. */
  665. function signUpUrl()
  666. {
  667. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for signUpUrl.") );
  668. if (method_exists($this->authorizationDelegate, 'signUpUrl'))
  669. {
  670. return $this->authorizationDelegate->signUpUrl();
  671. }
  672. return NULL;
  673. }
  674. /**
  675. * The message to display to a use on unsuccessful login.
  676. *
  677. * Will call the login delegate method.
  678. *
  679. * @param string The username that the attempted login was for.
  680. * @return mixed string: The message to display on failed login. array of strings; Multiple messages to display (as list items). DEFAULT: string:"Login username or password is not valid."
  681. * @see WFAuthorizationDelegate::loginFailedMessage()
  682. */
  683. function loginFailedMessage($username)
  684. {
  685. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for loginFailedMessage.") );
  686. $loginFailedMessage = 'Login failed for ' . $this->usernameLabel() . ' "' . $username . '". Please check your ' . $this->usernameLabel() . ' and password and try again.';
  687. if ($this->shouldEnableForgottenPasswordReset())
  688. {
  689. $loginFailedMessage .= " If you have forgotten your password, <a href=\"" . WFRequestController::WFURL('login', 'doForgotPassword') . '/' . $username . "\">click here</a>.";
  690. }
  691. if (method_exists($this->authorizationDelegate, 'loginFailedMessage'))
  692. {
  693. $loginFailedMessage = $this->authorizationDelegate->loginFailedMessage($username);
  694. }
  695. return $loginFailedMessage;
  696. }
  697. /**
  698. * Should a "forgot your password" link be shown?
  699. *
  700. * Will call the login delegate method.
  701. *
  702. * @return boolean TRUE to enable forgotten password reset feature.
  703. * @see WFAuthorizationManager::shouldEnableForgottenPasswordReset()
  704. */
  705. function shouldEnableForgottenPasswordReset()
  706. {
  707. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for shouldEnableForgottenPasswordReset.") );
  708. $shouldEnableForgottenPasswordReset = false;
  709. if (method_exists($this->authorizationDelegate, 'shouldEnableForgottenPasswordReset'))
  710. {
  711. $shouldEnableForgottenPasswordReset = $this->authorizationDelegate->shouldEnableForgottenPasswordReset();
  712. }
  713. return $shouldEnableForgottenPasswordReset;
  714. }
  715. /**
  716. * Reset the password for the given user.
  717. *
  718. * Your delegate method should craft an email or such to that user with the new password info.
  719. * If there is a problem (ie user doesn't exist) throw a WFException with an appropriate message to be displyed.
  720. * If not, just send your email and that's it. The default implementation will show an appropriate confirmation message.
  721. *
  722. * Alternatively, if you have more complicated reset password logic you want to implement, throw a WFRedirectRequestException.
  723. *
  724. * Will call the login delegate method.
  725. *
  726. * @param string The username that the attempted login was for.
  727. * @return string The message to show the user on successful password reset.
  728. * @throws object WFException If the password cannot be reset, throw a WFException with the message to be displayed as the string.<br>
  729. * @see WFAuthorizationDelegate::resetPassword($username)
  730. */
  731. function resetPassword($username)
  732. {
  733. if (!$this->authorizationDelegate) throw( new Exception("WFAuthorizationDelegate required for resetPassword.") );
  734. if (!method_exists($this->authorizationDelegate, 'resetPassword')) throw( new Exception("WFAuthorizationDelegate::resetPassword() must be definied to use the password reset feature.") );
  735. return $this->authorizationDelegate->resetPassword($username);
  736. }
  737. }
  738. ?>