File Manager

Current Directory: /home/astoriaah/www/plugins/system/shlib/shl_packages/api
Viewing File: /home/astoriaah/www/plugins/system/shlib/shl_packages/api/authorizer.php
<?php /** * Shlib - programming library * * @author Yannick Gaultier * @copyright (c) Yannick Gaultier 2020 * @package shlib * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL * @version 0.4.0.716 * @date 2020-12-07 */ defined('_JEXEC') or die; /** * Decide to authorize the processing of the provided request by the provided route. * * Workflow: * * If HTTPS, allow logged-in user authorization AND/OR token authorization. * If HTTP, only allow logged-in user authorization. * * routeDef can have an authorization callback in the callback_auth field. * This is called with: * $routeDef[](apiRequest, $namespace, $routeDef, currentAuthorization) * * and must return an array: * * array ( * 'status' => 200/401/403, * 'errors' => array( * array( * 'code' => 12345, * 'message' => 'First error message' * ), * array( * 'code' => 3456, * 'message' => 'Second error message' * ) * ) * ) * * The 'errors' field is optional. * * @TODO: implement token access over HTTPS. * * Token access = API to generate token and store them, revoke them, renew them. * A token must be associated with permissions rights, ie fairly complicated stuff. * \ShlApi_Token::create( * $namespace, * $authorizations_granted = array( * array( * 'asset' => 'xxxx, * 'action' => 'yyyy' * ), * array( * 'asset' => 'xxxx_2, * 'action' => 'yyyy_2' * ) * ) * ); * * Providing this token in a request is equivalent to being logged-in and having * the described privileges. * * Token does not seem urgent. Can be left to the implementer I think. Tokens can be managed * directly by the client app. * */ class ShlApi_Authorizer extends \ShlBase { /** * All access granted, no authorization required. */ const AUTH_PUBLIC = 'public'; /** * Authentication through cookie-based user authentication, platform-dependant. */ const AUTH_LOG_IN = 'login'; /** * Authentication based on token passed in request. To be defined, not implemented, falls back to AUTH_LOG_IN. */ const AUTH_TOKEN = 'token'; /** * @var string Authentication type: log-in, token or public. */ private $type; /** * @var Authorizations required to be granted access. */ private $authorizations; /** * @var Callable Optional callback provided at creation time to filter the built-in authorization check. */ private $authCallback; /** * \ShlApi_Authorizer constructor. Stores type, authorizations list and optional callback. * * @param string $type Authentication type: log-in, token or public. * @param array $authorizations Authorizations required to be granted access. Platform-dependant. * @param Callable $authCallback Optional callback provided at creation time to filter the built-in authorization * check. */ public function __construct($type, $authorizations, $authCallback = null) { parent::__construct(); // @TODO implement token auth. For now, only login if (self::AUTH_TOKEN == $type) { $type = self::AUTH_LOG_IN; } $this->type = $type; $this->authorizations = $authorizations; $this->authCallback = $authCallback; } /** * Getter for the authentication type. * * @return string */ public function getType() { return $this->type; } /** * Authorize a request against authorization rules passed * at this object creation. * * @param \ShlApi_Request $apiRequest * * @return array */ public function authorize($apiRequest) { switch ($this->type) { case self::AUTH_PUBLIC: return array( 'status' => \ShlSystem_Http::RETURN_OK ); break; case self::AUTH_LOG_IN: case self::AUTH_TOKEN: // can call auth method. $methodName = 'authorize' . ucfirst($this->type); $authorization = $this->{$methodName}( $apiRequest ); break; default: \ShlSystem_Log::error( 'shlib', 'API authorization method unknown: %s.', $this->type ); return array( 'status' => \ShlSystem_Http::RETURN_INTERNAL_ERROR ); break; } return $authorization; } /** * Decide to authorize the processing of the provided request against this object * authorizations set, authentication being based on user login. * * @param \ShlApi_Request $apiRequest * * @return int */ public function authorizeLogin($apiRequest) { $authorization = array( 'status' => \ShlSystem_Http::RETURN_OK ); // @TODO: removed dev hack $is_Dev = \JFactory::getApplication()->input->getInt('shl_dev') == 1; // if state-changing method, require CRSF token if ( !$is_Dev && 'GET' != $apiRequest->getMethod() && !$this->platform->checkCSRFToken( $apiRequest->getOriginalMethod() ) ) { return array( 'status' => \ShlSystem_Http::RETURN_NOT_FOUND ); } // we have some permissions requirements. $acl = $this->factory->getA('\ShlSystem_Acl'); $authorized = true; foreach ($this->authorizations as $requiredPermission) { $authorized = $authorized && $acl->userCan( wbArrayGet($requiredPermission, 'action'), wbArrayGet($requiredPermission, 'asset') ); } if (!$authorized) { $authorization = array( 'status' => \ShlSystem_Http::RETURN_UNAUTHORIZED, 'errors' => array( 'code' => \ShlSystem_Http::RETURN_UNAUTHORIZED, 'message' => 'Invalid authorization token or credentials.' ) ); } if (is_callable($this->authCallback)) { $authorization = call_user_func_array( $this->authCallback, array( $apiRequest, $authorization ) ); } return $authorization; } /** * Authorize a request based on a passed token. * * Not implemented. * * @param \ShlApi_Request $apiRequest * * @return array */ public function authorizeToken($apiRequest) { $authorization = array( 'status' => \ShlSystem_Http::RETURN_FORBIDDEN ); // if not secure, only log-in auth allowed (cookies) if (!$apiRequest->isSecure()) { $this->type = self::AUTH_LOG_IN; \ShlSystem_Log::info( 'shlib', 'API route %s allows token, but not when requested in an insecure manner. Downgraded to AUTH_LOG_IN.', $this->namespace . ':' . $this->method . ':' . $this->route ); return $this->authorizeLogin( $apiRequest ); } return $authorization; } }