Request header not set in test - php

I have a test which is trying to login and get details. I need to pass a bearer token in request header for this operation. Please see the below code. I could see that the header seldom has the headers that I set. Can anyone give me a pointer to fix this issue?
I am using Laravel 7.2.2, PHP 7.4,
And I am running php artisan test
Code:
public function a_user_can_get_details()
{
$this->create_user();
$response = $this->json('POST',
'/api/login',
[
"email" => "john.doe#example.com",
"password" => "john123"
]);
$response->assertSuccessful();
$token = Str::replaceLast('"', '', Str::replaceFirst('"', '', $response->getContent()));
$headers = [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $token
];
$response = $this->withHeaders($headers)
->get('api/user');
$response->assertSuccessful();
$this->assertCount(1, User::all());
}
And here is the error I am getting. Actually, the test must pass. That is the right user name and password:
Response status code [403] is not a successful status code. Failed asserting that false is true.
at tests/Feature/UserTest.php:141
137|
138| $response = $this->withHeaders($headers)
139| ->get('api/user');
140|
> 141| $response->assertSuccessful();
142| $this->assertCount(1, User::all());
143|
144| }
145|

I solved this issue.
Cause: I had added a middleware condition in Spatie Permissions to check for a permission for that specific route. I had to remove that to get this working.
Instead of that, I now, check the logged in status of the user. So that the route could be hit and needed checks are done inside the route.
Thanks all for the questions/comments which helped me to solve this.

Related

Can't redirect user in Laravel

I am trying to redirect user to different url after certain event has fired but I keep receiving this error:
Symfony\Component\HttpFoundation\Response::setContent(): Argument #1 ($content) must be of type ?string, Illuminate\Routing\Redirector given, called in /var/www/html/vendor/laravel/framework/src/Illuminate/Http/Response.php on line 72
I have event listener in EventServiceProvider:
\Slides\Saml2\Events\SignedIn::class => [
SamlLoginListener::class.'#handle',
]
and then in SamlLoginListener:
public function handle(SignedIn $event)
{
$messageId = $event->auth->getLastMessageId();
// your own code preventing reuse of a $messageId to stop replay attacks
$samlUser = $event->auth->getSaml2User();
$user_data = [
'id' => $samlUser->getUserId(),
'attributes' => $samlUser->getAttributes(),
'assertion' => $samlUser->getRawSamlAssertion()
];
AuthController::saml_login($user_data);
}
Then In the AuthController::saml_login I tried all of these but the response was allways the same error:
return redirect()->away($frontend_url, 302, [
'X-SSO-AUTH-TOKENS' => json_encode($data),
]);
//
$response = new RedirectResponse($redirect_url, 302, [
'X-SSO-AUTH-TOKENS' => json_encode($data),
]);
return $response;
//
return redirect($redirect_url, 302, [
'X-SSO-AUTH-TOKENS' => json_encode($data),
]);
I decided to try it again by just returning 'ok' but still received the same error. I tried clearing the cache - no result.
Here is the full error trace: https://pastebin.com/4eZYni0w
The answer to the problem is in the error message. Your error is saying that the redirect helper method expects a string, but you're passing an object.
Not sure what version of Laravel you're using but in Laravel, Redirect responses are instances of the Illuminate\Http\RedirectResponse class and contain the proper headers needed to redirect the user to another URL.
you can try:
return redirect('/frontend_route');
Redirect to named route:
return redirect()->route('frontend_route');
If this your route has parameters like in your case, here's what to do:
return redirect()->route('frontend_route', ['X-SSO-AUTH-TOKENS' => json_encode($data)]);
Hope this helps.
source: Redirects in Laravel 8
I ended up doing this and it worked:
header("Location: " . $redirect_url);
header("X-SSO-AUTH-TOKENS: " . json_encode($data));
exit();

Symfony 5.* + Guzzle : cookies persistence

I'm currently developping an application in Symfony using Guzzle. I succesfully created a service where I make my requests (one request to get a list of enterprises, another to get user infos, ...) but I have issues regarding cookies in Guzzle. I've got to say I'm a newbie regarding API so I'm learning as I read the documentation but found nothing interesting for the moment. I've tried everything found on the internet so far but didn't get the result I wanted.
When I make a request, I get a property "Set-Cookie" in my response that I need to put in my next requests. The "Set-Cookie" property is something like "EfficySession=XX-XXXXX~XXXXXXXX-XXXXXXXX; path=/crm/; expires=Wed, 13 Oct 2021 23:22:14 GMT; HttpOnly".
So far this is where I am :
I create my client in the construct in order to be able to use the same client in every method :
public function __construct()
{
$this->client = new Client(["base_uri" => "BASE_URI", "allow_redirect" => true]);
}
And this is my test request to try setting my cookies right :
public function testFunction()
{
$json = json_encode([
[
"#name" => "api",
"#func" => [
[
"#name" => "currentuserfullname"
]
]
]
]);
$jar = new CookieJar();
$headers = [
'X-Efficy-ApiKey' => $this->apiKey,
'X-Efficy-Logoff' => 'false',
'Content-Type' => 'application/json'
];
$options = ["headers" => $headers, "body" => $json, "cookies" => $jar];
$response = $this->client->request('GET', 'json', $options);
$cookieParser = new SetCookie();
$cookie = $cookieParser->fromString($response->getHeader("Set-Cookie")[0]);
$cookie->setDomain('DOMAIN');
$this->jar->setCookie($cookie);
return json_decode($response->getBody()->getContents())[0]->{'#func'}[0];
}
But my cookies doesn't seem to be stored since I always get the property "Set-Cookie" in my response's headers... I think I've tried everything, from using SessionCookieJar to using CookieJar but nothing seems to be working.
Maybe I don't understand things the right way but as I said above, I'm just starting with API so sorry if you see big mistakes in my code.

How to send a request to another controller in Laravel using Guzzle

I am trying to send a POST request using Guzzle to a route defined in my routes/web.php from a model. Both the model and the controller are defined in the same Laravel application. The controller action linked to the route returns a JSON response and works fine when called from javascript using Ajax. However, when I try to do this using Guzzle, I have the following error:
GuzzleHttp \ Exception \ ClientException (419)
Client error: `POST https://dev.application.com/login` resulted in a `419 unknown status` response
When searching for a solution, I read that it may be caused by a missing csrf token, so I added it to my reuqest, but I still get the same error.
Here's the model code that uses Guzzle to send the request:
$client = new Client();
$response = $client->post(APPLICATION_URL.'login', [
'headers' => [
'X-CSRF-Token' => csrf_token()
],
'form_params' => [
'socialNetwork' => 'L',
'id_token' => $id
],
]);
APPLICATION_URL is simply the base URL of the application, starting with https://.
Am I missing something? Thanks in advance!
Don't send requests internally in your app, forward the call by dispatching post requests to routes instead
This method seems faster than using an HTTP client library like Guzzle
Your code should look something like this
$request = Request::create(APPLICATION_URL . 'login', 'POST', [
'socialNetwork' => 'L',
'id_token' => $id
]);
$request->headers->set('X-CSRF-TOKEN', csrf_token());
$response = app()->handle($request);
$response = json_decode($response->getContent(), true);
Update
You have to manually handle the response from internally dispatched routes, here's an example to get started
web.php
use Illuminate\Http\Request;
Route::get('/', function () {
$request = Request::create('/test', 'POST', ['var' => 'bar']);
$request->headers->set('X-CSRF-TOKEN', csrf_token());
$response = app()->handle($request);
$responseContent = json_decode($response->getContent(), true);
return $responseContent;
});
Route::post('test', function () {
$upperCaseVar = strtoupper(request()->var);
return response(['foo' => $upperCaseVar]);
});
Access / route by GET request and get response from /test as if it's POST request
Result
{
"foo": "BAR"
}
Hope this helps

Laravel 5.0 Socialite with Wunderlist

I've created a custom Provider for Laravel Socialite.
The authentication part is going well until i'll try to call the user method.
Not sure what's going wrong.
Method documentation at wunderlist
My code:
/**
* {#inheritdoc}
*/
protected function getUserByToken($token)
{
$response = $this->getHttpClient()->get('https://a.wunderlist.com/api/v1/users', [
'X-Access-Token: ' . $token . ' X-Client-ID: ' . $this->clientId
]);
return json_decode($response->getBody(), true);
}
I get the following error:
InvalidArgumentException in MessageFactory.php line 202:
allow_redirects must be true, false, or array
Do i miss things in the options array?
Jos
Actually socialite is not supposed to do something like this. But instead you may use Guzzle. There is a good video at laracasts. Just search for Easy HTTP Requests. And here's the code that you may use for guzzle:
$client = new \Guzzle\Service\Client('a.wunderlist.com/api/v1/');
$response = $client->get('user')->send();
// If you want this response in array:
$user = $response->json();
Just read the docs here.
When using this with straight forward curl there is no issue.
As far as i can see the issue lies in the headers i'll parse.
The following solution is something i can live with, although it's not perfect.
$headers = array();
$headers[] = 'X-Access-Token: ' . $token;
$headers[] = 'X-Client-ID: ' . $this->clientId;
$response = $this->getHttpClient()->get('a.wunderlist.com/api/v1/user', [
'config' => [
'curl' => [
CURLOPT_POST => 0,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => false
]
]
]);
return json_decode($response->getBody(), true);

Reddit Api endpoint returns 302 found

I'm using CakePHP and I've already got a access token and a refresh token for the Reddit API, when I make a get request to a endpoint like '/subreddits/popular.json' it works and returns json. My problem is when I make a get request to /subreddits/mine/subscriber.json I get the following response:
302 Found
The resource was found at https://www.reddit.com/subreddits/login.json?dest=https%3A%2F%2Foauth.reddit.com%2Freddits%2Fmine%2Fsubscriber.json%3Fcount%3D100%26limit%3D100; you should be redirected automatically. "
Why is json not returned? or have I missed something the code used to send a get request is:
$endpoint = $this->ENDPOINT_OAUTH . '/subreddits/mine/subscriber.json';
$options = array(
'header' => array(
'Authorization' => $accessToken,
'Accept' => 'application/json',
'Content-Type' => 'application/json; charset=UTF-8'
)
);
$results = $HttpSocket->get($endpoint, $data, $options);
print_r('<pre>');
var_dump($results);
print_r('</pre>');
EDIT: if I add to my options array 'redirect' => true then it redirects to the 302 found url and then returns a 200 ok response but with no data
EDIT 2: After adding the 'redirect' => true I then removed the ':' from in front of Bearer TOKEN and it works
To get it working I needed to add redirect => true to my options parameter so that it sent the second GET request.
When setting my access token it was set like this:
$accessToken = 'Bearer: ' . $accessToken;
When I removed the ':' from the front of Bearer it then worked and returns the results

Categories