I updated from Symfony 5.3 to Symfony 5.4 and everything that has to do with security seems to have changed.
I was wondering why i get a 401 with Invalid Credentials. Even tho my user is found when i dump my auth.
Here is my AuthTokenProvier
<?php
namespace App\Security;
use App\Entity\User;
use App\Repository\UserAuthTokenRepository;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class AuthTokenUserProvider implements UserProviderInterface
{
/**
* #var UserAuthTokenRepository
*/
private UserAuthTokenRepository $userAuthTokenRepository;
/**
* BraddiveUserProvider constructor.
*
* #param UserAuthTokenRepository $userLoginTokenRepository
*/
public function __construct(
UserAuthTokenRepository $userLoginTokenRepository
) {
$this->userAuthTokenRepository = $userLoginTokenRepository;
}
/**
* #param string $credential
*
* #return UserInterface
*/
public function loadUserByUsername(string $credential): UserInterface
{
return $this->loadUserByIdentifier($credential);
}
/**
* method
*
* #param UserInterface $user
*
* #return UserInterface|User
*/
public function refreshUser(UserInterface $user)
{
/**
* #var $user User
*/
return $this->userAuthTokenRepository->findByAuthToken($user->getUserAuthToken()->getAuthToken());
}
/**
* method
*
* #param string $class
*
* #return bool
*/
public function supportsClass(string $class): bool
{
return $class === self::class;
}
/**
* Loads the user for the given user identifier (e.g. username or email).
*
* This method must throw UserNotFoundException if the user is not found.
*
* #throws UserNotFoundException
*/
public function loadUserByIdentifier(string $identifier): UserInterface
{
$user = $this->userAuthTokenRepository->findByAuthToken($identifier);
if (($user instanceof User) === false) {
throw new AccessDeniedException('Invalid Credentials');
}
return $user;
}
}
In which when i dump my $user I find him.
But when i try to use /api/login I get a 401 Invalid credentials.
And Im not sure why it is.
Here are my JWT yml Configs
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: 2592000 # token TTL in seconds, defaults to 1 hour
user_identity_field: token
And here is my security bundle
security:
enable_authenticator_manager: true
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\BackendUser:
algorithm: auto
App\Entity\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\BackendUser
property: email
auth_token:
id: App\Security\AuthTokenUserProvider
jwt:
id: App\Security\JwtUserProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
provider: auth_token
json_login:
check_path: /api/login
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
custom_authenticators:
- App\Security\UserAuthenticator
api:
pattern: ^/api
stateless: true
provider: jwt
custom_authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
easy_admin:
pattern: ^/admin
lazy: true
provider: app_user_provider
custom_authenticators:
- App\Security\EasyAdminAuthenticator
logout:
path: app_logout
target: app_login
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# Easy Admin Routes
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: IS_AUTHENTICATED_FULLY }
# Api Routes
- { path: ^/api/login, roles: PUBLIC_ACCESS }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
# Translations
- { path: ^/translations, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/translations/grid, roles: IS_AUTHENTICATED_FULLY }
If anyone could tell me what the Problem is or how i can debug better please let me know
Update:
I tried
guard:
- App\Security\UserAuthenticator
Now it says
Unrecognized option "authenticators" under "security.firewalls.guard". Available options are "access_denied_handler", "access_denied_url", "anonymous
", "context", "custom_authenticators", "entry_point", "form_login", "form_login_ldap", "guard", "host", "http_basic", "http_basic_ldap", "json_login"
, "json_login_ldap", "jwt", "lazy", "login_link", "login_throttling", "logout", "methods", "pattern", "provider", "remember_me", "remote_user", "requ
est_matcher", "required_badges", "security", "stateless", "switch_user", "user_checker", "x509".
When i try with custom_authenticators (like it says above)
like so
guard:
custom_authenticators:
- App\Security\UserAuthenticator
I get
Unrecognized option "custom_authenticators" under "security.firewalls.api.guard". Available options are "authenticators", "entry_point", "provider".
Does this make any sense ?
Related
I am trying to implement Gitlab authentication in my Symfony project. These are the list of my files.
GitlabAuthController.php
/**
* Class GitlabAuthController.
* #Route("/api")
*/
class GitlabAuthController extends AbstractController
{
/**
* Link to this controller to start the "connect" process.
*
* #Route("/connect/gitlab", name="connect_gitlab_start")
*
* #param ClientRegistry $clientRegistry
*
* #return RedirectResponse
*/
public function connectAction(ClientRegistry $clientRegistry): RedirectResponse
{
// will redirect to gitlab!
return $clientRegistry
->getClient('gitlab') // key used in config/packages/knpu_oauth2_client.yaml
->redirect()
;
}
security.yaml
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
app_user_provider:
id: App\Security\UserProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: lazy
access_control:
- { path: ^/api/connect, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
But I am receiving following error:
Full authentication is required to access this resource.
Can anybody please help me fix this issue.
Thank You.
Stumped here. Using HWIOAuthBundle to allow social login with FOSUserBundle on Symfony3.
Log in with username and password functions fine, but when authenticating with social logins (in my case, Facebook and LinkedIn), error "Username could not be found" is returned on a redirect to the login page.
Any ideas?
Relevant portions of relevant files:
config.yml
fos_user:
db_driver: orm
firewall_name: main
user_class: AppBundle\Entity\User
hwi_oauth:
firewall_names: [secured_area]
connect:
account_connector: hwi_oauth.user.provider.fosub_bridge
confirmation: true
resource_owners:
facebook:
type: facebook
client_id: xxx
client_secret: xxx
linkedin:
type: linkedin
client_id: xxx
client_secret: xxx
fosub:
username_iterations: 30
properties:
facebook: facebookId
linkedin: linkedinId
security.yml
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:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
secured_area:
anonymous: ~
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
oauth:
resource_owners:
facebook: "/login/check-facebook"
linkedin: "/login/check-linkedin"
login_path: /login
use_forward: false
failure_path: /login
check_path: /login
oauth_user_provider:
service: hwi_oauth.user.provider.fosub_bridge
logout:
path: /logout
main:
pattern: ^/
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/connect$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
routing.yml
fos_user:
resource: "#FOSUserBundle/Resources/config/routing/all.xml"
hwi_oauth_connect:
resource: "#HWIOAuthBundle/Resources/config/routing/connect.xml"
prefix: /login
hwi_oauth_login:
resource: "#HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /login
hwi_oauth_redirect:
resource: "#HWIOAuthBundle/Resources/config/routing/redirect.xml"
prefix: /login
facebook_login:
path: /login/check-facebook
linkedin_login:
path: /login/check-linkedin
User.php
<?php
// src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=200, name="firstName", nullable=true)
*/
protected $firstName;
/**
* #ORM\Column(type="string", length=200, name="lastName", nullable=true)
*/
protected $lastName;
/**
* #ORM\Column(name="facebookId", type="string", length=255, nullable=true)
*/
private $facebookId;
/**
* #ORM\Column(name="linkedinId", type="string", length=255, nullable=true)
*/
private $linkedinId;
private $facebookAccessToken;
public function getFirstName() {
return $this->firstName;
}
public function getLastName() {
return $this->lastName;
}
public function setFirstName($firstName)
{
$this->firstName = $firstName;
return $this;
}
public function setLastName($setLastName)
{
$this->lastName = $setLastName;
return $this;
}
/**
* #param string $facebookId
* #return User
*/
public function setFacebookId($facebookId)
{
$this->facebookId = $facebookId;
return $this;
}
/**
* #param string $linkedinId
* #return User
*/
public function setLinkedinId($linkedinId)
{
$this->linkedinId = $linkedinId;
return $this;
}
/**
* #return string
*/
public function getFacebookId()
{
return $this->facebookId;
}
/**
* #return string
*/
public function getLinkedinId()
{
return $this->linkedinId;
}
/**
* #param string $facebookAccessToken
* #return User
*/
public function setFacebookAccessToken($facebookAccessToken)
{
$this->facebookAccessToken = $facebookAccessToken;
return $this;
}
/**
* #return string
*/
public function getFacebookAccessToken()
{
return $this->facebookAccessToken;
}
public function __construct()
{
parent::__construct();
// your own logic
}
}
I had a similar issue, but it ended up being an issue with the getUser function in my custom guard class not returning a valid user.
So for anyone finding this question, check that your getUser is returning a valid user object, which inherits from the relevant Symfony security user class or implements the relevant UserInterface.
Eg. Symfony\Component\Security\Core\User\UserInterface
I think you have to extend FOS\UserBundle\Entity\User instead of FOS\UserBundle\Model\User.
I have an issue with Symfony authentification.
My security.yml file looks like this :
providers:
corebundle_admin:
entity:
class: CoreAdminBundle:Admin
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
pattern: ^/admin
form_login:
provider: corebundle_admin
login_path: /admin/login
check_path: /admin/login
logout: true
anonymous: true
access_control:
- { path: ^/admin/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, role: ROLE_ADMIN }
And my controller :
/**
* #Route("/login")
* #Method("GET")
*/
public function loginAction() {
return $this->render('CoreAdminBundle:Admin:login.html.twig');
}
/**
* #param Request $request
*
* #Route("/login")
* #Method("POST")
*/
public function checkAction(Request $request) {
// do something
}
Everything works fine, but when i'm trying to send a POST request to /admin/login, the response is a 302 and redirects to /admin/login ...
I'm stuck here, any help will be appreciated.
Thanks
change your login check action to : /login_check or any name expect '/login' it will work
/**
* #Route("/login")
* #Method("GET")
*/
public function loginAction() {
return $this->render('CoreAdminBundle:Admin:login.html.twig');
}
/**
* #param Request $request
*
* #Route("/login_check")
* #Method("POST")
*/
public function checkAction(Request $request) {
// do something
}
edit your security.yml
provider: corebundle_admin
login_path: /admin/login
check_path: /admin/login_check
I'm using Symfony 2.4.3. I've try several methods from many tutorials but still can't make this login works. There are 2 different tables for my login page. mst_pelajar for ROLE_USER with nis field as username and mst_pegawai for ROLE_ADMIN with na field as username.
I can make it works for in_memory username and password definitions. I try to make this login system works by insert plain text into database first. I get bad credentials error with this settings.
Here my security.yml :
security:
encoders:
#Symfony\Component\Security\Core\User\User: plaintext
Sifo\AdminBundle\Entity\MstPelajar: plaintext
Sifo\AdminBundle\Entity\MstPegawai: plaintext
role_hierarchy:
#ROLE_ADMIN: ROLE_USER
#ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
#in_memory:
# memory:
# users:
# user: { password: userpass, roles: [ 'ROLE_USER' ] }
# admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
admin_area:
entity: { class: SifoAdminBundle:MstPegawai, property: na }
user_area:
entity: { class: SifoAdminBundle:MstPelajar, property: nis }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
anonymous: true
alogin:
pattern: ^/admin/login$
security: false
anonymous: true
ulogin:
pattern: ^/user/login$
security: false
anonymous: true
admin_area:
pattern: ^/admin
anonymous: false
form_login:
check_path: /admin/login_check
login_path: /admin/login
logout:
path: /admin/logout
target: /admin
user_area:
pattern: ^/user
anonymous: false
form_login:
check_path: /user/login_check
login_path: /user/login
logout:
path: /user/logout
target: /user
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 }
Entity for admin :
<?php
namespace Sifo\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* MstPelajar
*/
class MstPelajar implements UserInterface, \Serializable
{
/**
* #var integer
*/
private $id;
* #var string
*/
private $nis;
/**
* #var string
*/
private $password;
/**
* #var string
*/
private $salt;
/**
* #var boolean
*/
private $aktif;
/**
* #var \DateTime
*/
private $timestamp;
/**
* #var string
*/
private $operator;
private $username;
/**
* Set id
*
* #param integer $id
* #return MstPelajar
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set nis
*
* #param string $nis
* #return MstPelajar
*/
public function setNis($nis)
{
$this->nis = $nis;
return $this;
}
/**
* Get nis
*
* #return string
*/
public function getNis()
{
return $this->nis;
}
/**
* Set password
*
* #param string $password
* #return MstPelajar
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* #return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Set salt
*
* #param string $salt
* #return MstPelajar
*/
public function setSalt($salt)
{
$this->salt = $salt;
return $this;
}
/**
* Get salt
*
* #return string
*/
public function getSalt()
{
return $this->salt;
}
public function __construct()
{
$this->aktif = true;
// may not be needed, see section on salt below
// $this->salt = md5(uniqid(null, true));
}
public function getUsername()
{
return $this->nis;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function eraseCredentials()
{
}
public function serialize()
{
return serialize(array(
$this->id,
$this->nis,
$this->password,
// see section on salt below
// $this->salt,
));
}
public function unserialize($serialized)
{
list (
$this->id,
$this->nis,
$this->password,
// see section on salt below
// $this->salt
) = unserialize($serialized);
}
}
The user entity almost same with admin, I'll make admin login work first after get the problem. I just show important field at top.
Here my DefaultController for admin :
<?php
namespace Sifo\AdminBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Sifo\AdminBundle\Form\DefaultType;
class DefaultController extends Controller
{
public function indexAction()
{
return $this->render('SifoAdminBundle:Default:index.html.twig');
}
public function loginAction()
{
$request = $this->getRequest();
$session = $request->getSession();
// get the login error if there is one
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} else {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
return $this->render('SifoAdminBundle:Default:login.html.twig', array(
// last username entered by the user
'last_username' => $session->get(SecurityContext::LAST_USERNAME),
'error' => $error,
));
}
}
I just fix my problem. I need to add provider in my firewall. It will be look like this :
security:
encoders:
#Symfony\Component\Security\Core\User\User: plaintext
Sifo\AdminBundle\Entity\MstPelajar: plaintext
Sifo\AdminBundle\Entity\MstPegawai: plaintext
role_hierarchy:
#ROLE_ADMIN: ROLE_USER
#ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
#in_memory:
# memory:
# users:
# user: { password: userpass, roles: [ 'ROLE_USER' ] }
# admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }
admin_area:
entity: { class: SifoAdminBundle:MstPegawai, property: na }
user_area:
entity: { class: SifoAdminBundle:MstPelajar, property: nis }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
anonymous: true
alogin:
pattern: ^/admin/login$
security: false
anonymous: true
ulogin:
pattern: ^/user/login$
security: false
anonymous: true
admin_area:
pattern: ^/admin
provider: admin_area
anonymous: false
form_login:
check_path: /admin/login_check
login_path: /admin/login
logout:
path: /admin/logout
target: /admin
user_area:
pattern: ^/user
provider: user_area
anonymous: false
form_login:
check_path: /user/login_check
login_path: /user/login
logout:
path: /user/logout
target: /user
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 }
I'm trying to connect my app to facebook using FOSOAuthBundle and FOSUserBundle. When connecting to facebook, it works fine and after connect to facebook, the app will be redirect to register form that created by FOSUserBundle in order to create a new user that have been connected to facebook. Now I want my app to create a new user automatically based on facebook user information such as username = facebook username, email = facebook email, etc after my app has successfully connected to facebook. How to do that?
Here is some of my code:
User.php
namespace Wirata\MainBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="users")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="facebook_id", type="string", nullable=true)
*/
private $facebookID;
public function __construct()
{
parent::__construct();
// your own logic
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function setfacebookID($facebookID)
{
$this->facebookID = $facebookID;
return $this;
}
}
Security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
...
providers:
fos_userbundle:
id: fos_user.user_provider.username
...
firewalls:
...
secure_area:
pattern: ^/
oauth:
failure_path: /connect
login_path: /connect
check_path: /connect
provider: fos_userbundle
resource_owners:
facebook: "/login/check-facebook"
oauth_user_provider:
service: hwi_oauth.user.provider.fosub_bridge
anonymous: true
logout:
path: /logout
target: /
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/connect, roles: IS_AUTHENTICATED_ANONYMOUSLY }
config.yml
fos_user:
db_driver: orm
firewall_name: secure_area
user_class: Wirata\MainBundle\Entity\User
registration:
confirmation:
enabled: false
hwi_oauth:
firewall_name: secure_area
connect:
confirmation: true
#account_connector: hwi_oauth.user.provider.fosub_bridge
#registration_form_handler: hwi_oauth.registration.form.handler.fosub_bridge
#registration_form: fos_user.registration.form
resource_owners:
facebook:
type: facebook
client_id: 'xxxxxxx'
client_secret: 'xxxxxxxxxxxxxxxx'
scope: "email"
infos_url: 'https://graph.facebook.com/me?fields=username,name,picture.type(square)'
http_client:
verify_peer: false
fosub:
username_iterations: 30
properties:
facebook: facebookID
You will have to write quite a bit of code in order to achieve what you are looking for. Check out this Gist which contains the solution to your problem and also a nice explanation:
https://gist.github.com/danvbe/4476697
EDIT
In order to get the email from the user in those OAuth resource owners which support it, you will need to define the scope of the data you want to get. For example, for Facebook it would be:
hwi_oauth:
resource_owners:
facebook:
scope: "email"
You will need to see under the resource owner's documentation to see what kind of data you can request in your scope. For Facebook, see this page: https://developers.facebook.com/docs/facebook-login/permissions#categories