Symfony Authentication Providers

I am using fr3d/ldap-bundle . It registers me and imports users from AD if they are not in db. It's great.

Despite AD users, I also have local users who are in my db. There is a special authType column that says how the user should be authenticated - through LDAP or initially (FOS). I created my own user:

 public function chooseProviderForUsername($username) { if($user->getAuthType() == User::LOGIN_LDAP) { $this->properProvider = $this->ldapUserProvider; } elseif($user->getAuthType() == User::LOGIN_NATIVE) { $this->properProvider = $this->fosUserProvider; } else { throw new InvalidArgumentException('Error'); } } public function loadUserByUsername($username) { return $this->chooseProviderForUsername($username)->loadUserByUsername($username); } 

PROBLEM: The chain provider is not an option - it allows the user to log in with his LDAP password and with his local password! This is a serious security issue.

Is there a way to log in through different authentication providers, depending on the db field?

EDIT:

My security.yml:

  providers: fos_userbundle: id: fos_user.user_provider.username appbundle_user_provider: id: appbundle.user_provider fr3d_ldapbundle: id: fr3d_ldap.security.user.provider firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false admin: pattern: ^/admin.* context: user fr3d_ldap: ~ form_login: provider: appbundle_user_provider csrf_provider: security.csrf.token_manager always_use_default_target_path: true default_target_path: admin_main login_path: /admin/login check_path: /admin/login_check logout: path: /admin/logout target: /admin/login anonymous: true 

Here is security.yml. This fr3d_ldap: ~ allows you to create an ldap package that allows ldap users and saves them in my db. Without this, I cannot resolve them, I may have to write my own authentication method.

+8
authentication php symfony ldap
source share
4 answers

I am not very familiar with ldap, but I would suggest trying a completely manual login

  $token = new UsernamePasswordToken($user, null, "firewallname", $user->getRoles()); $securityContext = $this->container->get('security.context'); $securityContext->setToken($token); 

Then you can manually perform the checks yourself, and depending on the result of the verification, decide how you want to verify the user before authentication. For example, run a query by username and password before executing this login code or anything else, depending on the db field you want.

+1
source share

Your approach seems fine, but you should check the logic of your methods. First of all, this:

 public function chooseProviderForUsername($username) { if($user->getAuthType() == User::LOGIN_LDAP) { $this->properProvider = $this->ldapUserProvider; } elseif($user->getAuthType() == User::LOGIN_NATIVE) { $this->properProvider = $this->fosUserProvider; } else { throw new InvalidArgumentException('Error'); } } 

You pass $username this method as an argument, but then use the $user object, which appears to be undefined in the current context. Secondly:

 public function loadUserByUsername($username) { return $this->chooseProviderForUsername($username)->loadUserByUsername($username); } 

Since the chooseProviderForUsername method does not actually return any value, you cannot chain it this way.

I hope that refactoring these problems should make your provider workable.

0
source share

Ok, so a very short answer, but I think that at the moment, Symfony is looking for a user among any old User Provider, and not the one you want for that particular user (which explains the whole entry into the system with two passwords). The solution should be to make AppBundleUserProvider implement UserProviderInterface , remove other users from security.yml , and then make sure that the first thing AppBundleUserProvider does is to find out which user provider is required for this user, and then simulate for each method in UserProviderInterface . You can set $this->realUP based on the username, and then set for each method to simply return $this->realUP->someMethod() .

0
source share

The cleanest way I can come up with is to create my own ChainProvider class that allows login with only one provider and use the injection container to use .

You just need to override the definition of the security.user.provider.chain.clas parameter in the package configuration file.

0
source share

All Articles