$this->type = $type;
}
- public function needAuth()
- {
- return $this->auth > S::i('auth', AUTH_PUBLIC);
- }
-
public function checkPerms()
{
- if (!$this->perms || $this->auth == AUTH_PUBLIC) { // No perms, no check
- return true;
- }
- $s_perms = S::v('perms');
- return $s_perms->hasFlagCombination($this->perms);
+ // Don't check permissions if there are no permission requirement
+ // (either no requested group membership, or public auth is allowed).
+ return !$this->perms || $this->auth == AUTH_PUBLIC ||
+ Platal::session()->checkPerms($this->perms);
}
public function hasType($type)
public function call(PlPage &$page, array $args)
{
global $globals, $session, $platal;
- if ($this->needAuth()) {
+ if (!$session->checkAuth($this->auth)) {
if ($this->hasType(DO_AUTH)) {
if (!$session->start($this->auth)) {
$platal->force_login($page);
}
}
+/** The standard plat/al hook, for interactive requests.
+ * It optionally does active authentication (DO_AUTH). The handler is invoked
+ * with the PlPage object, and with each of the remaining path components.
+ */
class PlStdHook extends PlHook
{
- private $hook;
+ private $callback;
public function __construct($callback, $auth = AUTH_PUBLIC, $perms = 'user', $type = DO_AUTH)
{
parent::__construct($auth, $perms, $type);
- $this->hook = $callback;
+ $this->callback = $callback;
}
protected function run(PlPage &$page, array $args)
global $session, $platal;
$args[0] = $page;
- $val = call_user_func_array($this->hook, $args);
+ $val = call_user_func_array($this->callback, $args);
if ($val == PL_DO_AUTH) {
if (!$session->start($session->loggedLevel())) {
$platal->force_login($page);
}
- $val = call_user_func_array($this->hook, $args);
+ $val = call_user_func_array($this->callback, $args);
}
return $val;
}
}
+/** A specialized hook for token-based requests.
+ * It is intended for purely passive requests (typically for serving CSV or RSS
+ * content outside the browser), and can fallback to regular session-based
+ * authentication when the token is not valid/available.
+ *
+ * Note that $auth is only applied for session-backed authentication; it is
+ * assumed that token-based auth is always enough for the hook (otherwise, just
+ * use PlStdHook above).
+ *
+ * Also, this hook requires that the first two unmatched path components are the
+ * user and token (for instance /<matched path>/<user>/<token>/....). They will
+ * be popped before being passed to the handler, and replaced by the request's
+ * PlUser object.
+ */
+class PlTokenHook extends PlHook
+{
+ private $actualAuth;
+ private $callback;
+
+ public function __construct($callback, $auth = AUTH_PUBLIC, $perms = 'user', $type = NO_AUTH)
+ {
+ // As mentioned above, $auth is only applied for session-based auth
+ // (as opposed to token-based). PlHook is initialized to AUTH_PUBLIC to
+ // avoid it refusing to approve requests; this is important as the user
+ // is not yet authenticated at that point (see below for the actual
+ // permissions check).
+ parent::__construct(AUTH_PUBLIC, $perms, $type);
+ $this->actualAuth = $auth;
+ $this->callback = $callback;
+ }
+
+ protected function run(PlPage &$page, array $args)
+ {
+ // Retrieve the user, either from the session (less expensive, as it is
+ // already there), or from the in-path (user, token) pair.
+ if (S::logged() && Platal::session()->checkAuth($this->actualAuth)) {
+ $user = S::user();
+ } else {
+ $user = Platal::session()->tokenAuth(@$args[1], @$args[2]);
+ }
+
+ // Check the permissions, unless the handler is fully public.
+ if ($this->actualAuth > AUTH_PUBLIC) {
+ if (is_null($user) || !$user->checkPerms($this->perms)) {
+ return PL_FORBIDDEN;
+ }
+ }
+
+ // Replace the first three remaining elements of the path with the
+ // PlPage and PlUser objects.
+ array_shift($args);
+ $args[0] = $page;
+ $args[1] = $user;
+ return call_user_func_array($this->callback, $args);
+ }
+}
+
+/** A specialized plat/al hook for serving wiki pages.
+ */
class PlWikiHook extends PlHook
{
public function __construct($auth = AUTH_PUBLIC, $perms = 'user', $type = DO_AUTH)
return $this->iterator->last();
}
- public function run(PlPage& $page, $login, $token, $require_auth = true, $type = 'rss2')
+ public function run(PlPage& $page, PlUser& $user, $require_auth = true, $type = 'rss2')
{
- $user = Platal::session()->tokenAuth($login, $token);
- if (empty($user)) {
- if ($require_auth) {
- return PL_FORBIDDEN;
- } else {
- $user = null;
- }
+ if (empty($user) && $require_auth) {
+ return PL_FORBIDDEN;
}
$page->assign('rss_hash', $token);
abstract public function handlers();
/** Register a hook
- * @param fun name of the handler (the exact name will be handler_$fun)
- * @param auth authentification level of needed to run this handler
+ * @param fun name of the handler (the exact name will be handler_$fun); the
+ * handler will be invoked with the PlPage object, and the unmatched path
+ * components
+ * @param auth authentification level required to run this handler
* @param perms permission required to run this handler
* @param type additionnal flags
*
* Perms syntax is the following:
- * perms = rights(,rights)*
- * rights = right(:right)*
+ * perms = rights(,rights)*
+ * rights = right(:right)*
* right is an atomic right permission (like 'admin', 'user', 'groupadmin', 'groupmember'...)
*
- * If type is set to NO_AUTH, the system will return 403 instead of asking auth data
- * this is useful for Ajax handler
- * If type is not set to NO_SKIN, the system will consider redirecting the user to https
+ * If type is set to NO_AUTH, the system will return 403 instead of asking
+ * auth data; this is useful for Ajax handler. If type is not set to
+ * NO_SKIN, the system will consider redirecting the user to https.
*/
public function make_hook($fun, $auth, $perms = 'user', $type = DO_AUTH)
{
- return new PlStdHook(array($this, 'handler_' . $fun),
- $auth, $perms, $type);
+ return new PlStdHook(array($this, 'handler_' . $fun), $auth, $perms, $type);
+ }
+
+ /** Register a token-authentified hook (rss, csv, ical, ...)
+ * @param fun name of the handler (the exact name will be handler_$fun); the
+ * handler will be invoked with the PlPage object, the PlUser of the
+ * request, and the unmatched path components
+ * @param auth authentification level required, when not token-authentified
+ * @param perms permission required to run this handler
+ * @param type additionnal flags
+ *
+ * See {@link make_hook} above for details on permissions and additional
+ * flags. Note that DO_AUTH has no effect here, as the request will always
+ * be passively identified.
+ *
+ * This hook requires that the first two unmatched path components form a
+ * valid (user, token) pair; if not, a session-based authentification will
+ * be attempted, in which case $auth will be honored.
+ * Note that because token-based authentication is weak, it should only be
+ * used for readonly handlers normally served in AUTH_COOKIE.
+ */
+ public function make_token_hook($fun, $auth, $perms = 'user', $type = NO_HTTPS)
+ {
+ return new PlTokenHook(array($this, 'handler_' . $fun), $auth, $perms, $type);
}
/** Register a hook that points to a wiki page.
require_once dirname(__FILE__) . '/version.inc.php';
require_once dirname(__FILE__) . '/misc.inc.php';
-define('PERMS_EXT', 'ext');
+// Common basic permission flags.
define('PERMS_USER', 'user');
define('PERMS_ADMIN', 'admin');
-define('SKINNED', 0);
-define('SIMPLE', 1);
-define('NO_SKIN', 2);
-
+// Page style options, used when rendering pages. Options are exclusive.
+define('SKINNED', 0); // Page is rendered with the normal skin.
+define('SIMPLE', 1); // Page is rendered with a light skin (no leftnav).
+define('NO_SKIN', 2); // Page content is passed as-is (use for csv, xml, ...).
+
+// Hook options bitmasks. Authentication options are mutually exclusive, but
+// others (NO_HTTPS at the moment) are not.
+//
+// With PlStdHook, NO_AUTH indicates that no session will be started, and that
+// the actual handler is responsible for doing authentication; DO_AUTH forces
+// the engine to try to authenticate the user, including redirecting to the
+// login page. Note that DO_AUTH is ignored if AUTH_PUBLIC is requested.
+//
+// Options NO_AUTH and DO_AUTH are ignored with PlTokenHook.
define('NO_AUTH', 0);
define('DO_AUTH', 1);
define('NO_HTTPS', 2);