I use Silex framework in my project.
I defined a road / login that points to my form of authentication to connect to the app but when I do: ipsrv / login (ipsrv being the ip web server) he does not know the road (404 ).
My app.php file (extract):
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login',
'anonymous' => true,
'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
'users' => $app->share(function () use ($app) {
return new Nautilus\DAO\UserDAO($app['db']);
})
),
'general' => array(
'pattern' => '^/',
'anonymous' => false,
'logout' => true
),
),
));
My routes.php file (extract):
$app->match('/login', function(Request $request) use ($app) {
return $app['twig']->render('login.html.twig', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']->get('_security.last_username'),
));
})->bind('login');
How do you use these 2 files? Check the server is configured to execute your silex app, and both files are actually included there.
It works perfectly well in single-script app:
<?php
// web/index.php
require_once __DIR__.'/../vendor/autoload.php';
$app = new Silex\Application();
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login',
'anonymous' => true,
'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
'users' => $app->share(function () use ($app) {
return new \Symfony\Component\Security\Core\User\InMemoryUserProvider();
})
),
'general' => array(
'pattern' => '^/',
'anonymous' => false,
'logout' => true
),
),
));
$app->match('/login', function(\Symfony\Component\HttpFoundation\Request $request) use ($app) {
return 'login form';
})->bind('login');
$app->run();
When you run web server as
php -S localhost:8080 -t ./web/
curl http://localhost:8080/login returns "login form";
File routes.php in full :
<?php
use Symfony\Component\HttpFoundation\Request;
// Index
$app->match('/', function () use ($app){
return $app['twig']->render('aff_index.html.twig');
})->bind('home');
// Login form
$app->match('/login', function(Request $request) use ($app) {
return $app['twig']->render('login.html.twig', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']->get('_security.last_username'),
));
})->bind('login');
File app.php in full :
<?php
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
// Register global error and exception handlers
ErrorHandler::register();
ExceptionHandler::register();
// Register service providers.
$app->register(new Silex\Provider\DoctrineServiceProvider());
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => array(
__DIR__.'/../views/layout',
__DIR__.'/../views/admin_bdd',
__DIR__.'/../views/admin_preferences',
__DIR__.'/../views/admin_users',
__DIR__.'/../views/app_connexion',
__DIR__.'/../views/app_main',
__DIR__.'/../views/audits_mesedits',
__DIR__.'/../views/reporting_lb',
__DIR__.'/../views/reporting_meteo',
__DIR__.'/../views/menu'
)));
$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
$app->register(new Silex\Provider\SessionServiceProvider());
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login',
'anonymous' => true,
'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
'users' => $app->share(function () use ($app) {
return new Nautilus\DAO\UserDAO($app['db']);
})
),
'general' => array(
'pattern' => '^/',
'anonymous' => false,
'logout' => true
),
),
));
$app->register(new Silex\Provider\MonologServiceProvider(), array(
'monolog.logfile' => __DIR__.'/../var/logs/nautilus.log',
'monolog.name' => 'Nautilus',
'monolog.level' => $app['monolog.level']
));
$app->register(new Silex\Provider\ServiceControllerServiceProvider());
if (isset($app['debug']) && $app['debug']) {
$app->register(new Silex\Provider\HttpFragmentServiceProvider());
$app->register(new Silex\Provider\WebProfilerServiceProvider(), array(
'profiler.cache_dir' => __DIR__.'/../var/cache/profiler'
));
}
$app['dao.user'] = $app->share(function ($app) {
return new Nautilus\DAO\UserDAO($app['db']);
});
Index.php :
<?php
require_once __DIR__.'/../vendor/autoload.php';
$app = new Silex\Application();
require __DIR__.'/../app/config/dev.php';
require __DIR__.'/../app/app.php';
require __DIR__.'/../app/routes.php';
$app->run();
For information I use Wamp (latest version) on Windows 10 Pro x64 with a MySQL database. And I use PhpStorm 10.0.
Problem solved. Xampp is incompatible with WIndows 10 (impossible to create a user: Error) and Wamp does not handle URL rewriting Windows 10. I have tested with Windows 7 and Xampp with URL rewriting and virtual hosts go well and no worries Silex roads.
Related
i need to setup my silex firewall like:
www.mysite.com/* => access to all users
www.mysite.com/admin/* => access to only logged in users
i use this set up but it does not work as expected:
$app->register(new SecurityServiceProvider(), array(
'security.firewalls' => array(
'secure' => [
'pattern' => '^/.*$',
'anonymous' => true,
'form' => array(
'login_path' => '/admin/login',
'check_path' => '/admin/auth'
),
'logout' => array(
'logout_path' => '/admin/logout'
),
'users' => $app->share(function() use ($app) {
return new AuthenticationSuccessHandler($app['db']);
}),
]
),
'security.access_rules' => array(
array('^/admin$', 'ROLE_ADMIN')
)
));
Any help?
Many Thanks!! ;-)
'users' => $app->share(function() use ($app) {
return new AuthenticationSuccessHandler($app['db']);
}),
The above function needs to return an object which implements
Symfony\Component\Security\Core\User\UserProviderInterface
Check here for custom user provider documentation
It may also be appropriate to move login_path outside the secured area. Another way of configuring would be:
$app['security.firewalls'] = array(
'secure' => array(
'pattern' => '^/admin/',
'form' => array('login_path' => '/login', 'check_path' => '/admin/auth'),
'users' => $app->share(function () use ($app) {
return new MyUserProvider($app['db']);
}),
),
),
);
$app['security.access_rules'] = array(
array('^/admin', 'ROLE_ADMIN')
);
Make sure you register doctrine dbal.
I am trying to build a simple authentication code for my Silex app but I can't make it work.
I spent hours trying to figure out where is the mistake but can't find it..
Here is the code:
use Symfony\Component\Security\Core\User\User;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$app = new Silex\Application();
$app['debug'] = true;
$app->register(new Silex\Provider\SessionServiceProvider());
$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'admin' => array(
'pattern' => '^/admin.*',
'http' => true,
'form' => array(
'login_path' => '/login',
'check_path' => '/admin/login_check',
),
'logout' => array(
'logout_path' => '/admin/logout',
'invalidate_session' => true
),
'users' => $usersData,
),
)
));
$app->get('/login', function(Request $request) use ($app) {
return $app['twig']->render('login.html', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']- >get('_security.last_username'),
));
});
The app is not blocking any path, I really don't understand what I'm missing as I already did this in another app and everything works fine there...
Thank you in advance for any help.
I had a problem with the provisioning of my vagrant machine, rebuilt everything from scratch and now it works flawlessly.
How in Silex redirect admin (ROLE_ADMIN) to /admin page after successful login and user (ROLE_USER) to / page after successful login?
My config so far:
$app['security.firewalls'] = array(
'login' => array(
'pattern' => '^/login$',
),
'secured' => array(
'pattern' => '^.*$',
'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
'logout' => array('logout_path' => '/logout'),
'users' => $app->share(function() use ($app) {
return new App\User\UserProvider($app['db']);
}),
),
);
$app['security.access_rules'] = array(
array('^/admin', 'ROLE_ADMIN', 'http'),
array('^.*$', 'ROLE_USER'),
);
Thx in advance
I think there are a few ways to do this - I would recommend adding a new controller for /login/redirect and then sending people there after login. The controller can then perform the logic for where to send users based on their roles.
class LoginRedirect implements ControllerProviderInterface {
public function connect(Application $app) {
$controller = $app['controllers_factory'];
$controller->get('/', array($this, 'index'))->bind('login-redirect');
return $controller;
}
public function index(Application $app) {
if ($app['security']->isGranted('ROLE_ADMIN')) {
return $app->redirect($app['url_generator']->generate('admin-home'));
}
return $app->redirect($app['url_generator']->generate('non-admin-home'));
}
}
Add a route for it:
$app->mount('/login/redirect', new Controller\LoginRedirect());
And then in your security firewall settings add the options in the form section to use this route as the default target path - i.e. where all users are redirected to after login. Note that with this setting, you will loose the feature where users are redirected to the HTTP referer.
...
'form' => array(
'login_path' => '/login',
'check_path' => '/login_check',
'always_use_default_target_path' => true,
'default_target_path' => '/login/redirect'
),
...
I'm working for the first time with Silex's Security Provider and I'm having issues with the process. I currently have the basic HTTP auth working (using the coded example user as shown here in the docs).
When switching HTTP out for the form option however the login form is submitting, and returning to itself. I have created a UserProvider class and the loadUserByUsername method is being successfully called, however the email isn't being passed in (being set to "NONE_PROVIDED" - altered from username). This I found when working through the vendor code is because the token isn't being set ($app['security']->getToken() returning null at all points). I've trawled through all the docs I can but I can't find any mention of this.
The main code is included below, let me know if there is anything else, thanks!
Security Provider Configuration
// Protects all routes within /auth, redirecting to /login successfully
$app->register(new SecurityServiceProvider(), array(
'security.firewalls' => array(
'unauth_area' => array(
'pattern' => '^/(?!auth)'
),
'auth_area' => array(
'pattern' => '^/.*$',
'form' => array(
'login_path' => '/login',
'check_path' => '/auth/login_check',
'default_target_path' => '/auth/overview',
),
'users' => $app->share(function () use ($app) {
return new UserProvider($app['db']);
}),
),
),
'access_control' => array(
array('path' => '^/.*$', 'role' => 'ROLE_USER'),
// Include the following line to also secure the /admin path itself
// array('path' => '^/admin$', 'role' => 'ROLE_ADMIN'),
),
));
(My Custom) method - UserProvider class
public function loadUserByUsername($email) {
// Dying at this point shows it reaches here, but $email is null
$stmt = $this->conn->executeQuery('SELECT * FROM user WHERE email = ?', array(strtolower($email)));
if (!$user = $stmt->fetch()) {
throw new UsernameNotFoundException(sprintf('Email "%s" does not exist.', $email));
}
return new User($user['email'], $user['password'], explode(',', $user['roles']), true, true, true, true);
}
Form Class
class LoginType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('_username', 'text', array(
'required' => true,
'constraints' => array(
new Assert\NotBlank(),
new Assert\Email(),
)
))
->add('_password', 'password', array(
'required' => true,
'constraints' => array(
new Assert\NotBlank(),
),
))
->add('Login', 'submit');
}
public function getName() {
return 'login';
}
}
Silex Security Provider docs
It has nothing to do with the token… I just had the same problem with
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'admin' => array(
'pattern' => '^/admin',
'form' => array(
'login_path' => '/',
'check_path' => '/admin/login_check',
'username_parameter'=> 'mail',
'password_parameter' => 'password',
),
'logout' => array('logout_path' => '/logout'),
//'anonymous' => true,
'users' => function () use ($app) {
return new UserProvider($app['db']);
},
)
),
'security.access_rules' => array(
array('^/$', 'IS_AUTHENTICATED_ANONYMOUSLY'),
array('^/admin', 'ROLE_USER')
)
));
After a couple hours trying and testing, I checked the name attribute in my form's input… Saw form[mail]
So I tried
'username_parameter'=> 'form[mail]',
'password_parameter' => 'form[password]',
And … ALLELUIA!!!!! had my mail in loadUserByUsername($mail)
I've got a issue creating a login form to authenticate users. I followed exactly the example in this page: http://silex.sensiolabs.org/doc/providers/security.html#defining-more-than-one-firewall, but I've got a redirect loop when I try to access my site.
I'd like to secure my entire website, so I wrote this lines:
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login$',
),
'secured' => array(
'pattern' => '^.*$',
'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
'logout' => array('logout_path' => '/logout'),
'users' => array(
// password is foo
'user1' => array('ROLE_USER', '5FZ2Z8QIkA7UTZ4BYkoC+GsReLf569mSKDsfods6LYQ8t+a8EW9oaircfMpmaLbPBh4FOBiiFyLfuZmTSUwzZg=='),
),
),
),
));
$app->mount('/login', include '../src/login.php');
Then I created a login.php file:
$controllers->get('/', function(Silex\Application $app, Request $request) {
return $app->render('login.html.twig', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']->get('_security.last_username'),
));
});
When I try to go to my homepage http://localhost I've got a redirect loop message by the browser.
Where am I wrong?
Thanks all!
Ok I spotted the issue: it's on the mount behaviour with /login path. I had to change those lines in:
$app->mount('/', include '../src/login.php');
And in the login.php:
$controllers->get('/login', ...