Chapters
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Welcome back friends! I'm so happy that you've stumbled into my Symfony 5 security tutorial for a bunch of reasons. The first is that well... uh... the site that we've been building has NO security... and the raptors are starting to jiggle the door handles.
The other reason is that, once we make it to the maintenance shed on other side of the compound, we're going to explore Symfony's new security system, called the "authenticator" system. Ooh. If you've used the old system, you'll feel right at home. If you're new to Symfony security, you chose a great time to start. The new system is easier to learn and understand... but it's also more powerful.
Project Setup
And because the security system isn't going to come online by itself, let's get to work. To learn how to authenticate & authorize & do other cool security stuff at a pro level, you should definitely download the course code from this page and code along with me. Making real-world mistakes.... yeah, it's the best way to remember this stuff.
After unzipping the file, you'll find a start/
directory with the same code that you see here. Pop open the README.md
file for all the setup instructions. The last step will be to find a terminal, move into the project and start a web server. I'm going to use the symfony
binary for this:
symfony serve -d
This starts up a new server at https://127.0.0.1:8000. Open that in your browser... or be lazy and run:
symfony open:local
to... "delegate" the work to someone else. Say hello to Cauldron Overflow! A question and answer site for witches and wizards, who... unfortunately... keep casting their spells live on production first without testing them... and usually on a Friday afternoon. Sheesh. Then they come here to ask how to undo the damage.
Installing Security
Because Symfony's philosophy is to start small and then allow you to install the stuff you need later, right now our app... literally does not have a security system.
That's no fun, so let's install one! Go back to your terminal and run:
composer require security
This installs Symfony's security bundle. After it finishes... run:
git status
to see what its recipe did. In addition to the normal stuff, it added one new configuration file: security.yaml
. Let's go check that out: config/packages/security.yaml
:
security: | |
# https://symfony.com/doc/current/security/authenticator_manager.html | |
enable_authenticator_manager: true | |
# https://symfony.com/doc/current/security.html#c-hashing-passwords | |
password_hashers: | |
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' | |
# 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: | |
lazy: true | |
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 } |
As you hopefully guessed by its name, this file powers the security system! By the time we're done, each section in here will be simple and boring to you. I love when programming stuff is boring.
enable_authenticator_manager
Oh, but see this enable_authenticator_manager
key?
security: | |
# https://symfony.com/doc/current/security/authenticator_manager.html | |
enable_authenticator_manager: true | |
Show Lines
|
// ... lines 4 - 29 |
In Symfony 5.3 - the version I'm using - the old and new security systems live side-by-side and you get to choose which one you want! When you set enable_authenticator_manager
to true
, you are activating the new system. Yay! Shiny! If you're working on a legacy project and need to learn the old system, check out our Symfony 4 Security tutorial. It's pretty cool too!
Authentication & Authorization
Anyways, when you talk about security, there are two big parts: authentication and authorization. Authentication asks the question, "who are you"? And "can you prove it?" Users, login forms, remember me cookies, passwords, API keys... all of that stuff is related to authentication.
Authorization asks a different question: "Should you have access to this resource?" Authorization doesn't care much about who you are... it's all about allowing or denying access to different things, like different URLs or controllers.
In Symfony, or really in any security system, authentication is the tricky part. I mean, just think about how many ways there are to authenticate! Login forms, API token authentication, social authentication with OAuth, SSO's, LDAP, putting on a fake mustache and walking confidently passed a security guard. I mean... the possibilities are endless. But I also think that authentication is super fun.
So next: let's start on our journey into the new shiny authenticator system by creating the most basic part of authentication: a user class.
36 Comments
To anyone having this issue, for me the easiest solution is to erase the files on the migrations folder, and run "symfony console make:migration" to generate a new one before executing "symfony console doctrine:migrations:migrate" .
Cheers!
Hey Miguel,
Thank you for this tip! Yeah, it sounds like a good workaround. Or, you can even simplify this by just running bin/console doctrine:schema:update --force
- both ways are good for learning purposes when you do not afraid to lose data in your local database. But for production - probably neither of these options will fit.
Cheers!
Hey Oliver W.
Your version of MariaDB does not allow to rename an index, here's a related issue to your problem https://github.com/PomeloFo...
You can tweak the query to regenerate the index instead, or, you could upgrade your database version, I believe the "RENAME INDEX" operation is supported by the latest MariaDB version
Cheers!
thx, I've been changing the name of the idex manually and manipulated the migrations table. So it finally worked.
Hi
I make an effort to follow this course with latest versions. I will post my composer.json file bellow.
I have the following problem: When I run the application, the database is empty.
Database creation, migration and fixtures load did not yield any errors. But, when I run the app, there are no questions, answers, tags, nothing. If I query the database, query is executed successfully, but the queries returns 0 results.
{
"type": "project",
"license": "proprietary",
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "^3.7",
"composer/package-versions-deprecated": "1.11.99.5",
"doctrine/doctrine-bundle": "^2.9.1",
"doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.15.1",
"knplabs/knp-markdown-bundle": "^1.10.0",
"knplabs/knp-time-bundle": "^1.20.0",
"pagerfanta/doctrine-orm-adapter": "^4.1",
"pagerfanta/twig": "^4.1",
"sensio/framework-extra-bundle": "^6.2",
"stof/doctrine-extensions-bundle": "1.7.1",
"symfony/asset": "6.2.*",
"symfony/console": "6.2.*",
"symfony/dotenv": "6.2.*",
"symfony/flex": "^1.3.1",
"symfony/framework-bundle": "6.2.*",
"symfony/monolog-bundle": "^3.0",
"symfony/runtime": "6.2.*",
"symfony/stopwatch": "6.2.*",
"symfony/twig-bundle": "6.2.*",
"symfony/ux-chartjs": "^2.8",
"symfony/webpack-encore-bundle": "^1.7",
"symfony/yaml": "6.2.*",
"twig/extra-bundle": "^3.6",
"twig/string-extra": "^3.6",
"twig/twig": "^3.6"
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4",
"symfony/debug-bundle": "6.2.*",
"symfony/maker-bundle": "^1.48",
"symfony/var-dumper": "6.2.*",
"symfony/web-profiler-bundle": "6.2.*",
"zenstruck/foundry": "^1.1"
},
"config": {
"preferred-install": {
"*": "dist"
},
"sort-packages": true,
"platform": {},
"allow-plugins": {
"symfony/flex": true,
"symfony/runtime": true
}
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"paragonie/random_compat": "2.*",
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php71": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-php56": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": true,
"require": "6.2.*",
"docker": true
}
}
}
Answer why the database is empty is in the log file (I am posting just few last lines):
[2023-05-16T15:21:30.985395+02:00] doctrine.DEBUG: Executing statement: INSERT INTO doctrine_migration_versions (version, executed_at, execution_time) VALUES (?, ?, ?) (parameters: array{"1":"DoctrineMigrations\\Version20210907192236","2":"2023-05-16 15:21:30","3":113}, types: array{"1":2,"2":2,"3":1}) {"sql":"INSERT INTO doctrine_migration_versions (version, executed_at, execution_time) VALUES (?, ?, ?)","params":{"1":"DoctrineMigrations\\Version20210907192236","2":"2023-05-16 15:21:30","3":113},"types":{"1":2,"2":2,"3":1}} []
[2023-05-16T15:21:30.987883+02:00] doctrine.DEBUG: Executing query: ALTER TABLE question_tag CHANGE tagged_at tagged_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)' {"sql":"ALTER TABLE question_tag CHANGE tagged_at tagged_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)'"} []
[2023-05-16T15:21:31.016749+02:00] doctrine.DEBUG: Executing statement: INSERT INTO doctrine_migration_versions (version, executed_at, execution_time) VALUES (?, ?, ?) (parameters: array{"1":"DoctrineMigrations\\Version20210907192620","2":"2023-05-16 15:21:30","3":29}, types: array{"1":2,"2":2,"3":1}) {"sql":"INSERT INTO doctrine_migration_versions (version, executed_at, execution_time) VALUES (?, ?, ?)","params":{"1":"DoctrineMigrations\\Version20210907192620","2":"2023-05-16 15:21:30","3":29},"types":{"1":2,"2":2,"3":1}} []
[2023-05-16T15:21:31.027088+02:00] doctrine.INFO: Disconnecting [] []
[2023-05-16T15:21:44.411377+02:00] doctrine.INFO: Connecting with parameters array{"url":"<redacted>","driver":"pdo_mysql","host":"127.0.0.1","port":59049,"user":"root","password":"<redacted>","driverOptions":[],"defaultTableOptions":[],"dbname":"root","sslmode":"disable","charset":"utf8mb4"} {"params":{"url":"<redacted>","driver":"pdo_mysql","host":"127.0.0.1","port":59049,"user":"root","password":"<redacted>","driverOptions":[],"defaultTableOptions":[],"dbname":"root","sslmode":"disable","charset":"utf8mb4"}} []
[2023-05-16T15:21:44.438096+02:00] doctrine.DEBUG: Executing query: SELECT DATABASE() {"sql":"SELECT DATABASE()"} []
[2023-05-16T15:21:48.606397+02:00] doctrine.DEBUG: Beginning transaction [] []
[2023-05-16T15:21:48.696434+02:00] doctrine.DEBUG: Executing statement: DELETE FROM answer {"sql":"DELETE FROM answer"} []
[2023-05-16T15:21:48.697922+02:00] doctrine.DEBUG: Executing statement: DELETE FROM question_tag {"sql":"DELETE FROM question_tag"} []
[2023-05-16T15:21:48.698974+02:00] doctrine.DEBUG: Executing statement: DELETE FROM question {"sql":"DELETE FROM question"} []
[2023-05-16T15:21:48.700101+02:00] doctrine.DEBUG: Executing statement: DELETE FROM tag {"sql":"DELETE FROM tag"} []
[2023-05-16T15:21:48.701737+02:00] doctrine.DEBUG: Committing transaction [] []
[2023-05-16T15:21:48.703985+02:00] doctrine.INFO: Disconnecting [] []
Does anyone know who and why issues the delete queries? I can't find anything like that in the migration files.
Regards
hey there,
That's very strange. When does it happen? If you only run the fixtures and inspect the database, is it empty?
Did you download the course code? And if you did, did you change something?
Hi MolloKhan
Yes,If I only run the fixtures, and I inspect the database, she is still empty. And those queries "DELETE from Answer..." listed above in the log are again there.
I had downloaded the course code, and the only file that I messed with was the composer.json
Anyway, I will start all over again, and if still does not work, I will use the old versions. It would be great however, if symfony casts can provide 2 versions of the composer json file, one with original version and one with the latest version. Or make a few videos: how to resolve dependencies injection nightmares...
Regards
Wow, that's super odd. Perhaps something changed in the latest version of Doctrine Fixtures bundle but I can't be sure. My apologies for your troubles and thank you for your suggestions, we'll consider them.
Hi Symfony Casts,
I have ldap security all up and running in symfony 6+ and php 8+.
I'm using an external ldap /active directory server.
Local it was very easy to start with ldap security, because i used 'symfony serve'.
But on production, it was much harder to make it work.
So i decided to dockerize everything. Apache, php, composer etc. to make a container and never worry about configuration again.
But i just can't get ldap to work from docker on dev environment.
In my Dockerfile i have 'RUN a2enmod authnz_ldap'.
In a conf file i have this:
DocumentRoot /var/www
DirectoryIndex /index.php
<Directory /var/www>
AuthName "LDAP Authentication"
AuthType Basic
AuthBasicProvider ldap
AuthLDAPURL "ldap:// ..."
AuthLDAPBindDN "..."
AuthLDAPBindPassword "..."
</Directory>```
Is this the right way to do things?
Thanks in advance.
Annemieke
Hi Annemieke!
Bah, unfortunately, I have less than zero experience with LDAP + Docker, let alone LDAP + Docker + Apache... so I can't even muster a guess here.
Sorry I can't be useful in this case! Good luck!
Hi. I've a problem with the security system. My app was working 100%, but after reinstalling my windows 10 and then php 8.1... i'm unable to pass the login form. I've this anwser from my local server : " Warning: session_regenerate_id(): Session object destruction failed. ID: user (path: C:\xampp\tmp)"". Any solution...orientation?
Hey discipolat!
Hm, sounds like something internal to your laptop, most probably some misconfiguration of the XAMP, especially if. you did not do any changes to the source code of your project. I'd recommend you to re-install XAMP, it might help I think. If not, it seems like you have problems with session - you can try to store session in a different place, e.g. in your DB (at least locally), it might be a good workaround, but not perfect storing session in different places locally and on prod :/ Another solution - try to use a different from XAMP web server. Actaully, I'd recommend you to use the built in Symfony web server that you can start with "symfony serve" command - all you need to have is Symfony CLI and PHP installed. You may still spin the XAMP for MySQL if you get used to it, but do not use the webserver that causes issues now.
So, those are some tips, I hope something will be helpful for you.
Cheers!
Hi Victor, Thank's for all!
I've try the reinstallation solution but not working i don't know why....strange. I've even switch from Php 8.1 to 7.4 with xampp but same status.
So i've try to strore sessions elsewhere according to https://symfony.com/doc/4.4/session/database.html#store-sessions-in-a-relational-database-mariadb-mysql-postgresql and it working now.
Thank's.
Hey Discipolat,
Cool, I'm happy to hear you found a workaround for this! I understand it's not perfect (and not convenient probably) but sometimes things go weird on Windows, unfortunately. It might be a permissions issue (most probably). If you want to try to fix it correctly - probably google the error you see, it might be some tips on the internet.
Otherwise, I'd recommend you to take a look at the Windows WSL feature - some Windows guys in our team are using it and say that it's awesome :)
I hope this helps!
Cheers!
Hi Victor,
the 'problem' was pretty simple in reality !
As you said, it was just a permissions issue. I've just act on permissions and things works fine.
Thank's!
Hey Discipolat,
Awesome! Glad you figured it out :) And thanks for posting the real issue after all, it might be helpful for others.
Cheers!
Hi Victor,
Thank's very much.
On Symfony 6 the "enable_authenticator_manager" isn't longer in use? Right?
Hey, Rufnex
It is set to true
by default, so you don't have to configure anything to use the new security system
Cheers!
Thank you.
I'm happy to report solutions to a problem some people may encounter. If you are running PHP 8.1, composer cannot install.
You can install php-fpm7.4 or 8.0 alongside php-fpm8.1 on the same machine and use update-alternatives
(on Debian-ish systems) to switch php versions, and this seems a sane option. I have done this to roll back to 8.0 and it works fine.
Another alternative is to use <a href="http://devilbox.org/">Devilbox</a> It's a little more involved, but it's kind of cool.
Hi davidmintz
Another workaround will be to updatelaminas/laminas-code
package to unblock php 8.1
So you can install everything with composer update laminas/laminas-code
command
Cheers! and thanks again for the reporting
Hey David,
Thank you for reporting this! We will take a look at the course code and probably apply some fixes to make it possible to run the code on PHP 8.1
And thanks for the tips on how to workaround this problem!
Cheers!
Hi,
any idea why I get "an error occured while loading the web debug toolbar" from the very beginning? The page itself is displayed but no debug toolbar.
I alreday cleared the diretory vendor\cache. No changes.
Ah, I even tried do download the code once again today. No changes.
Trying to open /answers/popular brings an 404.
Starting composer require annotations brings no changes.
What else can I look for?
By the way: I am working on a local XAMPP. But in other projects the debug toolbar works fine.
Thx
Oliver
got it: it's that weird thing called .htaccess.
Hey Oliver,
Oh, yeah, it might be .htaccess. I'd recommend you to use Symfony's built-in server for developing purposes locally, but if you do want to use XAMPP that runs real Apache web server - I'd advice you to install "symfony/apache-pack" dependency that will bring the default Symfony .htaccess into your project, though you might still want to tweak it, depends on your local configuration.
I hope this helps!
Cheers!
Is there a guide or howto or something similar which explains the migration from GuardAuthentication to the new system? It seems that it runs on Symfony 5.4, but won´t with Symfony 6 (that is my understanding). Can you add one or two lessons about the migration?
Hi, I've tried setting up the project like the readme describes. I'm able to start the docker, but when I want to create a database using the symfony console command I get "SQLSTATE[HY000] [2002] Connection refused" as a response in the console.
Hey Daniel,
Please, double check your DB credentials in .env and .env.local files. Looks like they are not valid for your specific MySQL server. Tweak them to the correct ones and try again :)
Cheers!
Hi Victor,
this could be an issue with the initial docker-compose.yaml file
I actually got the same error message as Daniel but I figured out that the issue might be about naming of the database service. In the pre-generated docker-compose.yaml the service name was secure_db, while on other projects I had database. By simply renaming the service, removing and restarting the docker container and clearing symfony cache i got it work.
Hey Tomik!
Thank you for the tips how to fix things!
Yeah, naming might be different on different courses, that's why we recommend to download a new course code and start coding with us from start/ directory. Except some naming things, we may add more changes between courses, like upgrading dependencies, slightly changing code to have better use cases that we will cover in the videos, etc. So, if you continue the course code from a past tutorial, you may have differences between your code after a past tutorial and the code we show in the new course.
Cheers!
I'm using symfony 5.2 whit two type authentication using email & password and google oAuth. When I enable enable_authenticator_manager=true it comes out the error: 'you can not user enable_authenticator_manager with oAuth'. Not sure why enable_authenticator_manager does not work with oAuth
Hey Art A.!
What bundle are you using that gives you the OAuth support? Bundles need to add support for the new "authenticator" system. It's actually quite easy... but if the bundle hasn't done it yet, then it needs to :).
Cheers!
There is a small typo : require and not requires ;-)
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "^3.3", // v3.3.0
"composer/package-versions-deprecated": "^1.11", // 1.11.99.4
"doctrine/annotations": "^1.0", // 1.13.2
"doctrine/doctrine-bundle": "^2.1", // 2.6.3
"doctrine/doctrine-migrations-bundle": "^3.0", // 3.1.1
"doctrine/orm": "^2.7", // 2.10.1
"knplabs/knp-markdown-bundle": "^1.8", // 1.9.0
"knplabs/knp-time-bundle": "^1.11", // v1.16.1
"pagerfanta/doctrine-orm-adapter": "^3.3", // v3.3.0
"pagerfanta/twig": "^3.3", // v3.3.0
"phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
"scheb/2fa-bundle": "^5.12", // v5.12.1
"scheb/2fa-qr-code": "^5.12", // v5.12.1
"scheb/2fa-totp": "^5.12", // v5.12.1
"sensio/framework-extra-bundle": "^6.0", // v6.2.0
"stof/doctrine-extensions-bundle": "^1.4", // v1.6.0
"symfony/asset": "5.3.*", // v5.3.4
"symfony/console": "5.3.*", // v5.3.7
"symfony/dotenv": "5.3.*", // v5.3.8
"symfony/flex": "^1.3.1", // v1.21.6
"symfony/form": "5.3.*", // v5.3.8
"symfony/framework-bundle": "5.3.*", // v5.3.8
"symfony/monolog-bundle": "^3.0", // v3.7.0
"symfony/property-access": "5.3.*", // v5.3.8
"symfony/property-info": "5.3.*", // v5.3.8
"symfony/rate-limiter": "5.3.*", // v5.3.4
"symfony/runtime": "5.3.*", // v5.3.4
"symfony/security-bundle": "5.3.*", // v5.3.8
"symfony/serializer": "5.3.*", // v5.3.8
"symfony/stopwatch": "5.3.*", // v5.3.4
"symfony/twig-bundle": "5.3.*", // v5.3.4
"symfony/ux-chartjs": "^1.3", // v1.3.0
"symfony/validator": "5.3.*", // v5.3.8
"symfony/webpack-encore-bundle": "^1.7", // v1.12.0
"symfony/yaml": "5.3.*", // v5.3.6
"symfonycasts/verify-email-bundle": "^1.5", // v1.5.0
"twig/extra-bundle": "^2.12|^3.0", // v3.3.3
"twig/string-extra": "^3.3", // v3.3.3
"twig/twig": "^2.12|^3.0" // v3.3.3
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3", // 3.4.0
"symfony/debug-bundle": "5.3.*", // v5.3.4
"symfony/maker-bundle": "^1.15", // v1.34.0
"symfony/var-dumper": "5.3.*", // v5.3.8
"symfony/web-profiler-bundle": "5.3.*", // v5.3.8
"zenstruck/foundry": "^1.1" // v1.13.3
}
}
Hi,
when trying to runsymfony console doctrine:migrations:migrate I keep getting this as error:
[notice] Migrating up to DoctrineMigrations\Version20210907192620
[error] Migration DoctrineMigrations\Version20210902182514 failed during Execution. Error: "An exception occurred while executing 'ALTER TABLE answer RENAME INDEX idx_9474526c1e27f6bf TO IDX_DADD4A251E27F6BF':
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'INDEX idx_9474526c1e27f6bf TO IDX_DADD4A251E27F6BF' at line 1"
In AbstractMySQLDriver.php line 98:
An exception occurred while executing 'ALTER TABLE answer RENAME INDEX idx_9474526c1e27f6bf TO IDX_DADD4A251E27F6BF':
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'INDEX idx_9474526c1e27f6bf TO IDX_
DADD4A251E27F6BF' at line 1
I am working with XAMPP with PHP 7.4.9 and MariaDB 10.4.14. In my .env i noted ...serverVerion=mariadb-10.4.14 which works fine for other Smyfony projects.
By the way: when submitting ALTER TABLE answer RENAME INDEX idx_..... directly on the server it tells me that a comma is missing just before start of a new alter operation (near "TO")!?!?!?
What goes wrong?
Thx
Oliver