appserver-io/webserver

View on GitHub
src/AppserverIo/WebServer/Modules/AccessModule.php

Summary

Maintainability
C
1 day
Test Coverage
<?php

/**
 * \AppserverIo\WebServer\Modules\AccessModule
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 *
 * PHP version 5
 *
 * @author    Johann Zelger <jz@appserver.io>
 * @copyright 2015 TechDivision GmbH <info@appserver.io>
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
 * @link      https://github.com/appserver-io/webserver
 * @link      http://www.appserver.io/
 */

namespace AppserverIo\WebServer\Modules;

use AppserverIo\Psr\HttpMessage\Protocol;
use AppserverIo\Psr\HttpMessage\RequestInterface;
use AppserverIo\Psr\HttpMessage\ResponseInterface;
use AppserverIo\WebServer\Interfaces\HttpModuleInterface;
use AppserverIo\Server\Dictionaries\ModuleHooks;
use AppserverIo\Server\Dictionaries\ServerVars;
use AppserverIo\Server\Dictionaries\ModuleVars;
use AppserverIo\Server\Exceptions\ModuleException;
use AppserverIo\Server\Interfaces\RequestContextInterface;
use AppserverIo\Server\Interfaces\ServerContextInterface;

/**
 * Class AccessModule
 *
 * @author    Johann Zelger <jz@appserver.io>
 * @copyright 2015 TechDivision GmbH <info@appserver.io>
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
 * @link      https://github.com/appserver-io/webserver
 * @link      http://www.appserver.io/
 */
class AccessModule implements HttpModuleInterface
{

    /**
     * Defines the module name
     *
     * @var string
     */
    const MODULE_NAME = 'access';

    /**
     * Holds the server context instance
     *
     * @var \AppserverIo\Server\Interfaces\ServerContextInterface
     */
    protected $serverContext;

    /**
     * Holds an array of all accesses
     *
     * @var array
     */
    protected $accesses;

    /**
     * Returns the request instance
     *
     * @return \AppserverIo\Psr\HttpMessage\RequestInterface The request instance
     */
    public function getRequest()
    {
        return $this->request;
    }

    /**
     * Returns the response instance
     *
     * @return \AppserverIo\Psr\HttpMessage\ResponseInterface The response instance;
     */
    public function getResponse()
    {
        return $this->response;
    }

    /**
     * Returns the server context instance
     *
     * @return \AppserverIo\Server\Interfaces\ServerContextInterface
     */
    public function getServerContext()
    {
        return $this->serverContext;
    }

    /**
     * Initiates the module
     *
     * @param \AppserverIo\Server\Interfaces\ServerContextInterface $serverContext The server's context instance
     *
     * @return boolean
     * @throws \AppserverIo\Server\Exceptions\ModuleException
     */
    public function init(ServerContextInterface $serverContext)
    {
        $this->serverContext = $serverContext;
        $this->accesses = $serverContext->getServerConfig()->getAccesses();
    }

    /**
     * Implements module logic for given hook
     *
     * @param \AppserverIo\Psr\HttpMessage\RequestInterface          $request        A request object
     * @param \AppserverIo\Psr\HttpMessage\ResponseInterface         $response       A response object
     * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance
     * @param integer                                                $hook           The current hook to process logic for
     *
     * @return boolean
     * @throws \AppserverIo\Server\Exceptions\ModuleException
     */
    public function process(RequestInterface $request, ResponseInterface $response, RequestContextInterface $requestContext, $hook)
    {
        // In php an interface is, by definition, a fixed contract. It is immutable.
        // So we have to declair the right ones afterwards...
        /**
         * @var $request \AppserverIo\Psr\HttpMessage\RequestInterface
         */
        /**
         * @var $response \AppserverIo\Psr\HttpMessage\ResponseInterface
         */

        // if false hook is comming do nothing
        if (ModuleHooks::REQUEST_POST !== $hook) {
            return;
        }

        // set req and res object internally
        $this->request = $request;
        $this->response = $response;

        // get default access definitions
        $accesses = $this->accesses;

        // check if there are some volatile access definitions so use them and override global accesses
        if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_ACCESSES)) {
            // reset by volatile accesses
            $accesses = $requestContext->getModuleVar(ModuleVars::VOLATILE_ACCESSES);
        }

        // generally everything is not allowed
        $allowed = false;

        if (isset($accesses['allow'])) {
            // check allow accesses information if something matches
            foreach ($accesses['allow'] as $accessData) {
                // we are optimistic an initial say data will match
                $matchAllow = true;

                // check if accessData matches server vars
                foreach ($accessData as $serverVar => $varPattern) {
                    // check if server var exists
                    if ($requestContext->hasServerVar($serverVar)) {
                        // check if pattern matches
                        if (! preg_match('/' . $varPattern . '/', $requestContext->getServerVar($serverVar))) {
                            $matchAllow = false;
                            // break here if anything not matches
                            break;
                        }
                    }
                }

                if ($matchAllow) {
                    // set allowed flag true
                    $allowed = true;
                    // break here cause' we found an allowed access
                    break;
                }
            }
        }

        if (isset($accesses['deny'])) {
            // check deny accesses information if something matches
            foreach ($accesses['deny'] as $accessData) {
                // initial nothing denies the request
                $matchDeny = false;

                // check if accessData matches server vars
                foreach ($accessData as $serverVar => $varPattern) {
                    // check if server var exists
                    if ($requestContext->hasServerVar($serverVar)) {
                        // check if pattern matches
                        if (preg_match('/' . $varPattern . '/', $requestContext->getServerVar($serverVar))) {
                            $matchDeny = true;
                            // break here if anything matches
                            break;
                        }
                    }
                }

                if ($matchDeny) {
                    // set allowed flag false
                    $allowed = false;
                    // break here cause' we found an allowed access
                    break;
                }
            }
        }

        // check if it's finally not allowed
        if (! $allowed) {
            throw new ModuleException('This request is forbidden', 403);
        }
    }

    /**
     * Returns an array of module names which should be executed first
     *
     * @return array The array of module names
     */
    public function getDependencies()
    {
        return array();
    }

    /**
     * Returns the module name
     *
     * @return string The module name
     */
    public function getModuleName()
    {
        return self::MODULE_NAME;
    }

    /**
     * Prepares the module for upcoming request in specific context
     *
     * @return boolean
     * @throws \AppserverIo\Server\Exceptions\ModuleException
     */
    public function prepare()
    {
        // nothing to prepare for this module
    }
}