I have a static website where its pages may only be accessed if a user has authenticated via SAML2 SSO. Specifically, these pages are written with Twig, and the content is stored in JSON files which are fed in as variables to the Twig templates.
I was wondering if there was a simple way to leverage a PHP framework like Symfony to do this. Ideally, there would also be no database layer. Once a user has authenticated some cookie should be set that just permits them to cruise around as needed.
My background is with Drupal so that's why I'm looking in the direction of Symfony.
I do realize this question is kinda broad, so if there is a more appropriate place to inquire about this then please vote to close and point me in the right direction.
I've completed this functionality, posting my solution in the event this is useful to someone else down the line...
For a Symfony 5 project, I used https://github.com/hslavich/OneloginSamlBundle. Fill in config/packages/hslavich_onelogin_saml.yaml per the package's README.md, and according to how your SP and IdP are configured. One pro tip, the baseurl configuration value should be set to the application domain with /saml concatenated on to it (e.g. http://myapp.com/saml), there is a bug which strips off everything between the last path value (acs in /saml/acs) and the domain.
Update config/packages/security.yaml to look something like:
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
saml_provider:
saml:
user_class: App\Security\User
default_roles:
- ROLE_USER
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
id: App\Security\UserProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
app:
saml:
provider: saml_provider
# Match SAML attribute 'uid' with username.
# Uses getNameId() method by default.
username_attribute: eduPersonTargetedID
# Use the attribute's friendlyName instead of the name
check_path: saml_acs
login_path: saml_login
logout:
path: saml_logout
main:
lazy: true
provider: app_user_provider
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# 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: ^/saml/login, roles: PUBLIC_ACCESS }
- { path: ^/saml/metadata, roles: PUBLIC_ACCESS }
- { path: ^/, roles: ROLE_USER }
The net result is /saml/login and /saml/metadata are publicly available, while all other routes require the ROLE_USER role. Upon a successful authentication with the IdP, the user is redirected back and is granted a session, and can then access all routes within the site.
I want to include the logged in user's id to my logger.
So I have added a monolog.processor that adds the user id to the 'extra'-portion of the record, and added a custom format string that displays the id.
On my dev environment this works (mostly) as expected, but on the test environment it does not work at all, the TokenStorage always returns null on getToken().
There are no specific security configs for dev or test. The biggest differences between the configs is this part:
framework:
test: ~
session:
storage_id: session.storage.mock_file
profiler:
collect: false
I have add this to my dev config but could not reproduce the symptoms. I can only reproduce by making symfony think it really is in test.
To be honest, I don't even know where to begin to debug this.
Any ideas what might be causing this behaviour?
Any ideas how I could debug this so I can get to an answer?
In order to have a token you should be inside on of the symfony firewalls.
If any of the firewalls aren't matched by the URI, symfony security is not triggered and you will not have a token.
If it is a public area allow anonymous users from root '/*' and use ACL for the rest of the URI (or actions). Anonymous users will have the role IS_AUTHENTICATED_ANONYMOUSLY
# app/config/security.yml
security:
firewalls:
main:
pattern: ^/
anonymous: ~
Documentation:
http://symfony.com/doc/current/security.html
I have an AJAX worker they is called a API url every second. After 250-300 seconds, I don't get a valid response or a profile-token in case of the user was logged out. I have already configured the cookie_lifetime to 0 but it made no difference. Here's also my security.yml:
firewalls:
main:
pattern: ^/
anonymous: true
form_login:
login_path: /home
logout:
path: logout
handler: app.custom_logout
target: /home
The weird thing is, it seems completely random when a session expires. I have also reached over 1000 AJAX calls and on the other side only 300 calls.
I hope any one of you can help me.
PS: The AJAX calls are not only a JSON response, there are full generated twig templates (including a profiler).
I've found an answer for my question by myself.
You need to configure the gc_divisor, gc_probability and gc_maxlifetime. For example:
session:
cookie_lifetime: 0
gc_divisor: 10000
gc_probability: 1
gc_maxlifetime: 604800
After this configuration in your config.yml the chance that your session expire (because you have set cookie_lifetime to a specific time) is equal to zero.
Also have a look to the Symfony documentation of sessions: http://symfony.com/doc/current/reference/configuration/framework.html#session
I'm developing a website using Symfony2, and until today - had no problem logging in. But now when logging in I'm not correctly authenticated - Symfony profiler lists me as logged in as: anon instead of the user I logged in as. I'm also redirected back to the login page instead of the target path.
The login process consists of a traditional login form (i.e. username + password) with a submit button. All user credentials are stored in MySQL and I've setup a User entity as a provider.
There are no errors in my php errors log, or listed in the Symfony profiler under Exception or Logs.
One observation I've made is nothing is listed under the Session Attributes heading (within Symfony profiler > Request) - normally there would be some security context information listed after successfully logging in, but now it's always empty. I tried setting a basic session variable on the homepage which was partially successful as it gets set and is shown under Session Attributes, but get's cleared whenever attempting to login!
This is my security.yml file:
# app/config/security.yml
security:
encoders:
Woodcut\UserBundle\Entity\User: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class: Woodcut\UserBundle\Entity\User, property: username }
firewalls:
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: login
check_path: login_check
username_parameter: _username
success_handler: custom_authentication_handler
failure_handler: custom_authentication_handler
#always_use_default_target_path: true
#default_target_path: /login_router
logout:
path: /logout
target: /
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/ratings/update, roles: ROLE_USER }
- { path: ^/ratings/new, roles: ROLE_USER }
- { path: ^/favourite, roles: ROLE_USER }
I'm using a typical LAMP stack to run my site with Symfony 2.3.13 and PHP 5.4.28 on a Ubuntu 12.04 Virtual machine. PHP is running as mod_php.
Output from Symfony Profiler > Debug:
INFO - Populated SecurityContext with an anonymous Token
DEBUG - Notified event "kernel.exception" to listener "Symfony\Component\Security\Http\Firewall \ExceptionListener::onKernelException".
DEBUG - Access is denied (user is not fully authenticated) by "/vagrant_www/vprojects/woodcut/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/AccessListener.php" at line 70; redirecting to authentication entry point
DEBUG - Calling Authentication entry point
If someone can please help me determine why users are authenticated as anonymous instead of as themselves that would be great. Been pulling my hear out the last two days trying to find the cause.
Thanks in advance for any help provided!
Additional info: I have a VPS running a copy of the site (for client previewing). I dev on my local VM and git push my changes, I then SSH into my VPS and do a git pull to keep my two version in sync.
What's strange is the VPS version does not exhibit this issue (i.e. login works fine) yet both versions use an identical codebase except for some minor differences in their respective parameters.yml and parameters_dev.yml files.
Update: Problem started happening after making a large number of edits to the code base and performing a apt-get update and apt-get upgrade on my VM. So in an effort to isolate the possible cause I rolled back to an earlier commit - to see if the problem was code related. But despite rolling back to before my major coding changes, the problem is still there.
This has me thinking the cause may not be code related and instead could be server related, something in the new version of PHP (5.4.28) that was installed via apt-get upgrade perhaps OR a new php.ini directive maybe?
I've run the Symfony configuration checker tool and everything seems fine!
Weird.
I was struggling with the same problem. I checked almost everything and after that suspecion fell on session handler...
I have
session: ~
changed to:
session:
handler_id: ~
More about session handling:
http://symfony.com/doc/2.2/components/http_foundation/session_configuration.html#native-php-save-handlers
This problem happens when the PHPSESSID cookie is changing with each request.
If that is your case then you should check the PHPSESSID response cookies between these request, I bet you that they are changed. Why is that happening, that is the real question!
Let's assume for a moment that the above assertion is true.
By seeing this cookie changing all the time Symfony/PHP assumes that the session manager have created in fact a new user session, obviously that would require the user to re-authenticate (unless RememberMe=true which wouldn't cause a login page redirection).
For instance, while working in dev environment I had no problem with this session issue. However, as soon I switched to prod environment - and by this I mean (1) I flushed the --env=prod cache then (2) I loaded the production /app.php instead /app_dev.php page - it just started to redirect me to the login page after a successful authentication & request.
Obviously at first I thought that there is a configuration problem, perhaps I'm using a different set of params on these environments. But that wasn't the case. So there must be something else, but what?
I've checked the var/session/prod directory and I saw many sess_xxx files. The same in var/session/dev directory. Obviously that is not OK. So I removed the var/session/{prod,dev} entirely then I reloaded the /app.php page. This created 2-3 sess_xxx files in both environment, in prod but also in dev. That is not good. It is a sign that somehow something sends a request to the app_dev.php which will load the dev enviroment which might log out you automatically (based on your app's security/firewall configuration). I opened the app_dev.php and I added an exit(0) then suddenly everything started to work well. So that was what was happening, somehow these environments were mixed and a call to prod would eventually trigger a call to the dev which would log you out immediately.
For a quick fix some people just change the framework::session::save_path to /tmp, which is going to be shared by both environments and thus you are not going to be logged out although your app will somehow still send a request to both the app.php and app_dev.php but since they used the same session folder they think the session is the same (unchanged). So in general this is a quick fix as long the session path is the same for all environments. However this is not the solution to the problem!
One other fix is to not use the app_dev.php in the same time with app.php (or vice-versa) and by that I mean only one file/env at a time. That's also a quick fix and not the solution.
What I did, but I still don't understand what happened, was to remove entirely the web {assetic,css,js,fonts} (or bin/console assetic:dump --env=prod --no-debug) stuff and recreate them again with --env=prod --no-debug. That did the trick but I still don't understand how that could fix it.
I hope the steps above would help you to trace the cause of your problem better than I did :-)
I had the same issue as you.
While #plewandowski's answer solved my issue, the root cause was that the session.save_path as set in PHP's config was a directory with incorrect permissions.
As a sanity check, run
php -i | grep session. and then see if the permissions for the save_path are correct..
In my case, session.save_path => /var/lib/php/sessions => /var/lib/php/sessions
Checking the permissions
vagrant#vps:/var/www/site$ ls -lah /var/lib/php
total 16K
drwxr-xr-x 4 root root 4.0K Aug 5 18:01 .
drwxr-xr-x 56 root root 4.0K Aug 5 20:29 ..
drwxr-xr-x 6 root root 4.0K Aug 5 18:23 modules
drwx-wx-wt 2 root root 4.0K Jul 26 11:05 sessions
In this case, the user under which PHP runs (www) it could not access the directory and caused the issue.
Fixed with sudo chmod 1777 /var/lib/php/sessions/
In Symfony 4, I had this error.
In my entity I didn't have the username and password, just I have to add them.
/** #see \Serializable::serialize() */
public function serialize()
{
return serialize(array(
$this->userId,
$this->userUsername,
$this->userPassword
// see section on salt below
// $this->salt,
));
}
/** #see \Serializable::unserialize() */
public function unserialize($serialized)
{
list (
$this->userId,
$this->userUsername,
$this->userPassword
// see section on salt below
// $this->salt
) = unserialize($serialized, array('allowed_classes' => false));
}
First of all, I've been looking around for informations about this but it was all about Symfony 1.x or even more confusing...
Environment
Symfony 2.3
FOSUserBundle + Custom User entity
Problem
In the web site I'm developing I would like user session to end (= have to log in again) either when they close their browser or after 2 hours.
In the Symfony2 documentation they say that the default timeout is set with the parameter "framework.session.cookie_lifetime" of the config.yml, and that its default value is 0 which means that the session expires when the user closes his browser.
Those options are still on default in my configuration file, but when I a open a session and then close the browser, if I reopen it and go to the website I'm still logged in... So that's where I started getting confused... I tried to force the cookie_lifetime value to 0, but it's the same.
The config.yml with the cookie_lifetime option setted :
framework:
translator: {fallback: %locale%}
secret: %secret%
default_locale: "%locale%"
trusted_proxies: ~
session:
cookie_lifetime: 0
fragments: ~
http_method_override: true
Do you have any idea why this behavior ?
Usually browsers don't end a session if you keep the tab open — even if you restart the browser.