tuupola / slim-jwt-auth

PSR-7 and PSR-15 JWT Authentication Middleware
https://appelsiini.net/projects/slim-jwt-auth
MIT License
829 stars 142 forks source link

Slim 3 passthrough all routes when installed in subfolder #9

Closed ronaldo-systemar closed 9 years ago

ronaldo-systemar commented 9 years ago

When no public routes set, middleware runs ok, but when add the following:

    "rules" => [
        new \Slim\Middleware\JwtAuthentication\RequestPathRule([
            "path" => "/",
            "passthrough" => ["/api/ping"]
        ]),
        new \Slim\Middleware\JwtAuthentication\RequestMethodRule([
            "passthrough" => ["OPTIONS"]
        ])
    ]

Middleware just don't check JWT and passthrough all routes. The same code works fine on Slim 2, but Slim 3 don't.

Ps: Works fine on php built-in server, (without any dot (.) char in uri params), Apache doesn't work, passthrough all routes. Current .htaccess:

<IfModule mod_rewrite.c>
    RewriteEngine On

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [QSA,L]
    RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
tuupola commented 9 years ago

Just tested with Apache 2.2.15 on fresh CentOS 6.5 install. Everything works as expected.

$app = new \Slim\App;

$app->add(new \Slim\Middleware\JwtAuthentication([
    "secure" => false,
    "secret" => "supersecretkeyyoushouldnotcommittogithub",
    "rules" => [
        new \Slim\Middleware\JwtAuthentication\RequestPathRule([
            "path" => "/",
            "passthrough" => ["/api/ping"]
        ]),
        new \Slim\Middleware\JwtAuthentication\RequestMethodRule([
            "passthrough" => ["OPTIONS"]
        ])
    ]
]));

$app->get("/", function ($request, $response, $args) {
     return $response->write("hello");
});

$app->get("/foo", function ($request, $response, $args) {
    return $response->write("foo");
});

$app->get("/bar", function ($request, $response, $args) {
    return $response->write("bar");
});

$app->get("/api/ping", function ($request, $response, $args) {
    return $response->write("ping");
});

$app->run();

Yields

$ curl --insecure --include https://192.168.50.10/foo
HTTP/1.1 401 Unauthorized
Date: Tue, 15 Sep 2015 06:49:13 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.6.13
Content-Length: 0
Connection: close
Content-Type: text/html;charset=UTF-8

$ curl --insecure --include https://192.168.50.10/bar
HTTP/1.1 401 Unauthorized
Date: Tue, 15 Sep 2015 06:49:17 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.6.13
Content-Length: 0
Connection: close
Content-Type: text/html;charset=UTF-8

$ curl --insecure --include https://192.168.50.10/api/ping
HTTP/1.1 200 OK
Date: Tue, 15 Sep 2015 06:49:23 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.6.13
Content-Length: 4
Connection: close
Content-Type: text/html;charset=UTF-8

ping
tuupola commented 9 years ago

As a sidenote you should move RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}] up. Currently it is not reached because L flag in previous rule stops processing the ruleset.

http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l

ronaldo-systemar commented 9 years ago

I forgot to mention, maybe it's important, the route is in a group and calling external controllers, something like this:

$app->group("/api", function () { // Auth $this->post("/auth", "Controllers\Auth:attemp"); // Administradoras $this->get("/ping", "Controllers\Api:ping"); });

My index.php app is in a subfolder structure www/api/v3/public

tuupola commented 9 years ago

Test the code above to see if it works with your Apache. If not then it is probably server config issue. If yes then can you provide minimal code which I can reproduce the bug with.

ronaldo-systemar commented 9 years ago

Don't work. I do a fresh install and it just passthrough with your code above. Foo route returning status 200 at http://192.168.0.33/api/v4/public/foo it's running over windows xamp. As I said previously, I'm not running directly on server root, as you do in https://192.168.50.10/foo, but on slim 2 it's not a problem

ronaldo-systemar commented 9 years ago

I tried php built-in server to call http://192.168.0.33:1337/foo still get 200 code.

My .htaccess:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteRule ^ index.php [QSA,L]

My index.php code test:

<?php

require_once '/vendor/autoload.php';

$app = new \Slim\App;

$app->add(new \Slim\Middleware\JwtAuthentication([
    "secure" => false,
    "secret" => "supersecretkeyyoushouldnotcommittogithub",
    "rules" => [
        new \Slim\Middleware\JwtAuthentication\RequestPathRule([
            "path" => "/",
            "passthrough" => ["/api/ping"]
        ]),
        new \Slim\Middleware\JwtAuthentication\RequestMethodRule([
            "passthrough" => ["OPTIONS"]
        ])
    ]
]));

$app->get("/", function ($request, $response, $args) {
     return $response->write("hello");
});

$app->get("/foo", function ($request, $response, $args) {
    return $response->write("foo");
});

$app->get("/bar", function ($request, $response, $args) {
    return $response->write("bar");
});

$app->get("/api/ping", function ($request, $response, $args) {
    return $response->write("ping");
});

$app->run();

Composer requires:

{
    "minimum-stability": "dev",
    "prefer-stable": true,
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    },
    "require": {
        "slim/slim": "3.x-dev",
        "tuupola/slim-jwt-auth": "~2.0@dev"
    }
}

I do a fresh install and just requires Slim 3 and Slim-jwt-auth 2dev

tuupola commented 9 years ago

There is 200 code but what is the actual response? Response should be foo. Looks like your vendor require is wrong (unless you really have it on the root of your hard drive). It should be something like following instead:

require __DIR__ . "/vendor/autoload.php"; 

PHP builtin server does not use .htaccess file so it kind of moot.

ronaldo-systemar commented 9 years ago

Response is foo, it's passing. Vendor autoload file is ok, it's serving and all routes still unprotected. Sending a like of files, http://expirebox.com/download/2c68734ccef26a79cecb3336b7b1a522.html

tuupola commented 9 years ago

Copy pasted your composer.json and index.php. Fixed the vendor require as mentioned above. Works as expected.

php -S 0.0.0.0:8080 index.php 
PHP 5.6.9 Development Server started at Tue Sep 15 16:19:16 2015
Listening on http://0.0.0.0:8080
$  curl --include  http://0.0.0.0:8080/foo
HTTP/1.1 401 Unauthorized
Host: 0.0.0.0:8080
Connection: close
X-Powered-By: PHP/5.6.9
Content-type: text/html;charset=UTF-8
Content-Length: 0
tuupola commented 9 years ago

Unrarred your file, ran composer install and internal PHP webserver. Works as expected. Feels like Windows issue to me. Could also try clearing the composer cache just in case.

$ unrar x slim3jwt.rar

UNRAR 5.21 freeware      Copyright (c) 1993-2015 Alexander Roshal

Extracting from slim3jwt.rar

Creating    public                                                    OK
Extracting  public/.htaccess                                          OK 
Extracting  public/index.php                                          OK 
Extracting  composer.json                                             OK 
Creating    app                                                       OK
All OK
$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
...
Writing lock file
Generating autoload files
$ cd public/
$ php -S 0.0.0.0:8081 index.php
PHP 5.6.9 Development Server started at Tue Sep 15 16:31:11 2015
Listening on http://0.0.0.0:8081
$ curl --include http://0.0.0.0:8081/foo
HTTP/1.1 401 Unauthorized
Host: 0.0.0.0:8081
Connection: close
X-Powered-By: PHP/5.6.9
Content-type: text/html;charset=UTF-8
Content-Length: 0
ronaldo-systemar commented 9 years ago

Installed the lastest version of XAMP on windows, tried and same issue occurs, maybe it's a windows issue, because I have installed a totally fresh new webserver with php 5.6.12

tuupola commented 9 years ago

I would check Vagrant. Having same development and deployment environment is a real life saver. Less "Works on my machine" issues :)

ronaldo-systemar commented 9 years ago

WAMP also fails, maybe a native windows problem. Slim 2 works fine on both XAMP/WAMP.

Could you compress a project and pass the link? I wanna try uncompress here and install with composer for tests.

ronaldo-systemar commented 9 years ago

I found a clue. If RequestPathRule is defined, it fails, if there's no RequestPathRule defined in rules, middleware works fine, but, in my case, I can't define public routes.

It works:

$app->add(new \Slim\Middleware\JwtAuthentication([
    "secure" => false,
    "secret" => getenv('APP_KEY'),
    "callback" => function ($request, $response, $arguments) use ($app) {
        $app->jwt = $arguments["decoded"];
    },
    "rules" => [
        new \Slim\Middleware\JwtAuthentication\RequestMethodRule([
            "passthrough" => ["OPTIONS"]
        ])
    ]
]));

It doesn't work:

$app->add(new \Slim\Middleware\JwtAuthentication([
    "secure" => false,
    "secret" => getenv('APP_KEY'),
    "callback" => function ($request, $response, $arguments) use ($app) {
        $app->jwt = $arguments["decoded"];
    },
    "rules" => [
        new \Slim\Middleware\JwtAuthentication\RequestPathRule([
            "path" => "/",
            "passthrough" => ['api/ping'],
        ]),
        new \Slim\Middleware\JwtAuthentication\RequestMethodRule([
            "passthrough" => ["OPTIONS"]
        ])
    ]
]));

I've tested in alot of routes, namespaces and groups possible, it's not miss configuration because the same code works on slim 2, it's just RequestPathRule problem, when missed, middleware works.

tuupola commented 9 years ago

It is most likely this line which returns different value in Windows and *NIX hosts when using Slim 3. I do not use Windows myself so cannot debug.

elvispdosreis commented 9 years ago

I debug their two tuupola/slim-jwt-auth version 1.x 2.x and found the following error.

file slim-jwt-auth/src/JwtAuthentication/RequestPathRule.php

in version 2.x at line 34 $uri = $request->getUri()->getPath(); this command in slim 3 returns the route without the bar at first, for example the route /auth/login returns auth/login

in version 1.x at line 32 $uri = $app->request->getResourceUri(); this command in slim 2 returns with the bar /auth/login

with this regular expression under the function will not work correctly.

Sorry my English because I am Brazilian

ronaldo-systemar commented 9 years ago

I'm brazilian too =)

For some reason, in slim 2 this package works really fine, but, in slim 3, doesn't =( I got a full rewrite of my application in slim 3, everything works fine, but, tuupola middleware don't worked, so, i go back to slim 2. Slim 3 got modern conventions and is more organized than it's forefather

elvispdosreis commented 9 years ago

$uri = $request->getUri()->getPath(); replace $uri = "/".$request->getUri()->getPath();

while they do not release the patch.

ronaldo-systemar commented 9 years ago

@tuupola as @elvispdosreis mentioned, at line 34 $uri = $request->getUri()->getPath(); changes to $uri = "/".$request->getUri()->getPath(); works o/

tuupola commented 9 years ago

Is this in Windows version only or also *NIX? Note that Slim 3 itself is not released yet. There is only release candidate so breaks might occur.

elvispdosreis commented 9 years ago

Windows PHP 5.6.11 NTS

tuupola commented 9 years ago

I cannot reproduce with OSX nor Linux so it seems like Windows issue. Because I do not have access to Windows can you test what the following returns.

<?php
require_once "./vendor/autoload.php";
$app = new \Slim\App;
$app->get("/foo/bar", function ($request, $response, $args) {
    return $response->write($request->getUri()->getPath() . "\n");
});
$app->run();

For me it returns the following.

$  curl --include http://0.0.0.0:8080/foo/bar
HTTP/1.1 200 OK
Host: 0.0.0.0:8080
Connection: close
X-Powered-By: PHP/5.6.9
Content-type: text/html;charset=UTF-8
Content-Length: 9

/foo/bar

Apparently in Windows you get only foo/bar?

elvispdosreis commented 9 years ago

this in windows I get foo/bar only if the initial route bar

ronaldo-systemar commented 9 years ago

Windows 8. @elvispdosreis patch fix the problem.

tuupola commented 9 years ago

Thanks. Did some more testing and it happens also in *NIX hosts when installed into subfolder. My mistake, I did not test this in subfolder myself. Not sure yet if it is a bug or feature.

tuupola commented 9 years ago

Submitted a bug report https://github.com/slimphp/Slim/issues/1554.

elvispdosreis commented 9 years ago

Thanks

tuupola commented 9 years ago

This should now be fixed in 2.0.1.

ronaldo-systemar commented 9 years ago

Great. Keep your good job.