silexphp / Silex

[DEPRECATED -- Use Symfony instead] The PHP micro-framework based on the Symfony Components
https://silex.symfony.com
MIT License
3.58k stars 718 forks source link

Security - Add docs about success and failure handler for login and logout #656

Closed dbarcinas closed 9 years ago

dbarcinas commented 11 years ago

Cookbook?

davedevelopment commented 11 years ago

Yes please :wink:

cavady commented 11 years ago

According to this one, I am trying to inject an $app into success/failure/logout handlers, but unfortunately without luck.

Tried so far:

$app['security.authentication.failure_handler.auth'] = $app->share(function ($app) {
    return new Api\Security\AuthFailureHandler($app);
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

public function __construct(\Silex\Application $app) {
        $this->app = $app;
}

public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
        if ($this->app['security']->isGranted('ROLE_ADMIN')) {
            $include = array(
                'error'         => $this->app['security.last_error']($request),
                'last_username' => $this->app['session']->get('_security.last_username'),
                'granted'       => true
            );
        } else {
            $include = array(
                'error'         => $this->app['security.last_error']($request),
                'last_username' => $this->app['session']->get('_security.last_username'),
            );
        }
        return new JsonResponse(array(
            'type' => 'error', 
            'message' => 'Incorrect username or password.'
        ));
}

That's passing with lack of errors, but gets 302 status code ( redirect ), no json response is returned then. Could anyone point me into right direction?

davedevelopment commented 11 years ago

@cavady are you mixing things up a bit there? You've set up a success handler, but you've implemented a failure handler? Or at least that's what you have pasted.

cavady commented 11 years ago

Was a bit sleepy, but type of handler does not matter, Cannot pass an app in both.

Source updated.

davedevelopment commented 11 years ago

@cavady Which authentication method are you using? I think the failure handlers only work with some of them

cavady commented 11 years ago
class AuthFailureHandler implements AuthenticationFailureHandlerInterface
{

AuthenticationFailureHandlerInterface Doc

davedevelopment commented 11 years ago

@cavady for example, I don't think the HTTP Basic authentication listener uses the failure handlers, it just goes straight to the entry point.

cavady commented 11 years ago

There's no way to point an $app to failure handler then?

davedevelopment commented 11 years ago

@cavady yes, there is, but only if the authentication method you are using, uses the handlers:

<?php

require "vendor/autoload.php";

use Silex\Application;
use Silex\Provider\SecurityServiceProvider;
use Silex\Provider\SessionServiceProvider;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpKernel\Client;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;         

$app = new Application;
$app['debug'] = true;
$app['session.test'] = true; 

$app->register(new SessionServiceProvider());
$app->register(new SecurityServiceProvider(), [
    'security.firewalls' => [
        'admin' => [
            'pattern' => '^/admin',
            'form' => [
                'require_previous_session' => false,
                'login_path' => '/login', 
                'check_path' => '/admin/login_check'
            ],
            'users' => [],
        ], 
    ],
]);

class FailureHandler implements AuthenticationFailureHandlerInterface
{
    public function __construct(Application $app) {
        $this->app = $app;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        return new JsonResponse(array(
            'type' => 'error',
            'message' => $exception->getMessage(),
            'username' => $this->app['session']->get('_security.last_username'),
        ));
    }
}   

$app['security.authentication.failure_handler.admin'] = $app->share(function ($app) {
        return new FailureHandler($app);
});

$client = new Client($app);

$client->request('POST', '/admin/login_check', [
    '_username' => 'dave',
    '_password' => 'dave',
]);

echo $client->getResponse();
cavady commented 11 years ago

Just noticed, that my solution is working, everything except this:

$this->app['security']->isGranted('ROLE_ADMIN')

this is causing redirect, do not know why.

Simple JsonResponse works fine.