I have two symfony installations. One is a website and serves to store the users, sessions, account info, etc. The latter is an customer specific application install, with their own distinct DB and tables.
Authentication works fine on the main site. The idea being I could authenticate SSO and redirect the user back to their app instance.
I have managed to replicate my auth configuration in the application instances (mostly) how the application instances have slightly different doctrine config:
# config/packages/doctrine.yaml
doctrine:
dbal:
default_connection: default
connections:
default:
# configure these for your database server
url: '%env(resolve:DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
account:
# Sessions and users are stored here
url: '%env(resolve:DATABASE_URL_SITE)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
orm:
default_entity_manager: default
entity_managers:
default:
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
connection: default
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Core'
prefix: 'App\Entity'
alias: App
account:
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
connection: account
mappings:
Sso:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Shared'
prefix: 'App\Entity\Shared'
alias: Sso
This works - kinda - until Symfony tries to authenticate. The user entity is being retreived from the application DB, which does not have the Users table.
I thought the above ORM configuration made this obvious? All other scripts (schema:create, etc) seem to work...what am I missing?!?
EDIT security.yaml
security:
#enable_authenticator_manager: true
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\Shared\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
lazy: true
provider: app_user_provider
#custom_authenticators:
# - App\Security\SessionAuthenticator
# 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_USER }
# - { path: ^/profile, roles: ROLE_USER }
Related
Using Symfony 3.4.2 , I am trying to build a relationship between two entities of two different bundles which uses their own databases located on different servers.
In other words, we have two databases, and then two entities managers :
One existing MariaDB database [person] which store one "person" table, used by many other applications.
One new MariaDB database [app] dedicated for the application.
Note that I can't change anything on that situation (legacy applications must still running). Althought it is planned "in the future" to replace the [person] database by a REST Api.
Following the Symfony doc (https://symfony.com/doc/3.4/doctrine/multiple_entity_managers.html), this gives the following app/config/config.yml file :
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: services.yml }
# 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:
locale: en
framework:
#esi: ~
#translator: { fallbacks: ['%locale%'] }
secret: '%secret%'
router:
resource: '%kernel.project_dir%/app/config/routing.yml'
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
#serializer: { enable_annotations: true }
default_locale: '%locale%'
trusted_hosts: ~
session:
# https://symfony.com/doc/current/reference/configuration/framework.html#handler-id
handler_id: session.handler.native_file
save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
fragments: ~
http_method_override: true
assets: ~
php_errors:
log: true
# Twig Configuration
twig:
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
# Doctrine Configuration
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name%'
user: '%database_user%'
password: '%database_password%'
# charset: UTF8
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
# if using pdo_sqlite as your database driver:
# 1. add the path in parameters.yml
# e.g. database_path: '%kernel.project_dir%/var/data/data.sqlite'
# 2. Uncomment database_path in parameters.yml.dist
# 3. Uncomment next line:
#path: '%database_path%'
acme_another_db :
driver: pdo_mysql
host: '%acme_another_database_host%'
port: '%acme_another_database_port%'
dbname: '%acme_another_database_name%'
user: '%acme_another_database_user%'
password: '%acme_another_database_password%'
# charset: UTF8
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
# if using pdo_sqlite as your database driver:
# 1. add the path in parameters.yml
# e.g. database_path: '%kernel.project_dir%/var/data/data.sqlite'
# 2. Uncomment database_path in parameters.yml.dist
# 3. Uncomment next line:
#path: '%database_path%'
orm:
# Let's disable auto_mapping since we have several entity_managers
# auto_mapping: true
default_entity_manager: default
entity_managers:
default:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: default
mappings:
AppBundle: ~
acme_another_em:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: acme_another_db
mappings:
AcmeAnotherBundle: ~
auto_generate_proxy_classes: '%kernel.debug%'
# Swiftmailer Configuration
swiftmailer:
transport: '%mailer_transport%'
host: '%mailer_host%'
username: '%mailer_user%'
password: '%mailer_password%'
spool: { type: memory }
Since the "person" table is to be used by many other applications, I choosed to create a separate bundle.
In terms of entity, I have then 3 entities :
Acme/AnotherBundle/Entity/Person
AppBundle/Entity/Book
AppBundle/Entity/BookInterest
The first entity was generated without any error.
The AppBundle/Entity/Book and AppBundle/Entity/BookInterest entities were generated via bin\console generate:doctrine:entity without any problem.
Before updating the database schema, I added the relationship in the AppBundle/Entity/BookInterest entity class file (relation to Acme/AnotherBundle/Entity/Person and to AppBundle/Entity/Book), following the Symfony doc (http://symfony.com/doc/3.4/doctrine/associations.html).
/**
* #ORM\ManyToOne(targetEntity="Book", inversedBy="book")
* #ORM\JoinColumn(name="fk_book_id", referencedColumnName="id", nullable=false)
*/
private $book;
/**
* #ORM\ManyToOne(targetEntity="Acme\AnotherBundle\Entity\Person")
* #ORM\JoinColumn(name="fk_person_id", nullable=false)
*/
private $person;
But, when I try to update the schema via bin\console doctrine:schema:update --force --em=default, I have the following error message :
In MappingException.php line 37: The class
'Acme\AnotherBundle\Entity\Person' was not found in the chain
configured namespaces AppBundle\Entity
Adding "use Acme\AnotherBundle\Entity\Person;" in the top of \src\AppBundle\Entity\BookInterest.php and clearing the cache via bin\console cache:clear does not solve the problem.
Did I miss something in the app/config/config.yml configuration file, or in the \src\AppBundle\Entity\BookInterest.php entity class file ?
Doctrine2 unable to handle one relationship between two entity managers ?
I also found a (quite old) post on a similar problem (Using Relationships with Multiple Entity Managers), which indicates that Doctrine2 is unable to do that (due to the use of two entity managers).
If this is still the case, what is the best way to handle that situation ?
Is using one simple integer field without relation in the AppBundle/Entity/BookInterest for storing person_id and create manuals validation checks (then manual queries) in the BookInterestController is a good practice ?
Thanks a lot in advance for any tips (and good practice advices) to solve that case ! :-)
I am implementing a multi tenant application where the customer requires me to follow a specific data model. The customer required two seperate login systems that I am implementing using the guard system.
The first one is used to login customers. The difficulty here is that it is required to store the users passwords in the customer's database. To accomplish this I have implementation the guard system to first looks up the username in the 'login' database. From that same database the (encrypted) connection parameters for the users application database are retrieved. Using these parameters the users application database connection is created dynamically ('app') and the user is logged in using the information in this application database. On subsequent page requests the users application database is dynamically connected using a service on triggers on each pageload. So far so good.
The second Guard system is used to login to the back-end for management tasks. This login system is actually much simpler and uses a single database 'admin_login' to verify the users credentials. (So username, password and all other user properties are in one single database). The problem occurs after successfully logging in on the 2nd Guard implementation. The forward to the back-end home page triggers an error and I am unable to find to cause of this.
The error message is:
The class 'AppBundle\Entity\Login\Admin\AdminUser' was not found in the chain configured namespaces AppBundle\Entity\App
The error triggers before any code from the corresponding controller is hit. When I set the 'intercept_redirects' configuration item to true I can see that the administrative user is fully authorized before the redirect is taking place.
My doctrine configuration in config.yml
# Doctrine Configuration
doctrine:
dbal:
default_connection: app # specify the connexion used by default
connections:
login:
driver: pdo_mysql
host: '%database_login_host%'
port: '%database_login_port%'
dbname: '%database_login_name%'
user: '%database_login_user%'
password: '%database_login_password%'
charset: utf8mb4
admin_login:
driver: pdo_mysql
host: '%database_admin_host%'
port: '%database_admin_port%'
dbname: '%database_admin_name%'
user: '%database_admin_user%'
password: '%database_admin_password%'
charset: utf8mb4
app:
driver: pdo_mysql
host: '%database_app_host%'
port: '%database_app_port%'
dbname: '%database_app_name%'
user: '%database_app_user%'
password: '%database_app_password%'
charset: utf8mb4
orm:
auto_generate_proxy_classes: "%kernel.debug%"
default_entity_manager: app # specify the EM used by default (when using console commands f.e)
entity_managers:
login:
connection: login
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: false
mappings:
AppBundle :
type: annotation
dir: Entity/Login/Customer
prefix: AppBundle\Entity\Login\Customer
alias: Login
app:
connection: app
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: false
mappings:
AppBundle :
type: annotation
dir: Entity/App
prefix: AppBundle\Entity\App
alias: App
filters:
customer_flt:
class: AppBundle\Security\CustomerFilter
admin:
connection: admin_login
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: false
mappings:
AppBundle :
type: annotation
dir: Entity/Login/Admin
prefix: AppBundle\Entity\Login\Admin
alias: Admin
My security.yml
security:
encoders:
AppBundle\Entity\App\User:
algorithm: bcrypt
cost: 12
AppBundle\Entity\Login\Admin\AdminUser:
algorithm: bcrypt
cost: 12
role_hierarchy:
ROLE_SUPER_ADMIN: ROLE_ADMIN
ROLE_ADMIN: ROLE_USER
# http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers:
app:
entity:
class: AppBundle\Entity\App\User
property: username
admin:
entity:
class: AppBundle\Entity\Login\Admin\AdminUser
property: login
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/app
anonymous: ~
guard:
authenticators:
- app.security.login_form_authenticator
logout:
path: /app/logout
target: /
provider: app
admin:
pattern: ^/admin
anonymous: ~
guard:
authenticators:
- backend.security.login_form_authenticator
logout:
path: /admin/logout
target: /
provider: admin
access_control:
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_SUPER_ADMIN }
- { path: ^/app/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/app, roles: ROLE_USER }
What am I missing here?
Issue solved! Just an update so that everyone can find the answer when googling for it.
The issue was caused by a missing manager_name property in the providers section of the security.yml file. This property provides a mapping from a provider to a specific entity_manager. Without these Symfony takes the first (or default) entity manager and that fails (obviously) in my scenario.
providers:
app:
entity:
class: AppBundle\Entity\App\User
property: username
manager_name: app
admin:
entity:
class: AppBundle\Entity\Login\Admin\AdminUser
property: login
manager_name: admin
Sparse documentation of this can be found here: http://symfony.com/doc/current/security/entity_provider.html
I am working on an Guard authentication with 2 separate entity managers.
Here my config:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name%'
user: '%database_user%'
password: '%database_password%'
charset: UTF8
backoffice:
driver: pdo_mysql
host: '%database_backoffice_host%'
port: '%database_backoffice_port%'
dbname: '%database_backoffice_name%'
user: '%database_backoffice_user%'
password: '%database_backoffice_password%'
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
AppBundle: ~
CarBundle: ~
backoffice:
connection: backoffice
mappings:
BackofficeBundle: ~
This is my security setting
services:
backoffice.form_login_authenticator:
class: BackofficeBundle\Security\FormLoginAuthenticator
arguments: ["#router", "#security.password_encoder", "#doctrine.orm.backoffice_entity_manager"]
After the login form, the user is found and there is an redirect to my main route /backofice , but I become this error:
[2017-05-07 18:32:56] request.INFO: Matched route "backoffice_home". {"route":"backoffice_home","route_parameters":{"_controller":"BackofficeBundle\\Controller\\DefaultController::indexAction","_route":"backoffice_home"},"request_uri":"http://ip/backoffice","method":"GET"} []
[2017-05-07 18:32:56] security.DEBUG: Read existing security token from the session. {"key":"_security_main"} []
[2017-05-07 18:32:56] request.CRITICAL: Uncaught PHP Exception Doctrine\ORM\ORMException: "Unknown Entity namespace alias 'BackofficeBundle'." at /home/metahub/autotrader/vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.php line 271 {"exception":"[object] (Doctrine\\ORM\\ORMException(code: 0): Unknown Entity namespace alias 'BackofficeBundle'. at /home/metahub/autotrader/vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.php:271)"} []
The solution is this:
security:
encoders:
BackofficeBundle\Entity\User: bcrypt
providers:
database_users:
entity:
class: BackofficeBundle:User
property: username
manager_name: backoffice
We need to setup the manager "manager_name" for this Entity direct in the security settings.
try using auto_mapping: true
orm:
auto_generate_proxy_classes: "%kernel.debug%"
default_entity_manager: default
entity_managers:
default:
connection: default
auto_mapping: true
mappings:
AppBundle: ~
CarBundle: ~
backoffice:
connection: backoffice
auto_mapping: true
mappings:
BackofficeBundle: ~
I have my model entities saved in src/AppBundle/Model/Entity.
You can understand, that i have own custom folder for entities (in model folder).
This is my orm settings in config.yml:
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: false
mappings:
user:
type: annotation
dir: %kernel.root_dir%/../src/AppBundle/Model/Entity
alias: 'Entity'
prefix: AppBundle\Model\Entity
is_bundle: false
I have a problem with these lines in my security.yml:
providers:
our_db_provider:
entity:
class: AppBundle:User
property: username
# if you're using multiple entity managers
# manager_name: customer
There is some error:
Unknown Entity namespace alias 'AppBundle'.
I don't what ref I have to use (AppBundle:User probably not).
Thank you for your answers.
By default, all Symfony bundles will have a nice alias: XxxBundle (aliasing the NamespaceOfXxxBundle\Entity namespace). As you're bundle doesn't follow this convention and stores it in Model\Entity instead, you have 2 options:
Don't use the alias feature and pass the FQCN: AppBundle\Model\Entity\User
Create a new alias, give it a nice name and use it:
doctrine:
orm:
# ...
mappings:
user:
type: annotation
dir: %kernel.root_dir%/../src/AppBundle/Model/Entity
alias: App # <-- the alias name
prefix: AppBundle\Model\Entity
is_bundle: false
App:User
I am struggling to define entity mapper found here:
https://github.com/Payum/PayumBundle/blob/master/Resources/doc/capture_funds_with_paypal_express_checkout.md#2-a-configure-doctrine-storage
payum:
contexts:
your_context_name:
doctrine_storage:
driver: orm
model_class: AcmeDemoBundle\Entity\PaypalPaymentInstruction
doctrine:
orm:
entity_managers:
default:
mappings:
payum_paypal_express_checkout_nvp:
is_bundle: false
type: xml
dir: %kernel.root_dir%/../vendor/payum/paypal-express-checkout-nvp/src/Payum/Paypal/ExpressCheckout/Nvp/Bridge/Doctrine/Resources/mapping
prefix: Payum\Paypal\ExpressCheckout\Nvp\Bridge\Doctrine\Entity
My current doctrine configuration is having an autoload to true. Problem I have is to make this mapping work with my autoload: true
I can get mapping to work when i remove my autoload: true but
Any tips would be much appreciated, but question is how do i create a table from this mapping information?
This config works well for me. It added an id feild(it is come from bundle and was automapped) and the rest field come from manually defined mapping.
I added an example to sandbox. It works fine.
doctrine:
dbal:
driver: %database_driver%
host: %database_host%
port: %database_port%
dbname: %database_name%
user: %database_user%
password: %database_password%
charset: UTF8
# if using pdo_sqlite as your database driver, add the path in parameters.yml
# e.g. database_path: %kernel.root_dir%/data/data.db3
# path: %database_path%
orm:
auto_generate_proxy_classes: %kernel.debug%
auto_mapping: true
mappings:
payum_paypal_express_checkout_nvp:
is_bundle: false
type: xml
dir: %kernel.root_dir%/../vendor/payum/paypal-express-checkout-nvp/src/Payum/Paypal/ExpressCheckout/Nvp/Bridge/Doctrine/Resources/mapping
prefix: Payum\Paypal\ExpressCheckout\Nvp\Bridge\Doctrine\Entity