I've written my own password encoder which implements the PasswordEncoderInterface:
class BCryptPasswordEncoder implements PasswordEncoderInterface {
protected $encoder;
public function __construct(BCryptEncoder $encoder) {
$this->encoder = $encoder;
}
public function encodePassword($raw, $salt) {
return $this->encoder->encodeString($raw, $salt);
}
public function isPasswordValid($encoded, $raw, $salt) {
return $this->encoder->encodeString($raw, $salt) == $encoded;
}
}
The encoder is registered as a service with the id bcrypt.password.encoder. But I don't know, how to tell symfony to user it.
Currently the app/config/security.yml looks like this:
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
neo4j:
id: security.user.provider.neo4j
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
provider: neo4j
pattern: ^/.*
form_login:
check_path: /login_check
login_path: /login
logout:
path: /logout
target: /
anonymous: ~
access_control:
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/.*, role: ROLE_ADMIN }
Btw I'm not using any doctrine entities.
Edit: Symfony\Component\Security\Core\User\User is my UserObject. I modified the security.yml a bit:
encoders:
Symfony\Component\Security\Core\User\User:
id: bcrypt.password.encoder
which results in a fatal error:
Catchable Fatal Error: Argument 1 passed to EMC3\Bundle\UserBundle\Neo4jUserProvider::__construct() must be an instance of EMC3\Bundle\UserBundle\UserManager, instance of EMC3\Bundle\UserBundle\BCryptEncoder given, called in /var/www/emc3/app/cache/dev/appDevDebugProjectContainer.php on line 227 and defined in /var/www/emc3/src/EMC3/Bundle/UserBundle/Neo4jUserProvider.php line 29
Which doesn't make any sense for me.
Starting from Symfony 2.2, BCrypt is natively supported, so you can configure it easily as such:
security:
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 7
You may want to adjust the cost upwards if you have a fast enough server though.
As of November 2011, before Symfony 2.2, this is not directly supported.
Instead of reinventing the wheel, I suggest you to use the Blowfish Password Encoder bundle I wrote (ElnurBlowfishPasswordEncoderBundle), which solves the same problem. Or, at least, you can see how it's implemented.
If you're using Symfony 2.2 or later, see Seldaek's answer for configuration instructions.
Your encoders section should look like this:
encoders:
Acme\UserBundle\Entity\User:
id: bcrypt.password.encoder
where Acme\UserBundle is your vendor and bundle namespace, of course.
For reference, a complete example security config can be found here.
EDIT: The way the encoder factory works (source code here, relevant lines start on line 33) is that in your config, you have given the framework a class, and an encoder to use for the class. It's Doctrine-independent, so just provide the fully-qualified class name of your user object in the config instead of a "user entity," and when your password is encoded, Symfony will know how to handle it.
Related
I am having issue with FosUserBundle,
Acctualy I followed this tutorial
http://symfony.com/doc/current/bundles/FOSUserBundle/index.html
And in the end it says You now can log in at "/app.com/app_dev.php/login!"
Here is photo
My routing file:
app:
resource: "#AppBundle/Controller/"
type: annotation
# easy_admin_bundle:
# resource: "#EasyAdminBundle/Controller/"
# type: annotation
# prefix: /admin
fos_user:
resource: "#FOSUserBundle/Resources/config/routing/all.xml"
My security file:
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
# if you are using Symfony < 2.8, use the following config instead:
# csrf_provider: form.csrf_provider
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
Manually putting the users details into the database is likely the issue. Unless you go through the proper process you'll end up with an unencrypted password, so when you try to authenticate using bcrypt (as stated in your security file) the passwords wont match.
You have 2 options. Command line or do it programatically.
Command line creation
Have a look at the list of FOSUserBundle command line tools.
Follow the instructions for creating a user and you should have more success. I know you tried this, but follow the tutorial and have another go. Its worth trying to do this:
$ php bin/console fos:user:create adminuser --super-admin
and putting in the extra data as it asks you.
Controller creation
From a controller point of view, you need to use the fos_user.user_manager service to setup your new user.
So, something like this:
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->createUser();
then inside your form handling script:
$userManager->updateUser($user);
This will parse the plainPassword data gathered in and extracted from your form through the correct password encoder. It'll then null the plainPassword property so remains secure in the database.
So, your finished controller method might look something like this:
public function newUser( Request $request ) {
// get a blank user, you can use new User if you like but I like to use their tools seeing as they took the time to build them.
$user = $this->get('fos_user.user.manager')->createUser();
// build the form
$form = $this->createForm(UserType::class, $user);
// bind the form data (if there) to the entity.
$form->handleRequest( $request );
if ( $form->isSubmitted && $form->isValid() ) {
// this will properly encode the password, if changed, remove any plain text versions and flush into the db.
$this->get('fos_user.user.manager')->updateUser($user);
// send the user somewhere with a congrats message
} else {
// anything for invalid form;
}
return $this->render('forms/form.html.twig', [
'form' => $form->createView()
]);
}
you have to use FOS\UserBundle\Model\User::setPlainPassword() method but not setPassword()
Authenticated: No appears in the Symfony2 dev toolbar after a successful login.
In my success handler I can access $token->getRoles() and see the role objects assigned to the user so it appears to be serializing okay.
So I'm not sure why it's not authenticating.
Here is my security.yml:
security:
encoders:
FixedApp\Model\User:
algorithm: sha1
encode_as_base64: false
iterations: 1
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_LIMITED_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
administrators:
entity: { class: FixedApp\Model\User, property: username }
firewalls:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
login:
pattern: ^/$
security: false
secured_area:
pattern: ^/
form_login:
check_path: fixed_app_authentication_login
login_path: fixed_app_homepage
username_parameter: form[username]
password_parameter: form[password]
default_target_path: fixed_app_hub_homepage
always_use_default_target_path: true
success_handler: security.authentication.success_handler
logout:
path: fixed_app_authentication_logout
target: fixed_app_homepage
access_control:
- { path: ^/log-in$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /users/edit, roles: ROLE_ADMIN }
It not authenticating is a problem, because when I go to /users/edit as an admin it says Access Denied. So I need to figure out what is going on here. Any ideas would be most appreciated.
I saw a number of other people online with this same problem but I've never seen a solution put anywhere before - so hopefully this helps someone.
In UserRole.php class I was missing this function:
/**
* #see RoleInterface
*/
public function getRole()
{
return $this->role;
}
And secondly, in User.php class I made it implement EquatableInterface:
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
...
class User implements AdvancedUserInterface, EquatableInterface, \Serializable
{
...
public function isEqualTo(UserInterface $user)
{
if ($this->getId() == $user->getId())
{
return true;
}
else
{
return false;
}
}
And then it started working. The Symfony toolbar button went green, it says Authenticated: Yes and it lists all the roles for that user.
I am using the FOSUserBundle and am successfully creating users in my database. However, I'm trying to log users in and only have ROLE_ADMIN users access /admin by following the Symfony security walk-through.
However, even without having figured out logging users in, when I try to access localhost/app_dev.php/admin I am able to access it as the "Anon" user. Below are my security.yml and controller files:
app/config/security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/admin/, role: ROLE_ADMIN }
src/AppBundle/Controller/DefaultController.php
class DefaultController extends Controller
{
/**
* #Route("/admin", name="admin")
*/
public function AdminAction(Request $request)
{
return $this->render('default/admin.html.twig', array(
'title' => 'Welcome Admin!!'
));
}
}
I'm not familiar with FOSUserBundle however your access_control entry is for the path /admin/ - note the trailing slash whereas your example localhost/app_dev.php/admin doesn't. If you remove that from your access_control entry or change your routes then this should work as expected.
E.g.
access_control:
- { path: ^/admin, role: ROLE_ADMIN }
I'm working on a small app with Symfony 2.5, and I'd like to know what is the best way to handle security, but just for only one user. I could do this with an .htaccess but maybe their exists some light and quickly installable sf2 bundle which could do the job. I don't want role stuff, or profile, just a way to authenticate myself.
Symfony2 let's you easily use http authentication. Together with the in_memory provider, you have a perfect solution for your use case.
From the docs:
security:
firewalls:
secured_area:
pattern: ^/
anonymous: ~
http_basic:
realm: "Secured Demo Area"
access_control:
- { path: ^/admin/, roles: ROLE_ADMIN }
# Include the following line to also secure the /admin path itself
# - { path: ^/admin$, roles: ROLE_ADMIN }
providers:
in_memory:
memory:
users:
ryan: { password: ryanpass, roles: 'ROLE_USER' }
admin: { password: kitten, roles: 'ROLE_ADMIN' }
encoders:
Symfony\Component\Security\Core\User\User: plaintext
I have problem wtih login. I use correct login in the table in database. Here is my controller.
My security.yml:
security:
encoders:
My\HelloBundle\Entity\User:
algorithm: sha512
encode_as_base64: true
iterations: 10
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
users_db:
entity: { class: My\HelloBundle\Entity\User, property: email }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/demo/secured/login$
security: false
secured_area:
pattern: ^/
anonymous: ~
form_login:
check_path: /login_check
login_path: /login
logout:
path: /logout
target: /
#http_basic:
# realm: "Secured Demo Area"
access_control:
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
#- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
My Entity is too long to paste here, so I put it on pastebin
I have problem during login, but it works fine with registration (passwords got salted and saves fine to the database).
This is the error message:
exception 'Symfony\Component\Security\Core\Exception\BadCredentialsException' with message 'Bad credentials' in C:\xampp\htdocs\mgr\4_symfony\vendor\symfony\src\Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider.php:83 Stack trace: #0
Please help me.
Regards.
I notice a couple of issues:
You are not using the Symfony provided encoder, basically your encoder configuration in the security.yml is being ignored, you can change the code (HelloController starting at line 70) to encode your password to:
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($user->getPassword(),
$user->getSalt());
$user->setPassword($password);
I used that stub from the Symfony Security documentation and worked for me.
I don't think the user is being persisted in any part of the provided code, maybe adding this after $user->setPassword($password);?
$em = $this->getDoctrine()->getEntityManager();
$em->persist($entity);
$em->flush();
Check that the user is being inserted in your database and that the password and the salt are present, the authentication will fail if the salt is not persisted.
Also, I haven't used sha512 but I think you're not creating the salt properly, try instead:
$user->setSalt(hash('sha512', $user->getPassword()));