How to redirect back to original Url after OAuth login in Micronaut - security

I'm writing a webapp using micronaut which uses oauth2 to secure the apis. its working well in the sense that the login page from the oauth provider is shown when a secured url is accessed. But after login the page doesn't redirect back to the original requested url, instead it goes bat to '/'. I believe this is because micronaut uses "micronaut.security.session.login-success-target-url" property find the url to go to after login. Since there are multiple secured urls I'd like to auto redirect to the original url if available.
Any help to achieve the same would be appreciated.
Please find below the properties:
---
micronaut:
security:
enabled: true
token:
propogation:
enabled: true
intercept-url-map:
-
pattern: /
http-method: GET
access:
- isAnonymous()
-
pattern: /oauth/**
http-method: GET
access:
- isAnonymous()
-
pattern: /**/login
access:
- isAnonymous()
endpoints:
login:
enabled: false
logout:
enabled: true
session:
enabled: true
login-failure-target-url: /oauth/login/cognito
unauthorized-target-url: /oauth/login/cognito
forbidden-target-url: /oauth/login/cognito
oauth2:
enabled: true
state:
persistence: session
clients:
cognito:
client-secret: '${OAUTH_CLIENT_SECRET}'
client-id: '${OAUTH_CLIENT_ID}'
openid:
issuer: 'https://cognito-idp.${COGNITO_REGION}.amazonaws.com/${COGNITO_POOL_ID}/'
authorization:
display: 'POPUP'
prompt: 'CONSENT'
token:
jwt:
enabled: true
signatures:
secret:
generator:
secret: '${JWT_GENERATOR_SIGNATURE_SECRET:pleaseChangeThisSecretForANewOne}'
endpoints:
oauth:
enabled: true
logout:
enabled: true
get-allowed: true

Related

Symfony 4.4 Security / Session is saved but not used

Full config files are available bellow.
My website is using 2 guards at differents entries :
lexik_jwt_authentication.jwt_token_authenticator to access the ^/api routes
App\Security\LoginAuthenticator to access ^/secured routes
The JWT authetification is working well, allowing users to call a API plateform routes such as localhost/api/types
The problem is about using the LoginAuthenticator session. This is the basic symfony configuration (auto-generated files with php bin/console make:auth)
When login with correct user/password, the guard save a session to app/var/sessions/dev/sess_ras4up86e1c8a1bs9khr5t7scg
When the session is saved and set, the LoginAuthenticator trigger onAuthenticationSuccess function redirecting the user to route name `test.
But the testController is not working, redirecting the user to login page (302 HTTP code). It also throwing the following error in var/log/dev/dev.log :
[2021-07-08 13:07:40] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\\Controller\\SecurityController::login"},"request_uri":"https://krang.local/login","method":"POST"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"login","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Calling getCredentials() on guard authenticator. {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Passing guard token information to the GuardAuthenticationProvider {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] doctrine.DEBUG: SELECT t0.id AS id_1, t0.username AS username_2, t0.password AS password_3, t0.is_active AS is_active_4, t0.roles AS roles_5, t0.customer_id AS customer_id_6 FROM users t0 WHERE t0.username = ? LIMIT 1 ["matthieu"] []
[2021-07-08 13:07:40] security.INFO: Guard authentication successful! {"token":"[object] (Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken: PostAuthenticationGuardToken(user=\"matthieu\", authenticated=true, roles=\"ROLE_USER, ROLE_ADMIN\"))","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator set success response. {"response":"[object] (Symfony\\Component\\HttpFoundation\\RedirectResponse: HTTP/1.0 302 Found\r\nCache-Control: no-cache, private\r\nDate: Thu, 08 Jul 2021 11:07:40 GMT\r\nLocation: /secured/backmarketProducts\r\n\r\n<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"UTF-8\" />\n <meta http-equiv=\"refresh\" content=\"0;url='/secured/backmarketProducts'\" />\n\n <title>Redirecting to /secured/backmarketProducts</title>\n </head>\n <body>\n Redirecting to /secured/backmarketProducts.\n </body>\n</html>)","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Remember me skipped: it is not configured for the firewall. {"authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: The "App\Security\LoginAuthenticator" authenticator set the response. Any later authenticator will not be called {"authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] request.INFO: Matched route "test". {"route":"test","route_parameters":{"_route":"test","_controller":"App\\Controller\\BackMarketController::productsList"},"request_uri":"https://krang.local/secured/backmarketProducts","method":"GET"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"secured","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"secured","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"secured","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): A Token was not found in the TokenStorage. at /home/matthieu/krang/webservice/vendor/symfony/security-http/Firewall/AccessListener.php:69)"} []
[2021-07-08 13:07:40] security.DEBUG: Calling Authentication entry point. [] []
[2021-07-08 13:07:40] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\\Controller\\SecurityController::login"},"request_uri":"https://krang.local/login","method":"GET"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"login","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
[2021-07-08 13:07:40] request.INFO: Matched route "_wdt". {"route":"_wdt","route_parameters":{"_route":"_wdt","_controller":"web_profiler.controller.profiler::toolbarAction","token":"ad25b7"},"request_uri":"https://krang.local/_wdt/ad25b7","method":"GET"} []
We can see this error :
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"secured","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): A Token was not found in the TokenStorage. at /home/matthieu/krang/webservice/vendor/symfony/security-http/Firewall/AccessListener.php:69)"} []
Guard authenticator does not support the request
What does this mean ? I give you some useful code to checkout :
security.yaml : (full file)
security:
encoders:
App\Entity\User:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
guard:
authenticators:
- App\Security\LoginAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
docs:
pattern: ^/docs
stateless: true
anonymous: true
secured:
pattern: ^/secured
stateless: true
provider: entity_provider
guard:
authenticators:
- App\Security\LoginAuthenticator
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }
SecurityController: (unchanged from default)
class SecurityController extends AbstractController
{
/**
* #Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
die();
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
/**
* #Route("/logout", name="app_logout")
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
LoginAuthenticator: (src/Security/LoginAuthenticator.php)
class LoginAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'username' => $request->request->get('username'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['username']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);
if (!$user) {
throw new UsernameNotFoundException('Username could not be found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function getPassword($credentials): ?string
{
return $credentials['password'];
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('test'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
BackMarketController (just a function)
function called on authentification success
/**
* #return JsonResponse
* #Route("/secured/backmarketProducts", name="test")
*/
public function productsList(Request $request)
{
return $this->render('back_market/backmarketProducts.html.twig');
}
About the webserver :
Apache2
Debian 8
using HTTPS
Symfony 4.4
I can give you more informations of course, just ask for it.
What i tried by looking on other similar subjects :
Symfony 4 login Guard authenticator errors (save the session information elsewhere from default)
update project components
Symfony 4 login form : authenticating successfully, but authentication immediately lost after redirect (add EquatableInterface to User entity)
Kill onAuthenticationSuccess BEFORE REDIRECTION show on the profiler that a session is created but cant follow redirection (look at the error above)
UPDATE 1 (3 days later)
I found a way to allow jwt token and securityauthentificator to work together.
There is the security.yaml :
security:
encoders:
App\Entity\User:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
guard:
entry_point: lexik_jwt_authentication.jwt_token_authenticator
authenticators:
- App\Security\SecurityAuthenticator
- lexik_jwt_authentication.jwt_token_authenticator
logout:
path: app_logout
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
docs:
pattern: ^/docs
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
secured:
pattern: ^/secured
anonymous: false
guard:
authenticators:
- App\Security\SecurityAuthenticator
logout:
path: app_logout
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }
I think that block solve the issue, the symfony security compenent got both guards declared on main firewall, using jwt by default.
To use the basic symfony auth system (securityAuthentificator) i just added a secured firewall providing SecurityAuthenticator
Is there a good way to work with security ? Does this trick seems legit ? Im not sure im providing a good solution.
Nobody seems able to help me. In any case I solved the problem on my own.
There is my full functionnal security.yaml :
This config is working, making symfony able to use API PLATEFORM with JWT tokens and to log user on a simple back office application.
security:
encoders:
App\Entity\User:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
guard:
entry_point: lexik_jwt_authentication.jwt_token_authenticator
authenticators:
- App\Security\SecurityAuthenticator
- lexik_jwt_authentication.jwt_token_authenticator
logout:
path: app_logout
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
docs:
pattern: ^/docs
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
secured:
pattern: ^/secured
anonymous: false
guard:
authenticators:
- App\Security\SecurityAuthenticator
logout:
path: app_logout
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }

security configuration: access_denied_url not working

My application is separated in three parts:
administration: ^/backend protected by ip
secured area: ^/member protected by login
public routes: ^/
Everything works fine except the access_denied_url. I tried specifying a route name as well as a plain path.
When I access /backend from an ip other than the configured one I get the following message:
Full authentication is required to access this resource.
500 Internal Server Error - InsufficientAuthenticationException
1 linked Exception: AccessDeniedException ยป
In dev environment this exception isn't catched at all leading to a fatal error but shouldn't the access_denied_url option somehow redirect to the given url anyway?
This is my security.yml:
security:
firewalls:
backend:
pattern: ^/backend
anonymous: ~
access_denied_url: /403
main:
pattern: ^/
anonymous: ~
form_login:
success_handler: my_auth_handler
failure_handler: my_auth_handler
use_referer: true
check_path: login_check
logout:
path: /logout
success_handler: my_auth_handler
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
access_control:
- { path: ^/backend, roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.1] }
- { path: ^/backend, roles: ROLE_NO_ACCESS }
- { path: ^/userlounge, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
providers:
frontend:
id: my_user_provider
encoders:
My\FrontEndBundle\User\MyUser:
algorithm: md5
encode_as_base64: false
iterations: 1
Thanks in advance for any help!
access_denied_url only works when the user's token is not anonymous and rememberme.
For more detail, see:
https://github.com/symfony/symfony/blob/2.6/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php#L120
https://github.com/symfony/symfony/blob/2.6/src/Symfony/Component/Security/Core/Authentication/AuthenticationTrustResolver.php#L65
I think you should try to specify the option access_denied_url on the security node not on the specific firewall (backend) because I think it might be the other firewall throwing the AccessDenied Exception.
Source: http://symfony.com/doc/current/reference/configuration/security.html
Alternatively you can create an AcccessDeniedListener, see this page for a tutorial: http://www.insanevisions.com/articles/view/symfony-2-access-denied-listener

Redirect loop on any url with https in Symfony2

Wherever I try to implement the https channel, there will be an infinite redirect loop. This is what the security.yml file looks like:
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
main:
pattern: .*
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
check_path: /login_check
login_path: /login
default_target_path: /home
logout:
path: /logout
target: /index
security: true
anonymous: true
remember_me:
key: mySecret
lifetime: 604800 #seven days
path: /
domain: ~
access_control:
- { path: ^/js, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/css, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/_wdt, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/_profiler, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/index*, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/.*, role: ROLE_ADMIN }
- { path: ^/.*, roles: ROLE_USER }
For example if I change the admin path to:
- { path: ^/admin/.*, role: ROLE_ADMIN, requires_channel: https }
the loop will occur.
Also in the routing/entity.yml I tried something like this:
entity_index:
pattern: /
defaults: { _controller: MyBundle:Entity:index }
schemes: [https]
Anybody has an idea how to solve this?
I had the same problem because the server was sitting behind a reverse proxy, which commmunicated over ssl with the client, but http with the server the application was running on. I only used this, because the connection between RP and App Server is secure since it doesn't leave the internal network. if you're really positive you really have SSL running and this problem occurs, there's one ugly fix for that... But it's really last resort and to use on your own risk:
you can overwrite the server vars in your app.php like this:
$_SERVER['HTTPS'] = 'on';
$_SERVER['SERVER_PORT'] = 443;
again, this is an ugly fix, not a solution, only use at your only risks and responsibilty, I wouldn't do this if I didn't have the problem with my reverse proxy not forwarding the port and wasn't 100% sure I had SSL between client and RP. Don't forget, this makes you vulnerable if you're not really running valid ssl
For me the problem was not on the side of Symfony but Nginx config was wrong. In case you're using Nginx as well make sure, that you don't have this set:
fastcgi_param HTTPS off; Otherwise set it to on and restart the server. Hope it helps
While it looks like the original poster's issue was a case of HTTPS not being enabled on their development server, I recently encountered a similar issue, and thought I would share how I resolved it.
In my case, my security.yml looked something like this:
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_provider: form.csrf_provider
default_target_path: /dm
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
- { path: ^/dm, role: IS_AUTHENTICATED_REMEMBERED, requires_channel: https }
- { path: ^/dm/*, role: IS_AUTHENTICATED_REMEMBERED, requires_channel: https }
- { path: ^/*, role: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
And in my case, https worked on every page, except any that required any sort of login. Additionally, my javascript and css files I was pulling from google cdn were failing to load. In the end there were two issues with the code that I had:
Issue 1:
Identifying the channel multiple times. In my case, I had a directive in my routing.yml file that was specifying to use http, as well as the one in my security.yml file above, specifying https. This meant that the paths managed by my app (the ones that required me to login) were being routed to https by the security system, which sent it back to the routing system that tried to change it to http, then sent it back to the security system which changed it back to https, infinite redirect loop. By removing the directive in routing.yml, this issue was fixed.
Issue 2:
I was missing one line from my cdn configuration for assetic:
ssl: ['https://ajax.googleapis.com/ajax/libs/']
Placed in config.yml like so:
framework:
#esi: ~
translator: { fallbacks: ["en"] }
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
templating:
engines: ['twig']
#assets_version: SomeVersionScheme
packages:
cdn:
base_urls:
http: ['https://ajax.googleapis.com/ajax/libs/']
ssl: ['https://ajax.googleapis.com/ajax/libs/']
Missing this line meant that assetic ignored my package definition when using ssl, and tried to load the files from my own server, where they didn't exist.

Symfony2 version 2.0.23, login with users from database always return: 'The presented password is invalid'

I'm trying to set up 2 firewall with 2 different providers and encoders in my security.yml that looks like this:
security:
encoders:
Devsign\UserBundle\Entity\AgentUser:
algorithm: sha512
iterations: 5000
encode_as_base64: true
Devsign\UserBundle\Entity\PressUser:
algorithm: sha512
iterations: 5000
encode_as_base64: true
providers:
agent_secured_area:
entity: {class: Devsign\UserBundle\Entity\AgentUser } # using a custom repository to login with username or email, details in AgentUserRepository.php
press_secured_area:
entity: {class: Devsign\UserBundle\Entity\PressUser, property: username }
firewalls:
agent_secured_area:
pattern: /(it|en)/reserved/
provider: agent_secured_area
anonymous: ~
form_login:
check_path: /it/reserved/login-check
login_path: /reserved/login
logout:
path: /reserved/logout
target: /
press_secured_area:
pattern: /(it|en)/press/
provider: press_secured_area
anonymous: ~
form_login:
check_path: /it/press/login-check
login_path: /press/login
logout:
path: /press/logout
target: /
access_control:
agent_login:
path: /reserved/login
roles: IS_AUTHENTICATED_ANONYMOUSLY
agent_register:
path: /reserved/register
roles: IS_AUTHENTICATED_ANONYMOUSLY
agent_area:
path: /(it|en)/reserved/.*
roles: ROLE_AGENT
press_login:
path: /press/login
roles: IS_AUTHENTICATED_ANONYMOUSLY
press_register:
path: /press/register
roles: IS_AUTHENTICATED_ANONYMOUSLY
press_area:
path: /(it|en)/press/.*
roles: ROLE_PRESS
I get no exception but when I try to login against agent_secured_area i get always: 'The presented password is invalid'.
I created the first user password and salt using this code in a controller:
$factory = $this->get('security.encoder_factory');
$user = new \Devsign\UserBundle\Entity\AgentUser();
$encoder = $factory->getEncoder($user);
$salt = $user->getSalt();
$password = $encoder->encodePassword('grab', $salt);
die("pwd: $password - salt: $salt");
And then i fill the database field password and salt with the echoed values.
Can someone spot the error?
UPDATE 1
I made some test setting in the config_dev.yml:
web_profiler:
toolbar: true
intercept_redirects: true
verbose: true
1) I try to go to /it/reserved/info but it is access protected so I'm redirected correctly to /it/reserved/login
2) I try to login from /it/reserved/login posting the form to /it/reserved/login-check
3) Thanks to web_profile: intercepts_redirects: true I can see the debug toolbar in /it/reserved/login-check and I'm correctly authenticated with the correct Role: ROLE_AGENT. By the way looking in the doctrine section of the profiler I see two queries against my user table, the first one with parameter username NULL and a second one with the correct username.
4) Then I'm redirected to /it/reserved/info where for some reason I see a single query against my user table with parameter username NULL. Infact in /it/reserved/info I'm not authenticated anymore. So I'm redirected again to /it/reserved/login.
So I think the problem is that query with parameter username null, someone knows where it's coming from? Maybe from some misconfiguration on security.yml?

app.user is not accessible from unsecured area

How is it possible to get app.user from unsecure area?
So I have secured area which starts from ^/user.
But I need to display logout form on area which is accessible for everyone and not secured. How is this possible? My security.yml:
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
###:
algorithm: sha512
encode-as-base64: true
iterations: 10
###:
algorithm: sha512
encode-as-base64: true
iterations: 10
role_hierarchy:
providers:
admin:
name: admin
entity: { class: ###, property: login }
user:
name: user
entity: { class: ###, property: login }
firewalls:
admin:
pattern: ^/admin
form_login:
login_path: ###_login
check_path: ###_login_process
default_target_path: /admin/dashboard
anonymous: ~
logout:
path: /admin/logout
target: /admin/login
provider: admin
remember_me:
key: "###"
lifetime: 604800
path: /
domain: ~
user:
pattern: ^/user
form_login:
login_path: ###_login
check_path: ###_login_process
default_target_path: ###
anonymous: ~
logout:
path: /user/logout
target: /user/login
provider: user
remember_me:
key: "###"
lifetime: 604800
path: /
domain: ~
access_control:
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, roles: ROLE_ADMIN }
- { path: ^/user/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user/, roles: ROLE_USER }
Well I changed a little bit my security.yml. So currently everything works ok.
user:
pattern: ^/
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
...
UPDATE 1
It seems that line in access_controll is not required. Moreover by some reason(might be cache) anonymoous users were accessing /user areas
You can get app.user in some unsecured area because Symfony security relies on 2 different mechanisms: authentication and authorization.
Authentication is defined by firewalls. As soon as you get under a firewall, you get a token and eventually a app.user, even if it is anonymous.
Authorization is related to access_control rules. It is a second step, you can't put access control rules outside of a firewall. There you will deal with the ROLE requirement, in example if ROLE_ANONYMOUS is enoug, if you want ROLE_USER...
One more thing: to complexify a little further, a firewall can allow or disallow anonymous users. By default it is true, as it is required to have you login and login_check paths under yoru firewall though you cant' require there users to have a role other than ROLE_ANONYMOUS (if you do so, you will have an infinite loop).

Resources