diff --git a/README.md b/README.md index e5869eb20..eb0251f35 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Amadeus documentation portal can be found at https://webservices.amadeus.com * PHP 5.4+ * SOAP and XSL extensions activated -* A WSDL & authentication details from Amadeus +* A WSDL & authentication details from Amadeus _(SoapHeader 4 or SoapHeader 2)_ # Installation diff --git a/docs/about-get-started.rst b/docs/about-get-started.rst index 411b8998a..5717d6771 100644 --- a/docs/about-get-started.rst +++ b/docs/about-get-started.rst @@ -11,7 +11,7 @@ See `the Amadeus Web Services website `_ for m The basic pieces of information you will need to use this library are: - **The WSDL file with all its includes**: You can just extract the ZIP file you received from Amadeus to a location on your filesystem where the client can access it. -- **The authentication information required to start a session**: Office ID's, User Id (=Originator), Password, Duty Code. *For legacy WSAP's using Soap Header 1 or 2, you'll need: Office ID, Originator, Organization ID, Password Length, Password Data. Soap Header 1 & 2 is not yet implemented in this library* +- **The authentication information required to start a session**: Office ID's, User Id (=Originator), Password, Duty Code. *For legacy WSAP's using Soap Header 1 or 2, you'll need: Office ID, Originator, Organization ID, Password Length, Password Data. Soap Header 1 is not yet implemented in this library* You usually receive this information after the project kick-off has been done and a support person has been assigned to your project. @@ -20,9 +20,12 @@ Support for Amadeus Soap Header versions **************************************** Upon receiving access, Amadeus will give you a Web Service Access Point with a specific Soap Header version to use. This will define how you can handle session management *(e.g. support for stateless calls, requiring session pooling or not)*. -This library is initially built to support the current Soap Header v4, which is the Soap Header Version you would get for a new WSAP requested today (2016). +This library is built to support the current **Soap Header 4** and the legacy **Soap Header 2**. -Legacy applications using already certified WSAP's can still be running on legacy Soap Header versions - most notably Soap Header 1 & 2. This library currently doesn't support those yet, but we plan to add that in the future. +- Soap Header 4 is the Soap Header Version you would get for a new WSAP requested today (2016). +- Soap Header 2 is still in use in legacy applications. + +Legacy applications using already certified WSAP's can still be running on legacy Soap Header versions (Soap Header 1 & 2). This library doesn't support Soap Header 1 at the moment. ****************************************** Support for different versions of messages @@ -52,6 +55,8 @@ Install the client library in your PHP project by requiring the package with Com Set up a test client ******************** +Soap Header 4 example: + .. code-block:: php 'ABC123']) ); +Soap Header 2 example: + +.. code-block:: php + + [ + 'soapHeaderVersion' => Client::HEADER_V2, + 'wsdl' => '/home/user/mytestproject/data/amadeuswsdl/1ASIWXXXXXX_PDT_20110101_080000.wsdl', //Points to the location of the WSDL file for your WSAP. Make sure the associated XSD's are also available. + 'logger' => new Psr\Log\NullLogger(), + 'authParams' => [ + 'officeId' => 'BRUXX1111', //The Amadeus Office Id you want to sign in to - must be open on your WSAP. + 'userId' => 'WSBENXXX', //Also known as 'Originator' for Soap Header 1 & 2 WSDL's + 'passwordData' => 'dGhlIHBhc3N3b3Jk' // **base 64 encoded** password + 'passwordLength' => 12, + 'dutyCode' => 'SU', + 'organizationId' => 'DUMMY-ORG', + ] + ], + 'requestCreatorParams' => [ + 'receivedFrom' => 'my test project' // The "Received From" string that will be visible in PNR History + ] + ]); + + $client = new Client($params); + + $authResult = $client->securityAuthenticate(); + + if (isset($authResult->processStatus->statusCode) && $authResult->processStatus->statusCode === 'P') { + //We are authenticated! + $pnrContent = $client->pnrRetrieve( + new PnrRetrieveOptions(['recordLocator' => 'ABC123']) + ); + } + ****************** Messages supported @@ -92,6 +139,7 @@ Messages supported This is the list of messages that are at least partially supported at this time: +- Security_Authenticate - Security_SignOut - PNR_Retrieve - PNR_RetrieveAndDisplay @@ -135,5 +183,3 @@ On the to-do list / work in progress: - Ticket_DisplayTST - Ticket_DeleteTST - SalesReports_DisplayQueryReport - -- Support for SoapHeader V2 diff --git a/docs/samples.rst b/docs/samples.rst index 57f6ebeb6..cac15d1fc 100644 --- a/docs/samples.rst +++ b/docs/samples.rst @@ -4,9 +4,9 @@ EXAMPLES Here are some examples of how you can handle some problems you might encounter and how to send specific messages. -*********************************************** -Switching between stateful & stateless messages -*********************************************** +*************************************************************** +Switching between stateful & stateless messages (Soap Header 4) +*************************************************************** If you do not require an active context in your session, you're better off using stateless messages. @@ -38,9 +38,9 @@ It's also possible to specify the default stateful setting at construction time $client = new Client($params); -************************* -Ending a stateful session -************************* +***************************************** +Ending a stateful session (Soap Header 4) +***************************************** After doing multiple calls with a stateful session, there are two ways to end the session: @@ -59,6 +59,30 @@ After doing multiple calls with a stateful session, there are two ways to end th ['endSession' => true] ); +************************************ +Handling sessions with Soap Header 2 +************************************ + +Soap Header 2 based applications are a bit more cumbersome to handle in order to get a successful certification: + +- you need to implement session pooling in order to limit the number of session creation/destruction events +- you need to enforce your maximum number of concurrent sessions +- you need to send a separate authentication message before you can do anything + +This library does not provide any session pooling mechanism, you'll have to implement this yourself. + +You can get a current session's info (for later re-use) by calling + +.. code-block:: php + + $client->getSessionData(); + +You can restore a previous current session after you retrieved it from your session pool for later re-use: + +.. code-block:: php + + $client->setSessionData($previousSessionData); + ********************* Handling the response diff --git a/src/Amadeus/Client.php b/src/Amadeus/Client.php index 000f1cd00..2aab39114 100644 --- a/src/Amadeus/Client.php +++ b/src/Amadeus/Client.php @@ -36,8 +36,7 @@ * Amadeus Web Service Client. * * TODO: - * - have a solution for session pooling for stateful sessions (soapheader 1 & 2) - * - support older versions of SoapHeader (1, 2) + * - support older versions of SoapHeader (1) * - implement calls for full online booking flow: * SalesReports_DisplayQueryReport * Air_MultiAvailability @@ -97,6 +96,13 @@ class Client */ protected $responseHandler; + /** + * Authentication parameters + * + * @var Params\AuthParams + */ + protected $authParams; + /** * Set the session as stateful (true) or stateless (false) * @@ -149,6 +155,19 @@ public function getLastResponse() return $this->sessionHandler->getLastResponse(); } + /** + * Restore a previously used session + * + * To be used when implementing your own session pooling system on legacy Soap Header 2 applications. + * + * @param array $sessionData + * @return bool + */ + public function setSessionData(array $sessionData) + { + return $this->sessionHandler->setSessionData($sessionData); + } + /** * Construct Amadeus Web Services client * @@ -156,6 +175,13 @@ public function getLastResponse() */ public function __construct($params) { + if ($params->authParams instanceof Params\AuthParams) { + $this->authParams = $params->authParams; + if (isset($params->sessionHandlerParams) && $params->sessionHandlerParams instanceof Params\SessionHandlerParams) { + $params->sessionHandlerParams->authParams = $this->authParams; + } + } + $this->sessionHandler = $this->loadSessionHandler( $params->sessionHandler, $params->sessionHandlerParams @@ -174,6 +200,31 @@ public function __construct($params) ); } + /** + * Authenticate. + * + * Parameters were provided at construction time (sessionhandlerparams) + * + * @return \stdClass + * @throws Exception + */ + public function securityAuthenticate() + { + $msgName = 'Security_Authenticate'; + $messageOptions = $this->makeMessageOptions([], false, false); + + return $this->sessionHandler->sendMessage( + $msgName, + $this->requestCreator->createRequest( + $msgName, + new RequestOptions\SecurityAuthenticateOptions( + $this->authParams + ) + ), + $messageOptions + ); + } + /** * Terminate a session - only applicable to non-stateless mode. * diff --git a/src/Amadeus/Client/Params.php b/src/Amadeus/Client/Params.php index 55a045fb8..0a5da35a6 100644 --- a/src/Amadeus/Client/Params.php +++ b/src/Amadeus/Client/Params.php @@ -22,6 +22,7 @@ namespace Amadeus\Client; +use Amadeus\Client\Params\AuthParams; use Amadeus\Client\Params\RequestCreatorParams; use Amadeus\Client\Params\SessionHandlerParams; use Amadeus\Client\RequestCreator\RequestCreatorInterface; @@ -57,6 +58,13 @@ class Params */ public $responseHandler; + /** + * Parameters for authenticating to the Amadeus Web Services + * + * @var Params\AuthParams + */ + public $authParams; + /** * Parameters required to create the Session Handler * @@ -72,7 +80,6 @@ class Params public $requestCreatorParams; - /** * @param array $params */ @@ -98,6 +105,14 @@ protected function loadFromArray(array $params) { $this->responseHandler = $params['responseHandler']; } + if (isset($params['authParams'])) { + if ($params['authParams'] instanceof AuthParams) { + $this->authParams = $params['authParams']; + } elseif (is_array($params['authParams'])) { + $this->authParams = new AuthParams($params['authParams']); + } + } + if (isset($params['sessionHandlerParams'])) { if ($params['sessionHandlerParams'] instanceof SessionHandlerParams) { $this->sessionHandlerParams = $params['sessionHandlerParams']; diff --git a/src/Amadeus/Client/RequestCreator/Base.php b/src/Amadeus/Client/RequestCreator/Base.php index a042a560a..f7a8cb714 100644 --- a/src/Amadeus/Client/RequestCreator/Base.php +++ b/src/Amadeus/Client/RequestCreator/Base.php @@ -50,6 +50,7 @@ use Amadeus\Client\RequestOptions\QueuePlacePnrOptions; use Amadeus\Client\RequestOptions\QueueRemoveItemOptions; use Amadeus\Client\RequestOptions\RequestOptionsInterface; +use Amadeus\Client\RequestOptions\SecurityAuthenticateOptions; use Amadeus\Client\RequestOptions\TicketCreateTstFromPricingOptions; use Amadeus\Client\Struct; @@ -110,6 +111,17 @@ protected function createSecuritySignOut() return new Struct\Security\SignOut(); } + /** + * Create request object for Security_Authenticate message + * + * @param SecurityAuthenticateOptions $params + * @return Struct\Security\Authenticate + */ + protected function createSecurityAuthenticate(SecurityAuthenticateOptions $params) + { + return new Struct\Security\Authenticate($params); + } + /** * Create request object for PNR_Retrieve message * diff --git a/src/Amadeus/Client/RequestOptions/SecurityAuthenticateOptions.php b/src/Amadeus/Client/RequestOptions/SecurityAuthenticateOptions.php new file mode 100644 index 000000000..17269a262 --- /dev/null +++ b/src/Amadeus/Client/RequestOptions/SecurityAuthenticateOptions.php @@ -0,0 +1,114 @@ + + */ +class SecurityAuthenticateOptions extends Base +{ + /** + * The Amadeus Office ID to sign in to + * + * @var string + */ + public $officeId; + + /** + * User ID / Originator + * + * @var string + */ + public $userId; + + /** + * Originator Typecode + * + * @var string + */ + public $originatorTypeCode; + + /** + * Duty code + * + * @var string + */ + public $dutyCode; + + /** + * Organization ID + * + * @var string + */ + public $organizationId; + + /** + * Password Length of plain password. + * + * Only for SoapHeader < 4. + * + * @var int + */ + public $passwordLength; + + /** + * Password Data (base-64 encoded password) + * + * @var string + */ + public $passwordData; + + /** + * SecurityAuthenticateOptions constructor. + * + * @param AuthParams|null $authParams + */ + public function __construct(AuthParams $authParams = null) + { + if ($authParams instanceof AuthParams) { + $this->loadFromAuthParams($authParams); + } + + parent::__construct([]); + } + + /** + * Load security authenticate options from auth params + * + * @param AuthParams $authParams + */ + protected function loadFromAuthParams(AuthParams $authParams) + { + $this->officeId = $authParams->officeId; + $this->dutyCode = $authParams->dutyCode; + $this->organizationId = $authParams->organizationId; + $this->originatorTypeCode = $authParams->originatorTypeCode; + $this->userId = $authParams->userId; + $this->passwordLength = $authParams->passwordLength; + $this->passwordData = $authParams->passwordData; + } +} diff --git a/src/Amadeus/Client/Session/Handler/Base.php b/src/Amadeus/Client/Session/Handler/Base.php index f05a6f628..cb9ce165e 100644 --- a/src/Amadeus/Client/Session/Handler/Base.php +++ b/src/Amadeus/Client/Session/Handler/Base.php @@ -22,8 +22,13 @@ namespace Amadeus\Client\Session\Handler; +use Amadeus\Client; +use Amadeus\Client\Struct\BaseWsMessage; +use Amadeus\Client\Params\SessionHandlerParams; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; use Psr\Log\NullLogger; /** @@ -41,12 +46,350 @@ abstract class Base implements HandlerInterface, LoggerAwareInterface use LoggerAwareTrait; + /** + * XPATH query to retrieve all operations from the WSDL + * + * @var string + */ + const XPATH_ALL_OPERATIONS = '/wsdl:definitions/wsdl:portType/wsdl:operation/@name'; + /** + * XPATH query to retrieve the full operation name + version from the WSDL for a given operation. + * + * @var string + */ + const XPATH_VERSION_FOR_OPERATION = "string(/wsdl:definitions/wsdl:message[contains(./@name, '%s_')]/@name)"; + + + /** + * Status variable to know wether the given session is in a certain context. + * + * @todo implement this feature - currently the application using the client must know the context itself. + * @var bool + */ + protected $hasContext = false; + + /** + * The context of the currently active session + * + * @todo implement this feature - currently the application using the client must know the context itself. + * @var mixed + */ + protected $context; + + + /** + * Session information: + * - session ID + * - sequence number + * - security Token + * + * @var array + */ + protected $sessionData = [ + 'sessionId' => null, + 'sequenceNumber' => null, + 'securityToken' => null + ]; + + /** + * Status variable to know if the session is currently logged in + * + * @var bool + */ + protected $isAuthenticated = false; + /** * @var \SoapClient */ protected $soapClient; + /** + * SoapClient options used during initialisation + * + * @var array + */ + protected $soapClientOptions = [ + 'trace' => 1, + 'exceptions' => 1, + 'soap_version' => SOAP_1_1 + ]; + + + /** + * @var SessionHandlerParams + */ + protected $params; + + + /** + * Dom Document where the WSDL's contents will be loaded + * + * @var \DOMDocument + */ + protected $wsdlDomDoc; + /** + * To query the WSDL contents + * + * @var \DOMXpath + */ + protected $wsdlDomXpath; + + /** + * Get the session parameters of the active session + * + * @return array|null + */ + public function getSessionData() + { + return $this->sessionData; + } + + /** + * Set the session data to continue a previously started session. + * + * @param array $sessionData + * @return bool + */ + public function setSessionData(array $sessionData) + { + if (isset($sessionData['sessionId'], $sessionData['sequenceNumber'], $sessionData['securityToken'])) { + $this->sessionData['sessionId'] = $sessionData['sessionId']; + $this->sessionData['sequenceNumber'] = $sessionData['sequenceNumber']; + $this->sessionData['securityToken'] = $sessionData['securityToken']; + $this->isAuthenticated = true; + } else { + $this->isAuthenticated = false; + } + + return $this->isAuthenticated; + } + + + /** + * @param SessionHandlerParams $params + */ + public function __construct(SessionHandlerParams $params) + { + $this->params = $params; + if($params->logger instanceof LoggerInterface) { + $this->setLogger($params->logger); + $this->log(LogLevel::INFO, __METHOD__. "(): Logger started."); + } + if ($params->overrideSoapClient instanceof \SoapClient) { + $this->soapClient = $params->overrideSoapClient; + } + $this->setStateful($params->stateful); + } + + + /** + * @param string $messageName Method Operation name as defined in the WSDL. + * @param BaseWsMessage $messageBody + * @param array $messageOptions options: bool 'asString', bool 'endSession' + * @return mixed + * @throws \InvalidArgumentException + * @throws Client\Exception + * @throws \SoapFault + */ + public function sendMessage($messageName, Client\Struct\BaseWsMessage $messageBody, $messageOptions = []) + { + $result = null; + + $this->prepareForNextMessage($messageName, $messageOptions); + + try { + $result = $this->getSoapClient()->$messageName($messageBody); + + $this->logRequestAndResponse($messageName); + + $this->handlePostMessage($messageName, $this->getLastResponse(), $messageOptions, $result); + + } catch(\SoapFault $ex) { + $this->log( + LogLevel::ERROR, + "SOAPFAULT while sending message " . $messageName . ": " . + $ex->getMessage() . " code: " .$ex->getCode() . " at " . $ex->getFile() . + " line " . $ex->getLine() . ": \n" . $ex->getTraceAsString() + ); + $this->logRequestAndResponse($messageName); + //TODO We must be able to handle certain soapfaults inside the client, so maybe pass through after logging? + throw $ex; + } catch (\Exception $ex) { + $this->log( + LogLevel::ERROR, + "EXCEPTION while sending message " . $messageName . ": " . + $ex->getMessage() . " at " . $ex->getFile() . " line " . $ex->getLine() . ": \n" . + $ex->getTraceAsString() + ); + $this->logRequestAndResponse($messageName); + //TODO We must be able to handle certain exceptions inside the client, so maybe pass through after logging? + throw new Client\Exception($ex->getMessage(), $ex->getCode(), $ex); + } + + if ($messageOptions['asString'] === true) { + $result = Client\Util\MsgBodyExtractor::extract($this->getLastResponse()); + } + + return $result; + } + + /** + * Prepare to send a next message and checks if authenticated + * + * @param string $messageName + * @param array $messageOptions + */ + protected abstract function prepareForNextMessage($messageName, $messageOptions); + + /** + * Handles post message actions + * + * Handles session state based on received response + * + * @param string $messageName + * @param string $lastResponse + * @param array $messageOptions + * @param mixed $result + */ + protected abstract function handlePostMessage($messageName, $lastResponse, $messageOptions, $result); + + /** + * Get the last raw XML message that was sent out + * + * @return string|null + */ + public function getLastRequest() + { + return $this->getSoapClient()->__getLastRequest(); + } + + /** + * Get the last raw XML message that was received + * + * @return string|null + */ + public function getLastResponse() + { + return $this->getSoapClient()->__getLastResponse(); + } + + /** + * Get the office that we are using to sign in to. + * + * @return string + */ + public function getOriginatorOffice() + { + return $this->params->authParams->officeId; + } + + + /** + * Extract the Messages and versions from the loaded WSDL file. + * + * Result is an associative array: keys are message names, values are versions. + * + * @return array + */ + public function getMessagesAndVersions() + { + $this->loadWsdlXpath($this->params->wsdl); + + $msgAndVer = []; + $operations = $this->wsdlDomXpath->query(self::XPATH_ALL_OPERATIONS); + + foreach ($operations as $operation) { + if (!empty($operation->value)) { + $fullVersion = $this->wsdlDomXpath->evaluate(sprintf(self::XPATH_VERSION_FOR_OPERATION, $operation->value)); + if (!empty($fullVersion)) { + $extractedVersion = $this->extractMessageVersion($fullVersion); + $msgAndVer[$operation->value] = $extractedVersion; + } + } + } + + return $msgAndVer; + } + + /** + * extractMessageVersion + * + * extracts "4.1" from a string like "Security_SignOut_4_1" + * + * @param string $fullVersionString + * @return string + */ + protected function extractMessageVersion($fullVersionString) + { + $secondUnderscore = strpos($fullVersionString, '_', strpos($fullVersionString, '_')+1); + $num = substr($fullVersionString, $secondUnderscore+1); + + return str_replace('_', '.', $num); + } + + /** + * Load the WSDL contents to a queryable DOMXpath. + * + * @param string $wsdlFilePath + * @uses $this->wsdlDomDoc + * @uses $this->wsdlDomXpath + */ + protected function loadWsdlXpath($wsdlFilePath) + { + if (is_null($this->wsdlDomXpath)) { + $wsdlContent = file_get_contents($wsdlFilePath); + + $this->wsdlDomDoc = new \DOMDocument('1.0', 'UTF-8'); + $this->wsdlDomDoc->loadXML($wsdlContent); + $this->wsdlDomXpath = new \DOMXPath($this->wsdlDomDoc); + $this->wsdlDomXpath->registerNamespace( + 'wsdl', + 'http://schemas.xmlsoap.org/wsdl/' + ); + $this->wsdlDomXpath->registerNamespace( + 'soap', + 'http://schemas.xmlsoap.org/wsdl/soap/' + ); + } + } + + + /** + * @return \SoapClient + */ + protected function getSoapClient() + { + if (!$this->soapClient instanceof \SoapClient) { + $this->soapClient = $this->initSoapClient(); + } + + return $this->soapClient; + } + + /** + * @return \SoapClient + */ + protected abstract function initSoapClient(); + + + /** + * @param string $messageName + * @uses $this->log + */ + protected function logRequestAndResponse($messageName) + { + $this->log( + LogLevel::INFO, + 'Called ' . $messageName . ' with request: ' . $this->getSoapClient()->__getLastRequest() + ); + $this->log( + LogLevel::INFO, + 'Response: ' . $this->getSoapClient()->__getLastResponse() + ); + } + + /** * @param mixed $level * @param string $message @@ -61,5 +404,4 @@ protected function log($level, $message, $context = []) return $this->logger->log($level, $message, $context); } - -} \ No newline at end of file +} diff --git a/src/Amadeus/Client/Session/Handler/Classmap.php b/src/Amadeus/Client/Session/Handler/Classmap.php index fcd0a37cf..32bc32ce0 100644 --- a/src/Amadeus/Client/Session/Handler/Classmap.php +++ b/src/Amadeus/Client/Session/Handler/Classmap.php @@ -43,6 +43,15 @@ class Classmap 'Session' => 'Amadeus\Client\Struct\HeaderV4\Session', ]; + /** + * The PHP -> WSDL translation classmap for Soap Header 2 specific message parts + * + * @var array + */ + public static $soapheader2map = [ + 'Session' => 'Amadeus\Client\Struct\HeaderV2\Session', + ]; + /** * The PHP -> WSDL translation classmap for the Amadeus WS Client * diff --git a/src/Amadeus/Client/Session/Handler/HandlerFactory.php b/src/Amadeus/Client/Session/Handler/HandlerFactory.php index 8c4cf29de..91954ddfd 100644 --- a/src/Amadeus/Client/Session/Handler/HandlerFactory.php +++ b/src/Amadeus/Client/Session/Handler/HandlerFactory.php @@ -55,9 +55,11 @@ public static function createHandler($handlerParams) $theHandler = new SoapHeader4($handlerParams); break; case Client::HEADER_V2: + $theHandler = new SoapHeader2($handlerParams); + break; case Client::HEADER_V1: default: - //TODO implement Client::HEADER_V2 & Client::HEADER_V1 + //TODO implement Client::HEADER_V1 throw new \InvalidArgumentException( 'No Session Handler found for soapHeaderVersion ' . $handlerParams->soapHeaderVersion ); diff --git a/src/Amadeus/Client/Session/Handler/HandlerInterface.php b/src/Amadeus/Client/Session/Handler/HandlerInterface.php index 1104c3115..113aecfde 100644 --- a/src/Amadeus/Client/Session/Handler/HandlerInterface.php +++ b/src/Amadeus/Client/Session/Handler/HandlerInterface.php @@ -80,6 +80,14 @@ public function setStateful($stateful); */ public function getSessionData(); + /** + * Set the session data to continue a previously started session. + * + * @param array $sessionData + * @return bool success or failure + */ + public function setSessionData(array $sessionData); + /** * Get the current stateful mode (true is stateful, false is stateless) * diff --git a/src/Amadeus/Client/Session/Handler/InvalidSessionException.php b/src/Amadeus/Client/Session/Handler/InvalidSessionException.php new file mode 100644 index 000000000..5e73ebb3b --- /dev/null +++ b/src/Amadeus/Client/Session/Handler/InvalidSessionException.php @@ -0,0 +1,38 @@ + + */ +class InvalidSessionException extends Exception +{ + +} diff --git a/src/Amadeus/Client/Session/Handler/SoapHeader2.php b/src/Amadeus/Client/Session/Handler/SoapHeader2.php new file mode 100644 index 000000000..b4b273f61 --- /dev/null +++ b/src/Amadeus/Client/Session/Handler/SoapHeader2.php @@ -0,0 +1,187 @@ + + */ +class SoapHeader2 extends Base +{ + /** + * Namespace of SoapHeader V2 + */ + const CORE_WS_V2_SESSION_NS = 'http://xml.amadeus.com/ws/2009/01/WBS_Session-2.0.xsd'; + + /** + * Node for Session ID + */ + const NODENAME_SESSIONID = "SessionId"; + /** + * Node for Session Sequence Number + */ + const NODENAME_SEQENCENR = "SequenceNumber"; + /** + * Node for Session Security Token + */ + const NODENAME_SECURITYTOKEN = "SecurityToken"; + + /** + * Prepare to send a next message and checks if authenticated + * + * @param string $messageName + * @param array $messageOptions + * @throws InvalidSessionException When trying to send a message without session. + */ + protected function prepareForNextMessage($messageName, $messageOptions) + { + if (!$this->isAuthenticated && $messageName !== 'Security_Authenticate') { + throw new InvalidSessionException('No active session'); + } + + $this->getSoapClient()->__setSoapHeaders(null); + + if ($this->isAuthenticated === true && is_int($this->sessionData['sequenceNumber'])) { + $this->sessionData['sequenceNumber']++; + + $session = new Client\Struct\HeaderV2\Session( + $this->sessionData['sessionId'], + $this->sessionData['sequenceNumber'], + $this->sessionData['securityToken'] + ); + + $this->getSoapClient()->__setSoapHeaders( + new \SoapHeader(self::CORE_WS_V2_SESSION_NS, self::NODENAME_SESSIONID, $session) + ); + } + } + + /** + * Handles post message actions + * + * Handles session state based on received response + * + * @param string $messageName + * @param string $lastResponse + * @param array $messageOptions + * @param mixed $result + */ + protected function handlePostMessage($messageName, $lastResponse, $messageOptions, $result) + { + if ($messageName === "Security_Authenticate") { + $this->sessionData = $this->getSessionDataFromHeader($lastResponse); + $this->isAuthenticated = (!empty($this->sessionData['sessionId']) && + !empty($this->sessionData['sequenceNumber']) && + !empty($this->sessionData['securityToken'])); + } + } + + /** + * @param string $responseMsg the full response XML received. + * @return array + */ + protected function getSessionDataFromHeader($responseMsg) + { + $newSessionData = [ + 'sessionId' => null, + 'sequenceNumber' => null, + 'securityToken' => null + ]; + + $responseDomDoc = new \DOMDocument('1.0', 'UTF-8'); + $ok = $responseDomDoc->loadXML($responseMsg); + + if ($ok) { + $sessionId = $responseDomDoc->getElementsByTagName(self::NODENAME_SESSIONID)->item(0)->nodeValue; + if ($sessionId) { + $newSessionData['sessionId'] = $sessionId; + } + $sequence = (int)$responseDomDoc->getElementsByTagName(self::NODENAME_SEQENCENR)->item(0)->nodeValue; + if ($sequence) { + $newSessionData['sequenceNumber'] = $sequence; + } + $securityToken = $responseDomDoc->getElementsByTagName(self::NODENAME_SECURITYTOKEN)->item(0)->nodeValue; + if ($securityToken) { + $newSessionData['securityToken'] = $securityToken; + } + } + + unset($responseDomDoc); + + return $newSessionData; + } + + /** + * Cannot set stateless on Soap Header v2 + * + * @param bool $stateful + * @throws UnsupportedOperationException + */ + public function setStateful($stateful) + { + if ($stateful === false) { + throw new UnsupportedOperationException('Stateful messages are mandatory on SoapHeader 2'); + } + } + + /** + * Soap Header 2 sessions are always stateful + * + * @return bool + */ + public function isStateful() + { + return true; + } + + /** + * @return \SoapClient + */ + protected function initSoapClient() + { + $client = new Client\SoapClient( + $this->params->wsdl, + $this->makeSoapClientOptions(), + $this->params->logger + ); + + return $client; + } + + /** + * @return array + */ + protected function makeSoapClientOptions() + { + $options = $this->soapClientOptions; + $options['classmap'] = array_merge(Classmap::$soapheader2map, Classmap::$map); + + return $options; + } +} diff --git a/src/Amadeus/Client/Session/Handler/SoapHeader4.php b/src/Amadeus/Client/Session/Handler/SoapHeader4.php index 020cc99c9..212391682 100644 --- a/src/Amadeus/Client/Session/Handler/SoapHeader4.php +++ b/src/Amadeus/Client/Session/Handler/SoapHeader4.php @@ -22,12 +22,9 @@ namespace Amadeus\Client\Session\Handler; -use Amadeus\Client\Struct\BaseWsMessage; use Amadeus\Client; -use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; - /** * SoapHeader4: Session Handler for web service applications using Amadeus WS Soap Header v4. * @@ -48,138 +45,14 @@ class SoapHeader4 extends Base * @var string */ const XPATH_ENDPOINT = 'string(/wsdl:definitions/wsdl:service/wsdl:port/soap:address/@location)'; - /** - * XPATH query to retrieve all operations from the WSDL - * - * @var string - */ - const XPATH_ALL_OPERATIONS = '/wsdl:definitions/wsdl:portType/wsdl:operation/@name'; - /** - * XPATH query to retrieve the full operation name + version from the WSDL for a given operation. - * - * @var string - */ - const XPATH_VERSION_FOR_OPERATION = "string(/wsdl:definitions/wsdl:message[contains(./@name, '%s_')]/@name)"; - /** - * Status variable to know if the session is currently logged in - * - * @var bool - */ - protected $isAuthenticated = false; - /** - * Status variable to know wether the given session is in a certain context. - * - * @var bool - */ - protected $hasContext = false; + /** * Switch between stateful & stateless sessions. Default: stateful * * @var bool */ protected $isStateful = true; - /** - * The context of the currently active session - * - * @todo implement this feature - currently the application using the client must know the context itself. - * @var mixed - */ - protected $context; - /** - * Session information: - * - session ID - * - sequence number - * - security Token - * - * @var array - */ - protected $sessionData = [ - 'sessionId' => null, - 'sequenceNumber' => null, - 'securityToken' => null - ]; - /** - * SoapClient options used during initialisation - * - * @var array - */ - protected $soapClientOptions = [ - 'trace' => 1, - 'exceptions' => 1, - 'soap_version' => SOAP_1_1 - ]; - - /** - * Dom Document where the WSDL's contents will be loaded - * - * @var \DOMDocument - */ - protected $wsdlDomDoc; - /** - * To query the WSDL contents - * - * @var \DOMXpath - */ - protected $wsdlDomXpath; - - /** - * @var Client\Params\SessionHandlerParams - */ - protected $params; - - /** - * @param Client\Params\SessionHandlerParams $params - */ - public function __construct(Client\Params\SessionHandlerParams $params) - { - $this->params = $params; - if($params->logger instanceof LoggerInterface) { - $this->setLogger($params->logger); - //$this->log(LogLevel::INFO, __METHOD__. "(): Logger started."); - } - if ($params->overrideSoapClient instanceof \SoapClient) { - $this->soapClient = $params->overrideSoapClient; - } - $this->setStateful($params->stateful); - } - - /** - * Get the office that we are using to sign in to. - * - * @return string - */ - public function getOriginatorOffice() - { - return $this->params->authParams->officeId; - } - - /** - * Extract the Messages and versions from the loaded WSDL file. - * - * Result is an associative array: keys are message names, values are versions. - * - * @return array - */ - public function getMessagesAndVersions() - { - $this->loadWsdlXpath($this->params->wsdl); - - $msgAndVer = []; - $operations = $this->wsdlDomXpath->query(self::XPATH_ALL_OPERATIONS); - - foreach ($operations as $operation) { - if (!empty($operation->value)) { - $fullVersion = $this->wsdlDomXpath->evaluate(sprintf(self::XPATH_VERSION_FOR_OPERATION, $operation->value)); - if (!empty($fullVersion)) { - $extractedVersion = $this->extractMessageVersion($fullVersion); - $msgAndVer[$operation->value] = $extractedVersion; - } - } - } - - return $msgAndVer; - } /** * @param bool $stateful @@ -199,88 +72,6 @@ public function isStateful() return $this->isStateful; } - /** - * Get the session parameters of the active session - * - * @return array|null - */ - public function getSessionData() - { - return $this->sessionData; - } - - /** - * Get the last raw XML message that was sent out - * - * @return string|null - */ - public function getLastRequest() - { - return $this->getSoapClient()->__getLastRequest(); - } - - /** - * Get the last raw XML message that was received - * - * @return string|null - */ - public function getLastResponse() - { - return $this->getSoapClient()->__getLastResponse(); - } - - - /** - * @param string $messageName Method Operation name as defined in the WSDL. - * @param BaseWsMessage $messageBody - * @param array $messageOptions options: bool 'asString', bool 'endSession' - * @return mixed - * @throws \InvalidArgumentException - * @throws Client\Exception - * @throws \SoapFault - */ - public function sendMessage($messageName, BaseWsMessage $messageBody, $messageOptions = []) - { - $result = null; - - $this->prepareForNextMessage($messageName, $messageOptions); - - try { - $result = $this->getSoapClient()->$messageName($messageBody); - - $this->logRequestAndResponse($messageName); - - $this->handlePostMessage($messageName, $this->getLastResponse(), $messageOptions, $result); - - } catch(\SoapFault $ex) { - $this->log( - LogLevel::ERROR, - "SOAPFAULT while sending message " . $messageName . ": " . - $ex->getMessage() . " code: " .$ex->getCode() . " at " . $ex->getFile() . - " line " . $ex->getLine() . ": \n" . $ex->getTraceAsString() - ); - $this->logRequestAndResponse($messageName); - //TODO We must be able to handle certain soapfaults inside the client, so maybe pass through after logging? - throw $ex; - } catch (\Exception $ex) { - $this->log( - LogLevel::ERROR, - "EXCEPTION while sending message " . $messageName . ": " . - $ex->getMessage() . " at " . $ex->getFile() . " line " . $ex->getLine() . ": \n" . - $ex->getTraceAsString() - ); - $this->logRequestAndResponse($messageName); - //TODO We must be able to handle certain exceptions inside the client, so maybe pass through after logging? - throw new Client\Exception($ex->getMessage(), $ex->getCode(), $ex); - } - - if ($messageOptions['asString'] === true) { - $result = Client\Util\MsgBodyExtractor::extract($this->getLastResponse()); - } - - return $result; - } - /** * Handles authentication & sessions * @@ -336,8 +127,6 @@ protected function handlePostMessage($messageName, $lastResponse, $messageOption } else { $this->isAuthenticated = false; } - - //TODO: check for errors in response? } /** @@ -374,6 +163,8 @@ protected function getSessionDataFromHeader($responseMsg) $newSessionData['securityToken'] = $responseDomXpath->evaluate($querySecurityToken); } + unset($responseDomDoc, $responseDomXpath); + return $newSessionData; } @@ -511,58 +302,32 @@ protected function createSoapHeaders($sessionData, $params, $messageName, $messa } /** - * Get the SOAPAction for a given message from the WSDL contents. + * Get the Web Services server Endpoint from the WSDL. * * @param string $wsdlFilePath - * @param string $messageName * @return string */ - protected function getActionFromWsdl($wsdlFilePath, $messageName) + protected function getEndpointFromWsdl($wsdlFilePath) { $this->loadWsdlXpath($wsdlFilePath); - $action = $this->wsdlDomXpath->evaluate(sprintf(self::XPATH_OPERATION_ACTION, $messageName)); - - return $action; + return $this->wsdlDomXpath->evaluate(self::XPATH_ENDPOINT); } /** - * Get the Web Services server Endpoint from the WSDL. + * Get the SOAPAction for a given message from the WSDL contents. * * @param string $wsdlFilePath + * @param string $messageName * @return string */ - protected function getEndpointFromWsdl($wsdlFilePath) + protected function getActionFromWsdl($wsdlFilePath, $messageName) { $this->loadWsdlXpath($wsdlFilePath); - return $this->wsdlDomXpath->evaluate(self::XPATH_ENDPOINT); - } + $action = $this->wsdlDomXpath->evaluate(sprintf(self::XPATH_OPERATION_ACTION, $messageName)); - /** - * Load the WSDL contents to a queryable DOMXpath. - * - * @param string $wsdlFilePath - * @uses $this->wsdlDomDoc - * @uses $this->wsdlDomXpath - */ - protected function loadWsdlXpath($wsdlFilePath) - { - if (is_null($this->wsdlDomXpath)) { - $wsdlContent = file_get_contents($wsdlFilePath); - - $this->wsdlDomDoc = new \DOMDocument('1.0', 'UTF-8'); - $this->wsdlDomDoc->loadXML($wsdlContent); - $this->wsdlDomXpath = new \DOMXPath($this->wsdlDomDoc); - $this->wsdlDomXpath->registerNamespace( - 'wsdl', - 'http://schemas.xmlsoap.org/wsdl/' - ); - $this->wsdlDomXpath->registerNamespace( - 'soap', - 'http://schemas.xmlsoap.org/wsdl/soap/' - ); - } + return $action; } /** @@ -660,35 +425,6 @@ protected function createDateTimeStringForAuth($creationDateTime, $micro) return $creationDateTime->format("Y-m-d\TH:i:s:") . $micro . 'Z'; } - /** - * extractMessageVersion - * - * extracts "4.1" from a string like "Security_SignOut_4_1" - * - * @param string $fullVersionString - * @return string - */ - protected function extractMessageVersion($fullVersionString) - { - $secondUnderscore = strpos($fullVersionString, '_', strpos($fullVersionString, '_')+1); - $num = substr($fullVersionString, $secondUnderscore+1); - - return str_replace('_', '.', $num); - } - - /** - * @return \SoapClient - */ - protected function getSoapClient() - { - if (!$this->soapClient instanceof \SoapClient) { - $this->soapClient = $this->initSoapClient(); - } - - return $this->soapClient; - } - - /** * @return \SoapClient */ @@ -713,21 +449,4 @@ protected function makeSoapClientOptions() return $options; } - - - /** - * @param string $messageName - * @uses $this->log - */ - protected function logRequestAndResponse($messageName) - { - $this->log( - LogLevel::INFO, - 'Called ' . $messageName . ' with request: ' . $this->getSoapClient()->__getLastRequest() - ); - $this->log( - LogLevel::INFO, - 'Response: ' . $this->getSoapClient()->__getLastResponse() - ); - } } diff --git a/src/Amadeus/Client/Struct/SessionHeaderV2.php b/src/Amadeus/Client/Session/Handler/UnsupportedOperationException.php similarity index 80% rename from src/Amadeus/Client/Struct/SessionHeaderV2.php rename to src/Amadeus/Client/Session/Handler/UnsupportedOperationException.php index 15e2f28ec..d5b18e552 100644 --- a/src/Amadeus/Client/Struct/SessionHeaderV2.php +++ b/src/Amadeus/Client/Session/Handler/UnsupportedOperationException.php @@ -20,16 +20,17 @@ * @license https://opensource.org/licenses/Apache-2.0 Apache 2.0 */ -namespace Amadeus\Client\Struct; +namespace Amadeus\Client\Session\Handler; + +use Amadeus\Client\Exception; /** - * Class SessionHeaderV2 + * UnsupportedOperation * - * @todo NOT YET IMPLEMENTED - * @package Amadeus\Client\Struct + * @package Amadeus\Client\Session\Handler * @author Dieter Devlieghere */ -class SessionHeaderV2 +class UnsupportedOperationException extends Exception { - //TODO + } diff --git a/src/Amadeus/Client/Struct/HeaderV2/Session.php b/src/Amadeus/Client/Struct/HeaderV2/Session.php new file mode 100644 index 000000000..29f9b6a80 --- /dev/null +++ b/src/Amadeus/Client/Struct/HeaderV2/Session.php @@ -0,0 +1,57 @@ + + */ +class Session +{ + /** + * @var string + */ + public $sessionId; + /** + * @var int + */ + public $sequenceNumber; + /** + * @var string + */ + public $securityToken; + + /** + * @param string $sessId + * @param int $seqNr + * @param string $secTok + */ + public function __construct($sessId, $seqNr, $secTok) + { + $this->sessionId = $sessId; + $this->sequenceNumber = $seqNr; + $this->securityToken = $secTok; + } +} diff --git a/src/Amadeus/Client/Struct/Security/ApplicationDetails.php b/src/Amadeus/Client/Struct/Security/ApplicationDetails.php new file mode 100644 index 000000000..5ba6d7677 --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/ApplicationDetails.php @@ -0,0 +1,41 @@ + + */ +class ApplicationDetails +{ + /** + * @var string + */ + public $internalId; + /** + * @var string + */ + public $seqNumber; +} diff --git a/src/Amadeus/Client/Struct/Security/ApplicationId.php b/src/Amadeus/Client/Struct/Security/ApplicationId.php new file mode 100644 index 000000000..7551b65f1 --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/ApplicationId.php @@ -0,0 +1,37 @@ + + */ +class ApplicationId +{ + /** + * @var ApplicationDetails + */ + public $applicationDetails; +} diff --git a/src/Amadeus/Client/Struct/Security/Authenticate.php b/src/Amadeus/Client/Struct/Security/Authenticate.php index fb47964e1..cfaa638f1 100644 --- a/src/Amadeus/Client/Struct/Security/Authenticate.php +++ b/src/Amadeus/Client/Struct/Security/Authenticate.php @@ -22,12 +22,12 @@ namespace Amadeus\Client\Struct\Security; +use Amadeus\Client\RequestOptions\SecurityAuthenticateOptions; use Amadeus\Client\Struct\BaseWsMessage; /** * Authenticate * - * @todo Implement this message when we support SoapHeader v. 1 or 2 * @package Amadeus\Client\Struct\Security * @author Dieter Devlieghere */ @@ -61,4 +61,27 @@ class Authenticate extends BaseWsMessage * @var ApplicationId */ public $applicationId; + + /** + * Authenticate constructor. + * + * @param SecurityAuthenticateOptions $params + */ + public function __construct(SecurityAuthenticateOptions $params) + { + $this->userIdentifier = new UserIdentifier( + $params->officeId, + $params->originatorTypeCode, + $params->userId + ); + + $this->dutyCode = new DutyCode($params->dutyCode); + + $this->systemDetails = new SystemDetails($params->organizationId); + + $this->passwordInfo = new PasswordInfo( + $params->passwordData, + $params->passwordLength + ); + } } diff --git a/src/Amadeus/Client/Struct/Security/ConversationClt.php b/src/Amadeus/Client/Struct/Security/ConversationClt.php new file mode 100644 index 000000000..962c1c18b --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/ConversationClt.php @@ -0,0 +1,49 @@ + + */ +class ConversationClt +{ + /** + * @var string + */ + public $senderIdentification = 0; + /** + * @var string + */ + public $recipientIdentification = 0; + /** + * @var string + */ + public $senderInterchangeControlReference = 0; + /** + * @var string + */ + public $recipientInterchangeControlReference = 0; +} diff --git a/src/Amadeus/Client/Struct/Security/DutyCode.php b/src/Amadeus/Client/Struct/Security/DutyCode.php new file mode 100644 index 000000000..8fb873f3a --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/DutyCode.php @@ -0,0 +1,47 @@ + + */ +class DutyCode +{ + /** + * @var DutyCodeDetails + */ + public $dutyCodeDetails; + + /** + * DutyCode constructor. + * + * @param string $dutyCode + */ + public function __construct($dutyCode) + { + $this->dutyCodeDetails = new DutyCodeDetails($dutyCode); + } +} diff --git a/src/Amadeus/Client/Struct/Security/DutyCodeDetails.php b/src/Amadeus/Client/Struct/Security/DutyCodeDetails.php new file mode 100644 index 000000000..d85d458b3 --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/DutyCodeDetails.php @@ -0,0 +1,62 @@ + + */ +class DutyCodeDetails +{ + /** + * Definition of Dutycode Reference qualifier "Duty Code" + * + * See Amadeus Core Webservices documentation + * [Reference qualifier codesets (Ref: 1153 IA 01.2.57)] + * @var string + */ + const RQ_DUTYCODE = "DUT"; + + /** + * @var string + */ + public $referenceQualifier; + /** + * @var string + */ + public $referenceIdentifier; + + /** + * DutyCodeDetails constructor. + * + * @param string $dutyCode + * @param string $qual + */ + public function __construct($dutyCode, $qual = self::RQ_DUTYCODE) + { + $this->referenceIdentifier = $dutyCode; + $this->referenceQualifier = $qual; + } +} diff --git a/src/Amadeus/Client/Struct/Security/OrganizationDetails.php b/src/Amadeus/Client/Struct/Security/OrganizationDetails.php new file mode 100644 index 000000000..2db829c3a --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/OrganizationDetails.php @@ -0,0 +1,47 @@ + + */ +class OrganizationDetails +{ + /** + * @var string + */ + public $organizationId; + + /** + * OrganizationDetails constructor. + * + * @param string $organizationId + */ + public function __construct($organizationId) + { + $this->organizationId = $organizationId; + } +} diff --git a/src/Amadeus/Client/Struct/Security/OriginIdentification.php b/src/Amadeus/Client/Struct/Security/OriginIdentification.php new file mode 100644 index 000000000..64a4f5cb1 --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/OriginIdentification.php @@ -0,0 +1,47 @@ + + */ +class OriginIdentification +{ + /** + * @var string + */ + public $sourceOffice; + + /** + * OriginIdentification constructor. + * + * @param string $officeId + */ + public function __construct($officeId) + { + $this->sourceOffice = $officeId; + } +} diff --git a/src/Amadeus/Client/Struct/Security/PasswordInfo.php b/src/Amadeus/Client/Struct/Security/PasswordInfo.php new file mode 100644 index 000000000..06af03392 --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/PasswordInfo.php @@ -0,0 +1,76 @@ + + */ +class PasswordInfo +{ + /** + * Definition of Password Data type "EDIFACT DATA" + * + * See Amadeus Core Webservices documentation + * [DATA TYPE codesets (Ref: 116Z 1A 02.1.8)] + * @var string + */ + const DATA_TYPE_EDIFACT = 'E'; + /** + * Definition of Password Data type "BINARY DATA" + * + * See Amadeus Core Webservices documentation + * [DATA TYPE codesets (Ref: 116Z 1A 02.1.8)] + * @var string + */ + const DATA_TYPE_BINARY = 'B'; + + /** + * @var int + */ + public $dataLength; + /** + * @var string + */ + public $dataType; + /** + * @var string + */ + public $binaryData; + + /** + * PasswordInfo constructor. + * + * @param string $passwordData + * @param int $passwordLength + * @param string $type + */ + public function __construct($passwordData, $passwordLength, $type = self::DATA_TYPE_EDIFACT) + { + $this->binaryData = $passwordData; + $this->dataLength = $passwordLength; + $this->dataType = $type; + } +} diff --git a/src/Amadeus/Client/Struct/Security/SystemDetails.php b/src/Amadeus/Client/Struct/Security/SystemDetails.php new file mode 100644 index 000000000..71294f69b --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/SystemDetails.php @@ -0,0 +1,55 @@ + + */ +class SystemDetails +{ + /** + * @var string + */ + public $workstationId; + /** + * @var OrganizationDetails + */ + public $organizationDetails; + /** + * @var string + */ + public $idQualifier; + + /** + * SystemDetails constructor. + * + * @param string $organizationId + */ + public function __construct($organizationId) + { + $this->organizationDetails = new OrganizationDetails($organizationId); + } +} diff --git a/src/Amadeus/Client/Struct/Security/UserIdentifier.php b/src/Amadeus/Client/Struct/Security/UserIdentifier.php new file mode 100644 index 000000000..c63cf9aa9 --- /dev/null +++ b/src/Amadeus/Client/Struct/Security/UserIdentifier.php @@ -0,0 +1,59 @@ + + */ +class UserIdentifier +{ + /** + * @var OriginIdentification + */ + public $originIdentification; + /** + * @var string + */ + public $originatorTypeCode; + /** + * @var string + */ + public $originator; + + /** + * UserIdentifier constructor. + * + * @param string $officeId + * @param string $originatorTypeCode + * @param string $originator + */ + public function __construct($officeId, $originatorTypeCode, $originator) + { + $this->originIdentification = new OriginIdentification($officeId); + $this->originatorTypeCode = $originatorTypeCode; + $this->originator = $originator; + } +} diff --git a/src/Amadeus/Client/Util/MsgBodyExtractor.php b/src/Amadeus/Client/Util/MsgBodyExtractor.php index c28602cf1..572ccfef0 100644 --- a/src/Amadeus/Client/Util/MsgBodyExtractor.php +++ b/src/Amadeus/Client/Util/MsgBodyExtractor.php @@ -37,6 +37,13 @@ class MsgBodyExtractor */ const REGEXP_SOAP_ENVELOPE_CONTENTS = "|\\(.*?)\\<\\/SOAP-ENV:Body\\>|"; + /** + * Regular expression for extracting the Soap Envelope Body's content - legacy format for Soap Header v2 and older + * + * @var string + */ + const REGEXP_SOAP_ENVELOPE_CONTENTS_LEGACY = "|\\(.*?)\\<\\/soap:Body\\>|"; + /** * Extracts the message content from the soap envelope (i.e. everything under the soap body) * @@ -52,6 +59,12 @@ public static function extract($soapResponse) $messageBody = $matches[1]; } + if (empty($messageBody)) { + if (preg_match(self::REGEXP_SOAP_ENVELOPE_CONTENTS_LEGACY, $soapResponse, $matches) === 1) { + $messageBody = $matches[1]; + } + } + return $messageBody; } } diff --git a/tests/Amadeus/Client/Session/Handler/HandlerFactoryTest.php b/tests/Amadeus/Client/Session/Handler/HandlerFactoryTest.php index cb05526eb..2c4797410 100644 --- a/tests/Amadeus/Client/Session/Handler/HandlerFactoryTest.php +++ b/tests/Amadeus/Client/Session/Handler/HandlerFactoryTest.php @@ -49,13 +49,33 @@ public function testCreateWithoutAuthWillThrowException() HandlerFactory::createHandler($params); } - public function testCreateSoapHeader2WillThrowException() + + public function testCreateSoapHeader4WillCreateSoapHeader4Handler() { - $this->setExpectedException('\InvalidArgumentException'); + $params = $par = new SessionHandlerParams([ + 'wsdl' => '/dummy/path', + 'soapHeaderVersion' => Client::HEADER_V4, + 'receivedFrom' => 'unittests', + 'logger' => new NullLogger(), + 'authParams' => [ + 'officeId' => 'BRUXX0000', + 'originatorTypeCode' => 'U', + 'userId' => 'DUMMYORIG', + 'organizationId' => 'DUMMYORG', + 'passwordLength' => 12, + 'passwordData' => 'dGhlIHBhc3N3b3Jk' + ] + ]); + $createdHandler = HandlerFactory::createHandler($params); + + $this->assertInstanceOf('Amadeus\Client\Session\Handler\SoapHeader4', $createdHandler); + } + + public function testCreateSoapHeader2WillCreateSoapHeader2Handler() + { $params = $par = new SessionHandlerParams([ 'wsdl' => '/dummy/path', - 'stateful' => false, 'soapHeaderVersion' => Client::HEADER_V2, 'receivedFrom' => 'unittests', 'logger' => new NullLogger(), @@ -69,6 +89,30 @@ public function testCreateSoapHeader2WillThrowException() ] ]); + $createdHandler = HandlerFactory::createHandler($params); + + $this->assertInstanceOf('Amadeus\Client\Session\Handler\SoapHeader2', $createdHandler); + } + + public function testCreateSoapHeader1WillThrowException() + { + $this->setExpectedException('\InvalidArgumentException'); + + $params = $par = new SessionHandlerParams([ + 'wsdl' => '/dummy/path', + 'soapHeaderVersion' => Client::HEADER_V1, + 'receivedFrom' => 'unittests', + 'logger' => new NullLogger(), + 'authParams' => [ + 'officeId' => 'BRUXX0000', + 'originatorTypeCode' => 'U', + 'userId' => 'DUMMYORIG', + 'organizationId' => 'DUMMYORG', + 'passwordLength' => 12, + 'passwordData' => 'dGhlIHBhc3N3b3Jk' + ] + ]); + HandlerFactory::createHandler($params); } } diff --git a/tests/Amadeus/Client/Session/Handler/SoapHeader2Test.php b/tests/Amadeus/Client/Session/Handler/SoapHeader2Test.php new file mode 100644 index 000000000..dbc8ae998 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/SoapHeader2Test.php @@ -0,0 +1,211 @@ + + */ +class SoapHeader2Test extends BaseTestCase +{ + + public function testCanTrySendMessageWhenNotAuthenticated() + { + $this->setExpectedException('Amadeus\Client\Session\Handler\InvalidSessionException'); + + $handler = new SoapHeader2($this->makeSessionHandlerParams()); + + $handler->sendMessage( + 'PNR_Retrieve', + new Client\Struct\Pnr\Retrieve(Client\Struct\Pnr\Retrieve::RETR_TYPE_BY_RECLOC, 'ABC123'), + [ + 'asString' => false, + 'endSession' => false + ] + ); + } + + public function testCanTryPrepareNextMessageWhenAuthenticated() + { + $overrideSoapClient = $this->getMock( + 'Amadeus\Client\SoapClient', + ['__getLastRequest', '__getLastResponse', 'PNR_Retrieve'], + [], + '', + false + ); + + $dummyPnrRequest = $this->getTestFile('dummyPnrRequestsoapheader2.txt'); + $dummyPnrReply = $this->getTestFile('dummyPnrReplysoapheader2.txt'); + $dummyPnrReplyExtractedMessage = $this->getTestFile('dummyPnrReplyExtractedMessageSoapHeader2.txt'); + + $overrideSoapClient + ->expects($this->atLeastOnce()) + ->method('__getLastRequest') + ->will($this->returnValue($dummyPnrRequest)); + + $overrideSoapClient + ->expects($this->atLeastOnce()) + ->method('__getLastResponse') + ->will($this->returnValue($dummyPnrReply)); + + $overrideSoapClient + ->expects($this->any()) + ->method('PNR_Retrieve') + ->will($this->returnValue('')); + + $handler = new SoapHeader2($this->makeSessionHandlerParams( + $overrideSoapClient + )); + $handler->setSessionData([ + 'sessionId' => 'XFHZEKLRZHREJ', + 'sequenceNumber' => 12, + 'securityToken' => 'RKLERJEZLKRHZEJKLRHEZJKLREZRHEZK' + ]); + + $messageResponse = $handler->sendMessage( + 'PNR_Retrieve', + new Client\Struct\Pnr\Retrieve(Client\Struct\Pnr\Retrieve::RETR_TYPE_BY_RECLOC, 'ABC123'), + [ + 'asString' => true, + 'endSession' => false + ] + ); + + $this->assertInternalType('string', $messageResponse); + $this->assertEquals($dummyPnrReplyExtractedMessage, $messageResponse); + } + + public function testCanSendAuthCallAndStartSession() + { + $overrideSoapClient = $this->getMock( + 'Amadeus\Client\SoapClient', + ['__getLastRequest', '__getLastResponse', 'Security_Authenticate'], + [], + '', + false + ); + + $dummyRequest = $this->getTestFile('soapheader2' . DIRECTORY_SEPARATOR . 'dummySecurityAuth.txt'); + $dummyReply = $this->getTestFile('soapheader2' . DIRECTORY_SEPARATOR . 'dummySecurityAuthReply.txt'); + + $messageResult = new \stdClass(); + $messageResult->processStatus = new \stdClass(); + $messageResult->processStatus->statusCode = 'P'; + + $overrideSoapClient + ->expects($this->atLeastOnce()) + ->method('__getLastRequest') + ->will($this->returnValue($dummyRequest)); + + $overrideSoapClient + ->expects($this->atLeastOnce()) + ->method('__getLastResponse') + ->will($this->returnValue($dummyReply)); + + $overrideSoapClient + ->expects($this->any()) + ->method('Security_Authenticate') + ->will($this->returnValue($messageResult)); + + $handlerParams = $this->makeSessionHandlerParams( + $overrideSoapClient + ); + + $handler = new SoapHeader2($handlerParams); + + //SEND MESSAGE AND CHECK RESULT + $actualSendResult = $handler->sendMessage( + 'Security_Authenticate', + new Client\Struct\Security\Authenticate( + new Client\RequestOptions\SecurityAuthenticateOptions( + $handlerParams->authParams + ) + ), + [ + 'asString' => false, + 'endSession' => false + ] + ); + + $this->assertEquals($messageResult, $actualSendResult); + + //ASSERT THAT THE SESSION HAS BEEN STARTED CORRECTLY + $expectedSessionData = [ + 'sessionId' => 'IROZERIIOP', + 'sequenceNumber' => 1, + 'securityToken' => 'FDKLSDMJFSMLRJEZRHZJ' + ]; + + $this->assertEquals( + $expectedSessionData, + $handler->getSessionData() + ); + } + + public function testGetLastRequestEmptyWithNoMessages() + { + + $handlerParams = $this->makeSessionHandlerParams(); + + $handler = new SoapHeader2($handlerParams); + + $result = $handler->getLastRequest(); + + $this->assertNull($result); + } + + /** + * @param \SoapClient|null $overrideSoapClient + * @return SessionHandlerParams + */ + protected function makeSessionHandlerParams($overrideSoapClient = null) + { + $wsdlpath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'testfiles' . DIRECTORY_SEPARATOR . 'soapheader2' . DIRECTORY_SEPARATOR . 'testwsdlsoapheader2.wsdl'; + + $par = new SessionHandlerParams([ + 'wsdl' => realpath($wsdlpath), + 'soapHeaderVersion' => Client::HEADER_V2, + 'receivedFrom' => 'unittests', + 'logger' => new NullLogger(), + 'overrideSoapClient' => $overrideSoapClient, + 'authParams' => [ + 'officeId' => 'BRUXX0000', + 'originatorTypeCode' => 'U', + 'userId' => 'DUMMYORIG', + 'organizationId' => 'DUMMYORG', + 'passwordLength' => 12, + 'passwordData' => 'dGhlIHBhc3N3b3Jk' + ] + ]); + + return $par; + } +} diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrReplyExtractedMessageSoapHeader2.txt b/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrReplyExtractedMessageSoapHeader2.txt new file mode 100644 index 000000000..45bdfda32 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrReplyExtractedMessageSoapHeader2.txt @@ -0,0 +1 @@ +1AABC123090914RPXXXXBRUBGXXXXxxxBRUBGXXXXBRUBRUBGXXXY0001AA090914000000007173P12--- TST RLR ---000000BRUBGXXXXT1ABRUBE0000000BRUBGXXXYE1ABRUBE000000000BRUBGXXXYE1ABRUBE302015311PT2NM1BOWIE1DAVID MRST1AIR210031507551003151020BRUMADIB3207NET1IBABC1231HK321024ST2AIR311031519351103152155MADBRUIB3208NET1IBABC1231HK321034OT7AP4350322112121212-BOT22TK5TL100914BRUBGXXXXOT8OS6328YYDAVIDBOWIE//AMADEUS.COMOT6RM7RMPRICING ENTRY FXP/R,UP,BRU.BRUST1ST2PT2OT9RM8RMMODETICKETOT11RM9RMTIDBOWIEXDAVOT12RM10RMTSA INFORMATION OMITTED ON PURPOSEPT2OT13RM11RMAGENT FEE OF 10.00 EUR VISIBLE IN FEEOT14RM12RMFARE197.52 EURPT2OT15RM13RMFARE :197.52 EURST1ST2OT19RM14RMCOSECONOMY RESTRICTEDST1ST2OT20RM15RMMOPINVOICING TO CORPORATIONOT21RM16RMFTYPRIVATEST1ST2PT2OT16RM17RM*BOOKED BY AMADEUS E-TRAVEL MANAGEMENTOT17RM18RM*TRP/RECBUSOT18RM19RM*TRP/RETBUSINESSOT26RM20RM*ACERMK-FEE-ETMOT4FE21310PAX 22 NOREF-NON END/NO CHGSST1ST2PT2OT23FP22316CASHOT5FV233P18PAX IBST1ST2PT2OT10AB2432A DUMMY ADDRESS \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrReplysoapheader2.txt b/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrReplysoapheader2.txt new file mode 100644 index 000000000..33a9f4476 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrReplysoapheader2.txt @@ -0,0 +1 @@ +XFHZEKLRZHREJ13RKLERJEZLKRHZEJKLRHEZJKLREZRHEZK1AABC123090914RPXXXXBRUBGXXXXxxxBRUBGXXXXBRUBRUBGXXXY0001AA090914000000007173P12--- TST RLR ---000000BRUBGXXXXT1ABRUBE0000000BRUBGXXXYE1ABRUBE000000000BRUBGXXXYE1ABRUBE302015311PT2NM1BOWIE1DAVID MRST1AIR210031507551003151020BRUMADIB3207NET1IBABC1231HK321024ST2AIR311031519351103152155MADBRUIB3208NET1IBABC1231HK321034OT7AP4350322112121212-BOT22TK5TL100914BRUBGXXXXOT8OS6328YYDAVIDBOWIE//AMADEUS.COMOT6RM7RMPRICING ENTRY FXP/R,UP,BRU.BRUST1ST2PT2OT9RM8RMMODETICKETOT11RM9RMTIDBOWIEXDAVOT12RM10RMTSA INFORMATION OMITTED ON PURPOSEPT2OT13RM11RMAGENT FEE OF 10.00 EUR VISIBLE IN FEEOT14RM12RMFARE197.52 EURPT2OT15RM13RMFARE :197.52 EURST1ST2OT19RM14RMCOSECONOMY RESTRICTEDST1ST2OT20RM15RMMOPINVOICING TO CORPORATIONOT21RM16RMFTYPRIVATEST1ST2PT2OT16RM17RM*BOOKED BY AMADEUS E-TRAVEL MANAGEMENTOT17RM18RM*TRP/RECBUSOT18RM19RM*TRP/RETBUSINESSOT26RM20RM*ACERMK-FEE-ETMOT4FE21310PAX 22 NOREF-NON END/NO CHGSST1ST2PT2OT23FP22316CASHOT5FV233P18PAX IBST1ST2PT2OT10AB2432A DUMMY ADDRESS \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrRequestsoapheader2.txt b/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrRequestsoapheader2.txt new file mode 100644 index 000000000..8f5767b6a --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/dummyPnrRequestsoapheader2.txt @@ -0,0 +1,2 @@ + +XFHZEKLRZHREJ13RKLERJEZLKRHZEJKLRHEZJKLREZRHEZK2ABC123 \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/PriceXplorer_ExtremeSearchReply_10_3_1A.xsd b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/PriceXplorer_ExtremeSearchReply_10_3_1A.xsd new file mode 100644 index 000000000..7db1e9361 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/PriceXplorer_ExtremeSearchReply_10_3_1A.xsd @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/PriceXplorer_ExtremeSearch_10_3_1A.xsd b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/PriceXplorer_ExtremeSearch_10_3_1A.xsd new file mode 100644 index 000000000..fe8fdc736 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/PriceXplorer_ExtremeSearch_10_3_1A.xsd @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_AuthenticateReply_06_1_1A.xsd b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_AuthenticateReply_06_1_1A.xsd new file mode 100644 index 000000000..3d478f50b --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_AuthenticateReply_06_1_1A.xsd @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + Format limitations: an..5 + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + + + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + Format limitations: an..4 + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + + + + Format limitations: an..70 + + + + + + + + + + + + + + + + + + + + Format limitations: a..6 + + + + + + + + + + + + + + + + + + + + Format limitations: an..10 + + + + + + + + + + + + + + + + + + + + Format limitations: an..10 + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_Authenticate_06_1_1A.xsd b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_Authenticate_06_1_1A.xsd new file mode 100644 index 000000000..31b9c6201 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_Authenticate_06_1_1A.xsd @@ -0,0 +1,367 @@ + + + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + Format limitations: an..14 + + + + + + + + + + + Format limitations: an..14 + + + + + + + + + + + + + + + + + + + + Format limitations: an..9 + + + + + + + + + + + + + + Format limitations: an1 + + + + + + + + + + + Format limitations: an..30 + + + + + + + + + + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + + + + Format limitations: an1 + + + + + + + + + + + + + + + + + Format limitations: n..15 + + + + + + + + + Format limitations: an1 + + + + + + + + + + + Format limitations: an..99999 + + + + + + + + + + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + Format limitations: an..17 + + + + + + + + + + + + + + + + + Format limitations: an..25 + + + + + + + + + + + Format limitations: an..17 + + + + + + + + + + + + + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + Format limitations: an..5 + + + + + + + + + + + + + + + + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + Format limitations: an..6 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_SignOutReply_04_1_1A.xsd b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_SignOutReply_04_1_1A.xsd new file mode 100644 index 000000000..74c9cb884 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_SignOutReply_04_1_1A.xsd @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + Format limitations: an..5 + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + + + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + Format limitations: an..4 + + + + + + + + + + + Format limitations: an..3 + + + + + + + + + + + + + + Format limitations: an..70 + + + + + + + + + + + + + + + + + + + + Format limitations: a..6 + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_SignOut_04_1_1A.xsd b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_SignOut_04_1_1A.xsd new file mode 100644 index 000000000..b6239ab6d --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/Security_SignOut_04_1_1A.xsd @@ -0,0 +1,59 @@ + + + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + Format limitations: an..35 + + + + + + + + + + + Format limitations: an..14 + + + + + + + + + + + Format limitations: an..14 + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/WBS_Session-2.0.xsd b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/WBS_Session-2.0.xsd new file mode 100644 index 000000000..fcf3ad6ab --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/WBS_Session-2.0.xsd @@ -0,0 +1,27 @@ + + + + + + + + + + + This element defines the identifier part of the SessionId. + + + + + This element defines the sequence number of the SessionId. + + + + + This element defines the SecurityToken of the SessionId. + + + + + + \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/dummySecurityAuth.txt b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/dummySecurityAuth.txt new file mode 100644 index 000000000..18cac6001 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/dummySecurityAuth.txt @@ -0,0 +1,2 @@ + +BRUXX0000UDUMMYORIGDUTSUDUMMYORG12EdGhlIHBhc3N3b3Jk \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/dummySecurityAuthReply.txt b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/dummySecurityAuthReply.txt new file mode 100644 index 000000000..efd636d83 --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/dummySecurityAuthReply.txt @@ -0,0 +1 @@ +IROZERIIOP1FDKLSDMJFSMLRJEZRHZJP \ No newline at end of file diff --git a/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/testwsdlsoapheader2.wsdl b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/testwsdlsoapheader2.wsdl new file mode 100644 index 000000000..70c6a5bca --- /dev/null +++ b/tests/Amadeus/Client/Session/Handler/testfiles/soapheader2/testwsdlsoapheader2.wsdl @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Amadeus/Client/Struct/Security/AuthenticateTest.php b/tests/Amadeus/Client/Struct/Security/AuthenticateTest.php new file mode 100644 index 000000000..2d4946308 --- /dev/null +++ b/tests/Amadeus/Client/Struct/Security/AuthenticateTest.php @@ -0,0 +1,70 @@ + + */ +class AuthenticateTest extends BaseTestCase +{ + + public function testCanConstructAuthMessage() + { + $authParams = new AuthParams([ + 'officeId' => 'BRUXXXXXX', + 'originatorTypeCode' => 'U', + 'userId' => 'WSXXXXXX', + 'passwordData' => base64_encode('TEST'), + 'passwordLength' => 4, + 'dutyCode' => 'SU', + 'organizationId' => 'DUMMY-ORG', + ]); + + $reqOpt = new SecurityAuthenticateOptions($authParams); + + $message = new Authenticate($reqOpt); + + $this->assertEquals('BRUXXXXXX' , $message->userIdentifier->originIdentification->sourceOffice); + $this->assertEquals('U' , $message->userIdentifier->originatorTypeCode); + $this->assertEquals('WSXXXXXX' , $message->userIdentifier->originator); + + $this->assertEquals('DUT' , $message->dutyCode->dutyCodeDetails->referenceQualifier); + $this->assertEquals('SU' , $message->dutyCode->dutyCodeDetails->referenceIdentifier); + + $this->assertEquals('DUMMY-ORG' , $message->systemDetails->organizationDetails->organizationId); + + $this->assertEquals(PasswordInfo::DATA_TYPE_EDIFACT , $message->passwordInfo->dataType); + $this->assertEquals(4 , $message->passwordInfo->dataLength); + $this->assertEquals(base64_encode('TEST') , $message->passwordInfo->binaryData); + + } +} diff --git a/tests/Amadeus/ClientTest.php b/tests/Amadeus/ClientTest.php index dcd526a30..3ab45ba67 100644 --- a/tests/Amadeus/ClientTest.php +++ b/tests/Amadeus/ClientTest.php @@ -74,6 +74,29 @@ public function testCanCreateClientWithOverriddenSessionHandlerRequestCreatorAnd $this->assertInstanceOf('Amadeus\Client', $client); } + public function testCanCreateClientWithAuthOptionsAndSessionParams() + { + $par = new Params([ + 'authParams' => [ + 'officeId' => 'BRUXXXXXX', + 'originatorTypeCode' => 'U', + 'userId' => 'WSXXXXXX', + 'passwordData' => base64_encode('TEST') + ], + 'sessionHandlerParams' => [ + 'wsdl' => $this->makePathToDummyWSDL(), + 'stateful' => true, + 'logger' => new NullLogger() + ], + 'requestCreatorParams' => [ + 'receivedFrom' => 'some RF string' + ] + ]); + + $client = new Client($par); + + $this->assertTrue($client->isStateful()); + } /** * @dataProvider dataProviderMakeMessageOptions @@ -1354,6 +1377,88 @@ public function testCanDoSignOutCall() $this->assertEquals($messageResult, $response); } + public function testCanDoAuthenticateCall() + { + $mockSessionHandler = $this->getMockBuilder('Amadeus\Client\Session\Handler\HandlerInterface')->getMock(); + + $authParams = new Params\AuthParams([ + 'officeId' => 'BRUXXXXXX', + 'originatorTypeCode' => 'U', + 'userId' => 'WSXXXXXX', + 'passwordData' => base64_encode('TEST'), + 'passwordLength' => 4, + 'dutyCode' => 'SU', + 'organizationId' => 'DUMMY-ORG', + ]); + + $messageResult = new \stdClass(); + $messageResult->processStatus = new \stdClass(); + $messageResult->processStatus->statusCode = 'P'; + + $expectedMessageResult = new Client\Struct\Security\Authenticate( + new Client\RequestOptions\SecurityAuthenticateOptions( + $authParams + ) + ); + + $mockSessionHandler + ->expects($this->once()) + ->method('sendMessage') + ->with('Security_Authenticate', $expectedMessageResult, ['asString' => false, 'endSession' => false]) + ->will($this->returnValue($messageResult)); + $mockSessionHandler + ->expects($this->never()) + ->method('getLastResponse'); + $mockSessionHandler + ->expects($this->once()) + ->method('getMessagesAndVersions') + ->will($this->returnValue(['Security_Authenticate' => "6.1"])); + + $par = new Params(); + $par->authParams = $authParams; + $par->sessionHandler = $mockSessionHandler; + $par->requestCreatorParams = new Params\RequestCreatorParams([ + 'receivedFrom' => 'some RF string', + 'originatorOfficeId' => 'BRUXXXXXX' + ]); + + $client = new Client($par); + + $response = $client->securityAuthenticate(); + + $this->assertEquals($messageResult, $response); + } + + public function testCanSetSessionData() + { + $mockSessionHandler = $this->getMockBuilder('Amadeus\Client\Session\Handler\HandlerInterface')->getMock(); + + $dummySessionData = [ + 'sessionId' => 'XFHZEKLRZHREJ', + 'sequenceNumber' => 12, + 'securityToken' => 'RKLERJEZLKRHZEJKLRHEZJKLREZRHEZK' + ]; + + $mockSessionHandler + ->expects($this->once()) + ->method('setSessionData') + ->with($dummySessionData) + ->will($this->returnValue(true)); + + $par = new Params(); + $par->sessionHandler = $mockSessionHandler; + $par->requestCreatorParams = new Params\RequestCreatorParams([ + 'receivedFrom' => 'some RF string', + 'originatorOfficeId' => 'BRUXXXXXX' + ]); + + $client = new Client($par); + + $result = $client->setSessionData($dummySessionData); + + $this->assertTrue($result); + } + public function testCanGetSessionInfo() { $mockSessionHandler = $this->getMockBuilder('Amadeus\Client\Session\Handler\HandlerInterface')->getMock(); @@ -1385,6 +1490,7 @@ public function testCanGetSessionInfo() + public function dataProviderMakeMessageOptions() { return [