diff --git a/README.rst b/README.rst index c340b6b..c4b67e6 100644 --- a/README.rst +++ b/README.rst @@ -128,7 +128,7 @@ Git Workflow Steps git checkout master git pull origin master - git tag -a v -m "Release " + git tag -a -m "Release " git push origin master --tags Usage diff --git a/lib/Payplug/Authentication.php b/lib/Payplug/Authentication.php index e581052..6eddb78 100644 --- a/lib/Payplug/Authentication.php +++ b/lib/Payplug/Authentication.php @@ -14,8 +14,8 @@ class Authentication * This function is for user-friendly interface purpose only. * You should probably not use this more than once, login/password MUST NOT be stored and API Keys are enough to interact with API. * - * @param string $email the user email - * @param string $password the user password + * @param string $email the user email + * @param string $password the user password * * @return null|array the API keys * @@ -130,6 +130,36 @@ public static function getPublishableKeys(Payplug $payplug = null) } } + /** + * Generate a token JWT. + * + * @param Payplug $payplug the client configuration + * + * @return array the token JWT + * + * @throws Exception + */ + public static function generateJWT($client_id = '', Payplug $payplug = null) + { + if ($client_id == '') { + return array(); + } + + if ($payplug === null) { + $payplug = Payplug::getDefaultConfiguration(); + } + + $httpClient = new Core\HttpClient($payplug); + try { + return $httpClient->post( + Core\APIRoutes::getRoute(Core\APIRoutes::$HYDRA_RESOURCE), + array('client_id' => $client_id, 'grant_type' => 'client_credentials') + ); + } catch (Exception $e) { + return array(); + } + } + /** * Validates the Payplug token * @@ -144,4 +174,98 @@ private static function validateToken(Payplug $payplug) throw new ConfigurationException('The Payplug configuration requires a valid token.'); } } + + /** + * Retrieve client datas from the user manager resource. + * + * @param Payplug $payplug the client configuration + * + * @return array the client id and client_secret_mask + * + * @throws Exception + */ + public static function getClientData($session = null, Payplug $payplug = null) + { + if ($payplug === null) { + $payplug = Payplug::getDefaultConfiguration(); + } + $kratosSession = self::setKratosSession($session); + + $httpClient = new Core\HttpClient($payplug); + $response = $httpClient->get(Core\APIRoutes::$USER_MANAGER_RESOURCE, null, $kratosSession); + $result = array(); + foreach ($response['httpResponse'] as $client) { + $result[] = array( + 'client_id' => $client['client_id'], + 'client_secret_mask' => $client['client_secret_mask'], + 'client_name' => $client['client_name'], + 'client_type' => $client['client_type'], + 'mode' => $client['mode'], + + ); + } + + return $result; + } + + /** + * Create a client ID and secret for a given mode + * + * @param $company_id + * @param $client_name + * @param $mode + * @param $session + * @param Payplug|null $payplug + * @return array + * @throws ConfigurationException + * @throws Exception\ConfigurationNotSetException + * @throws Exception\ConnectionException + * @throws Exception\HttpException + * @throws Exception\UnexpectedAPIResponseException + */ + public static function createClientIdAndSecret($company_id='', $client_name='', $mode='', $session = null, Payplug $payplug = null) + { + + if ($payplug === null) { + $payplug = Payplug::getDefaultConfiguration(); + } + $kratosSession = self::setKratosSession($session); + + $httpClient = new Core\HttpClient($payplug); + $result = array(); + + $response = $httpClient->post(Core\APIRoutes::$USER_MANAGER_RESOURCE, array( + 'company_id' => $company_id, + 'client_name' => $client_name, + 'client_type' =>'oauth2', + 'mode' => $mode, + ), $kratosSession); + foreach ($response['httpResponse'] as $client) { + $result[] = array( + 'client_id' => $client['client_id'], + 'client_secret' => $client['client_secret'], + ); + } + + return $result; + } + + + + /** + * Set the Kratos session cookie. + * + * @param string $session The session value to be set in the cookie. + * + * @return string The formatted Kratos session cookie string. + * @throws ConfigurationException + */ + public static function setKratosSession($session) + { + if (empty($session)) { + throw new ConfigurationException('The session value must be set.'); + } + return 'ory_kratos_session=' . $session; + } + } diff --git a/lib/Payplug/Core/APIRoutes.php b/lib/Payplug/Core/APIRoutes.php index dc39efc..c8055e0 100644 --- a/lib/Payplug/Core/APIRoutes.php +++ b/lib/Payplug/Core/APIRoutes.php @@ -18,6 +18,16 @@ class APIRoutes */ public static $MERCHANT_PLUGINS_DATA_COLLECTOR_RESOURCE; + /** + * @var string the root URL of the Hydra microService + */ + public static $HYDRA_RESOURCE; + + /** + * @var string the root URL of the User Manager microService + */ + public static $USER_MANAGER_RESOURCE; + const API_VERSION = 1; // Resources routes @@ -77,6 +87,24 @@ public static function setMerchantPluginsDataCollectorService($microServiceBaseU self::$MERCHANT_PLUGINS_DATA_COLLECTOR_RESOURCE = $microServiceBaseUrl; } + /** + * @description set $HYDRA_RESOURCE from plugin + * @param $microServiceBaseUrl + */ + public static function setHydraResource($microServiceBaseUrl) + { + self::$HYDRA_RESOURCE = $microServiceBaseUrl; + } + + /** + * @description set $USER_MANAGER_RESOURCE from plugin + * @param $microServiceBaseUrl + */ + public static function setUserManagerResource($microServiceBaseUrl) + { + self::$USER_MANAGER_RESOURCE = $microServiceBaseUrl; + } + /** * Gets a route that allows to check whether the remote API is up. * @@ -89,5 +117,6 @@ public static function getTestRoute() } APIRoutes::$API_BASE_URL = 'https://api.payplug.com'; -APIRoutes::$MERCHANT_PLUGINS_DATA_COLLECTOR_RESOURCE = 'Microservice Url'; - +APIRoutes::$MERCHANT_PLUGINS_DATA_COLLECTOR_RESOURCE = 'https://retail.service.payplug.com/merchant-plugin-data-collectors/api/v1/plugin_telemetry'; +APIRoutes::$USER_MANAGER_RESOURCE ='User manager resource'; +APIRoutes::$HYDRA_RESOURCE = 'Microservice Url'; diff --git a/lib/Payplug/Core/HttpClient.php b/lib/Payplug/Core/HttpClient.php index 0da94c5..08ed9ca 100644 --- a/lib/Payplug/Core/HttpClient.php +++ b/lib/Payplug/Core/HttpClient.php @@ -122,9 +122,9 @@ public function delete($resource, $data = null) * @throws Payplug\Exception\HttpException When status code is not 2xx. * @throws Payplug\Exception\ConnectionException When an error was encountered while connecting to the resource. */ - public function get($resource, $data = null) + public function get($resource, $data = null, $cookie=null) { - return $this->request('GET', $resource, $data); + return $this->request('GET', $resource, $data, true, $cookie); } /** @@ -226,7 +226,7 @@ public static function getUserAgent() * @throws Payplug\Exception\HttpException When status code is not 2xx. * @throws Payplug\Exception\ConnectionException When an error was encountered while connecting to the resource. */ - private function request($httpVerb, $resource, array $data = null, $authenticated = true) + private function request($httpVerb, $resource, array $data = null, $authenticated = true, $cookie = null) { if (self::$REQUEST_HANDLER === null) { $request = new CurlRequest(); @@ -246,6 +246,10 @@ private function request($httpVerb, $resource, array $data = null, $authenticate $headers[] = 'PayPlug-Version: ' . $this->_configuration->getApiVersion(); } + if (!empty($cookie)) { + $headers[] = 'Cookie:' . $cookie; + } + $request->setopt(CURLOPT_FAILONERROR, false); $request->setopt(CURLOPT_RETURNTRANSFER, true); $request->setopt(CURLOPT_CUSTOMREQUEST, $httpVerb); @@ -254,6 +258,7 @@ private function request($httpVerb, $resource, array $data = null, $authenticate $request->setopt(CURLOPT_SSL_VERIFYPEER, true); $request->setopt(CURLOPT_SSL_VERIFYHOST, 2); $request->setopt(CURLOPT_CAINFO, self::$CACERT_PATH); + $request->setopt(CURLOPT_FOLLOWLOCATION, true); if (!empty($data)) { $request->setopt(CURLOPT_POSTFIELDS, json_encode($data)); } diff --git a/lib/Payplug/PluginTelemetry.php b/lib/Payplug/PluginTelemetry.php index 98d9eab..387a8cf 100644 --- a/lib/Payplug/PluginTelemetry.php +++ b/lib/Payplug/PluginTelemetry.php @@ -27,12 +27,15 @@ class PluginTelemetry public static function send(string $data, Payplug\Payplug $payplug = null) { $data = json_decode($data,true); - $httpClient = new Payplug\Core\HttpClient(); + if ($payplug === null) { + $payplug = Payplug\Payplug::getDefaultConfiguration(); + } + + $httpClient = new Payplug\Core\HttpClient($payplug); return $response = $httpClient->post( Payplug\Core\APIRoutes::$MERCHANT_PLUGINS_DATA_COLLECTOR_RESOURCE, - $data, - false + $data ); } diff --git a/tests/unit_tests/AuthenticationTest.php b/tests/unit_tests/AuthenticationTest.php index 1c0de7a..90c6249 100644 --- a/tests/unit_tests/AuthenticationTest.php +++ b/tests/unit_tests/AuthenticationTest.php @@ -11,6 +11,7 @@ */ class AuthenticationTest extends \PHPUnit\Framework\TestCase { + private $_configuration; private $_requestMock; /** @@ -211,4 +212,168 @@ public function testPublishableKeys() $this->assertEquals(200, $publishable_keys['httpStatus']); $this->assertEquals('pk_test_everythingIsUnderControl', $publishable_keys['httpResponse']['publishable_key']); } + + /** + * Test the getClientIdAndSecretMask method. + * + * This test verifies that the getClientData method correctly retrieves + * the client_id, client_secret_mask , client_name client_type and mode from the user manager resource. + * + * @throws \Exception + */ + public function testGetClientData() + { + $response = array( + array( + 'client_id' => 'test_client_id', + 'client_secret_mask' => 'test_secret_mask', + 'client_name' => 'test_client_name', + 'client_type' => 'test_client_type', + 'mode' => 'test_mode', + ), + ); + + $this->_requestMock + ->expects($this->once()) + ->method('exec') + ->will($this->returnValue(json_encode($response))); + + $this->_requestMock + ->expects($this->any()) + ->method('getinfo') + ->will($this->returnCallback(function($option) { + switch($option) { + case CURLINFO_HTTP_CODE: + return 200; + } + return null; + })); + + $session = 'test_session_value'; + $result = Authentication::getClientData($session, $this->_configuration); + $this->assertCount(1, $result); + $this->assertEquals('test_client_id', $result[0]['client_id']); + $this->assertEquals('test_secret_mask', $result[0]['client_secret_mask']); + $this->assertEquals('test_client_name', $result[0]['client_name']); + $this->assertEquals('test_client_type', $result[0]['client_type']); + $this->assertEquals('test_mode', $result[0]['mode']); + + } + + /** + * Test the createClientIdAndSecret correctly creates + * a client ID and client secret. + * + * @throws \Exception + */ + public function testCreateClientIdAndSecret() + { + $response = array( + array( + 'client_id' => 'test_client_id', + 'client_secret' => 'test_client_secret', + ), + ); + + $this->_requestMock + ->expects($this->once()) + ->method('exec') + ->will($this->returnValue(json_encode($response))); + + $this->_requestMock + ->expects($this->any()) + ->method('getinfo') + ->will($this->returnCallback(function($option) { + switch($option) { + case CURLINFO_HTTP_CODE: + return 200; + } + return null; + })); + $session = 'test_session_value'; + $company_id = 'test_company_id'; + $client_name = 'test_client_name'; + $mode = 'test'; + $result = Authentication::createClientIdAndSecret($company_id, $client_name, $mode, $session, $this->_configuration); + $this->assertCount(1, $result); + $this->assertEquals('test_client_id', $result[0]['client_id']); + $this->assertEquals('test_client_secret', $result[0]['client_secret']); + } + + /** + * Test the setKratosSession method with a null session. + */ + public function testSetKratosSessionNull() + { + $this->expectException('\PayPlug\Exception\ConfigurationException'); + $this->expectExceptionMessage('The session value must be set.'); + Authentication::setKratosSession(null); + } + + public function testGenerateJWTWithEmptyClientId() + { + $jwt = Authentication::generateJWT($this->_configuration); + $this->assertEquals(array(), $jwt); + } + + public function testGenerateJWTWhenErrorResponse() + { + $response = array( + 'access_token' => 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImE2NmQxZWU3LTQzMWMtNDNiYS04NzA4LWQ1MzNkNTVmZjhlZCIsInR5cCI6IkpXVCJ9.eyJhdWQiOltdLCJjbGllbnRfaWQiOiIyNzdlNDk4MS0yYTBjLTQ4NGEtYTE3Ni1hZWNhOWRjNDhkNTQiLCJleHAiOjE3Mjc5NjU3OTQsImV4dCI6eyJjb21wYW55X2lkIjoiZDE0NzQ1ZmQtMTc5Yy00N2IxLTlkZDgtMTk3OTVmMzQ1MjJiIiwicmVhbG1faWQiOiIxNTM0N2NjNy0xZThmLTQzYzMtYjJjZi1iZDMxY2M5ZWU4YTEiLCJyZXNvdXJjZV9hY2Nlc3MiOnsiYXBpIjp7InJvbGVzIjpbIk1FUkNIQU5UX0FQUFMiXX19fSwiaWF0IjoxNzI3OTYyMTk0LCJpc3MiOiJodHRwczovLzEyNy4wLjAuMTo0NDQ0IiwianRpIjoiMGNhMzUyOWItOGQ5Zi00NDQxLWEyNDAtMGZhY2YyNDNmN2JiIiwibmJmIjoxNzI3OTYyMTk0LCJzY3AiOltdLCJzdWIiOiIyNzdlNDk4MS0yYTBjLTQ4NGEtYTE3Ni1hZWNhOWRjNDhkNTQifQ.K1pavlVMz4D4cAJtL8IklLXIos7ZjiC9YSofb343uLkjXdhbgel23k0GyEE_JkQ2xSSB46XLYQp0j-M1AaJIoNjCfVR-O1yWNpLYnLM07ECETO3kQc63vcvzOm5trn5oBq_T3FE78EmAIA5B3oaSu_m5_qUBci_C7oM0ItMMIpFnKYqk2ta8y2eUFFPu7detxJRLlBK4I7hW0xAt07GNhfyRl8eN7twC3aYFFkUejZmuEB_FmZkj7OqZDsNblDR21Ci_cahuZmt9WOmIqTW58l7wxXOB9vq5APtBi2LpQtE52ARofUNCWWOK1KHz_vSQlGiGDM6_56K85Whfkkj-LYvLRRZUuIXE2m528JTtnCarZr7Md5P9zHQOZyIbcWrjiUdM_daI1vELPT4UaCBIfpy-vY0wywiPtoosokNsFQNrwxo8f9affUkiuEwZedK9sreDfVL_tmrz5Bh6XzxMZB5ZiVQckUUPF7LKrBB8qDwotYvwdLIN-Wy3l2IeeTzF_NOFmO6mrNift2RhSQZP0s7Xfn2dVK1eiyO4gERNrsPvasb9nB15PIQ57wwWKzN8ue6z9utAX6YThTgc2fadrOWYMeo2W4c7KmuKr9hhLK2ThIWRM7H5rQq3H7Ke5AzlKyCQdgFlQzSl0O1gjzA0T4AnfuNW1zNedSfUsqMJCfM', + 'expires_in' => 3599, + 'scope' => '', + 'token_type' => 'bearer' + ); + + $this->_requestMock + ->expects($this->once()) + ->method('exec') + ->will($this->returnValue(json_encode($response))); + + $this->_requestMock + ->expects($this->any()) + ->method('getinfo') + ->will($this->returnCallback(function($option) { + switch($option) { + case CURLINFO_HTTP_CODE: + return 401; + } + return null; + })); + + $jwt = Authentication::generateJWT('some_client_id', $this->_configuration); + + $this->assertEquals(array(), $jwt); + } + + public function testGenerateJWTWhenSuccessResponse() + { + $response = array( + 'access_token' => 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImE2NmQxZWU3LTQzMWMtNDNiYS04NzA4LWQ1MzNkNTVmZjhlZCIsInR5cCI6IkpXVCJ9.eyJhdWQiOltdLCJjbGllbnRfaWQiOiIyNzdlNDk4MS0yYTBjLTQ4NGEtYTE3Ni1hZWNhOWRjNDhkNTQiLCJleHAiOjE3Mjc5NjU3OTQsImV4dCI6eyJjb21wYW55X2lkIjoiZDE0NzQ1ZmQtMTc5Yy00N2IxLTlkZDgtMTk3OTVmMzQ1MjJiIiwicmVhbG1faWQiOiIxNTM0N2NjNy0xZThmLTQzYzMtYjJjZi1iZDMxY2M5ZWU4YTEiLCJyZXNvdXJjZV9hY2Nlc3MiOnsiYXBpIjp7InJvbGVzIjpbIk1FUkNIQU5UX0FQUFMiXX19fSwiaWF0IjoxNzI3OTYyMTk0LCJpc3MiOiJodHRwczovLzEyNy4wLjAuMTo0NDQ0IiwianRpIjoiMGNhMzUyOWItOGQ5Zi00NDQxLWEyNDAtMGZhY2YyNDNmN2JiIiwibmJmIjoxNzI3OTYyMTk0LCJzY3AiOltdLCJzdWIiOiIyNzdlNDk4MS0yYTBjLTQ4NGEtYTE3Ni1hZWNhOWRjNDhkNTQifQ.K1pavlVMz4D4cAJtL8IklLXIos7ZjiC9YSofb343uLkjXdhbgel23k0GyEE_JkQ2xSSB46XLYQp0j-M1AaJIoNjCfVR-O1yWNpLYnLM07ECETO3kQc63vcvzOm5trn5oBq_T3FE78EmAIA5B3oaSu_m5_qUBci_C7oM0ItMMIpFnKYqk2ta8y2eUFFPu7detxJRLlBK4I7hW0xAt07GNhfyRl8eN7twC3aYFFkUejZmuEB_FmZkj7OqZDsNblDR21Ci_cahuZmt9WOmIqTW58l7wxXOB9vq5APtBi2LpQtE52ARofUNCWWOK1KHz_vSQlGiGDM6_56K85Whfkkj-LYvLRRZUuIXE2m528JTtnCarZr7Md5P9zHQOZyIbcWrjiUdM_daI1vELPT4UaCBIfpy-vY0wywiPtoosokNsFQNrwxo8f9affUkiuEwZedK9sreDfVL_tmrz5Bh6XzxMZB5ZiVQckUUPF7LKrBB8qDwotYvwdLIN-Wy3l2IeeTzF_NOFmO6mrNift2RhSQZP0s7Xfn2dVK1eiyO4gERNrsPvasb9nB15PIQ57wwWKzN8ue6z9utAX6YThTgc2fadrOWYMeo2W4c7KmuKr9hhLK2ThIWRM7H5rQq3H7Ke5AzlKyCQdgFlQzSl0O1gjzA0T4AnfuNW1zNedSfUsqMJCfM', + 'expires_in' => 3599, + 'scope' => '', + 'token_type' => 'bearer' + ); + + $this->_requestMock + ->expects($this->once()) + ->method('exec') + ->will($this->returnValue(json_encode($response))); + + $this->_requestMock + ->expects($this->any()) + ->method('getinfo') + ->will($this->returnCallback(function($option) { + switch($option) { + case CURLINFO_HTTP_CODE: + return 200; + } + return null; + })); + + $jwt = Authentication::generateJWT('some_client_id', $this->_configuration); + + $this->assertEquals(200, $jwt['httpStatus']); + $this->assertEquals($response, $jwt['httpResponse']); + } }