I would like to know if from the same login form we could connect from two tables: User and Player
Here is my attempt.
security:
encoders:
App\Entity\User:
algorithm: auto
App\Entity\Player:
algorithm: auto
providers:
chain_provider:
chain:
providers: [mon_provider_player, mon_provider_user]
mon_provider_player :
entity:
class: App\Entity\Player
property: email
mon_provider_user :
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
player:
anonymous: lazy
provider: mon_provider_player
form_login:
login_path: login
check_path: login
success_handler: redirect.after.login
logout:
path: logout
target: login
main:
anonymous: lazy
provider: mon_provider_user
form_login:
login_path: login
check_path: login
success_handler: redirect.after.login
logout:
path: logout
target: login
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 an par défaut
path: /
domain: ~ # Defaults to the current domain from $_SERVER
access_control:
- { path: ^/pol, roles: ["ROLE_POLISTE"] }
- { path: ^/user, roles: ["ROLE_USER"] }
I found the solution. Here to help if needed
Everything happens in the file: loginFormAuthenticator.php which extends AbstractFormLoginAuthenticator in symfony.
There are 5 methods, one of which allows the $user in several tables.
public function getUser($credentials, UserProviderInterface $userProvider)
{
$userFound = $this->userRepository->findOneBy(['email' => $credentials['email']]);
if ($userFound !== NULL) {
return $userFound;
} else {
return $this->playerRepository->findOneBy(['emailJoueur' =>
$credentials['email']]);
}
}
Related
I'm working on a project with Symfony 5.
I created the User entity, created the authentication flow on security.yaml and all works well: if user wants to access to protected area, login page was shown and authentication process works! So good!
Now, I want to build an API REST with FOSRest Bundle.
I've created a specific controller for expose some routes:
/**
* #Rest\Route("/api")
*
*/
class APICustomController extends AbstractController
{
...
/**
* #Rest\Get("/shoes")
* #param Request $request
* #Method({"GET"})
*
* #return JsonResponse
*/
public function getShoes(Request $request){
....
return JsonResponse::fromJsonString(array('msg' => 'OK'));
}
}
Here my security.yaml
security:
enable_authenticator_manager: true
encoders:
App\Entity\User:
algorithm: auto
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_VIEWER: ROLE_USER
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: username
api_user_provider:
entity:
class: App\Entity\User
property: api_token
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
guard:
authenticators:
- App\Security\DealmapLoginAuthenticator
logout:
path: app_logout
api:
stateless: true
lazy: true
guard:
authenticators:
- App\Security\TokenAuthenticator
pattern: ^/api/
provider: api_user_provider
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, role: IS_AUTHENTICATED_FULLY }
I followed the steps given here: https://symfony.com/doc/current/security/guard_authentication.html
The problem is the call below
curl -X GET \
http://www.example.com/api/shoes \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-H 'x-auth-token: test'
it is protected by the main firewall (so it returns me the login page), and not by api as expected. I expect to receive an error message in json format.
What's wrong??
Thanks in advance
OK, I found the solution!
I'm posting it here in case someone might need it in the future.
The configuration was all correct, but the reason why the path /api/shoes was managed by the main firewall was due to the order of execution of the rules.
The firewall main handles all the rules, while the api one handles only the ones with the ^/api pattern, so the most stringent rules should go first in the firewall definition in the security.yaml, as below:
security:
enable_authenticator_manager: true
encoders:
App\Entity\User:
algorithm: auto
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_VIEWER: ROLE_USER
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: username
api_user_provider:
entity:
class: App\Entity\User
property: api_token
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api:
stateless: true
lazy: true
guard:
authenticators:
- App\Security\TokenAuthenticator
pattern: ^/api/
provider: api_user_provider
main:
lazy: true
provider: app_user_provider
guard:
authenticators:
- App\Security\DealmapLoginAuthenticator
logout:
path: app_logout
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, role: IS_AUTHENTICATED_FULLY }
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_
I installed HWIOAuthBundle.
But I have this error when I try to login with Google Account :
No ressource owner with name 'check-google'.
And I have the same kind of errror with the others API (Facebook, twitter...)
This is my security.yml :
firewalls:
main:
pattern: ^/login$
security: true
anonymous: true
provider: user_provider
form_login:
login_path: fos_user_security_login
check_path: fos_user_security_check
logout:
path: fos_user_security_logout
target: /
oauth:
resource_owners:
facebook: "/login/check-facebook"
google: "/login/check-google"
twitter: "/login/check-twitter"
linkedin: "/login/check-linkedin"
login_path: /login
check_path: /login
failure_path: /login
oauth_user_provider:
#this is my custom user provider, created from FOSUBUserProvider - will manage the
#automatic user registration on your site, with data from the provider (facebook. google, etc.)
service: my_user_provider
My routing.yml :
#HWIOAuthBundle routes
hwi_oauth_security:
resource: "#HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /connect/by
hwi_oauth_connect:
resource: "#HWIOAuthBundle/Resources/config/routing/connect.xml"
prefix: /connect/by
hwi_oauth_redirect:
resource: "#HWIOAuthBundle/Resources/config/routing/redirect.xml"
prefix: /login
facebook_login:
pattern: /login/check-facebook
options: { i18n: false }
google_login:
pattern: /login/check-google
options: { i18n: false }
twitter_login:
pattern: /login/check-twitter
linkedin_login:
pattern: /login/check-linkedin
and my config.yml :
# HWIOAuthBundle
hwi_oauth:
connect:
account_connector: my_user_provider
firewall_name: main
fosub:
username_iterations: 30
properties:
# these properties will be used/redefined later in the custom FOSUBUserProvider service.
facebook: facebook_id
google: google_id
twitter: twitter_id
linkedin: linkedin_id
resource_owners:
facebook:
type: facebook
client_id: xxxxx
client_secret: xxxxx
scope: ""
options:
display: popup
google:
type: google
client_id: xxxx
client_secret: xxxx
scope: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
twitter:
type: twitter
client_id: xxxx
client_secret: xxxx
scope: ""
linkedin:
type: linkedin
client_id: xxxx
client_secret: xxxx
scope: "r_basicprofile"
services:
hwi_oauth.user.provider.entity:
class: HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUserProvider
cmf_create.persistence.orm.object_mapper:
class: Midgard\CreatePHP\Mapper\DoctrineOrmMapper
arguments:
- "%cmf_create.map%"
- "#doctrine"
My problem is same than No resource owner with name 'google' (HWIOAuthBundle & FOSUserBundle integration). How can i fix this ?
my best bet is that your firewall is not active on "login with *" URLs
try change:
pattern: ^/login$
I personaly use firewall to all URLs:
pattern: ^/
and explicitly set public urls:
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/add, role: ROLE_USER }
I have been running into the same issue:
No ressource owner with name 'check-google'.
For me it was solved by changing the routing.yml to this:
google_login:
pattern: /api/login/check/google
I resolved this issue. I found this link helpfull :
http://m2mdas.github.io/blog/2013/11/21/integrate-hwioauthbundle-with-fosuserbundle/
In the above link, After I added cacert.pem to the path, it resolved the issue.
HWIOAuthBundle uses Buzz curl client to communicate with web services. Buzz by default enables SSL certificate check. On some server CA certificate information may not exist. To add CA certificate info download cacert.pem from this page and set curl.cainfo php ini variable to the location of cacert.pem e.g
curl.cainfo = /path/to/cacert.pem
and I missed the above step.
Regards,
Mk6ix
After setting up Symfony2.2, I have the following code in my login form:
<input type="hidden" name="_target_path" value="{{path('rok_admin_default_index')}}"/>
Where rok_admin_default_index is pointing to "/" so it's basically the homepage of the application. During the development I'm using app_dev.php (which I obviously), but after successful login in dev environment Symfony redirects me to domain.com/app_dev.php/app_dev.php/ instead of domain.com/app_dev.php/
My security.yml:
jms_security_extra:
secure_all_services: false
expressions: true
security:
encoders:
ROK\AdminBundle\Entity\User: sha512
role_hierarchy:
ROLE_MOD: ROLE_USER
ROLE_ADMIN: [ROLE_MOD, ROLE_USER]
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class: ROK\AdminBundle\Entity\User, property: email }
in_memory:
memory:
users:
user: { password: userpass, roles: [ 'ROLE_USER' ] }
mod: {password: modpass, roles: ['ROLE_MOD']}
admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login$
security: false
secured_area:
pattern: ^/admin/
form_login:
check_path: login_check
login_path: login
logout: ~
#anonymous: ~
#http_basic:
# realm: "Secured Demo Area"
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN}
The symfony2 documentation says
The value attribute can be a relative path, absolute URL, or a route
name.
So we can try the second and third options
Use absolute path
<input type="hidden" name="_target_path" value="{{url('rok_admin_default_index')}}"/>
Or Use route name
<input type="hidden" name="_target_path" value="rok_admin_default_index"/>
Hi everyone and huge thanks for the help,
I am trying to get FOSFacebook work, but it seems to be impossible until now.
I tried a lot of configuration, and a lot of fix but nothing worked for me.
Here is my configuration :
security.yml
chain_provider:
chain:
providers: [fos_userbundle, fos_facebook_provider]
fos_userbundle:
id: fos_user.user_provider.username
fos_facebook_provider:
id: fos.facebook.custom_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
login_path: fos_user_security_login
check_path: fos_user_security_check
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout: true
anonymous: true
public:
pattern: ^/
fos_facebook:
app_url: "http://apps.facebook.com/myApp/"
server_url: "http://www.mywebsite.com"
login_path: /facebook/login
check_path: /facebook/check
default_target_path: /
provider: fos_facebook_provider
anonymous: false
logout:
handlers: ["fos_facebook.logout_handler"]
config.yml
fos.facebook.custom_provider:
class: Bundles\UserBundle\Security\User\Provider\FacebookProvider
arguments:
facebook: "#fos_facebook.api"
userManager: "#fos_user.user_manager"
validator: "#validator"
container: "#service_container"
fos_facebook:
file: %kernel.root_dir%/../vendor/facebook/php-sdk/src/base_facebook.php
alias: facebook
app_id: myid
secret: mysecret
cookie: true
permissions: [email]
routing.yml
_security_check:
pattern: /facebook/check
_security_logout:
pattern: /logout
Twig Template
<script type="text/javascript">
function goLogIn(){
window.location.href = "{{ path('_security_check') }}";
}
function onFbInit() {
if (typeof(FB) != 'undefined' && FB != null ) {
FB.Event.subscribe('auth.statusChange', function(response) {
if (response.session || response.authResponse) {
setTimeout(goLogIn, 500);
} else {
window.location.href = "{{ path('_security_logout') }}";
}
});
}
}
</script>
{{ facebook_initialize({'xfbml': true, 'fbAsyncInit': 'onFbInit();'}) }}
UserController.php
* #Route("/facebook/check")
*/
public function loginCheckFacebookAction(){
}
And the provider and the modification to User class (as in the Readme).
But the problem is that the service not seemed to be called. Indeed, the method in the UserController must be a dummy method, and it is not like that here.
The method is called and of course I get this error :
LogicException: The controller must return a response (null given). Did you forget to add a return statement somewhere in your controller? (uncaught exception).
What is my error here ?
Remove your UserController route/action loginCheckFacebookAction