# Documentation

FIFA Connect Service Bus PHP SDK, v3.0

# 1. Introduction

The main responsibility of FIFA Connect ID Service Bus is to provide unified infrastructure for asynchronous messaging. Using FIFA Connect Service Bus and its SDK it is possible to exchange encrypted messages with other applications connected to the bus.

## 1.1 Prerequisites

### PHP version

PHP 5.6 (or higher) is required.

### Installing via Composer

After downloading zip file from FIFA Confluence into local directory, add an entry "fifaconnectservicebus/php-sdk": "^3.0.0" to require section in your composer.json file, and add new repository type artifact in repositories section. See https://getcomposer.org/doc/05-repositories.md#artifact for more information.

Example:

    {
      "require": {
        "fifaconnectservicebus/php-sdk": "^3.0.0"
      },
      "repositories": [
        {
          "type": "artifact",
          "url": "/path/to/directory/with/zips/"
        }
      ]
    }

## 1.2 How encryption works in Connect Service Bus

FIFA Connect Service Bus provides end-to-end encryption which means that message is encrypted in SDK of sending party and is decrypted in SDK or receiving party. Consequently none of the devices transferring message (including FIFA Connect Service Bus servers) can read its content.

Such a feature of Connect Service Bus is possible due to usage of infrastructure based on public and private pairs of certificates. This section briefly describes how this is achieved.

1. Using provided tools Administrator of organisation "A" generates pair of public and private certificates. Public certificate can be shared with anyone (e.g. uploaded on a server) but private key should be kept in secret.
2. Administrator of organisation "A" uploads public certificates to FIFA Connect Service Bus server using provided tool.
3. Now application of organisation "B" wants to send an encrypted message to Organisation "A". Then the code in application calls Connect Service Bus SDK which in a seamless way:

- connects to FIFA Connect Service Bus server and downloads public certificate of organisation "A" (which was uploaded in previous step).
- uses downloaded public certificate of Organisation "A" to encrypt content of the message. Due to nature of asymmetric encryption with public-private certificates only holder of private certificate can decrypt that message. Since private key of Organisation "A" was not shared with anyone only Organisation "A" can decrypt that message.
- sends encrypted message to the Organisation A

4. Then application of Organisation A using SDK receives message. Under the hood SDK

- receives message from Connect Service Bus
- uses private certificate of Organisation "A" to decrypt content of the message
- returns decrypted message to application of Organisation A.
- application "A" can decide what to do with received message

# 2. FIFA Connect Service Bus Client

## 2.1 Creating a client

The entry point of the SDK is `Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusClient`. With a single instance of this class all the requests can be made. In order to authenticate to the service you have to provide a set of client credentials.

### 2.1.1 Logger implementation

Each SDK client method uses `Psr\Log\LoggerInterface` in order to log any errors that might happen during the application runtime. There is no default Logger implementation provided, as different parties could want a different way of storing logs. Implementation of such Logger class is mandatory.

Each logger method needs to have two parameters provided: `$message` (string) and `$context` (key-value array of strings). A frequent mistake when implementing `Psr\Log\LoggerInterface` is ignoring the `$context` parameter - these keys and values should be logged alongside the `$message`.

Please take a look at the following example of logger method call:

    /**
     * Detailed debug information.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function debug($message, array $context = array());

    $logger->debug('Uploading certificate has completed successfully',
        array('response' => $response));

Consider inheriting from `Psr\Log\AbstractLogger` which only requires implementation of `public function log($level, $message, array $context = array());`.

### 2.1.2 Basic instance

In order to create an instance of `Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusClient` four parameters need to be provided: environment, client credentials, private certificate storage (see chapter 3. Encryption) and logger.

    <?php
    use Fifa\ConnectServiceBus\Sdk\Authentication\Model\ClientCredentials;
    use Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateMemoryStorage;
    use Fifa\ConnectServiceBus\Sdk\Encryption\Model\PrivateCertificate;
    use Fifa\ConnectServiceBus\Sdk\Environment\Environment;
    use Fifa\ConnectServiceBus\Sdk\Utils\File;

    $clientCredentials = new ClientCredentials('clientId', 'secretKey');

    $privateCertificate = new PrivateCertificate(File::getContents($filePath), 'Test123');
    $privateStore = new PrivateCertificateMemoryStorage($privateCertificate);
    $logger = new YourOwnLogger();

    $client = FifaConnectServiceBusClient::create(Environment::Beta(), $clientCredentials, $privateStore, $logger);

where environment is an instance of type `Fifa\ConnectServiceBus\Sdk\Environment\Environment`. It provides information about the service to make request to.

### 2.1.3 Certificate client instance

In case of need for upload or download certificate, you have to use an instance of `Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusCertificateClient`.

    <?php
    use Fifa\ConnectServiceBus\Sdk\Authentication\Model\ClientCredentials;
    use Fifa\ConnectServiceBus\Sdk\Environment\Environment;
    use Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusCertificateClient;

    $clientCredentials = new ClientCredentials('clientId', 'secretKey');
    $logger = new YourOwnLogger();

    $client = new FifaConnectServiceBusCertificateClient(Environment::Beta(), $clientCredentials, $logger);

### 2.1.4 Setup cache storage

SDK utilizes caching to keep authentication tokens and downloaded public certificates. By default SDK uses local file storage, which is implemented in `CacheFileStorage` class. Default location for cached objects is `.cache` folder located in a root folder of Service Bus SDK. Location of this folder can be changed by passing relevant path to constructor of `EnvironmentSettings`.

Alternatively, implementing `CacheStorageInterface` may introduce custom caching storage (e.g. Amazon S3 bucket). Instance of class implementing `CacheStorageInterface` should be passed to `EnvironmentSettings` instance when creating `Environment` object.

Example below shows how to provide path to local folder:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Environment\Environment;
    use Fifa\ConnectServiceBus\Sdk\Environment\EnvironmentSettings;

    $cacheFolder = '/path/to/cache/folder';
    $settings = new EnvironmentSettings($cacheFolder);

    Environment::Beta($settings);

Example below shows how to use own implementation of `CacheStorageInterface`:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Authentication\CacheStorageInterface;
    use Fifa\ConnectServiceBus\Sdk\Environment\Environment;
    use Fifa\ConnectServiceBus\Sdk\Environment\EnvironmentSettings;

    /** @var CacheStorageInterface $cacheStorage */
    $cacheStorage = new CustomCacheStorage();
    $settings = new EnvironmentSettings($cacheStorage);

    Environment::Beta($settings);

### 2.1.5 Addressing a message

Recipient of the message is specified by the `recipient` parameter. It's actually a name of a queue that acts as an inbox for other client (e.g. registration system in a different MA).

### 2.1.6 Creating custom environment instance

As there are some pre-defined environments defined in the `Environment` class, it's also possible to create a custom instance using environment code. In order to achieve that, environment code needs to be provided to the static factory method.

Example:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Environment\Environment;

    $envCode = 'testenv';
    $environment = Environment::create($envCode);

## 2.2 Sending a message

In order to send a message in FIFA Connect Service Bus service provide instance of `Fifa\ConnectServiceBus\Sdk\Message\Message` class. A `recipient` needs to be provided as well.

By convention value of the `recipient` is the FIFA ID of the receiving organisation. However, for certain applications it may have format of `FIFAID_application`. In case of any doubts, please contact FIFA Connect Service Bus Support team to get proper value of `recipient`.

Example:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Exception\AuthenticationException;
    use Fifa\ConnectServiceBus\Sdk\Exception\FifaConnectServiceBusSdkException;
    use Fifa\ConnectServiceBus\Sdk\Exception\InvalidClientDataException;
    use Fifa\ConnectServiceBus\Sdk\Exception\QueueNotFoundException;
    use Fifa\ConnectServiceBus\Sdk\Exception\UnauthorizedException;
    use Fifa\ConnectServiceBus\Sdk\Message\Message;

    try {
        $message = new Message('message content');

        $client->send('recipient', $message);
    }
    catch (InvalidClientDataException $e) {
        $details = $e->getDetails();
    }
    catch (QueueNotFoundException $e) {
        // there is no queue for specified recipient
    }
    catch (UnauthorizedException $e) {
        // unauthorized
    }
    catch (AuthenticationException $e) {
        // invalid client credentials
    }
    catch (TooManyRequestsException $e) {
        // call rate limit was exceeded
        $retryAfterInSeconds = $e->getRetryAfter();
    }
    catch (FifaConnectServiceBusSdkException $e) {
        // handle exception
    }

To send additional metadata of the message:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Message\Message;

    $action = '/person/getDetails';
    $properties = array(
        'id' => 'BVGE8T6',
    );

    $message = new Message('message content', $action, $properties);

    $client->send('recipient', $message);

## 2.3 Transactional receive

In order to receive a message from Connect Service Bus and leave it in the queue use `peekLock` method. The `timeout` parameter can be specified. In Connect Service Bus context `timeout` defines how long a request waits before returning that there is no message in the queue. When no message is found, `null` will be returned. Received message will not be visible for other Connect Service Bus clients for 120 seconds. The 'timeout' value does not impact this, therefore it is recommended to keep 'timeout' value smaller than 120. During that time period actions like `delete` or `unlock` can be triggered. If none of the above actions is taken, message will be returned to the queue.

In the `Message` some metadata can be found in method `getBrokerProperties`. The most important are `MessageId` and `LockToken` that are used as required parameters in `delete` and `unlock` methods.

Example:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Exception\AuthenticationException;
    use Fifa\ConnectServiceBus\Sdk\Exception\FifaConnectServiceBusSdkException;
    use Fifa\ConnectServiceBus\Sdk\Exception\InvalidClientDataException;
    use Fifa\ConnectServiceBus\Sdk\Exception\QueueNotFoundException;
    use Fifa\ConnectServiceBus\Sdk\Exception\UnauthorizedException;
    use Fifa\ConnectServiceBus\Sdk\Message\Message;

    try {
        $timeout = 60;
        /** @var Message $message */
        $message = $client->peekLock($timeout);
    }
    catch (QueueNotFoundException $e) {
        // there is no queue for specified recipient
    }
    catch (InvalidClientDataException $e) {
        $details = $e->getDetails();
    }
    catch (UnauthorizedException $e) {
        // unauthorized
    }
    catch (CryptographyException $e) {
        // exception when decrypting service bus message
    }
    catch (AuthenticationException $e) {
        // invalid client credentials
    }
    catch (TooManyRequestsException $e) {
        // call rate limit was exceeded
        $retryAfterInSeconds = $e->getRetryAfter();
    }
    catch (FifaConnectServiceBusSdkException $e) {
        // handle exception
    }

## 2.4 Delete a message

Method used to delete a locked message.

Example:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Exception\AuthenticationException;
    use Fifa\ConnectServiceBus\Sdk\Exception\FifaConnectServiceBusSdkException;
    use Fifa\ConnectServiceBus\Sdk\Exception\InvalidClientDataException;
    use Fifa\ConnectServiceBus\Sdk\Exception\MessageNotFoundException;
    use Fifa\ConnectServiceBus\Sdk\Exception\UnauthorizedException;

    try {
        $client->delete($message->getId(), $message->getLockToken());
    }
    catch (MessageNotFoundException $e) {}
    catch (InvalidClientDataException $e) {
        $details = $e->getDetails();
    }
    catch (UnauthorizedException $e) {
        // unauthorized
    }
    catch (AuthenticationException $e) {
        // invalid client credentials
    }
    catch (TooManyRequestsException $e) {
        // call rate limit was exceeded
        $retryAfterInSeconds = $e->getRetryAfter();
    }
    catch (FifaConnectServiceBusSdkException $e) {
        // some other error occurred, see the details
    }

## 2.5 Unlock a message

Message can be returned to the queue using `unlock` method.

Example:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Exception\AuthenticationException;
    use Fifa\ConnectServiceBus\Sdk\Exception\FifaConnectServiceBusSdkException;
    use Fifa\ConnectServiceBus\Sdk\Exception\InvalidClientDataException;
    use Fifa\ConnectServiceBus\Sdk\Exception\MessageNotFoundException;
    use Fifa\ConnectServiceBus\Sdk\Exception\UnauthorizedException;

    try {
        $client->unlock($message->getId(), $message->getLockToken());
    }
    catch (MessageNotFoundException $e) {}
    catch (InvalidClientDataException $e) {
        $details = $e->getDetails();
    }
    catch (UnauthorizedException $e) {
        // unauthorized
    }
    catch (AuthenticationException $e) {
        // invalid client credentials
    }
    catch (FifaConnectServiceBusSdkException $e) {
        // some other error occurred, see the details
    }

# 3. Encryption

In order to enable encryption when sending the messages, there is a need of generating and configuring the certificates. Generation process is described in separate documentation file (`fifa-connectservicebus-certificates-generation.html`). Below you will find information about how to use certificates in SDK.

## 3.1 Upload a public certificate

Recommended way to upload a public certificate is the upload using console application located in `certificate-upload-console` folder. For more information please refer to Certificate Generation documentation. If console application can't be used, use `uploadCertificate` method from `Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusCertificateClient` class. instead. Take a look at the following example:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Exception\AuthenticationException;
    use Fifa\ConnectServiceBus\Sdk\Exception\FifaConnectServiceBusSdkException;
    use Fifa\ConnectServiceBus\Sdk\Exception\InvalidClientDataException;
    use Fifa\ConnectServiceBus\Sdk\Exception\UnauthorizedException;
    use Fifa\ConnectServiceBus\Sdk\Utils\File;

    $certificateData = File::getContents($certificateFilePath);
    try {
        $certificateClient->uploadCertificate($certificateData);
    }
    catch (InvalidClientDataException $e) {
        // data sent to the service was invalid
        $details = $e->getBadRequestResponse();
    }
    catch (UnauthorizedException $e) {
        // unauthorized
    }
    catch (AuthenticationException $e) {
        // invalid client credentials
    }
    catch (TooManyRequestsException $e) {
        // call rate limit was exceeded
        $retryAfterInSeconds = $e->getRetryAfter();
    }
    catch (FifaConnectServiceBusSdkException $e) {
        // some other error occurred, see the details
    }

## 3.2 Download a public certificate

In case of need, there is a possibility to download public certificate for specific queue. In order to do that use `downloadCertificate` method from `Fifa\ConnectServiceBus\Sdk\FifaConnectServiceBusCertificateClient` class. Please take a look at the following example:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Exception\AuthenticationException;
    use Fifa\ConnectServiceBus\Sdk\Exception\DataNotFoundException;
    use Fifa\ConnectServiceBus\Sdk\Exception\FifaConnectServiceBusSdkException;
    use Fifa\ConnectServiceBus\Sdk\Exception\InvalidClientDataException;
    use Fifa\ConnectServiceBus\Sdk\Exception\UnauthorizedException;

    try {
        $certificateRawData = $certificateClient->downloadCertificate($queueIdentifier);
    }
    catch (InvalidClientDataException $e) {
        // data sent to the service was invalid
        $details = $e->getBadRequestResponse();
    }
    catch (DataNotFoundException $e) {
        // certificate has not been found
    }
    catch (UnauthorizedException $e) {
        // unauthorized
    }
    catch (AuthenticationException $e) {
        // invalid client credentials
    }
    catch (TooManyRequestsException $e) {
        // call rate limit was exceeded
        $retryAfterInSeconds = $e->getRetryAfter();
    }
    catch (FifaConnectServiceBusSdkException $e) {
        // some other error occurred, see the details
    }

## 3.3 Setup private certificate

In order to create a new instance of the client, instance of `Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateStorageInterface` must be provided. By default SDK uses `Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateMemoryStorage` class that implements mentioned interface. Next step is to provide instance(s) of `Fifa\ConnectServiceBus\Sdk\Encryption\Model\PrivateCertificate` into such container. Each certificate consists of the key (from generated file) and password (optionally). Please take a look at the following example:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateMemoryStorage;
    use Fifa\ConnectServiceBus\Sdk\Encryption\Model\PrivateCertificate;
    use Fifa\ConnectServiceBus\Sdk\Environment\Environment;
    use Fifa\ConnectServiceBus\Sdk\Utils\File;

    $filePath = '/path/to/folder/private_key.pem';

    $privateCertificate = new PrivateCertificate(File::getContents($filePath), 'SomePassword');
    $privateStore = new PrivateCertificateMemoryStorage($privateCertificate);
    $logger = new YourOwnLogger();

    $client = FifaConnectServiceBusClient::create(Environment::Beta(), $clientCredentials, $privateStore, $logger);

## 3.4 Generate new certificate

In order to generate a new certificate follow instructions from `fifa-connectservicebus-certificates-generation.html`. When a new pair of certificates (public and private) is generated and a new public certificate is uploaded, then it's required to update collection of private certificates returned by implementation of `Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateStorageInterface`. Since some messages could be encrypted before new public certificate was uploaded, implementation of `Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateStorageInterface` must return current and previous private certificate to ensure that all messages can be decrypted.

Correct order of steps is the following:

1. Generate pair of certificates
2. Modify and deploy code so that `Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateStorageInterface` returns old and new private certificates
3. Upload new public certificate to Connect Service Bus

Please take a look at the following example, where two certificates are used by `Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateStorageInterface`:

    <?php
    use Fifa\ConnectServiceBus\Sdk\Encryption\Decrypt\PrivateCertificateMemoryStorage;
    use Fifa\ConnectServiceBus\Sdk\Encryption\Model\PrivateCertificate;
    use Fifa\ConnectServiceBus\Sdk\Utils\File;

    $privateCertificate = new PrivateCertificate(File::getContents($filePath), 'Test123');
    $oldPrivateCertificate = new PrivateCertificate(File::getContents($oldFilePath), 'Test123');

    $privateStore = new PrivateCertificateMemoryStorage($oldPrivateCertificate);
    $privateStore->addNewKey($privateCertificate);

# 4. Limits

## 4.1 Maximum queue size

Currently each recipient's queue has a quota of 80 GB (both content and message headers size is counted). When queue reaches its limit, new messages cannot be send to the recipient, so senders get an error from Service Bus API and SDK.

## 4.2. Maximum time-to-live

Each queue stores messages for 7 days. If message is not received by the recipient, it is moved to dead-letter queue and support team receives notification about unprocessed message. On client request support team can move a message to primary queue so that it can be received and processed by an application. Alternatively message can be permanently deleted from a dead-letter queue.

## 4.3. Maximum delivery retries

If client using Connect Service Bus SDK downloads message but fails to process it correctly (i.e. handler throws an exception), the counter of failed delivery is increased. If delivery fails 10 times, message is moved to a dead-letter queue. Depending on the reason different actions can be taken:

- message is invalid or content is malformed, so that message cannot be processed by receiver - support team can delete the message, if needed sender should be notified that the message was invalid and was not processed by recipient
- issue on the receiving side preventing correct message to be processed - support team can move message to primary queue so that message can be reprocessed after the issue is solved on the receiving side

## 4.4 Maximum message size

Maximum message size is 10MB. If this limit is exceeded then Connect Service Bus will return 400 (Bad Request) response code. As a result `InvalidClientDataException` will be thrown.

# 5 Known issues

## 5.1 SSL certificate verification issue

For a PHP installation that doesn’t come with curl libraries bundled, like the Windows PHP distribution, you need to download the certificate file and tell PHP where to find it. Then you need to edit `php.ini` file by adding a path in following setting:

    curl.cainfo=c:\php\cacert.pem

# 6. Release notes

The following changes were introduced in version 3.0 of the SDK when comparing to version 2.1:

- All occurrences of "organizationId" parameter renamed to "queueIdentifier"
- Added support for setting custom directory path where cache files will be stored
- SSL verification turned on
- Fixed problem with hanging peek lock connection