In a Laravel feature test, I'm trying to store a variable in a session so that I can use it in the rest of my tests, like so:
public function testLogin()
{
$response = $this->json('POST', '/login', $myCredentials);
$response
->assertStatus(200)
->assertJson([
'token' => true
]);
session(['token' => $response['token']]);
}
When I run "phpunit" in the command line, I get this error:
PHP Fatal error: Uncaught ReflectionException: Class session does
not exist in
/vendor/laravel/framework/src/Illuminate/Container/Container.php:752
Apparently the "session()" global helper doesn't work in test classes. I also tried to work with the class directly by using "Illuminate\Session" or just "\Session", but both returned in "not found" errors. How can I store and retrieve session variables within test classes?
In tests it's a bit different.
https://laravel.com/docs/5.2/testing#sessions-and-authentication
Here is an example:
public function testApplication()
{
$this->withSession(['foo' => 'bar'])
->visit('/');
}
There a way to do that you want. The unic problem it's that doesn't work with session.
When you start the test, you must generate the function "master" that will call the rest of functions.
/**
* Try to login the api client (if you have another middleware use it)
* #group groupTests
* #test
*/
public function masterFunction() {
//create the body data to try generate the oauth token
$body = [
'client_id' => $this->client_id_test,
'client_secret' => $this->secret,
'grant_type' => 'client_credentials',
'scope' => ''
];
//get the response with the data
$response = $this->json('POST','/oauth/token',$body,['Accept' => 'application/json']);
//check that return a valid token
$response->assertStatus(200)->assertJsonStructure(['token_type','expires_in','access_token']);
//get token data in var
$token = $response->json("token_type")." ".$response->json("access_token");
//send string token to the next function
$this->childrenFunction($token);
}
When you construct "children functions" must make them like this:
/**
* This function get the token as param
* #param String $token The token that we want
* #group groupTests
*/
private function childrenFunction($token){
//here can call to $token as a var
dd($token);
}
It's important that "children functions" doesn't have * #test at the header description.
Related
I recently changed my DocuSign integration to use the JWT OAuth flow. To achieve this I have a few classes.
OAuth Client
<?php
namespace App\DocuSign;
use DocuSign\eSign\Client\ApiClient;
use DocuSign\eSign\Client\Auth\OAuth;
use DocuSign\eSign\Configuration;
use Exception;
use Illuminate\Support\Facades\Log;
/**
* Helper class to generate a DocuSign Client instance using JWT OAuth2.
*
* #see
*
*/
class OAuthClient
{
/**
* Create a new DocuSign API Client instance using JWT based OAuth2.
*/
public static function createApiClient()
{
$config = (new Configuration())->setHost(config('docusign.host'));
$oAuth = (new OAuth())->setOAuthBasePath(config('docusign.oauth_base_path'));
$apiClient = new ApiClient($config, $oAuth);
try {
$response = $apiClient->requestJWTUserToken(
config('docusign.integrator_key'),
config('docusign.user_id'),
config('docusign.private_key'),
'signature impersonation',
60
);
if ($response) {
$accessToken = $response[0]['access_token'];
$config->addDefaultHeader('Authorization', 'Bearer ' . $accessToken);
$apiClient = new ApiClient($config);
return $apiClient;
}
} catch (Exception $e) {
// If consent is required we just need to give the consent URL.
if (strpos($e->getMessage(), 'consent_required') !== false) {
$authorizationUrl = config('docusign.oauth_base_path') . '/oauth/auth?' . http_build_query([
'scope' => 'signature impersonation',
'redirect_uri' => config('docusign.redirect_url'),
'client_id' => config('docusign.integrator_key'),
'response_type' => 'code'
]);
Log::critical('Consent not given for DocuSign API', [
'authorization_url' => $authorizationUrl
]);
abort(500, 'Consent has not been given to use the DocuSign API');
}
throw $e;
}
}
}
Signature Client Service
<?php
namespace App\DocuSign;
use DocuSign\eSign\Api\EnvelopesApi;
use DocuSign\eSign\Client\ApiClient;
class SignatureClientService
{
/**
* DocuSign API Client
*/
public ApiClient $apiClient;
/**
* Create a new instance of our class.
*/
public function __construct()
{
$this->apiClient = OAuthClient::createApiClient();
}
/**
* Getter for the EnvelopesApi
*/
public function getEnvelopeApi(): EnvelopesApi
{
return new EnvelopesApi($this->apiClient);
}
}
Then, in my constructors where I want to use it I'm doing
/**
* Create a new controller instance
*/
public function __construct()
{
$this->clientService = new SignatureClientService();
$this->envelopesApi = $this->clientService->getEnvelopeApi();
}
Finally, I use it like so
$envelopeSummary = $this->envelopesApi->createEnvelope(config('docusign.api_account_id'), $envelopeDefinition);
But I get an error that reads
DocuSign\eSign\Client\ApiException: Error while requesting server,
received a non successful HTTP code [400] with response Body:
O:8:"stdClass":2:{s:9:"errorCode";s:21:"USER_LACKS_MEMBERSHIP";s:7:"message";s:60:"The
UserID does not have a valid membership in this Account.";} in
/homepages/45/d641872465/htdocs/sites/ita-portal/vendor/docusign/esign-client/src/Client/ApiClient.php:344
I researched this and this would imply that the user is not within the account, but they are. I also checked that this account owns the envelopes that I'm trying to send.
For reference I took inspiration for envelope sending from here: https://developers.docusign.com/docs/esign-rest-api/how-to/request-signature-template-remote/
What I think is happening is that the request is going to the wrong server or the wrong account.
I'd suggest using a packet analyser like Fiddler or Wireshark to log where your requests are headed (or just log the request within your application)
The auth URLs seem to be correct since you're not getting a 401 unauthorised error but the envelopes and other queries' must match the base URL located in your account under the Apps and Keys page. It would be of the form demo.docusign.net for our demo environment or xxx.docusign.net for our production environment
I have the following code:
$storedToken = getStoredToken();
/**
* Verify if the stored token has expired.
*/
if ($storedToken->hasExpired()) {
/**
* If the stored token has expired, then you request a new one.
*/
$newToken = $provider->getAccessToken('refresh_token', [
'refresh_token' => $storedToken->getRefreshToken()
In my db I have the following fields:
token
refreshtoken
expires
I tried:
public function StoredToken(){
$user = Auth::user(); //data is on users table.
return $refreshtoken = $user->melirefreshtoken; //eg.
}
But with no success. I cannot find the way to create a function to create an object passing all the information.
Right now I received error:
Call to undefined function App\Http\Controllers\getStoredToken()
any help appreciated.
The root of the problem seems to be this line:
$storedToken = getStoredToken();
// ^^^^^^^^^^^^^^^^^
If you are trying to call a function from another function (from the same class).. add this:
$storedToken = $this->getStoredToken();
// ^^^^^^^
I am using oauth2-microsoft to develop a 'sign in with Microsoft' tool for my app. I'm successfully authenticating and receiving a token, but then I receive an error from the sample code.
I am using the sample code below and have tried various combinations of URLs in the 'urlResourceOwnerDetails' field, including leaving it blank.
$provider = new \Stevenmaguire\OAuth2\Client\Provider\Microsoft([
'clientId' => '<redacted>',
'clientSecret' => '<redacted>',
'redirectUri' => 'http://localhost/test.php',
'urlAuthorize' => 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
'urlAccessToken' => 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
'urlResourceOwnerDetails' => 'https://graph.microsoft.com/v1.0/me/drive'
]);
$options = [
'scope' => ['wl.basic', 'wl.signin']
];
After this comes authentication and token generation.
Then this line throws errors:
$user = $provider->getResourceOwner($token);
A token is definitely being generated, as I can echo $token and see it.
The above code should create a $user object that contains details about the logged in user. However, instead it generates these errors:
If 'urlResourceOwnerDetails' is set to https://graph.microsoft.com/v1.0/me/drive I get:
League\OAuth2\Client\Provider\Exception\IdentityProviderException: Access token is empty
If 'urlResourceOwnerDetails' is set to https://outlook.office.com/api/v2.0/me I get:
UnexpectedValueException: Invalid response received from Authorization Server. Expected JSON.
And if 'urlResourceOwnerDetails' is empty I get:
GuzzleHttp\Exception\RequestException: cURL error 3: malformed (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)
Any ideas, please?
It appears oauth2-microsoft does not support Microsoft Graph Auth to a full extent at the moment, refer for example this thread
Regarding the error
League\OAuth2\Client\Provider\Exception\IdentityProviderException:
Access token is empty
access token is expected to be passed as Authorization header but according to Microsoft.php provider implementation it is passed instead as query string:
public function getResourceOwnerDetailsUrl(AccessToken $token)
{
$uri = new Uri($this->urlResourceOwnerDetails);
return (string) Uri::withQueryValue($uri, 'access_token', (string) $token);
}
The way how library is designed, the following provider class could be introduced to support Microsoft Graph calls (by including access token in the Authorization header of a request)
class MicrosoftGraphProvider extends AbstractProvider
{
/**
* Get provider url to fetch user details
*
* #param AccessToken $token
*
* #return string
*/
public function getResourceOwnerDetailsUrl(AccessToken $token)
{
return 'https://graph.microsoft.com/v1.0/me';
}
protected function getAuthorizationHeaders($token = null)
{
return ['Authorization'=>'Bearer ' . $token->getToken()];
}
public function getBaseAuthorizationUrl()
{
return 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
}
public function getBaseAccessTokenUrl(array $params)
{
return 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
}
protected function getDefaultScopes()
{
return ['openid profile'];
}
protected function checkResponse(\Psr\Http\Message\ResponseInterface $response, $data)
{
// TODO: Implement checkResponse() method.
}
protected function createResourceOwner(array $response, AccessToken $token)
{
return (object)$response;
}
}
I am a newbie to JWT Token System in laravel 5 and using tymon JWT Auth
I managed to create my custom JWT token and my code as follows
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Tymon\JWTAuth\JWTManager as JWT;
use JWTAuth;
use JWTFactory;
use Tymon\JWTAuth\Exceptions\JWTException;
public function login(Request $request)
{
$customClaims = ['foo' => 'bar', 'baz' => 'bob'];
$payload = JWTFactory::make($customClaims);
$token = JWTAuth::encode($payload);
// return response()->json(compact('token')); // This didnt work?Why?
return response()->json(compact($token))->header('Authorization','Bearer '.$token);
}
public function getUser(){
$token = JWTAuth::parseToken();
echo $token;
}
Here are my following clarifications required
// return response()->json(compact('token'));
Why this gave me an empty json object as {"token":{}}
Is it the right way, i could send my custom data in token and get it back the foo and baz values from the same token?
The output of my code while testing with postman is an empty array. as []. But my headers are added with Authorization →Bearer eyJ0eXAiOiJKV1QiLCJhbG...
Is this correct?
3a. Instead of a simple blank array, i need a success message as 'authorized':true. How can i achieve it?
How should i pass this token back to test. Where should this token be passed using postman. I passed it through Headers as shown in the image
How could i parse this token using laravel and get the custom data i.e foo and baz sent as a token. The method i called is getUser here.
I dont think the token creation is being built properly. Below is working code for login token creation. For this, make sure that the 'user' model under your config/jwt.php is the correct eloquent user model for your application.
$user = array(
'user' => $request->input('email'),
'password' => $request->input('pass')
);
$customClaims= ['usr' => $user['user']];
if(!$token = JWTAuth::attempt($user, $customClaims)){
abort(401);
}
else{
return response()->json(compact('token'));
}
Also included in the above code with the custom claims variable, you were on the right track with that just needs to be passed as a second parameter in the attempt function.
Only the client needs to send the authorization: Bearertoken header to prove that they are who they say they are (I am coming from an android client/server jwt background. So sorry if this doesnt apply to your application).
3a. For any subsequent pages that the user browses to, you simply add an if statement like this
if(!$user = JWTAuth::parseToken()->authenticate()){
abort(401);
}
else{
// Code allowing the user to see protected content
}
See answer to question 3. include an http header with authorization BearerToken
To extract the data from the JWT Payload, you will need to decode the base64 encoded text from the text after the first period in the token and send that to a string. Then run that string through the base64_decode($string) function. That should start to give you some of the payload data.
Hope this helps.
I had the same problem here and i got the following solution:
public function whatEver()
{
$token = JWTAuth::parseToken();
$response = $token->getPayload()->get('foo');
return $response
}
this should return bar.
you can use this method in your user model :
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [
'perms' => '
'
];
}
This is killing me.I have done everything but not right as its not still giving me this error
Fatal error: Uncaught exception 'CFCredentials_Exception' with message 'No credentials were provided. I am trying to upload files to S3 using AWS sdk 1.6 example and jquery file upload plugin.I found an example on the wiki.
This is my file where I set the credentials awssdk.php from the wiki example
require_once 'sdk.class.php';
require_once 'utilities.class.php';
require_once 'credential.class.php';
if (!class_exists('CFCredentials'))require_once('credentials.class.php');
$name=null;
CFCredentials::set(array(
$name => array(
'key' => 'access key',
'secret' => 'secret key',
'certificate_authority' => false
),
'#default' => $name
));
if (!class_exists('S3'))require_once('S3.php');
$s3 = new AmazonS3();
I am quite sure I should't need so many files but as the errors suggested I had to add the dependency classes.But still I get the above error. I also tried to include the config.class.php file for credentials and still got this error.I have been spending a lot of time on this and now kind of frustrated with this AWS sdk.
I am a bit new to OO PHP and probably hence finding it difficult.Experts please suggest some solution to where I am wrong.
EDIT: I believe this class causes the issue,not sure how!!
class CFCredentials
{
/**
* The key used to specify the default credential set
*/
const DEFAULT_KEY = 'my key';
/**
* The key used to identify inherited credentials
*/
const INHERIT_KEY = 'my secret key';
/**
* Stores the credentials
*/
protected static $credentials = array();
/**
* Prevents this class from being constructed
*/
final private function __construct() {}
/**
* Stores the credentials for re-use.
*
* #param array $credential_sets (Required) The named credential sets that should be made available to the application.
* #return void
*/
// private $credential_sets = array('key' => 'xxxxxxxxxxxxxxxxxxxx','secret' => 'xxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxx','certificate_authority' => false);
public static function set(array $credential_sets)
{
// Make sure a default credential set is specified or can be inferred
if (count($credential_sets) === 1)
{echo "in count if-->".self::DEFAULT_KEY;
$credential_sets[self::DEFAULT_KEY] = reset($credential_sets);
}
// Resolve any #inherit tags
foreach ($credential_sets as $credential_name => &$credential_set)
{
if (is_array($credential_set))
{
foreach ($credential_set as $credential_key => &$credential_value)
{
if ($credential_key === self::INHERIT_KEY)
{
if (!isset($credential_sets[$credential_value]))
{
throw new CFCredentials_Exception('The credential set, "' . $credential_value . '", does not exist and cannot be inherited.');
}
$credential_set = array_merge($credential_sets[$credential_value], $credential_set);
unset($credential_set[self::INHERIT_KEY]);
}
}
}
}
// Normalize the value of the #default credential set
if (isset($credential_sets[self::DEFAULT_KEY]))
{
$default = $credential_sets[self::DEFAULT_KEY];
if (is_string($default))
{
if (!isset($credential_sets[$default]))
{
throw new CFCredentials_Exception('The credential set, "' . $default . '", does not exist and cannot be used as the default credential set.');
}
$credential_sets[self::DEFAULT_KEY] = $credential_sets[$default];
}
}
// Store the credentials
self::$credentials = $credential_sets;
}
/**
* Retrieves the requested credentials from the internal credential store.
*
* #param string $credential_set (Optional) The name of the credential set to retrieve. The default value is set in DEFAULT_KEY.
* #return stdClass A stdClass object where the properties represent the keys that were provided.
*/
public static function get($credential_name = self::DEFAULT_KEY)
{
//echo $credential_name; exit;
// Make sure the credential set exists
if (!isset(self::$credentials[$credential_name]))
{
throw new CFCredentials_Exception('The credential set, "' . $credential_name . '", does not exist and cannot be retrieved.');
}
// Return the credential set as an object
return new CFCredential(self::$credentials[$credential_name]);
}
/**
* Retrieves a list of all available credential set names.
*
* #return CFArray A list of all available credential set names.
*/
public static function list_sets()
{
return new CFArray(array_keys(self::$credentials));
}
}
class CFCredentials_Exception extends Exception {}
Thank you
It seems like whatever tutorial you are following is making this unnecessarily difficult. Try this:
require_once 'sdk.class.php';
$s3 = new AmazonS3(array(
'key' => 'your_aws_access_key_id',
'secret' => 'your_aws_secret_key',
));
You shouldn't need to require any other files.
You have set all Credential well but still you have leave one credential 'default_cache_config' => ''
Just Put it in Credential array with some location for caching the default credential.
just have a look
$name=null;
CFCredentials::set(array(
$name => array(
'key' => 'access key',
'secret' => 'secret key',
'default_cache_config' => '/home/user/any location',
'certificate_authority' => false
),
'#default' => $name
));**