How to connect from SonataAdmin authenticator to other authenticator? - php

I have a symfony application which has inside the Sonata Admin Bundle for the admin part, with it's own firewall (admin) and the firewall for the user part of the application (main).
At the moment, the admin which is connected with sonata can't access the API that is designed for the user because it is authenticated for the Sonata Admin Bundle authenticator and for the API it sees him as a null user or not authenticated one.
I want to allow the admin to access an API that is made for the part of the application that is behind the firewall for the user part.
Config for the firewalls in the security.yaml file:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
pattern: ^/admin(.*)
form_login:
provider: app_user_admin
login_path: admin_login
use_forward: false
check_path: admin_login
failure_path: null
logout:
path: admin_logout
target: admin_login
anonymous: true
guard:
authenticators:
- App\Security\AdminLoginAuthenticator
main:
anonymous: true
logout:
path: security_logout
guard:
authenticators:
- App\Security\UserLoginAuthenticator
Is there a way to can connect the two authenticators for the admin? Like, on a success login for the admin to call the authenticator for the main firewall?

After some digging and some help, I found out that symfony security has something like this built in.
It's called Symfony context and does the exact same thing.
For future reference, this is what you really need to add to the config file:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
context: just_a_random_name
pattern: ^/admin(.*)
form_login:
provider: app_user_admin
login_path: admin_login
use_forward: false
check_path: admin_login
failure_path: null
logout:
path: admin_logout
target: admin_login
anonymous: true
guard:
authenticators:
- App\Security\AdminLoginAuthenticator
main:
context: just_a_random_name
anonymous: true
logout:
path: security_logout
guard:
authenticators:
- App\Security\UserLoginAuthenticator

Related

Symfony user login link in chain user providers

I am creating PasswordLess api for my symfony project by following this: https://symfony.com/doc/5.4/security/login_link.html
I have multiple firewalls:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
install:
pattern: ^/installer
security: false
anonymous: true
login:
pattern: ^/user/(login|reset-request|send-email|check-email|auto-login)$
provider: chain_provider
anonymous: true
#login_link: # ERROR HERE
# check_route: login_check
# signature_properties: ['id']
main:
pattern: ^/
provider: chain_provider
form_login:
csrf_token_generator: security.csrf.token_manager
check_path: main_security_check
login_path: main_security_login
use_forward: true
logout:
path: main_security_logout
remember_me:
secret: "%env(APP_SECRET)%"
name: BAPRM
lifetime: 1209600 # stay logged for two weeks
samesite: 'lax'
anonymous: false
But when I try to configure it I get this error:
The old authentication system is not supported with login_link.
How can I make it work, what I am missing here.
I am using Symfony 5.4
Thanks.
As mentionned in the documentation you have to enable the new authenticator system to use login links.
Login links are only supported by Symfony when using the authenticator system. Before using this authenticator, make sure you have enabled it with enable_authenticator_manager: true in your security.yaml file.
So modify your security.yaml to add:
enable_authenticator_manager: true
If you do not use it, for example if you use guards, you will have to replace it with the new system.

Symfony 4: Do not redirect to /login for matching routes

I have a Symfony Application that has two primary sections. / (everything under root e.g. /userProfile) and /api/ (everything under the /api route e.g. /api/userInfo/3).
I'm using Twig to render the actual pages under root, and a simple JsonResponse to render everything under /api. Currently, when a user tries to access any page / resource when they are not logged in, they are redirected to /login and then to the page / resource they requested.
I'd like to alter this behavior for all resources under /api. What I'd like /api/whatever to do is either return the requested resource (if logged in), or return a 401 if not logged in. I'd like to continue to redirect to /login for all other routes.
(NOTE: the /api routes are not "RESTful" API routes per ce. They are "internal" API routes that the UI uses to request data it needs to render the various pages. So it's safe to assume that a user would have logged in via the normal login form prior to their client requesting one of these routes.)
Here's my security.yaml:
security:
providers:
db_provider:
id: database_user_provider
encoders:
App\Utility\Security\DatabaseUser: bcrypt
access_decision_manager:
strategy: unanimous
allow_if_all_abstain: false
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
context: main
form_login:
provider: db_provider
login_path: login
check_path: process_login
default_target_path: manage
use_referer: true
failure_handler: App\Utility\Security\AuthenticationFailureHandler
user_checker: App\Utility\Security\UserChecker
anonymous: ~
logout:
path: logout
target: login
access_denied_handler: App\Utility\Security\AccessDeniedHandler #Turn this off in dev.
# 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: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/forgot, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/%app.locales%, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
I've tried adding a new firewall context of api:
api:
pattern: ^/api
context: main
# If I don't include this (from "main" firewall), I get an error stating no UserAuthenticationListener has been provided for secuirty.firewall.api.
form_login:
provider: db_provider
login_path: login
check_path: process_login
use_referer: true
failure_handler: App\Utility\Security\AuthenticationFailureHandler
Symfony complains if I do not include login_path and check_path.
So, how do I tell Symfony to simply fail and return a 401 when a user is not logged in (or session has expired), when (and only when) they are accessing a route under /api?
Thanks.
To get this working, move the api firewall above main.
We can then set it up on security.yaml with the following structure:
api:
pattern: ^/api
context: main
stateless: false
anonymous: true
guard:
authenticators:
- App\Security\ApiAuthenticator
provider: db_provider
The other thing we need is an implementation of AuthenticatorInterface. e.g. the App\Security\ApiAuthenticator
We only need to implement the following two methods from the interface:
start and supports
public function start(Request $request, AuthenticationException $authException = null)
{
return new Response('', Response::HTTP_UNAUTHORIZED);
}
public function supports(Request $request)
{
return false;
}
Note: The above implementation was tested on Symfony 4 (4.3)
Add the path ^/api with the allowed roles in the access_control section https://symfony.com/doc/current/security.html#add-code-to-deny-access
This is how my security is looking. It's working the way you wanted, just that I use OAuth
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
oauth_token:
pattern: ^/oauth/v2/token
security: false
oauth_authorize:
pattern: ^/oauth/v2/auth
form_login:
provider: fos_userbundle
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
use_referer: true
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
guard:
provider: fos_userbundle
authenticators:
- App\Security\GoogleAuthenticator
- App\Security\FacebookAuthenticator
entry_point: App\Security\LoginFormAuthenticator
i would use the #Security annotaion
https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html

symfony2 configuring the firewall - weird behaviour at login

I am using symfony2 with FOSUserBundle and i am trying to set up correctly my firewall.
I want the major part of my website to not be available to anonymous users. Home page (the $ in the public pattern) and some others should be available according to a pattern.
With my current configuration, after login I am redirected to the home page but still as anonymous. If i directly type a url of a page not allowed to anonymous directly afterwards, I can access it and I am logged (in the profiler).
My configuration:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
public:
pattern: /(login$|register|resetting|public|$)
anonymous: true
main:
pattern: ^/
anonymous: false
provider: main
form_login:
login_path: fos_user_security_login
check_path: fos_user_security_check
logout:
path: fos_user_security_logout
target: /
What can I do to make it work properly (logged correctly after login).
EDIT:
I understand better what is happening: after login, I am being redirected to the home page=root address. This falls first into the public firewall and that's whay I'm not seen as connected.
Well you always can hardcode the path that you're redirected after login (in your security.yml file). You can read more here
security:
firewalls:
main:
form_login:
default_target_path: default_security_target
Done! Solution involves the context property of the firewall which is better described here :
Authenticate multiple symfony2 firewalls with one login form
My configuration now becomes:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
guest:
pattern: /(user/login$|user/register|user/resetting|$)
anonymous: true
context: main_auth
main:
pattern: ^/(?!user/login$)
anonymous: false
provider: main
context: main_auth
form_login:
login_path: fos_user_security_login
check_path: fos_user_security_check
logout:
path: fos_user_security_logout
target: /
remember_me:
key: "%secret%"
lifetime: 86400 # 365 jours en secondes
path: /
domain: ~ # Prend la valeur par défaut du domaine courant depuis $_SERVER
oauth:
remember_me: true
resource_owners:
facebook: "/loginhwi/check-facebook"
github: "/loginhwi/check-github"
google: "/loginhwi/check-google"
twitter: "/loginhwi/check-twitter"
linkedin: "/loginhwi/check-linkedin"
flickr: "/loginhwi/check-flickr"
login_path: fos_user_security_login
check_path: fos_user_security_check
failure_path: fos_user_security_login
success_handler: foodmeup_user.handler_auth
oauth_user_provider:
service: fosubuser.provider

Symfony session, different route, different session

So, i have two differents route on my project :
/memberarea
/mobile
The first is for the web version on my application, and the second is for the mobile version.
Here you can see a part of my security.yml :
firewalls:
main:
pattern: ^/
form_login:
login_path: /
provider: fos_userbundle
csrf_provider: form.csrf_provider
default_target_path: /memberarea
logout: true
anonymous: true
mobile:
pattern: /mobile/.*
logout: true
anonymous: true
access_control:
- { path: ^/memberarea, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/mobile, roles: IS_AUTHENTICATED_FULLY }
My problem, when a user login on mobile, i create a session on symfony with the firewall mobile like : $token = new UsernamePasswordToken($user, $request->get('password'), "mobile", $user->getRoles());.....
this user can use all route in /mobile, it's ok. But he can use /memberarea too.
How can i do for login a user just for /mobile, just for /memberarea or for both ?
If I have correctly understood, you want to log into your mobile application with a different session than on your web application.
What I am doing in order to obtain this result is setting up in my security.yml file a different context for each firewall I have.
(If you want to have one session for both you must have the context with the same value for the given firewalls.)
File: app/config/security.yml
firewalls:
main:
pattern: ^/
**context: user**
form_login:
login_path: /
provider: fos_userbundle
csrf_provider: form.csrf_provider
default_target_path: /memberarea
logout: true
anonymous: true
mobile:
pattern: /mobile/.*
*context: mobile_user*
logout: true
anonymous: true
Hope this helped.

Symfony Security: Auth with session or oauth

I have developed a REST API, there are two ways to connect to it: session and oauth.
Basically, my website will use the session mode and third-party softwares will use the oauth mode.
I managed to make make both session and oauth modes to work in symfony, but I can't make them work at the same time.
Here is my firewalls security config:
firewalls:
auth_oauth_token:
pattern: ^/auth/oauth/v2/token
security: false
api:
pattern: ^/api
anonymous: false
fos_oauth: true
stateless: true
auth:
pattern: ^/
anonymous: ~
form_login:
login_path: /auth/session/check
check_path: /auth/session/login
always_use_default_target_path: true
default_target_path: /auth/session/check
failure_path: /auth/session/check
failure_forward: false
use_forward: false
failure_forward: false
username_parameter: username
password_parameter: password
post_only: true
remember_me: false
require_previous_session: false
logout:
path: /auth/session/logout
target: /auth/session/logged_out
invalidate_session: false
Session handling: /auth/session.
OAuth handling: /auth/oauth.
Api: /api.
So, with this config, with "api" firewall first, I can log in with a token.
But even logged in with a session, if I don't specify the token, I won't have access.
With "auth" firewall first, I can log in with the session form.
But even if I specify a token, I won't have access.
I'm getting crazy with this. I found on stack overflow something about chain providers, I would probably need something like "chain firewall"... if forbidden, check another firewall.
Thank you
I solved by duplicating the routes of the api controllers, so that I have a route /api/method which relies on OAuth2, and a /webapi/method route which relies on the standard (main) firewall:
In security.yml:
firewalls:
api:
pattern: ^/api
fos_oauth: true
stateless: true
oauth_token:
pattern: ^/oauth/v2/token
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /login
check_path: /login_check
logout: true
anonymous: true
access_control:
- { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }
- { path: ^/web-api, roles: [ IS_AUTHENTICATED_FULLY ] }
In routing.yml:
acme_api:
type: rest
prefix: /
resource: "#AcmeBundle/Resources/config/routing_api.yml"
In routing_api.yml:
# REST API - OAUTH Access
acme_api_users:
resource: AcmeBundle\Controller\UsersController
type: rest
defaults: {_format: json}
prefix: /api
name_prefix: api_
# REST API - Frontend Client Access
acme_webapi_users:
resource: AcmeBundle\Controller\UsersController
type: rest
defaults: {_format: json}
prefix: /web-api
name_prefix: webapi_

Categories