tuupola/slim-basic-auth

Multiple Paths

Closed this issue · 9 comments

I want to setup authentication on multiple paths for my API. In most cases I'll need authentication but in others I definitely don't want authentication (i.e. registration). I know I can create separate instances of \Slim\Middleware\HttpBasicAuthentication but is there a way to create a single instance that includes multiple paths?

Instead of using default "easy" mode for initializing middleware you have to pass all the rules as parameters. This is not properly doumented yet but code below would authenticate everything except /token and /hello. CORS preflight OPTIONS requests are not authenticated by default.

$auth = new \Slim\Middleware\HttpBasicAuthentication([ 
    "users" => [
        "root" => "t00r",
        "user" => "passw0rd"
    ]
]);

$auth->addRule(new \Slim\Middleware\HttpBasicAuthentication\RequestPathRule([
    "path" => "/",
    "passthrough" => ["/token", "/hello"]
]);

$app->add();

You could achieve the same with:

$app->add(new \Slim\Middleware\HttpBasicAuthentication([ 
    "users" => [
        "root" => "t00r",
        "user" => "passw0rd"
    ],
    "rules" => [
        new \Slim\Middleware\HttpBasicAuthentication\RequestPathRule([
            "path" => "/",
            "passthrough" => ["/token", "/hello"]
        ]),
        new \Slim\Middleware\HttpBasicAuthentication\RequestMethodRule([
            "passthrough" => ["OPTIONS"]
        ])
    ]
]));

You can also write you own rules. They are just callables. If callable returns false middleware will not authenticate. With below example nothing will be authenticated.

$app->add(new \Slim\Middleware\HttpBasicAuthentication([ 
    "users" => [
        "root" => "t00r",
        "user" => "passw0rd"
    ],
    "rules" => [
        function ($app) {
            /* Receives current Slim app as parameter. */
            return false; 
        }
    ]
]));

Thanks!

Works great with some minor adjustments. I had to change the class path to:

$app->add(new \Slim\Middleware\HttpBasicAuthentication([ 
"users" => [
    "root" => "t00r",
    "user" => "passw0rd"
],
"rules" => [
    new \Slim\Middleware\HttpBasicAuthentication\RequestPathRule([
        "path" => "/",
        "passthrough" => ["/token", "/hello"]
    ]),
    new \Slim\Middleware\HttpBasicAuthentication\RequestMethodRule([
        "passthrough" => ["OPTIONS"]
    ])
]
]));

Ooops. Bad copy paste. I updated the code in my previous comment for future reference.

I think you could add new field: paths, and if is not empty, before line: https://github.com/tuupola/slim-basic-auth/blob/master/src/HttpBasicAuthentication/RequestPathRule.php#L42 add new for with same check as you have for path, and if at least one condition give true - return it, otherwise check path

I'll write the code for this, next weekend, and maybe you could add it to the main repo.

Thanks for your effort!

Good idea. Although I prefer not to introduce too many parameters. One way to do it is if you could pass both string and array as path parameter. Then you could do both:

    new \Slim\Middleware\HttpBasicAuthentication\RequestPathRule([
        "path" => "/api",
        "passthrough" => ["/api/ping", "/api/hello"]
    ])

and

    new \Slim\Middleware\HttpBasicAuthentication\RequestPathRule([
        "path" => ["/api", "/secret"],
        "passthrough" => ["/api/ping", "/api/hello", "/secret/hello"]
    ])

agree, array is a nice option, we also can make a specific RuleClass for multiple paths
I'll make tests to see how it looks and what is simplier

Hello, here is my modified version of the file, if you think is ok, I could create a pull request for it

    public function __invoke(\Slim\Slim $app)
    {
        /* If request path matches passthrough should not authenticate. */
        foreach ($this->options["passthrough"] as $passthrough) {
            $passthrough = rtrim($passthrough, "/");
            if (!!preg_match("@^{$passthrough}(/.*)?$@", $app->request->getResourceUri())) {
                return false;
            }
        }

        /* Otherwise check if path matches and we should authenticate. */

        $paths = $this->options["path"];

        if(is_array($paths))
        {
            foreach ($paths as &$value) {
                $result = $this->shouldAuth($value, $app);

                if($result)
                {
                    return true;
                }
            }

            return false;
        }

        return $this->shouldAuth($paths, $app);
    }

    private function shouldAuth($path, \Slim\Slim $app)
    {
        $path = rtrim($path, "/");
        return !!preg_match("@^{$path}(/.*)?$@", $app->request->getResourceUri());
    }

Actually already implemented in tuupola/slim-jwt-auth@0875734. I just need to sync the rule from JWT Auth to Basic Auth.

wonderfull, thanks.