I'm trying to encode the password im passing through post but it is giving me an error when I declare the argument in the function.
Could not resolve argument $encoder of "App\Controller\UsuarioController::altapropietario()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?*
Here I paste the whole function, it has a form and its just for registering new users.
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class UsuarioController extends AbstractController
{
public function altaPropietario(Request $request, UserPasswordEncoderInterface $encoder )
{
$propietario = new Usuario();
$form = $this->createForm(AltaPropietarioType::class, $propietario);
$form->handleRequest($request);
if ($form->isSubmitted())
{
$propietario->setRole("ROLE_PROP");
$encoded = $encoder->encodePassword($propietario, $propietario->getPassword());
$propietario->setPassword($encoded);
// rest of the implementation not included.
}
}
}
My security yml is the following:
security:
encoders:
App\Entity\Usuario: bcrypt
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
users_in_memory: { memory: null }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: lazy
provider: users_in_memory
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
services.yaml:
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
Related
I looked in to this post but my problem is a little different and many things in symfony security component have changed for version 5.
So, I try to set entity manager other than default in user provider. I created two connections using documentation: https://symfony.com/doc/current/doctrine/multiple_entity_managers.html
doctrine:
dbal:
default_connection: default
connections:
default:
url: '%env(resolve:DATABASE_URL)%'
b2b:
url: '%env(resolve:DATABASE_B2B_URL)%'
users:
url: '%env(resolve:DATABASE_USERS_URL)%'
# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
#server_version: '5.7'
orm:
auto_generate_proxy_classes: true
default_entity_manager: default
entity_managers:
default:
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: false
connection: default
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Main'
prefix: 'App\Entity\Main'
alias: Main
b2b:
connection: b2b
users:
connection: users
mappings:
Users:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Users'
prefix: 'App\Entity\Users'
alias: Users
Next I change my security.yaml and add manager_name: users - exactly as in the documentation:
security:
encoders:
App\Entity\Users\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\Users\User
property: email
manager_name: users
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: lazy
provider: app_user_provider
guard:
authenticators:
- App\Security\LoginFormAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
Despite the above settings security component try to load class from default entity manager:
[2020-04-16T05:53:55.276798+00:00] request.CRITICAL: Uncaught PHP Exception Doctrine\Persistence\Mapping\MappingException: "The class 'App\Entity\Users\User' was not found in the chain configured namespaces App\Entity\Main" at /home/budmechzz/public_html/rfm.computermedia.com.pl/vendor/doctrine/persistence/lib/Doctrine/Persistence/Mapping/MappingException.php line 23 {"exception":"[object] (Doctrine\\Persistence\\Mapping\\MappingException(code: 0): The class 'App\\Entity\\Users\\User' was not found in the chain configured namespaces App\\Entity\\Main at /home/budmechzz/public_html/rfm.computermedia.com.pl/vendor/doctrine/persistence/lib/Doctrine/Persistence/Mapping/MappingException.php:23)"} []
What am I doing wrong?
Ok, I think I solved the problem.
The reason was the class /src/Security/LoginFormAuthenticator.php (automatically generated by php bin / console make: auth) in 68 line is:
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);
This line is trying to get the user from the default entity manager. I do not know why manager indication doesn't help eg. $this->entityManager->getRepository(User::class, 'users')
So I change __constructor in /src/Security/LoginFormAuthenticator.php and I get entity manager from ManagerRegistry (It was previously geted from EntityManagerInterface). This solves my login problem :)
use Doctrine\Common\Persistence\ManagerRegistry;
public function __construct(ManagerRegistry $managerRegistry, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $managerRegistry->getManager('users');
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
I hope it will be useful to someone
I'm struggeling to replace the LdapUserProvider.
I created my own provider (App\Security\MyLdapUserProvider based on LdapUserProvider but retrieves more information) and my own UserInterface (App\Security\MyUser) with more attributes to store the data.
In the end I want to retrieve the groups and the displayName of the user.
Here is my config:
services.yaml:
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
Symfony\Component\Ldap\Ldap:
arguments: ['#Symfony\Component\Ldap\Adapter\ExtLdap\Adapter']
Symfony\Component\Ldap\Adapter\ExtLdap\Adapter:
arguments:
- host: 10.106.1.1
port: 389
#encryption: tls
options:
protocol_version: 3
referrals: false
security.yaml:
providers:
#in_memory: { memory: ~ }
my_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: "dc=XXXXXX,dc=com"
search_dn: "CN=XXXXXXXXXX,OU=LDAP,OU=Services Accounts,OU=Administration,DC=XXXXXXXXX,DC=com"
search_password: "ergergergergerg"
default_roles: ROLE_USER
filter: "({uid_key}={username})"
uid_key: samAccountName
#password_attribute: displayName
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
security: true
anonymous: true
provider: my_ldap
form_login_ldap:
login_path: /login
check_path: /login
service: Symfony\Component\Ldap\Ldap
dn_string: 'dc=XXXXXX,dc=com'
query_string: '(samAccountName={username})'
logout:
path: /logout
target: /
Where can I tell the security provider to use my own ldap provider instead of the default one ?
Symfony processes are still a bit complicated to me so if someone can take time to explain..
Symfony docs is an endless loop of redirecting between CustomUserProvider > Ldap config > CustomeUSerProvider...
As described in the documentation chapter Creating A Custom User Provider you need to add your User Provider as a new key under security.providers and configure it's id.
This id is the name of of your custom User Provider service which - in recent versions of symfony - equals the FQCN .
# security.yaml
security:
providers:
# the name of your user provider can be anything
my_ldap_provider:
id: 'App\Security\MyLdapUserProvider'
Then you can use this provider for one of the firewalls like this:
security:
# [..]
firewalls:
main:
pattern: '^/'
provider: 'my_ldap_provider'
Symfony's LdapUserProvider looks like this:
class LdapUserProvider implements UserProviderInterface
{
private $ldap;
private $baseDn;
private $searchDn;
private $searchPassword;
private $defaultRoles;
private $uidKey;
private $defaultSearch;
private $passwordAttribute;
private $extraFields;
public function __construct(
LdapInterface $ldap,
string $baseDn,
string $searchDn = null,
string $searchPassword = null,
array $defaultRoles = [],
string $uidKey = null,
string $filter = null,
string $passwordAttribute = null,
array $extraFields = []
)
{
In order to create your MyLdapUserProvider service that extends LdapUserProvider correctly you need a service-definition like this:
# services.yaml
services:
App\Security\MyLdapUserProvider:
arguments:
$adminEmail: '%admin_email%'
$ldap: '#Symfony\Component\Ldap\Ldap'
$baseDn: 'dc=XXXXXX,dc=com'
$searchDn: 'CN=XXXXXXXXXX,OU=LDAP,OU=Services Accounts,OU=Administration,DC=XXXXXXXXX,DC=com'
$searchPassword: 'ergergergergerg'
$defaultRoles: ['ROLE_USER']
$filter: '({uid_key}={username})'
$uidKey: 'samAccountName'
I have the following simple class:
<?php
namespace App\EventListener;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
class LoginListener implements EventSubscriberInterface
{
private $logger = null;
public function __construct (LoggerInterface $logger)
{
$this->logger = $logger;
}
public function onInteractiveLogin (InteractiveLoginEvent $event)
{
$this->logger->info('TEST');
}
public static function getSubscribedEvents ()
{
return [
SecurityEvents::INTERACTIVE_LOGIN => 'onInteractiveLogin',
];
}
}
It is under the /src and should autoload (Symfony 4.1.0).
When I run:
bin/console debug:event-dispatcher security.interactive_login
I see expected results:
Registered Listeners for "security.interactive_login" Event
------- ------------------------------------------------------- ----------
Order Callable Priority
------- ------------------------------------------------------- ----------
#1 App\EventListener\LoginListener::onInteractiveLogin() 0
------- ------------------------------------------------------- ----------
And yet when I login successfully (or otherwise) that log message isn't where there - digging into Symfony profiler - I can see it's under the "Not Called Listeners" tab???
Any ideas what I am missing?
EDIT |
services.yaml:
imports:
- { resource: 'company.yaml' }
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Legacy}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
#
# ldap authentication service configuration
# https://symfony.com/doc/current/reference/configuration/security.html
Symfony\Component\Ldap\Ldap:
arguments: ['#Symfony\Component\Ldap\Adapter\ExtLdap\Adapter']
Symfony\Component\Ldap\Adapter\ExtLdap\Adapter:
arguments:
- host: davinci-1
port: 389
#encryption: tls
options:
protocol_version: 3
referrals: false
#
# We need to hook into default LDAP authentication to properly populate Symfony
# roles and / or return legacy groups
# http://symfony.com/doc/current/components/security/authentication.html#authentication-events
# http://symfony.com/doc/current/event_dispatcher.html
#App\EventListener\LoginListener:
# tags:
# - { name: kernel.event_listener, event: security.interactive_login, method: onInteractiveLogin }
security.yaml
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
ad_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: dc=company,dc=local
search_dn: 'appuser'
search_password: "XXX"
default_roles: ROLE_USER
uid_key: 'sAMAccountName'
filter: '({uid_key}={username})'
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
http_basic_ldap:
provider: ad_ldap
service: Symfony\Component\Ldap\Ldap
dn_string: 'Company\{username}'
#query_string: '(sAMAccountName={username})'
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
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()
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.