Custom FOSUBUserProvider not working properly - symfony

I've been following the instruction here: https://gist.github.com/danvbe/4476697, I have read the entire thread more than once, but I'm not getting a solution for my problem.
I want to use the oauth bundle just for account linking, persisting the user data from oauth provider. My users will not be authenticated using oauth.
Nevertheless, I have implemented the whole thing to see if it works with github as provider, but nothing. I'm able to go to the authorization page, but when I click on Allow Access, I'm inevitable redirected to the login page with this error No oauth code in the request.
If stop using the custom FOSUBUserProvider and change to the default HWI one, then I get the app registered in Github but cannot persist the data.
Important: I tried replicating exactly the FOSUBUserProvider from HWI and the same problem remained, so probably is not related it's implementation but maybe with the service definition or the config.
Any help is greatly appreciated.
These are the relevant files:
FOSUBUserProvider.php
class FOSUBUserProvider extends BaseClass
{
/**
* {#inheritDoc}
*/
public function connect(UserInterface $user, UserResponseInterface $response)
{
$property = $this->getProperty($response);
$username = $response->getUsername();
//on connect - get the access token and the user ID
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
//we "disconnect" previously connected users
if (null !== $previousUser = $this->userManager->findUserBy(array($property => $username))) {
$previousUser->$setter_id(null);
$previousUser->$setter_token(null);
$this->userManager->updateUser($previousUser);
}
//we connect current user
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
$this->userManager->updateUser($user);
}
/**
* {#inheritdoc}
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$username = $response->getUsername();
$user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
//when the user is registrating
if (null === $user) {
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
// create new user here
$user = $this->userManager->createUser();
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
//I have set all requested data with the user's username
//modify here with relevant data
$user->setUsername($username);
$user->setEmail($username);
$user->setPassword($username);
$user->setEnabled(true);
$this->userManager->updateUser($user);
return $user;
}
//if user exists - go with the HWIOAuth way
$user = parent::loadUserByOAuthUserResponse($response);
$serviceName = $response->getResourceOwner()->getName();
$setter = 'set' . ucfirst($serviceName) . 'AccessToken';
//update access token
$user->$setter($response->getAccessToken());
return $user;
}
}
config.yml
hwi_oauth:
#this is my custom user provider, created from FOSUBUserProvider - will manage the
#automatic user registration on your site, with data from the provider (facebook. google, etc.)
#and also, the connecting part (get the token and the user_id)
connect:
account_connector: custom.user.provider
# name of the firewall in which this bundle is active, this setting MUST be set
firewall_name: main
# optional FOSUserBundle integration
fosub:
# try 30 times to check if a username is available (foo, foo1, foo2 etc)
username_iterations: 30
# mapping between resource owners (see below) and properties
properties:
github: githubId
# optional HTTP Client configuration
http_client:
verify_peer: false
resource_owners:
github:
type: github
client_id: xxxxxxxxxxxxxxxxxxxxxx
client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
scope: "repo, delete_repo, notifications, gist"
options:
csrf: true
security.yml
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls: #CAUTION! The order of the firewalls IS ON PURPOSE! DON'T CHANGE!
# Disabling the security for the web debug toolbar, the profiler and Assetic.
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# -> custom firewall for the admin area of the URL
admin:
pattern: /admin(.*)
context: user
form_login:
provider: fos_userbundle
login_path: /admin/login
use_forward: false
check_path: /admin/login_check
failure_path: null
logout:
path: /admin/logout
anonymous: true
# -> end custom configuration
# defaut login area for standard users
# This firewall is used to handle the public login area
# This part is handled by the FOS User Bundle
main:
pattern: .*
context: user
form_login:
provider: fos_userbundle
login_path: /login
use_forward: false
check_path: /login_check
failure_path: null
logout: true
anonymous: true
# Login path for OAuth providers
oauth:
resource_owners:
github: "/login/check-github"
trello: "/login/check-trello"
login_path: /login
failure_path: /login
# FOSUB integration
# oauth_user_provider:
# service: hwi_oauth.user.provider.fosub_bridge
oauth_user_provider:
#this is my custom user provider, created from FOSUBUserProvider - will manage the
#automatic user registration on website, with data from the provider (github. trello, etc.)
service: custom.user.provider
access_control:
# URL of FOSUserBundle which need to be available to anonymous users
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Admin login page needs to be access without credential
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Secured part of the site
# This config requires being logged for the whole site and having the admin role for the admin part.
# Change these rules to adapt them to your needs
- { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
- { path: ^/.*, role: ROLE_USER } #This is on purpose.
routing.yml
hwi_oauth_security:
resource: "#HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /connect
hwi_oauth_connect:
resource: "#HWIOAuthBundle/Resources/config/routing/connect.xml"
prefix: /connect
hwi_oauth_redirect:
resource: "#HWIOAuthBundle/Resources/config/routing/redirect.xml"
prefix: /connect
services.yml
parameters:
custom.user.provider.class: My\Bundle\Path\Security\Core\User\FOSUBUserProvider
services:
sonata.admin.user:
class: My\Bundle\Path\Admin\Model\UserAdmin
tags:
# - { name: sonata.admin, manager_type: orm, group: users, label: users, label_translator_strategy: sonata.admin.label.strategy.underscore }
arguments:
- ~
- My\Bundle\Path\Entity\User
- SonataAdminBundle:CRUD
calls:
- [setTranslationDomain, [SonataUserBundle]]
- [setUserManager, [#fos_user.user_manager]]
- [setSecurityContext, [#security.context]]
custom.user.provider:
class: "%custom.user.provider.class%"
#this is the place where the properties are passed to the UserProvider - see config.yml
arguments: [#fos_user.user_manager,{github: github_id, trello: trello_id}]

Well, after a lot of try and error, I found the problem:
The callback URL in Github was: http://mywebsite/login/check-github but that was wrong. The truth is that I never found what this value had to be set up to, so I was guessing. By accident I discovered the right URL: http://mywebsite/connect/service/github applicable in my case, with my configuration.
I found it in one of the times in wich I tried the default HWI Provider, inspecting the redirects with the browser console.

Related

Public Access with Symfony's AbstractAuthenticator

I'm exploring the new system for User Authentication using the new AbstractAuthenticator class in my symfony 5 project.
My symfony app will contain a mix of routes, some will only be accessible to authenticated users and some for unauthenticated users (public access)
My security.yaml file looks something like this:
security:
enable_authenticator_manager: true
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
custom_authenticators:
- App\Security\JwtAuthenticator
access_control:
- { path: ^/auth/login, roles: PUBLIC_ACCESS }
- { path: ^/auth, roles: ROLE_USER }
I have also setup a route to auth/login
However, when I access the url https://myapp.test/auth/login I get the following message:
{"message":"Invalid credentials."}
If I remove the custom authenticator directive from security.yaml the url loads as expected.
Below is the authenticate function from the Authenticator class:
public function authenticate(Request $request): PassportInterface
{
return new SelfValidatingPassport(new UserBadge($request->get('email));
}
if I access /auth/login with a valid user matching the email address provided and with the ROLE_USER role, the page will load as expected. If I access it without providing an email address, the page will return the following (from the onAuthenticationFailure method):
{"message":"Invalid credentials."}
If I understand correctly, as stated in Symfony docs, the PUBLIC_ACCESS should skip authenticating the user and load the /auth/login route, while everything else under /auth/ should be protected. But I cannot get the PUBLIC_ACCESS directive to work.
I resolved it by changing the location of custom_authenticators like that:
security:
enable_authenticator_manager: true
firewalls:
main:
json_login: # that is my login for rest api
provider: user_provider
check_path: api_login
api:
pattern: ^/api
custom_authenticators: # here is the location for my custom authenticator
- App\Security\Authenticator
stateless: true
access_control:
- { path: ^/login, roles: PUBLIC_ACCESS }
I hope it helps!

I can't get the user from JWT

I have a project with Symfony 5.1 using Lexik JWT v2.8.0, gesdinet jwt refresh token v0.9.1 and my own entity user. I can log in with JWT and get the token, save it in a HttpOnly cookie and use it with the protected APIs successfully.
My web app has some API Rest but it has also pages to browse. So my intention is do it all from API, but also login in the web browser when user obtains a token.
But as api login is stateless, after the success login the web profiler still shows logged in as anon. and I can't get te user from the token. I made a service to get the user from the token, to call it in the controller and send some logged in user data to the front end.
I've got a service from this question. The service I have implemented to get the user is:
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use UserBundle\Domain\Entity\User;
class UserService
{
private TokenStorageInterface $tokenStorage;
private JWTTokenManagerInterface $jwtManager;
public function __construct( TokenStorageInterface $storage, JWTTokenManagerInterface $jwtManager )
{
$this->tokenStorage = $storage;
$this->jwtManager = $jwtManager;
}
public function getCurrentUser() : ?User
{
$decodedJwtToken = $this->jwtManager->decode($this->tokenStorage->getToken());
if ($decodedJwtToken instanceof TokenInterface) {
$user = $decodedJwtToken->getUser();
return $user;
} else {
return null;
}
}
}
And it is declared as a service:
get.token.user.service:
class: UserBundle\Domain\Service\UserService
arguments: [ '#security.token_storage' ]
But all I get from $this->tokenStorage->getToken() is a web token with "anon." user, so it is not a JWT and jwtManager can't decode it.
UserService.php on line 25:
Symfony\Component\Security\Core\Authentication\Token\AnonymousToken {#16 ▼
-secret: "RXVaVx3"
-user: "anon."
-roleNames: []
-authenticated: true
-attributes: []
}
I also tried to get the jwt from the cookie in the controller and send it to the service as an argument, but I get an error from decode that I'm passing a string and it expects a TokenInterface object, so it did not worked neither.
How can I get the user from the token in the service? is there a best practice to login in the web through api than get the user from the jwt and send it to the render?
Edit: add the code to use lexik jwt and to save token in cookie:
# /config/packages/lexik_jwt_authentication.yaml
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: 3600
user_identity_field: email
token_extractors:
cookie:
enabled: true
name: BEARER
the security file code
# /config/packages/security.yaml
security:
encoders:
UserBundle\Domain\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: UserBundle\Domain\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
provider: app_user_provider
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
refresh:
pattern: ^/api/token/refresh
stateless: true
anonymous: true
register:
pattern: ^/api/register
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: true
provider: app_user_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
anonymous: true
lazy: true
provider: app_user_provider
access_control:
- { path: ^/api/user, roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
- { path: ^/api/linkpage, roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Listener to save jwt in a cookie and avoid the token to be in the response:
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
use Symfony\Component\HttpFoundation\Cookie;
class AuthenticationSuccessListener
{
private bool $secure = false;
private int $tokenTtl;
public function __construct(int $tokenTtl)
{
$this->tokenTtl = $tokenTtl;
}
public function onAuthenticationSuccess( AuthenticationSuccessEvent $event)
{
$response = $event->getResponse();
$data = $event->getData();
$token = $data['token'];
unset($data['token']); // remove token from response. It works.
unset($data['refresh_token']); // remove token from refresh token, even though I still get this token in the response
$event->setData($data);
$response->headers->setCookie(
new Cookie(
'BEARER',
$token,
(new \DateTime())->add(new \DateInterval('PT'. $this->tokenTtl . 'S')),
'/',
null,
$this->secure
)
);
}
}
#services.yaml
app.listener.authenticationsuccesslistener:
class: UserBundle\Application\Listeners\AuthenticationSuccessListener
arguments: ['%lexik_jwt_authentication.token_ttl%']
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_authentication_success, method: onAuthenticationSuccess }
I still coded 2 more listeners for the refresh token, but I don't think they are needed.
The rest of the authentication is the default authentication code from lexik jwt bundle.
In the BEARER cookie is stored the jwt with the correct format, something like this:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1OTgzNTE0ODYsImV4cCI6MTU5ODM1NTA4Niwicm9sZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJlbWFpbCI6ImFkbWluQGVtYWlsLmNvbSJ9.p5WYCxEE-VSxp09Eo7CxXoxi6zy1ZcnLJiBe1YGsrk3iFm7T-6JAWbvyb9ZW_-1jtpYcWQlFOjOf7uET4wRHvlvygnPOeZck7tZM8TUlSqMXIllMeVARz8mEUvXVwhDWEk5T7Ibw9c3VgfvyiLUgSb_cmSyK3DwtgPCd9vOYarkag9XKxkxNI9M1OHGL61v1NoQHdkXloC72xdUUMcj5Y8yCJWZFdOp8-Xtfq8ZChAHzwCjXUhC3VnBqZcMT0tAvtilwTGDYDykppNKK1vbNoyOex47wQH_ILEFuX5Eh1p2xfbc0lWm3Ip21z3EQ2M_eOQgZvHR65T3b2dv9g5GPiFp3CNo8AuW8m6rXjWK6NZXJO8qYodxI5cUYYyFooCfVXXU8JXzGQfCZIdOPw-iBGzQEfFuLL50_sAOVcxjklAYCFZYRHwFKWmwl1BwJF4mAw4jnNIAdMmc66Z17ul2Jep9apOO90C1dZzGuVKxWqglc9GZo7-teHt0dMsg0ADrvaOKNJUwDBGJ4lZpWx6_stcl7DkCdc5k1kePGdLa7YXRO3umPwa_FVYVgnT_Z9x7RtfnGioa2TZJCIdbJnuj0L90vkgFBjHqFdVydDaaBu3Y0mKoQ2v3Sf1so4-uwJm8z1vQVZleMQgFibMiyyk3YyDidhPSxxyp4u-4xPNOSDNo
If I am not logged in and don't have jwt or I delete the BEARER cookie I can't access the protected APIs ({"code": 401, "message": "JWT Token not found"}), when I have the jwt assigned I can request APIs correctly.
The problem was on the security.yaml configuration, specifically in the firewalls.main section, where I had to add the jwt_token_authenticator as the guard. Finally, my security.yaml is:
security:
encoders:
UserBundle\Domain\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: UserBundle\Domain\Entity\User
property: email
jwt:
lexik_jwt: ~
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
provider: app_user_provider
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
refresh:
pattern: ^/api/token/refresh
stateless: true
anonymous: true
register:
pattern: ^/api/register
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: true
provider: jwt
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
anonymous: true
lazy: true
provider: jwt
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
logout:
path: app_logout
target: /
access_control:
- { path: ^/api/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/logout, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Then I had some problems with the logout, as the logout didn't erase the jwt cookies and the logout kept me logged in. So I made a Listener to the LogoutEvent and made the listener delete the cookies.
use Symfony\Component\Security\Http\Event\LogoutEvent;
class LogoutListener
{
public function onSymfonyComponentSecurityHttpEventLogoutEvent(LogoutEvent $event)
{
$response = $event->getResponse();
$response->headers->clearCookie('BEARER');
$response->headers->clearCookie('REFRESH_TOKEN');
$event->setResponse($response);
}
}
and declared it as a service:
app.listener.logout:
class: UserBundle\Application\Listeners\LogoutListener
tags:
- name: 'kernel.event_listener'
event: 'Symfony\Component\Security\Http\Event\LogoutEvent'
dispatcher: security.event_dispatcher.main
And now the login is working on the web without having to decode the jwt with the service I was using and pass the user to the front. Though the service that decoded the jwt, now is working fine.
I've lost almost a week with this issue, but finally I've found a solution and it's working fine. So I'll post it here to save time if anybody has some similar issue.

HWIOAuthBundle custom user provider will not login user

I'm using HWIOAuthBundle with Symfony 4.1.
My custom user provider gets called and returns a valid user, however the user is not logged in after the redirect. The web profiler shows: logged in as anon; anonymous token; firewall main
I've simplified the provider class below for brevity and it's only considering twitter right now. The conditions around $source are so I can add more later.
I have used xdebug to make sure loadUserByOauthuserResponse() is being called and that users are both being created in the case of a new user, or the existing user is being returned when it exists.
Question: If loadUserbyOauthUserResponse() IS returning a valid user entity, then what could be preventing it from creating a valid session with this user?
<?php
namespace App\Security;
...
class OAuthProvider extends OAuthUserProvider
{
...
public function loadUserByOAuthUserResponse(UserResponseInterface $response): User
{
/** #var EntityManager $em */
$em = $this->container->get('doctrine.orm.entity_manager');
$repo = $em->getRepository('App:User');
$source = $response->getResourceOwner()->getName();
$email = null;
$data = [];
$newUser = false;
// Set email and socialUser.
if ($source === 'twitter') {
$data = $response->getData();
$email = $data['email'];
}
// Check if this user already exists in our app.
$user = $repo->findOneBy(['email' => $email]);
if ($user === null) {
$newUser = true;
$user = new User();
$user->setPassword($this->strand(32));
}
// Set session and user data based on source.
if ($source === 'twitter') {
$name = $data['name'];
if ($newUser) {
$user->setNickName($name);
$user->setEmail($email);
$em->persist($user);
$em->flush();
}
}
return $user;
}
}
hwi_oauth.yaml
hwi_oauth:
# list of names of the firewalls in which this bundle is active, this setting MUST be set
firewall_names: [main]
# https://github.com/hwi/HWIOAuthBundle/blob/master/Resources/doc/2-configuring_resource_owners.md
resource_owners:
twitter:
type: twitter
client_id: '%env(TWITTER_ID)%'
client_secret: '%env(TWITTER_SECRET)%'
options:
include_email: true
services.yaml:
app.oauth_aware.user_provider.service:
class: App\Security\OAuthProvider
arguments: ['#service_container']
security.yaml:
security:
# https://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
encoders:
App\Entity\User: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
app_users:
entity: { class: App\Entity\User, property: email }
hwi:
id: app.oauth_aware.user_provider.service
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
provider: app_users
anonymous: ~
remember_me:
secret: "%env(APP_SECRET)%"
lifetime: 2592000
path: /
guard:
authenticators:
- App\Security\LoginFormAuthenticator
entry_point: App\Security\LoginFormAuthenticator
logout:
path: /logout
target: /
oauth:
resource_owners:
twitter: "/login/check-twitter"
default_target_path: /
login_path: /
failure_path: /user-login
oauth_user_provider:
service: app.oauth_aware.user_provider.service
switch_user: ~
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/recover, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
I had the same problem until I found in logs "Token was deauthenticated after trying to refresh it."
And after that I found this solution.
Token was deauthenticated after trying to refresh it
I added isEqualTo and did not logged me out.

Checking a user's password on Ldap with dynamic dn in symfony 3

With sf3
symfony 3 password can be checked but with a static dn
dn_string: 'uid={username},dc=example,dc=com'
So I created my own UserAuthenticationProvider class
But now I don't know how to declare it in my security.yml ?
security.yml
providers:
your_db_provider:
entity:
class: AcSecurityBundle:User
property: username
fos_userbundle:
id: fos_user.user_provider.username
secured_area:
pattern: ^/
anonymous: true
provider: your_db_provider
form_login:
csrf_token_generator: security.csrf.token_manager
use_referer: true
form_login_ldap:
service: ldap
use_referer: true
logout: true
AcSecurityBundle/AcUserAuthenticationProvider.php
class AcUserAuthenticationProvider extends UserAuthenticationProvider
{
function checkAuthentication(UserInterface $user, UsernamePasswordToken $token)
{
$username = $token->getUsername();
$password = $token->getCredentials();
if ('' === $password) {
throw new BadCredentialsException('The presented password must not be empty.');
}
try {
$query = "(sAMAccountName=$username)";
$search_dn = "CN=app,OU=apps,DC=domain,DC=be";
$search_password = "mdp";
$this->ldap->bind($search_dn, $search_password);
$t = $this->ldap->query("OU=At,OU=user,DC=domain,DC=be", $query);
$entry = $t->execute();
if ($entry->count() > 0) {
$dn = $entry[0]->getDn();
}
$this->ldap->bind($dn, $password);
} catch (ConnectionException $e) {
throw new BadCredentialsException('The presented password is invalid.');
}
}
}
Thank you
Since Symfony 3.1 Symfony uses a new ldap provider
Symfony\Component\Ldap\Ldap
Provider Example:
services:
app.ldap:
class: Symfony\Component\Ldap\Ldap
factory: [ 'Symfony\Component\Ldap\Ldap', 'create']
arguments:
- ext_ldap
- host: srv-host
#debug: true
The string associated to the adapter you wish to use. Only one is
supported for now, which is ext_ldap.
New Ldap provider by Symfony, explained.
Security Provider Example:
providers:
#webservice_provider:
#id: app.webservice_user_provider
company_ldap:
ldap:
service: app.ldap
base_dn: DC=example, DC=local
search_dn: "CN=AdminName,OU=YourAdminGroup,DC=example,DC=LOCAL"
search_password: 'AdminPass'
default_roles: ROLE_USER
Now you are allowed to look in your ldap system. If you set your
form_login_ldap right, your users can authenticate via your form
Security form_login_ldap Example:
form_login_ldap:
provider: company_ldap
service: app.ldap #system/provider your user authenticate to
dn_string: '{username}#example.local'
csrf_token_generator: security.csrf.token_manager
check_path: /login_check #make sure the check is behind the firewall
login_path: /login #make sure login IS_AUTHENTICATED_ANONYMOUSLY
logout:
path: /logout #logout path
target: /login #after logout redirect to login
anonymous: true
Access_control/firewall Example:
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/, role: ROLE_USER } #all pages require user to be logged in
Now you have your dynamic ldap login form.
Symfony login form setup.
Hope this helps you. Took me 8 days to figure this out by myself.
You don't need to do any of the above. You can use the DN string as:
dn_string: '{username}'
That's actually the default value according to the docs.This will work because AD supports several bind methods in addition to a full DN (such as the sAMAccountName or UPN).

Symfony FOSUserBundle - Login - Invalid Credentials

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()

Resources