Symfony 3 JWT Token Authentication Error with User Provider - php

I have a Problem with my JWT Token Authentication. I am pretty new in Symfony and if I add an User Provider to my User Entity the Token Authentication doesn't work and you don't need a token in the header anymore => Access to anything. But if I remove the User Provider I get this message on every second request but the other request works fine with the token:
"There is no user provider for user "AppBundle\Entity\TbluserBase"
Can someone help me please or suggest some tutorials for this problem? I think I am missing or have to change something in my securtiy file.
JWT Authenticator
class JWT_Authenticator extends AbstractGuardAuthenticator {
private $Entity_Manager;
private $JWT_Encoder;
public function __construct(EntityManager $em, DefaultEncoder $jwt_Encoder) {
$this->Entity_Manager = $em;
$this->JWT_Encoder = $jwt_Encoder;
}
public function start(Request $request, AuthenticationException $authException = null) {
$error = ['error' => 'Auth header required'];
return new JsonResponse($error, 401);
}
public function getCredentials(Request $request) {
if (!$request->headers->has('Authorization')) return;
$extractor = new AuthorizationHeaderTokenExtractor(
'Bearer',
'Authorization'
);
$token = $extractor->extract($request);
if(!$token) return;
return $token;
}
public function getUser($credentials, UserProviderInterface $user_Provider) {
$data = $this->JWT_Encoder->decode($credentials);
if (!$data) return;
$username = $data['usrnickname'];
$user = $this->Entity_Manager
->getRepository('AppBundle:TbluserBase')
->findOneBy(['usrnickname' => $username]);
if (!$user) return;
return $user;
}
public function checkCredentials($credentials, UserInterface $user) { return true; }
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) {
return new JsonResponse([
'message' => $exception->getMessage()
], 401);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { return; }
public function supportsRememberMe() { return false; }
}
Security
security:
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 15
FOS\UserBundle\Model\UserInterface:
algorithm: bcrypt
cost: 15
AppBundle\Entity\TbluserBase:
algorithm: bcrypt
cost: 15
harsh:
algorithm: bcrypt
cost: 15
# http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers:
in_memory:
memory: ~
base_users:
id: app.user_provider
firewalls:
api:
pattern: ^/api/(?!Get_Token)
guard:
authenticators:
- app.jwt_token_authenticator
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
http_basic: ~
# activate different ways to authenticate
# http://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
#http_basic: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
#form_login: ~
access_control:
- { path: /api/Get_Token, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: [ROLE_USER, ROLE_API_USER] }
Services
parameters:
#parameter_name: value
services:
app.user_provider:
class: AppBundle\Security\UserBaseProvider
app.jwt_token_authenticator:
class: AppBundle\Security\JWT_Authenticator
arguments: ['#doctrine.orm.entity_manager', '#lexik_jwt_authentication.encoder.default']
#service_name:
# class: AppBundle\Directory\ClassName
# arguments: ['#another_service_name', 'plain_value', '%parameter_name%']
User Provider
class UserBaseProvider implements UserProviderInterface
{
public function loadUserByUsername($username)
{
$user = new TbluserBase();
$user->setUsrnickname($username);
return $user;
}
public function refreshUser(UserInterface $user)
{
return $user;
}
public function supportsClass($class)
{
return $class == 'AppBundle\Entity\TbluserBase';
}
}
I worked with these tutorials:
https://kolabdigital.com/lab-time/symfony-json-web-tokens-authentication-guard
https://de.slideshare.net/weaverryan/symfony-guard-authentication-fun-with-api-token-social-login-jwt-and-more

Related

TwoFactorsAuthenticator not connect after second authenticate

here is my problem, I have to put a two-factor authentication. When I fill the first form no worries in the profiler I find my user connected, but when I scan the qrcode of the second form it tells me that the code provided is good but it sends me back to the first page of connection without user in the profiler as if I was disconnected
Could you help me
My Class LOGIN with email & password
class AppCustomAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
public function __construct(private readonly UrlGeneratorInterface $urlGenerator){}
public function authenticate(Request $request): Passport
{
$email = $request->get('login')['email'];
$request->getSession()->set(Security::LAST_USERNAME, $email);
return new Passport(
new UserBadge($email),
new PasswordCredentials($request->get('login')['password']),
[
new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
]
);
}
/**
* #throws Exception
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
return new RedirectResponse($this->urlGenerator->generate('app_security_setup_fa'));
}
protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
My Class TwoFactorsAuthenticator
class TwoFactorsAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_security_setup_fa';
public function __construct(private TokenStorageInterface $tokenStorage, private UrlGeneratorInterface $urlGenerator)
{
}
public function supports(Request $request): bool
{
return parent::supports($request)
&& $request->getSession()->has(SecurityController::QR_CODE_KEY);
}
/**
* #throws IncompatibleWithGoogleAuthenticatorException
* #throws SecretKeyTooShortException
* #throws InvalidCharactersException
*/
public function authenticate(Request $request): Passport
{
//Get user from login form
$existingToken = $this->tokenStorage->getToken();
if (null === $existingToken || $existingToken instanceof NullToken) {
throw new UserNotFoundException();
}
$user = $existingToken->getUser();
$qrCode = $request->request->get('qrCode', '');
$secretKey = $request->getSession()->get(SecurityController::QR_CODE_KEY);
$google2fa = new Google2FA();
$google2fa->setSecret($secretKey);
$google2fa->setWindow(1);
if (true !== $google2fa->verifyKey($google2fa->getSecret(), $qrCode)) {
throw new CustomUserMessageAuthenticationException('This code is not valid');
}
$email = $user->getUserIdentifier();
return new SelfValidatingPassport(
new UserBadge($email)
);
}
public function createToken(Passport $passport, string $firewallName): TokenInterface
{
$currentToken = parent::createToken($passport, $firewallName);
$roles = array_merge($currentToken->getRoleNames(), [DoubleAuthentificationSubscriber::ROLE_2FA_SUCCEED]);
return new PostAuthenticationToken(
$currentToken->getUser(),
$currentToken->getFirewallName(),
$roles
);
}
protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
$this->removeTargetPath($request->getSession(), $firewallName);
}
return new RedirectResponse($this->urlGenerator->generate('app_security_authentification_protected'));
}
}
My Class DoubleAuthentificationSubscriber
class DoubleAuthentificationSubscriber implements EventSubscriberInterface
{
public const ROLE_2FA_SUCCEED = 'ROLE_2FA_SUCCEED';
public const FIREWALL_NAME = 'main';
public function __construct(private RouterInterface $router, private TokenStorageInterface $tokenStorage)
{
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['onKernelRequest', -10],
];
}
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMainRequest()) {
return;
}
$route = $event->getRequest()->attributes->get('_route');
if (!in_array($route, ['app_security_authentification_protected'], true)) {
return;
}
$currentToken = $this->tokenStorage->getToken();
if (!$currentToken instanceof PostAuthenticationToken) {
$response = new RedirectResponse($this->router->generate('app_login'));
$event->setResponse($response);
return;
}
if (null === $currentToken->getUser() || self::FIREWALL_NAME !== $currentToken->getFirewallName()) {
return;
}
if ($this->hasRole($currentToken, self::ROLE_2FA_SUCCEED)) {
return;
}
$response = new RedirectResponse($this->router->generate('app_security_setup_fa'));
$event->setResponse($response);
}
private function hasRole(TokenInterface $token, string $role): bool
{
return in_array($role, $token->getRoleNames(), true);
}
}
My security.yaml
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
entry_point: App\Security\AppCustomAuthenticator
custom_authenticator:
- App\Security\AppCustomAuthenticator
- App\Security\TwoFactorsAuthenticator
logout:
path: app_logout
# where to redirect after logout
target: app_login
# 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: ^/login, roles: PUBLIC_ACCESS }
- { path: ^/logout, roles: PUBLIC_ACCESS }
- { path: ^/setup-2FA, roles: ROLE_USER }
when#test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
I've tried removing the double authentication and I'm able to log in.
But as soon as I put it back on, it loops on the authentication.

How to authenticate route with JWT token?

I am working on JWT Token authentication in symfony. After login, I have already got a valid token valid for 5 minutes.
What I need is mandatory pass Bearer TOKEN in other routes.
I tried in Postman, without Authorization, it is giving me result.
How can I make the token mandatory for the routes.
These are the codes, I have tried.
TokenAuthenticator.php
class TokenAuthenticator extends AbstractGuardAuthenticator
{
public function __construct(
private string $jwtSecret,
private EntityManagerInterface $entityManager
) {
}
public function start(Request $request, AuthenticationException $authException = null): JsonResponse
{
$data = [
'message' => 'Authentication Required'
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
public function supports(Request $request): bool
{
return $request->headers->has('Authorization');
}
public function getCredentials(Request $request)
{
return $request->headers->get('Authorization');
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
try {
$credentials = str_replace('Bearer ', '', $credentials);
$decodedJwt = (array) JWT::decode(
$credentials,
new Key($this->jwtSecret, 'HS256')
);
return $this->entityManager
->getRepository(User::class)
->findOneBy([
'username' => $decodedJwt['user'],
]);
} catch (Exception $exception) {
throw new AuthenticationException($exception->getMessage());
}
}
public function checkCredentials($credentials, UserInterface $user): bool
{
return true;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse
{
return new JsonResponse([
'message' => $exception->getMessage()
], Response::HTTP_UNAUTHORIZED);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
{
return;
}
public function supportsRememberMe(): bool
{
return false;
}
}
security.yaml
security:
enable_authenticator_manager: true
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
encoders:
App\Entity\User:
algorithm: bcrypt
providers:
user_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: user_provider
pattern: ^/api
guard:
authenticators:
- App\Security\TokenAuthenticator
logout:
path: api_logout
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
Can anybody help me, what I am missing ?
You can restrict access to routes in the security.yaml file by declaring your route in access_control with the IS_AUTHENTICATED_FULLY parameter.
Example:
access_control:
- { path: ^/authentication_token, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/admin/, roles: ROLE_ADMIN }
Route '/authentication_token' : everyone is allowed access
Route '/api/' : access is allowed only to authorized users (the role does not matter)
Route '/admin/' : access is allowed only to authorized users with the ROLE_ADMIN role
Note: This is described in more detail in the official symfony documentation.

PHPUnit - Symfony authorization with x-api-key

I am using PHPUnit test to write functional test for specific endpoint.
Problem with it is that for the authorization process I have to set X-API-KEY in headers section of the request.
I keep getting an error:
Authentication Required
I am using an valid api key form my test database table and it return this specific error I mentioned above.
public function testDoItSuccessful()
{
$client = static::createClient(
[],
['HTTP_x-api-key' => 'clWD0ggquG1Ok2xOVLIcMmPJtu1uYWG']
);
$client->request(
Request::METHOD_POST,
'/api/v1/do-it',
[],
[],
[
'CONTENT_TYPE' => 'application/json',
'ACCEPT' => 'application/json',
],
json_encode($myArray)
);
return $client;
}
As I am new, primarily with authorization process in test env any help is highly appreciated.
Note: I am using Symfony 4.4
I tried THIS.
Error is coming for these two functions in TokenAuthenticator class.
public function supports(Request $request)
{
$hasApiKey = true;
$requestHeaders = $this->getLowerCasedHeaders();
if (!isset($requestHeaders['x-api-key'])) {
$hasApiKey = false;
}
return $hasApiKey;
}
private function getLowerCasedHeaders()
{
$requestHeaders = getallheaders();
return array_change_key_case($requestHeaders, CASE_LOWER);
}
public function getCredentials(Request $request)
{
$requestHeaders = $this->getLowerCasedHeaders();
return $requestHeaders['x-api-key'];
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
if (null === $credentials) {
// Code 401 "Unauthorized"
return null;
}
return $this->entityManager->getRepository(Client::class)->findOneBy(['apiKey' => $credentials]);
}
public function checkCredentials($credentials, UserInterface $user)
{
if ($user->getStatus() != Client::STATUS_ACTIVE) {
throw new AuthenticationException("USER_NOT_ACTIVE", 403);
}
$user->setLastSeen(new DateTime('now'));
$this->entityManager->persist($user);
$this->entityManager->flush();
return true;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$data = [
'message' => 'Authentication failed, wrong api key'
];
if ($exception->getCode() == 403) {
$data = ['message' => $exception->getMessage()];
}
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
public function start(Request $request, AuthenticationException $authException = null)
{
$data = [
// you might translate this message
'message' => 'Authentication Required'
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
public function supportsRememberMe()
{
return false;
}
I have changed apache_request_headers() to getallheaders() and tests are passing with Authentication Required message.
When print_r() the:
$requestHeaders = $this->getLowerCasedHeaders();
I can not see my defined headers from request? It returns Array()..
You need to check how the Client Class parse the headers, specially on the test, there is a part where the code execute a search for the word HTTP_ for the custom header. So basically on your test instead of call only x-api-key you need to add the prefix HTTP_. Try with this:
TokenAuthenticator
public function supports(Request $request)
{
return $request->headers->has('x-api-key');
}
On your test:
public function testDoItSuccessful()
{
crawler = $this->client->request(
Request::METHOD_POST,
'/api/v1/do-it',
[],
[],
['HTTP_x-api-key' => self::TOKEN, 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json']
);
$status = $this->client->getResponse()->getStatusCode();
}
For me what worked is to return a UserInterface with the role defined in your security:
access_control:
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: ROLE_API }
My firewall:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api:
pattern: ^/api/
custom_authenticators:
- App\CrediFastCore\Infrastructure\Security\ApiKeyAuthenticator
Since we need ROLE_API
public function authenticate(Request $request): Passport
{
$apiToken = $request->headers->get('X-AUTH-TOKEN');
if (null === $apiToken) {
throw new CustomUserMessageAuthenticationException('No API token provided');
}
if ($this->parameters->get('api_key') != $apiToken) {
//I compare api token with the one I've set on my parameters.yaml
throw new CustomUserMessageAuthenticationException('Wrong API token provided');
}
$user = new User();
$user->setName('api');
$user->setRoles(['ROLE_API']);
return new SelfValidatingPassport(
new UserBadge($apiToken, function () use ($user, $apiToken) {
return $user;
})
);
}
This part was the "fix"
return new SelfValidatingPassport(
new UserBadge($apiToken, function () use ($user, $apiToken) {
return $user;
})
);

Symfony 3 Custom Form Password Authenticator

I'm trying to authenticating via the Custom Form Password Authenticator, I follow the Symfony Example at this page: Custom Form Password Authenticator, I changed a few snippet for put my authentication logic. All seem to work perfectly... But Symfony continued telling me that I'm authenticated as anonymous... Here is the code:
My Custom Athenticator:
class SippyAuthenticator implements SimpleFormAuthenticatorInterface
{
private $sippyAccounts;
public function __construct(SippyAccounts $sippyAccounts)
{
$this->sippyAccounts = $sippyAccounts;
}
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
$result = $this->sippyAccounts->login($token->getUsername(), $token->getCredentials());
if($result->isError()) {
throw new CustomUserMessageAuthenticationException('Invalid username or password');
} else {
$roles = array('ROLE_ACCOUNT');
$user = new User($token->getUsername(), $token->getCredentials(), $roles);
$tokenNew = new UsernamePasswordToken( $user, $user->getPassword(), $providerKey, $user->getRoles());
return $tokenNew;
}
}
public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof UsernamePasswordToken
&& $token->getProviderKey() === $providerKey;
}
public function createToken(Request $request, $username, $password, $providerKey)
{
return new UsernamePasswordToken($username, $password, $providerKey);
}
}
This is my security.yml:
security:
providers:
in_memory:
memory: ~
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
simple_form:
authenticator: sippy.authenticator
login_path: login
check_path: login
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/es/overview, roles: ROLE_ACCOUNT }
The problem was that I was generating the User object without call the $userProvider (because I didn't implement it), and symfony later use this object ($userProvider) to retrive the already autenticated user and put it in the session... Below the UserProvider class and the modified SippyAuthenticator:
class SippyUserProvider implements UserProviderInterface
{
private $sippyAccounts;
public function __construct(SippyAccounts $sippyAccounts)
{
$this->sippyAccounts = $sippyAccounts;
}
public function loadUserByUsername($username)
{
$result = $this->sippyAccounts->informationByUsername($username);
if (!$result->isError()) {
$password = null;
return new SippyUser($username, $password, null, array('ROLE_ACCOUNT'));
}
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof SippyUser) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === 'AppBundle\Model\SippyUser';
}
}
class SippyAuthenticator implements SimpleFormAuthenticatorInterface
{
private $sippyAccounts;
public function __construct(SippyAccounts $sippyAccounts)
{
$this->sippyAccounts = $sippyAccounts;
}
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
$result = $this->sippyAccounts->login($token->getUsername(), $token->getCredentials());
if($result->isError()) {
throw new CustomUserMessageAuthenticationException('Invalid username or password');
} else {
$user = $userProvider->loadUserByUsername($token->getUsername());
$tokenNew = new UsernamePasswordToken( $user, $user->getPassword(), $providerKey, $user->getRoles());
$tokenNew->setAttributes($token->getAttributes());
return $tokenNew;
}
}
public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof UsernamePasswordToken
&& $token->getProviderKey() === $providerKey;
}
public function createToken(Request $request, $username, $password, $providerKey)
{
return new UsernamePasswordToken($username, $password, $providerKey);
}
}
I hope this answer helpful to someone else...

doctrine 2 - The user provider must be an instance of WebserviceUserRepository

i wanted to create an Custom EntityRepository to load a User from the Database, so i followed http://symfony.com/doc/current/cookbook/security/entity_provider.html this tutorial.
Now i get a exception and i do not know why:
{"error":{"code":500,"message":"Internal Server Error","exception":[{"message":"The user provider must be an instance of WebserviceUserRepository (Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider was given)."
If I remove extends EntityRepository from my WebserviceUser repo and also change security.ml and services.yml than the authentication works and the class is an instanceof WebserviceUserRepository.
I am using Symfony 2.7
I hope somebody can help me with that i am starting to pull my hair out ;-)
My Api Key Authenticator looks like that:
class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface,
AuthenticationFailureHandlerInterface {
public function createToken(Request $request, $providerKey)
{
// look for an apikey query parameter
$apiKey = $request->query->get('apikey');
// or if you want to use an "apikey" header, then do something like this:
// $apiKey = $request->headers->get('apikey');
if (!$apiKey) {
throw new BadCredentialsException('No API key found');
// or to just skip api key authentication
//return null;
}
return new PreAuthenticatedToken(
'anon.',
$apiKey,
$providerKey
);
}
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
**if (!$userProvider instanceof WebserviceUserRepository) {**
throw new \InvalidArgumentException(
sprintf(
'The user provider must be an instance of WebserviceUserRepository (%s was given).',
get_class($userProvider)
)
);
}
$apiKey = $token->getCredentials();
$username = $userProvider->getUsernameForApiKey($apiKey);
if (!$username) {
throw new AuthenticationException(
sprintf('API Key "%s" does not exist.', $apiKey)
);
}
$user = $userProvider->loadUserByUsername($username);
return new PreAuthenticatedToken(
$user,
$apiKey,
$providerKey,
$user->getRoles()
);
}
public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
return new Response("Authentication Failed.".$exception->getMessage(), 403);
}
this is my user repo:
class WebserviceUserRepository extends EntityRepository implements UserProviderInterface {
public function getUsernameForApiKey($apiKey)
{
// Look up the username based on the token in the database, via
// an API call, or do something entirely different
$username = 'username';
return $username;
}
public function loadUserByUsername($username)
{
// make a call to your webservice here
$userData = "";
// pretend it returns an array on success, false if there is no user
if (false) {
$password = 'password';
$salt = '';
$roles = array('roles' => 'ROLE_ADMIN');
return new WebserviceUser($username, $password, $salt, $roles);
}
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
public function refreshUser(UserInterface $user)
{
$class = get_class($user);
if (!$this->supportsClass($class)) {
throw new UnsupportedUserException(
sprintf(
'Instances of "%s" are not supported.',
$class
)
);
}
return $this->find($user->getUsername());
}
public function supportsClass($class)
{
return $this->getEntityName() === $class
|| is_subclass_of($class, $this->getEntityName());
}
}
i also added the repository class to my entity object:
* #ORM\Table()
* #ORM\Entity(repositoryClass="Moera\RestBundle\Entity\WebserviceUserRepository")
*/
class WebserviceUser implements UserInterface, \Serializable, EquatableInterface
and i also registered bot classes in security.yml and services.yml:
services:
webservice_user_provider:
class: Moera\RestBundle\Entity\WebserviceUserRepository
apikey_authenticator:
class: Moera\RestBundle\Security\ApiKeyAuthenticator
public: false
security:
encoders:
Moera\RestBundle\Entity\WebserviceUser:
algorithm: bcrypt
providers:
webservice_user_provider:
entity:
class: MoeraRestBundle:WebserviceUser
firewalls:
secured_area:
pattern: ^/
stateless: true
simple_preauth:
authenticator: apikey_authenticator
provider: webservice_user_provider
Thank You very much!
Kind Regards,
Johannes

Categories