Cannot sent cookie with Guzzle request - php

I have a PHP script that needs to fetch a CSV file from an application. There is an API for the application that allows the script to lot in, which gives the script a session cookie for authentication. I then need to doa GET request to fetch the CSV file (which the API does not support).
Using curl directory works:
$c = curl_init($url);
curl_setopt($c, CURLOPT_COOKIE, 'PHPSESSID=' . $session_id_from_api);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$csv_file = curl_exec($c);
echo $csv_file;
That fetches the CSV file using the session ID obtained from the API login and passed through a coookie.
Now, I would like to do the same thing using Guzzle, but I just get the login page back instead. This is the code I'm using:
$client = new Guzzle\Http\Client();
$request = $client->get(
$url,
[
'cookies' => ['PHPSESSID' => $session_id_from_api],
]
);
$response = $client->send($request);
echo $response->getBody(true);
That gives me the login page, so the GET to the application is not recognising the session defined by the cookie.
Is there anything else I need to do to ensure the cookie and value I specify is sent to the remote application?
Edit: looking at $request->getRawHeaders(), I see this line in the headers:
cookies: vec6nb1egvvui6op7qr7b0oqf6
That obviously isn't right. The documentation for my version of Guzzle gives this example:
// Enable cookies and send specific cookies
$client->get('/get', ['cookies' => ['foo' => 'bar']]);
which looks to me to be consistent with what I am passing to Guzzle.
Just to be clear, I am not trying to manage cookies in both directions over multiple requests, so there is no need to store any cookies. I have a cookie name and its value (from another source), and I just want to make sure that name and value gets sent to the destination for a single GET request. I'm not trying to "maintain a session", but in a way I am having a session passed to me from another part of the application (not Guzzle) and need to set my Guzzle request up to use it.

Well, this seems to work. Guzzle was not sending the cookie without being sure the domain it was sending it to was correct:
// Set up a cookie - name, value AND domain.
$cookie = new Guzzle\Plugin\Cookie\Cookie();
$cookie->setName('PHPSESSID');
$cookie->setValue($session_id_from_api);
$cookie->setDomain($domain_of_my_service_url);
// Set up a cookie jar and add the cookie to it.
$jar = new Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar();
$jar->add($cookie);
// Set up the cookie plugin, giving it the cookie jar.
$plugin = new Guzzle\Plugin\Cookie\CookiePlugin($jar);
// Register the plugin with the client.
$client->addSubscriber($plugin);
// Now do the request as normal.
$request = $client->get($url);
$response = $client->send($request);
// The returned page body.
echo $response->getBody(true);

Related

Settings a Cookie by POSTing to a RESTful Magento controller

I am building an application which will eventually reside on the same domain where another application resides; both of which are written in PHP. One is a Laravel application and the other a Magento 1.9 store.
To authenticate the user, the Laravel application requires that a certain cookie be set by the Magento store's response, subsequently retrieved and parsed, all before authentication may continue.
My current strategy is a POST to a custom controller which delivers multiple Set-Cookie headers from the Magento store.
The one I need is something like:
Set-Cookie: auth_token=TheValueWeNeedToContinueAuthenticating; domain='.mydomain'; ...
The server I am testing on is an in-house staging environment. The server's VHost is set to Laravel's public directory, as usual.
The Magento store is on a different server however the TLD is the same .mydomain
I have verified the response in Postman, I am indeed returning the cookie with the correct Set-Cookie in place, however it is not visible in my Laravel application as the other cookies from Magento, are. The other cookies were verified within the response as I dumped Guzzle's CookieJar and still received all but the cookie I am looking for.
I am using PHP's Guzzle HTTP Library to post from a Laravel 5.6 app using PHP 7.1
The Magento1.9 store unfortunately uses PHP/5.6.35
When I dump the HTTP response I am getting the cookies which would normally receive had I actually visited any page within the store.
What else could I check to ensure I am taking to right approach to receiving this cookie? Https is the transmission protocol, and the content-type is x-www-form-urlencoded if that will assist an answer in any way.
Thank you.
UPDATE 1.0 - I was able to get a clean error reading from the request being sent.
{"status":"error","message":"invalid request"}
Here is my Guzzle Post request
$jar = new \GuzzleHttp\Cookie\CookieJar;
// Logging my error output -- I can share this if I must
$debug_file = fopen('../storage/logs/debug.txt', 'a');
try {
$payload = 'Knock, knock';
$url = '/api/for/post';
$client = new Client([
'base_uri'=> 'https://mySubdomain.myDomain.com',
'debug' => $debug_file,
'cookies' => $jar,
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
]
]);
$request = new \GuzzleHttp\Psr7\Request('POST', $url, [], $payload);
$rsp = $client->send($request);
dd($rsp->getBody()->read(1024));
$response->getBody()->read(1024) returns the error message

How to access the session using a session id in codeigniter

I am creating a API in Codeigniter.
In this API I have a login function for user. If Login is successful I set user data in CI session and return the session back to user.
Now is it possible that user can use that session id to validate himself for all his other requests like add/update/delete. Basically I want that when the user sends next request I can validate his credentials based on his session id.
Client Request Code :
public function login()
{
$url = 'http://localhost/bizCloudDS/server/login';
$timestamp = gmdate("His");
$parameters = array("reqest"=>"login", "username"=> "admin", "API_AccessKey"=> "b5741564rda4a4d91965d3b5", "GMT_Timestamp"=> $timestamp);
$json = json_encode($parameters);
$encrypted = $this->bizEncrypt($json , 'enc' );
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS, $encrypted);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
echo $result;
curl_close($ch);
}
Now above was a sample request from client to server for Login.
On Server Side the server validates the credentials give by the client, if validated returns this json response :
{"ResponseCode":"200","Reason":"Success","Session_ID":"euo1obqeekd5vtb0ult9nj84kii1kqni"}
Now I want that if the user send another request lets say create_user in this he will send the session_id returned from the login request. So how can i fetch the session data by this session id on server side?
Is this good practice ?
you are on wrong way:
I recomand:
Use database and cookie for login (not sessions). OR
You need persistant curl connection (explore CURLOPT_COOKIEJAR) to understand how you login then use same session for other things.
If the user isn't logged directly into your system, but is using a third-party tool via API, then using the session ID doesn't make sense because there actually is no session in the traditional sense. It's a one time call/response.
It seems a better idea to use some sort of request signature to verify that the individual accessing your system is who they say they are and have the access to do what they're trying to do (ie some kind of key hash). For each call, you would authenticate the call itself, not an active session.
Or you can use a persistent cURL connection, but that could be more prone to headache.

Hold Guzzle Cookies across multiple requests

I'd like to create a proxy for a specific site so users, which can't access that site (due to the sites IP being blocked by their ISP for instance), can access it through my proxy. I would use Guzzle to make HTTP requests, exchange all links to my own site and then display it.
I know this is not exactly ideal, but for a start it seemed to work and I don't expect hundreds of people to use it. It should just be in place, in case someone does need it.
The problem I am having is cookies. The other site obviously uses sessions/cookies to keep the users logged in. Basically there's nothing you can do without being logged in. I already pass all form data and such to the HTTP request, but cookies keep throwing me out.
protected function makeRequest($path, $parameters)
{
$cookieJar = new CookieJar;
$client = new Client(['base_uri' => self::$staticURL]);
$response = $client->request($parameters['method'], self::buildUrl($path), [
'form_params' => Request::all(),
'cookies' => $cookieJar,
]);
// Session::flash can only flash strings, but CookieJar is not serializable.
// Session::flash('cookie', $cookieJar);
return self::replaceURLs($parameters['original'], self::$staticURL, $response->getBody(), $parameters['base']);
}
As you can see I am passing a CookieJar instance to the request, as it was mentioned in the documentation. With this, I am able to log into the site, but as soon as I click another link, it throws me back out. So I assume it doesn't save the cookie across multiple requests.
Which ways do I have to do that?
I thought the cookies option required an instance of type CookieJar, which is not the case. What it requires is a CookieJarInterface. Looking further into the Guzzle library I found the FileCookieJar, which is saved in a file.
I now generate an ID for each session and write the cookies into a file using that ID. That way each user of my page has the cookies saved and they get loaded on each subsequent request.
protected function makeCookiePath()
{
$sessionId = $this->request->session()->get('cookie.id', str_random(40));
$this->request->session()->put('cookie.id', $sessionId);
return storage_path('cookies/' . $sessionId);
}
protected function makeRequest($path, $parameters)
{
$cookieJar = new FileCookieJar($this->makeCookiePath(), true);
// ...
}

How do I use this google IdToken to get the users email address using PHP? [duplicate]

I am trying to securely login a user via their Google account.
I am at the stage that I retrieve the userID and oAuthToken using this cordova plugin.
Now I am at the point where I need to send these credentials to my server and then on the server side validate the integrity of the token. Essentially I am trying to perform this part of the process.
I am confused as to which token I should try to verify using the Google client api. Should I use the userID or the oAuthToken ?
The documentation mentions validating the userID but I find this strange. Wouldn't this mean that if anyone gets my user id they can essentially break into my server ? The user id never changes (correct me if I am wrong here) so it seems insecure to validate on this. Wouldn't it make more sense to validate the oAuthToken which is set to expire ? Or does the user ID also expire ?
Any advice would be welcome.
Thanks,
Fido
Edit:
For anyone interested. My confusion arose due to not understanding fully three tokens which the google api can return: userId, oAuthToken, and idToken.
Briefly:The userId is returned with most api calls identifying the user. This appears to be constant. The oAuthToken in my case was returned when I accessed the google api as an Android client. The tokenId is returned when accessing the api as a web client. So those wishing to do server side validation using a mobile retrieved token should access the api as a web client. The token returned can then be validated server side using code similar to the accepted answer below.
you need to validate the IdToken, never send the userId on an open line. the IdToken expires quickly and it is virtually impregnable to brute force impersonation attacks.
this php snippet receives an HTTP request that starts with idtoken=, validates your token serverside and returns either the complete array or user email:
<?php
$inputRaw = file_get_contents('php://input');
$idToken= substr($inputRaw,8);
$fp = fopen('twoStepOutput.txt', 'a');
$url = 'https://www.googleapis.com/oauth2/v3/tokeninfo?id_token='.$idToken;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$json = json_decode($response, true);
curl_close($ch);
$userEmail = $json["email"];
$clientId = $json["azp"];
//fwrite($fp, date("YmdHis")."\r\n$idToken\r\n");
fwrite($fp, date("YmdHis")."\r\n");
fwrite($fp, "email Confirmed by GOOGLE:[$userEmail]\r\n");
//print_r($json); // returns array console readable
print_r($clientId); // returns google client id for verification (without transfering user data)
fclose($fp);
?>
just in case you are in doubts, this is what an IdToken looks like:
eypZCI6OiJSUzI1JhbGciNiIsImtIjk4MzQxMzgyMWJmMzhiNTJlM4OTI2YTllMTc0YTc5MWMwNGMifQ.eyJpc3MiOi3VizExYJhY2NvdW50cy5nb29nbGUuY29tIiwicmEIjoiMTAzNDUyNjAwODM5NzY3MjU2MDE0IiwiYXpwIjoiMTA3OTMxMTEyNTc1OS1lYWJhbWV0b2ZldjIwY28zbGQ5b2o1YWQwMzFuZG9nMC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImVtYWlsIjoidG9ueWdpbGJyQGdtYWlsLmNvbSIsImF0X2hhc2giOiJaSkhxbUZHcnR5Y29kdEhhOGJvMEYWY1NTk2NzUsImV4cCVBIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF1ZCI6IjEwNzkzMTExMjU3NTkt1ldG9mZXYyMGNvM2xkOW9qNWFkMDMxbmRvZzAuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJpYXQiOjE0MzZWFiI6MTQzNjU2MzI3NSwibmFtZSI6IlRvbnkgR2lsIiwicGljdHVyZSI6Imh0dHBzOi8vbGg0Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tQVREckRSbF9UdFEvQUFBQUFBQUFBQUkvQUFBQUFBQUFBRncvOVdDQnZkYlpUTEEvczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IlRvbnkiLCJmYW1pbHlfbmFtZSI6IkdpbCIsImxvY2FsZSI6ImVuIn0.L4peW11TD0bDOlvYKNY60ieZ1sbZfW9gEImcuxVA5f9U_4N49Io1CFXoGKmEPR_ij4q38tF2drPMOKijQePwlrxDui37ubzAdVkuksCJUobzjD1_eccF_8GldP5Y1_XsU8xrZeEnfabfiYpr-VwoLzIeNNUdy9SUbUWjMHNcvf4dGFMzE_SONHr57igjHK3rGkbvLo-UduFngm3e-EL0YR2zOKOVj1Qs8g8_qpWgkn8XABTme1thmuU8OfC-HaF9_B2Zk2UCsnOu4ApiYZk3DPIKgeX6AF11kYnzgvciYheWeddly0foT4G00C7w_wgtd-LSRw0XZltec_MPMa2QSA

How to post from php with cookies?

How can I make a post request using cookies from php.
My php code:
<?php
$time_start = microtime(true);
$id=$_GET[id];
$data = http_build_query( array ('act' => 'load_friends_silent', 'al' => '1', 'gid'=>'0' ,'id'=>$id) );
$opts = array(
'http'=>array(
'header'=>"Cookie: something=asdaefefe",
'method'=>"POST",
'content' => $data
)
);
$context = stream_context_create($opts);
print $context;
$contents = file_get_contents('http://vkontakte.ru/al_friends.php', false, $context);
$fil=fopen("./".$id."ne.txt","w");
echo '<br><br>'.$contents;
fputs($fil,$contents);
fclose($fil);
chmod("./".$id."ne.txt", 0777);
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "<br><br>execute time $time seconds\n";
?>
But this code won't work on the server; cookie not sent.
[EDIT]
To use PHP to post to a page that the user will NOT navigate to, you can use CURL:
http://davidwalsh.name/execute-http-post-php-curl
Where in the example, you set $fields to your cookie values:
$fields = array(
'lname' => urlencode($_COOKIE['last_name'] ),
'fname' => urlencode($_COOKIE['first_name'] ),
...
);
[EDIT AGAIN]
By your newly posted code it looks like you are trying to create a cookie on the page that you are posting to. First of all, creating cookies for other websites would seem to be a big security risk, so I'm 99.9% certain that this has never been nor ever will be possible. Secondly, PHP is not a browser and can't store cookies for other sites...so even if your post created a cookie, the user's browser would not have that cookie. All you can do is post 'something'=> urlencode('value'), and then the page you are posting to will have to create the cookie on their end. However, since PHP can't hold cookies since it's not a browser, this would be pointless.
If you want the user's browser to have a cookie, then you need to use something like jQuery's $.post. Using jQuery's post() method will use the user's browser to go to the page and post data. The page that gets the posted data can then create a cookie on the user's browser.
[Read These] they may contain some info for you. Is this what you're trying to do?
Simulating a cookie-enabled browser in PHP
Simulating a POST with PHP & cURL
It does sound like CURL should be able to mimic a browser's cookie capabilities...so you might be able to send cookie data, though, as I said, you woudln't be able to set the user to those cookies or anything...since I'm not sure of your purpose, that makes an answer harder:
http://php.net/manual/en/function.curl-setopt.php
Read this, maybe it will help. http://www.w3schools.com/PHP/php_cookies.asp

Categories