Why the passwords don't match in symfony after migration? - symfony

Currently we are migrating our website to another server, but we are still using the same database.
So we have 2 exact websites connected to 1 database.
On the first one we can log in with the defaul credentials, and on the other the passwords do not match.
This is how we check if the password matches:
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
public function checkCredentials($password, UserInterface $user ){
return $this->passwordEncoder->isPasswordValid($user, $password );
}
This is my security config:
security:
encoders:
App\Entity\User:
algorithm: auto
# ...
is there some hash that I have to use in order to obtain the same password?

Related

Symfony 4.2: How to get Encoder Instance outside of Controller

I need to check my password in Login form, so
I want to get the Encoder in class Authenticator (made by bin/console make:auth) in function checkCredentials($credentials, UserInterface $user).
The $credentials['password'] is plain text, and the $user->getPassword() is encoded password.
My security.yaml is:
encoders:
App\Entity\User:
algorithm: bcrypt
cost: 12
How to get instance of the Encoder?
You can get the encoder from the encoder factory which has a security.encoder_factory service ID (or Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface interface if using autowiring).
After injecting the factory, you can get the encoder for a specific user entity with:
use App\Entity\User;
...
$encoder = $encoderFactory->getEncoder(User:class);

Fosuser bundle - setting role to user

I want to set role for user. I ąm using code below:
$user = this->getDoctrine()->getRepository('BlogBundle:User')->findOneById('11');
$em = $this->getDoctrine()->getManager();
$t=array('ROLE_ADMIN');
$user->setRoles($t);
$em->persist($user);
$em->flush();
return new Response('okk');
When I set 'ROLE_ADMIN' everything is ok, but when I set 'ROLE_USER' database cell is empty. Why?
Thank you for help in advance.
The roles column in your users table, should have
a:0:{}
for users with just the role ROLE_USER
Programmatic way of checking .
check if a user has a particular role ( inclusing ROLE_USER )
if ($this->get('security.context')->isGranted('ROLE_USER')) {
// the user has the ROLE_USER role
}
there's also
$user->getRoles()
One more way to double check if the use really has the ROLE_USER
php app/console fos:user:promote
When prompted, enter the username followed by ROLE_USER
it should state that
User "example#example.com" did already have "ROLE_USER" role.
In FOS User Bundle, all users have the ROLE_USER role. It would be redundant to add/save this role.
If you're looking for it in FOSUserBundle's code base, the role is aliased as ROLE_DEFAULT in the UserInterface class.

Symfony: FOS user Bundle promote user via controller

I am new to FOS user bundle.
I have user and want to create a function to promote them (which will do the same than:
php app/console fos:user:promote testuser ROLE_MANAGER
my security.yml is:
role_hierarchy:
ROLE_MANAGER: ROLE_USER
ROLE_ADMIN: [ROLE_USER, ROLE_MANAGER, ROLE_ALLOWED_TO_SWITCH]
Any idea how to do that from a controller?
I created a UserBundle with a UserController.php to extend FOS user and create a profile.
Found the solution:
public function promoteUserAction(){
$user = $this->getUser();
$userManager = $this->get('fos_user.user_manager');
$user->addRole('ROLE_ADMIN');
$userManager->updateUser($user);
return $this->render('ACMEBundle:User:page.html.twig');
}
Hope it will be useful for others.
cheers
Also, if you happen to only know the FOS username and you want to promote the user being logged in as a different user (the accepted answer promotes the logged in user), you can use this sample code:
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->findUserBy(array('username' => 'gauss'));
$user->addRole('ROLE_ADMIN');
$userManager->updateUser($user);
In this case, I'm searching for the FOS username of 'gauss' and promoting use gauss to ROLE_ADMIN. You can then run a sql command of select id,username,roles from fos_user; on your database to verify the role has been added.
Hopefully this helps someone.

Login in symfony2

I'm trying to implement very basic authentication in Symfony2. Here are main parts of the code I really don't see any problem
EDIT
complete security.yml
jms_security_extra:
secure_all_services: false
expressions: true
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:
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
firewalls:
login:
pattern: ^/login
anonymous: ~
secured_area:
pattern: ^/
stateless: true
form_login:
login_path: /login
check_path: /login_check
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
This works fine, anonymous user is always redirected to loginAction controller.
EDIT
Here is the complete code
<?php
namespace AcmeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
class SecurityController extends Controller {
public function loginAction() {
$providerKey = 'secured_area';
$token = new UsernamePasswordToken('test', 'test', $providerKey, array('ROLE_USER'));
$this->container->get('security.context')->setToken($token);
return $this->redirect($this->generateUrl('fronthomepage'));
}
}
I don't see any problem, anonymous user is redirected to loginAction, there is created authenticated user, saved to token and than redirected to secured area as an authenticated user. Unfortunately my code ends with redirect loop which looks like security firewall doesn't accept user as authenticated. Do you see any problem?
Well, your controller job is to render just form but not to populate security context. Symfony2 security firewall will do that for you automatically. You don't need to handle it unless you want to build you own custom authentication.
In other words, your job is to display the login form and any login
errors that may have occurred, but the security system itself takes
care of checking the submitted username and password and
authenticating the user.
Please read this document for clear picture.
If you want to do some custom stuff when a user logs in, in Symfony2 you have to add an event listener that will fire after the user successfully logged in. The event that is fired is security.interactive_login and to hook to it you have to specify this in services.yml file form your bundle Resources/config directory:
Pretty sure you need an actual user object before setting an authenticated user. I did something like this:
class BaseController
protected function setUser($userName)
{
if (is_object($userName)) $user = $userName;
else
{
$userProvider = $this->get('zayso_core.user.provider');
// Need try/catch here
$user = $userProvider->loadUserByUsername($userName);
}
$providerKey = 'secured_area';
$providerKey = $this->container->getParameter('zayso_core.provider.key'); // secured_area
$token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
$this->get('security.context')->setToken($token);
return $user;
}
However doing something like this bypasses much of the security system and is not recommended. I also wanted to use a 3rd party authentication system (Janrain). I looked at the authentication system and initially could not make heads or tails out of it. This was before the cookbook entry existed.
I know it seems overkill but once you work through things then it starts to make more sense. And you get access to a bunch of nifty security functions. It took me quite some time to start to understand the authentication system but it was worth it in the end.
Hints:
1. Work through the cook book backward. I had a real hard time understanding what was going on but I started with adding a new firewall to security.yml and then adding the alias for my security factory. I then sort of traced through what the factory was being asked to do. From there I got the listener to fire up and again traced through the calls. Finally the authentication manager comes into play. Again, time consuming, but worth it in the end. Learned a lot.
One thing that drove me crazy is that classes are scattered all over the place. And the naming leaves something to be desired. Very hard to get an overview. I ended up making my own authentication bundle then putting everything under security.
If you want another example of a working bundle then take a look at: https://github.com/cerad/cerad/tree/master/src/Cerad/Bundle/JanrainBundle

symfony2 login by username or email

I'm using the standard authentication mechanism of Symfony2 and I want to let the user use either his username or email to login, but I can't find out why it's not working. I've tested the repository class and it works as expected. I've followed this how-to.
Here's my user provider class:
<?php
namespace My\UserBundle\Entity;
use Doctrine\ORM\EntityRepository ,
Symfony\Component\Security\Core\User\UserProviderInterface ,
Symfony\Component\Security\Core\User\UserInterface;
/**
* UserRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class UserRepository extends EntityRepository implements UserProviderInterface
{
function loadUserByUsername($username)
{
$qb = $this->createQueryBuilder('u') ;
return
$qb->select('u')
->where(
$qb->expr()->orx(
$qb->expr()->like('u.username' ,':username') ,
$qb->expr()->like('u.email' ,':username')
)
)
//->andWhere($qb->expr()->eq('u.enabled' ,'true') )
->setParameters(array('username' =>$username ) )
->getQuery()
->getResult() ;
}
function refreshUser(UserInterface $user)
{
return $this->loadUserByUsername($user->getUsername() );
}
function supportsClass($class)
{
return $class === 'My\UserBundle\Entity\User';
}
}
I propose a more simple approach that only requires to edit security.yml file.
You must to create two diferent security providers but both using the same User class. The first has username as property and the second has email as property.
Then you create a chain_provider that includes the two providers and use it in your firewall section
security:
providers:
chain_provider:
chain:
providers: [db_username, db_email]
db_username:
entity:
class: MyUserBundle:User
property: username
db_email:
entity:
class: MyUserBundle:User
property: email
firewalls:
default:
anonymous: ~
provider: chain_provider
form_login:
login_path: /login
check_path: /login
I don't know if this approach is a clean practice, but is fast, simple and it works ok.
well guys the thing is in my security.yml i had this
providers:
main:
entity: { class: My\UserBundle\Entity\User ,property : username}
so i had to take off that parameter property :username
Taking off the property: username lets the UserProviderInterface load the user as expected when it logs in, but does not call the refreshUser() method as expected. I put in checks to see if it gets called but it doesn't.
The class that reloads the user on each access is ContextListener::refreshUser(TokenInterface $token) method. In this the interface iterates through the UserProviders and calls the refreshUser that first returns a non-null user.
I could make sure of this because, in the original load, I combine all different entities to make one SQL call instead of 7. And when the user reloads, it calls 7 times.
Also the method EntityUserProvider::refreshUser() doesn't call the repository's method and instead reloads from the database directly.
Your provider class is correct, and you are correct that the problem is in security.yml, however, your solution is incorrect.
According to the documentation, your security.yml file should look like this:
security:
# ...
providers:
administrators:
entity: { class: MyUserBundle:User }
Notice that the class is defined as the Bundle, not the direct class.
The way you have your code right now, symfony is completly ignoring your repository class until you define your security.yml correctly. And as #Anand pointed out, just removing the property does not invoke refreshUser. However, it looks like if you are using your own Repository, you do not need to define the property (since it's being defined in your query).

Resources