How to get jwt token from controller (user already logged in) - symfony

So I'm using Lexik JWT bundle (Symfony 2.8) to authenticate over Google and when user is logging in it works well. My Success handler looks like this:
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
$user = $token->getUser();
$jwt = $this->jwtManager->create($user);
$response = new JsonResponse();
$event = new AuthenticationSuccessEvent(['token' => $jwt], $user, $response);
$this->dispatcher->dispatch(Events::AUTHENTICATION_SUCCESS, $event);
$redirectResponse = new RedirectResponse('http://localhost:3000?token='.$event->getData()['token']."&username=".$user->getUsername());
return $redirectResponse;
}
So I'm redirecting user to some localhost and passing token as "token" get variable and that works well. Later I can pass that token value trough header and I get authenticated.
Problem is - I want to get the same token from my controller. I'm using the similar code:
$jwtManager = $this->get('lexik_jwt_authentication.jwt_manager');
$tokenStorage = $this->get('security.token_storage');
$token = $tokenStorage->getToken();
$user = $token->getUser();
$jwt = $jwtManager->create($user);
$response = new JsonResponse();
$event = new AuthenticationSuccessEvent(['token' => $jwt], $user, $response);
$token = $event->getData()['token'];
echo $token;
And I really get some token, but that's not the same one I get from success handler. Tried passing it as header "Autorization" parameter, but it doesn't work. I'm getting 401 error and message:
Unable to verify the given JWT through the given configuration. If the \"lexik_jwt_authentication.encoder\" encryption options have been changed since your last authentication, please renew the token. If the problem persists, verify that the configured keys/passphrase are valid.
What I'm doing wrong here? Why I'm getting different token and how can I get token I'm getting form success handler?

Found the solution. It goes like:
$user = $this->get('security.token_storage')->getToken()->getUser();
$jwtManager = $this->get('lexik_jwt_authentication.jwt_manager');
$token = $jwtManager->create($user);

I know this is an old question, but I found a solution that let you use the token anywhere, not just in the controller.
Instead of using TokenInterface, use TokenStorageInterface
public function __construct(TokenStorageInterface $tokenStorage) {
$this->token = $tokenStorage->getToken();
$this->user = $this->token->getUser();
}

Related

Symfony - authentication of user in test env

I am trying to run tests in my Symfony test environment but keep getting an error.
Error: Call to a member function getContainer() on null
I figured I have problem with authentication of the user.
I have loaded a fixture to persist one user object into test database fort the needs of authentications (even if i do not know it that is needed).
protected function createAuthenticatedClient(): KernelBrowser
{
self::ensureKernelShutdown();
$client = static::createClient();
$session = $this->client->getContainer()->get('session');
$firewall = 'secured_area';
$token = new UsernamePasswordToken('admin', null, $firewall, array('ROLE_ADMIN'));
$session->set('_security_'.$firewall, serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$client->getCookieJar()->set($cookie);
return $client;
}
I do not know what am I doing wrong?
I have to note that my project does the authentication trough x-api-key value in header.
This is a whole new world in Symfony regarding tests for me, so any guidance and help is highly appreciated.

How to create a new FOSUserBundle user programatically using the same validation as on web form?

I am running a Symfony 2.8 based web app using FOSUserBundle to manage users. Creating new users with a web form is absolutely no problem.
Now I would like to add a feature to create new users with a REST api. Of course submitting username, password, email, etc. to a controller is no big deal:
public function registerAction(Request $request) {
$requestJson = json_decode($request->getContent(), true);
$username = $requestJson[JSON_KEY_USERNAME];
$email = $requestJson[JSON_KEY_MAIL];
$password = $requestJson[JSON_KEY_PASSWORD];
...
$this->registerUser($username, $email, $password);
...
}
private function registerUser($username, $email, $password, $locale, $timezone, $currency) {
$userManager = $this->get('fos_user.user_manager');
$emailExist = $userManager->findUserByEmail($email);
$userNameExists = $userManager->findUserByUsername($username);
if ($emailExist || $userNameExists)
return false;
$user = $userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
...
$user->setLocked(0);
$user->setEnabled(0);
$userManager->updateUser($user);
return true;
}
However, this performs no validation at all. If for example the username is empty an NotNullConstraintViolationException is thrown when persisting the user object.
Of course I could manually re-implement the same validation process which is used by the RegistrationForm (username not empty, not taken, no invalid characters, password min length, e-mail format, etc.) and pass back the same error messages but this would mean to reinvent the wheel.
Is it somehow possible to run the exact same validation which is used by the RegistrationForm?
Symfony validator can work independently. In a controller you can use validator service like this:
$violations = $this->get('validator')->validate($user, null, ['your_groups_here']);
// Or inject Symfony\Component\Validator\Validator\ValidatorInterface into a service.
It will return a ConstraintViolationListInterface, you can loop trough this object.
You can check FOSUserBundle validation groups here: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/config/validation.xml

Header HTTP apikey missing token authentication

I'm trying to authenticate users via ApiToken Authentication. The problem I'm facing right now is that I don't know how to retrieve the header Apikey just created that contains the token for the logged in user.
After I authenticate the user, I generate for him a token and then I tried to set in Apikey HTTP Header that specific token in order to use it in my api. But after I set it, when I try to access an url from api, the Apikey header is missing.
local.web.com/api/login
public function loginAction(Request $request)
{
(...)
$tokenUser = $serviceUser->generateToken($username);
$request->headers->add(array('apikey' => $tokenUser));
$response = new Response($request);
$response->send();
return $response;
}
local.web.com/api/list/products
public function createToken(Request $request, $providerKey)
{
$apiToken = $request->headers->get('apikey');
return new PreAuthenticatedToken(
'anon.',
$apiToken,
$providerKey
);
}
The HTTP Header Apikey is missing.
Any advice?

FOSRestBundle & invalid form CRF token

I'm trying to implement FOSRestBundle and Symfony forms.
I have found this tutorial but I have problem with this part
private function processForm(PageInterface $page, array $parameters, $method = "PUT")
{
$form = $this->formFactory->create(new PageType(), $page, array('method' => $method));
$form->submit($parameters, 'PATCH' !== $method);
if ($form->isValid()) { //form is not valid.
$page = $form->getData();
$this->om->persist($page);
$this->om->flush($page);
return $page;
}
throw new InvalidFormException('Invalid submitted data', $form);
}
ERROR: The CSRF token is invalid. Please try to resubmit the form.
Here is the controller from tutorial. And here is my class controller:
public function newAction(Request $request)
{
$form = new EntryType();
$newEntry = $this->container->get('entries.entry.handler')->post(
$request->request->get($form->getName())
);
return View::create()
->setStatusCode(200)
->setFormat('json')
->setSerializationContext(SerializationContext::create()->setGroups(array('list')))
->setData($newEntry);
}
Should I skip checking isValid() or fix this somehow? How?
OK, It is clear now. CRF verification (csrf_protection) should be disabled
CSRF token is invalid when calling rest post api from php Client
https://github.com/liuggio/symfony2-rest-api-the-best-2013-way/issues/1#issuecomment-31435232
CSRF validation needed or not when using RESTful API?
From part 3 of the tutorial :
It's possible to disable the CSRF based on the user’s role.
# app/config/config.yml
fos_rest:
disable_csrf_role: ROLE_API
# you can also try
# disable_csrf_role: IS_AUTHENTICATED_FULLY
See also this issue.

samlspbundle integration with fosuserbundle

I try to integrate the bundle samlspbundle on a project running with fosuserbundle.
I actually received information from my idp which send me the saml with the email address of the user.
What i'm trying to do is load the user from my table fosuser and then authenticate it.
this is the method i am in my model SamlToUser :
private function loadUserByTargetedID($targetedID)
{
$repository = $this->container->get('doctrine')->getManager()->getRepository('MCCAppBDDBundle:User');
$user = $repository->findOneBy(
array('email' => $targetedID)
);
if ($user) {
$userManager = $this->container->get('fos_user.user_manager');
$url = $this->container->get('router')->generate('homepage');
$response = new RedirectResponse($url);
$this->container->get('fos_user.security.login_manager')->loginUser(
$this->container->getParameter('fos_user.firewall_name'),
$user,
null
);
$userManager->updateUser($user);
return $user;
}
throw new \Symfony\Component\Security\Core\Exception\UsernameNotFoundException();
}
After that i have this error : PHP Warning: session_regenerate_id(): Cannot regenerate session id - headers already sent
I'm not sure is the right thing to do.
If you need other detail, i can give you.
Thanks to help.

Resources