Joshua Dalley
Joshua Dalley

Reputation: 339

Silex - Deny access to client from server side

On the server side I am receiving a request with a Uri path the client would like to access with a token in the header. My server will look at the hostname and token and make sure they are valid. If they aren't, I want to stop the client from accessing the API endpoint.

Here is the function

$app->before(function(Request $request) use ($app) {
    $host = $request->getHost();
    $token = $request->headers->get('token');

    if(!$app['isValidTokenService']($token)) {
        $app['monolog']->addInfo(sprintf("%s is a invalid token", $token));
        return $app->abort(401,'Unauthorized - bad credentials');
        //return new Response('Unauthorized - invalid ****',401);
    }

    if(!$app['isValidHostService']($host)) {
        $app['monolog']->addInfo(sprintf("%s is a invalid host", $host));
        return $app->abort(401,'Unauthorized - invalid host');
        //return new Response('Unauthorized - invalid ****',401);
    }

    return 'test';
});

I tried doing a return new Response('Unauthorized - invalid ****',401); which allowed the user to still access the end point. The $app->abort() seems to be working like a charm but its not responding to the client with anything which I am assuming its not the proper way of handling this situation.

How do I properly handle this situation to deny access to the API endpoint and return a proper error code to my client.

Upvotes: 0

Views: 244

Answers (1)

mTorres
mTorres

Reputation: 3590

Sorry Joshua, I couldn't reproduce your problem:

$ mkdir silex-test
$ cd silex-test
$ composer require silex/silex phpunit/phpunit
$ mkdir tests

Now create a file inside the tests folder appTest.php:

<?php

require_once __DIR__ . '/../vendor/autoload.php';

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Silex\Application;

class appTest extends \PHPUnit_Framework_TestCase
{
    public function testBeforeFilterPriorToRouteMatching()
    {
        $app = new Application();

        $app->before(function () {
            return new Response('before');
        });

        $app->get('/', function() { return new Response('you should never see me!'); });

        $request = Request::create('/');
        $this->assertEquals('before', $app->handle($request)->getContent(), "before test didn't canceled the execution!");

    }
}

Now just execute the test:

$ vendor/bin/phpunit tests/appTest.php
PHPUnit 4.8.7 by Sebastian Bergmann and contributors.

.

Time: 201 ms, Memory: 6.00Mb

OK (1 test, 1 assertion)

As you can see the controller for the / route was never called, so Silex is working as expected.

This only brings me the question: Which version are you using? (I've tried this with 1.3 and dev-master which is 2.0@dev) This PR (a little dated, though) solved and issue with the before middleware.

Update

In the above code, I've tried to shown that the return new Response('before') does indeed cancels all other execution. If you take a look at the assertion:

$this->assertEquals('before', $app->handle($request)->getContent(), "before test didn't canceled the execution!");

I compare the result of handling one request to the / URI which should return the string you should never see me! but it return the string before because the before filter returns a response with the string before and the controller code for the route path / is never called.

If you want to double check, change the controller code to:

$app->get('/', function() { 
    echo "You'll never see me as this is not called because of the before filter";

    return new Response('you should never see me!'); 
});

And check that running the test (vendor/bin/phpunit tests/appTest.php) never outputs the string You'll never see me as this is not called because of the before filter because the controller code is never called.

Upvotes: 2

Related Questions