zf2 api response event catched by bjyauthorize

262 views Asked by At

Hi can someone help me to prevent bjyauthorize to catch my api event error raised?

bjyauthorize redirect non logged user to login form as added to config. But since my api are allowed for all roles even for guest i just want it to return Json error message catched by ApiProblemListener

ApplicationRest\Module.php

class Module implements
    ConfigProviderInterface, 
    AutoloaderProviderInterface
{

    public function onBootstrap(MvcEvent $e)
    {
        $app = $e->getApplication();
        $sm = $app->getServiceManager();
        $events = $app->getEventManager();

        $listener = $sm->get('ApplicationRest\ApiAuthenticationListener');
        $events->getSharedManager()->attach('ApplicationRest\Controller', 'dispatch', $listener, 500);

        $events->attach('render', array($this, 'onRender'), 100);
        $events->attach($sm->get('ApplicationRest\ApiProblemListener'));
    }

    /**
     * Listener for the render event
     * Attaches a rendering/response strategy to the View.
     *
     * @param  \Zend\Mvc\MvcEvent $e
     */
    public function onRender($e)
    {
        $result = $e->getResult();
        if (!$result instanceof RestfulJsonModel) {
            return;
        }
        //var_dump(123);exit();


        $app = $e->getTarget();
        $services = $app->getServiceManager();
        $view = $services->get('View');
        $restfulJsonStrategy = $services->get('ApplicationRest\RestfulJsonStrategy');
        $events = $view->getEventManager();

        // register at high priority, to "beat" normal json strategy registered
        // via view manager
        $events->attach($restfulJsonStrategy, 500);
    }
}

Have many modules and i am really thinking to move away my apiModule "ApplicationRest" to another project but don't really want to update model and service each time i make some updates on main project.

Any suggestions would welcome! Thanks for your time!

EDIT: Provided more HeaderAuthentication class

class HeaderAuthentication implements AdapterInterface
{

    const AUTHORIZATION_HEADER = 'Authorization';
    const CRYPTO = 'sha256';

    protected $request;
    protected $repository;

    public function __construct(RequestInterface $request, UserRepository $repository)
    {
        $this->request = $request;
        $this->repository = $repository;
    }

    /**
     * Authorization: Key={key} Timestamp={timestamp} Signature={signature}
     * @return Result
     */
    public function authenticate()
    {
        $request = $this->getRequest();
        if (!$request instanceof Request) {
            return;
        }
        $headers = $request->getHeaders();

        // Check Authorization header presence
        if (!$headers->has(static::AUTHORIZATION_HEADER)) {
            return new Result(Result::FAILURE, null, array(
                'Authorization header missing'
            ));
        }

        $authorization = $headers->get(static::AUTHORIZATION_HEADER)->getFieldValue();

        // Validate public key
        $publicKey = $this->extractPublicKey($authorization);
        $user = $this->getUserRepository()
                     ->findOneByApiSecret($publicKey);

        if (null === $user) {
            $code = Result::FAILURE_IDENTITY_NOT_FOUND;
            return new Result($code, null, array(
                'User not found based on public key'
            ));
        }

        // Validate signature
        $signature = $this->extractSignature($authorization);
        /*$hmac = $this->getHmac($request, $user);
        if ($signature !== $hmac) {
            $code = Result::FAILURE_CREDENTIAL_INVALID;
            return new Result($code, null, array(
                'Signature does not match'
            ));
        }*/

        return new Result(Result::SUCCESS, $user);
    }
}

ApiAuthenticationListener

class ApiAuthenticationListener
{

    protected $adapter;

    public function __construct(HeaderAuthentication $adapter)
    {
        $this->adapter = $adapter;
    }

    public function __invoke(MvcEvent $event)
    {
        $result = $this->adapter->authenticate();

        if (!$result->isValid()) {
            $response = $event->getResponse();

            // Set some response content
            $response->setStatusCode(401);
            return $response;
        }

        // All is OK
        $event->setParam('user', $result->getIdentity());
    }

}
1

There are 1 answers

0
Saeven On

I'm guessing you configured guards on your route. You need to tell BJYAuthorize, through your module config, that this controller or route shouldn't be protected.

'bjyauthorize' => [

    'default_role'          => 'guest',

    ...     

    'guards' => [
        'BjyAuthorize\Guard\Controller' => [

            // system tools
            ['controller' => 'Application\Controller\Api', 'roles' => [] ],

            ['controller' => 'error', 'roles' => []],

        ],
    ],
],

I cut out the nitty gritty that's app specific, but this type of thing is quickly solved. I had a similar need for CLI routes to be unprotected by what is otherwise, http auth.