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?
Related
I tried to use RestTemplate to carry cookies and request a custom Wordpress logout interface, but the front end did not log out. When I directly accessed the logout url in the browser, I was able to logout successfully.
Here is my RestTemplate code:
public void logoutOfWordpress(HttpServletRequest request, HttpServletResponse response) {
Cookie[] cookies = request.getCookies();
String url = wordpressProper.getRestUrl() + "/community-rest/logout";
HttpHeaders httpHeaders = buildHeaderByCookies(cookies);
ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class);
Object body = exchange.getBody();
}
This is the WordPress logout interface:
add_action( 'rest_api_init', 'community_rest_logout');
function community_rest_logout() {
register_rest_route(
'community-rest',
'/logout/',
array(
'methods' => 'GET',
'callback' => 'logout'
)
);
}
function logout() {
wp_logout();
wp_redirect('http://192.168.100.5:8888/sign_in');
exit;
}
I tried to use Postman to call this logout interface and found that there is
Set-Cookie in the response header. It seems that this is necessary for logout. It seems that I can directly set the Max-Age of the cookie to
0 to achieve the purpose of logout without having to to call the logout interface
.
What are you using for user login? Sessions are not started internally in wordpress rest api. You should be able to get the user_id if the user is logged in on your logout endpoint. Can you get this?
Generally, nonce is used on rest for unregistered users. You need to send the nonce value in header or parameter. For registered users, you need to authenticate cookies or you can use some rest api authentication plugins.
For a simple hack you can use this at the top of your endpoints:
public function init_cookie() {
$userID = wp_validate_logged_in_cookie(false);
if($userID) {
wp_set_current_user($userID);
}
}
I would also suggest defining your code in a class or prefixing the names of the functions. The logout function is a very generic name. If this is just for an example, ignore what I said.
I am using symfony 3.3 with fos_userbundle and fr3d_ldapbundle to authentichate my users trough LDAP.
The login works correctly if a try to use the standard login form generated.
But what I need to do is a manual(programmatically) login.
What is the best way to do it with fr3d_ldapbundle?
Sorry guys, I give you more details:
I tried to follow this guide: https://ourcodeworld.com/articles/read/459/how-to-authenticate-login-manually-an-user-in-a-controller-with-or-without-fosuserbundle-on-symfony-3
If I try to use the fos_user.user_manager the login works correctly, but using the fr3d_ldap.ldap_manager it doesn't work. (the isPasswordValid function return me "Username or Password not valid")
The user is retrieved correctly from LDAP server, but the "password" field is empty if I print the $user object. Using the standard login form the authentication works correctly and the username is stored in my fos user bundle table with the password field empty. Could be this my problem?
Also the $salt is empty.
This is my code of LoginAction:
public function loginAction(Request $request)
{
// This data is most likely to be retrieven from the Request object (from Form)
// But to make it easy to understand ...
$_username = "user";
$_password = "password";
// Retrieve the security encoder of symfony
$factory = $this->get('security.encoder_factory');
/// Start retrieve user
// Let's retrieve the user by its username:
/*
// If you are using FOSUserBundle:
$user_manager = $this->get('fos_user.user_manager');
$user = $user_manager->findUserByUsername($_username);
//Or by yourself
$user = $this->getDoctrine()->getManager()->getRepository("ApiBundle:User")
->findOneBy(array('username' => $_username));
*/
//Using fr3d/ldap-bundle
$user_manager = $this->get('fr3d_ldap.ldap_manager');
$user = $user_manager->findUserByUsername($_username);
//print_r($user);die();
/// End Retrieve user
// Check if the user exists !
if(!$user){
return new Response(
'Username doesnt exists',
Response::HTTP_UNAUTHORIZED,
array('Content-type' => 'application/json')
);
}
/// Start verification
$encoder = $factory->getEncoder($user);
$salt = $user->getSalt();
if(!$encoder->isPasswordValid($user->getPassword(), $_password, $salt)) {
return new Response(
'Username or Password not valid.',
Response::HTTP_UNAUTHORIZED,
array('Content-type' => 'application/json')
);
}
/// End Verification
// The password matches ! then proceed to set the user in session
//Handle getting or creating the user entity likely with a posted form
// The third parameter "main" can change according to the name of your firewall in security.yml
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.token_storage')->setToken($token);
// If the firewall name is not main, then the set value would be instead:
// $this->get('session')->set('_security_XXXFIREWALLNAMEXXX', serialize($token));
$this->get('session')->set('_security_main', serialize($token));
// Fire the login event manually
$event = new InteractiveLoginEvent($request, $token);
$this->get("event_dispatcher")->dispatch("security.interactive_login", $event);
/*
* Now the user is authenticated !!!!
* Do what you need to do now, like render a view, redirect to route etc.
*/
return new Response(
'Welcome '. $user->getUsername(),
Response::HTTP_OK,
array('Content-type' => 'application/json')
);
}
Someone is able to help me?
Thank you.
#Jon Doe, you certainly cannot get the password information on user object while doing ldap authentication.
LDAP uses bind function which takes username and password information, tries to authenticate and return success or failure.
While using FR3DLdapBundle, this should be done inside Authentication Provider. Check LdapAuthenticationProvider.php file for following code.
if (!$this->ldapManager->bind($currentUser, $presentedPassword)) {
throw new BadCredentialsException('The credentials were changed from another session.');
}
In your controller - LoginAction you shouldn't be doing any authentication.
Just check for any authentication error and check for any access specific role if you need to have role based access as following example.
// get the login error if there is one
$error = $this->get('security.authentication_utils')->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $this->get('security.authentication_utils')->getLastUsername();
//if you need to check for the user role.
$roleGranted = $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN');
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();
}
I'm using SfGuardPlugin and on the backend of my site I have the full list of users and I want to be able to login on the frontend with the user that I choose from the list.
I've tried this method:
public function executeListLogin(sfWebRequest $request) {
// client that I've selected from list
$client = $this->getRoute()->getObject();
// create instance if doesn't exist
if(!sfContext::hasInstance('frontend')){
sfContext::createInstance(ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false));
}
// switch to frontend
sfContext::switchTo('frontend');
// also tried with: sfContext::getInstance('frontend')
sfContext::getInstance()->getUser()->signin($client->getSfGuardUser(), true);
// redirect to frontend homepage
$this->redirect('#homepage');
}
It redirects me to the frontend homepage, but I'm not logged in.
After more digging I've found out that I'm logged out from backend and now I'm logged in on frontend with admin instead of the user I choose. So the sfContext::switchTo doesn't work correctly.
I've found a workaround.
Create a new column(login_frontend_key) on the users table.
Create a new frontend route with a required parameter(named key)
Create the action in frontend controller witch is responsible for sign in the user, ex:
public function executeLoginClientKey(sfWebRequest $request){
// get the client by key
$this->forward404Unless($user = ClientPeer::getByLoginFrontendKey($request->getParameter("key")));
// if you already logged in with another user, signout
if($this->getUser()->isAuthenticated())
{
$this->getUser()->signOut();
}
// signin with the new user
$this->getUser()->signIn($user->getsfGuardUser(), false);
$user->setLoginFrontendKey(null); // delete the key from DB
$user->save();
$this->redirect('#homepage');
}
Use this to generate cross application links http://symfony.com/blog/cross-application-links
Create the object action on the backend users page:
public function executeListLogin(sfWebRequest $request)
{
// get the selected client
$client = $this->getRoute()->getObject();
$key = $client->generateLoginFrontendKey(); // generate a random key
$client->setLoginFrontendKey($key); // store the key in DB
$client->save();
// generate the frontend url for login
$url = $this->getContext()->getConfiguration()->generateFrontendUrl('login_frontend_key', array('key' => $key, 'sf_culture' => 'nb'));
$this->redirect($url);
}
I have to get the user's plain password for LDAP authentification and then retrieve LDAP user informations in the Active Directory with Symfony2.
/**
* #Route("/infos-profil/{id}", name="infos_profil")
* #Template()
*/
public function infosProfilAction($id)
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('MyUserBundle:LdapUser')->find($id); // Find User Entity
if (!$user) {
throw $this->createNotFoundException('Unable to find LdapUser entity.');
}
$login = $user->getUsername(); // Login
$pass = $user->getPlainPassword(); // Password
$ds = ldap_connect("12.34.56.789"); // Domain connexion
if ($ds) {
$r = ldap_bind($ds, $login, $pass); // LDAP User connexion
if ($r) {
$filter = "(&(objectClass=user)(samaccountname=".$login.")(cn=*))";
$sr=ldap_search($ds, "ou=DOMAIN, ou=Test, ou=Users, dc=ats, dc=lan", $filter);
$info = ldap_get_entries($ds, $sr); // Retrieve user's Active Direcory informations
}
}
return array(
'user' => $user,
'info' => $info,
}
But it doesn't work, $pass is empty. When I put the plain password manually in the ldap_bind() function it works perfectly, I just have to get the plain password ! ...
Is it possible ?
It isn't possible to retrieve plain password from database for obvious security reasons.
For your problem, you should create a custom Authentication Provider, following this tutorial : https://symfony.com/doc/4.4/security/custom_authentication_provider.html
This way, your provider will get the plain password from the login form and you will be able to send it to your LDAP server.
You don't need the user's password to retrieve information about them from active directory. Once they are authenticated simply look them up via LDAP using their username, with either an anonymous connection or failing that, a known privileged account.