Skip to content

Commit

Permalink
Merge pull request #12 from madmatt/pulls/api-adjustments
Browse files Browse the repository at this point in the history
  • Loading branch information
madmatt authored Sep 2, 2021
2 parents 3705011 + b9f2386 commit 78689c4
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 43 deletions.
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The WSDL file gives an overview of the values that can be provided, these will v
* [Online WSDL viewer](http://www.id3globalsupport.com/Website/content/Web-Service/WSDL%20Page/WSDL%20HTML/ID3%20Global%20WSDL-%20Live.xhtml)
* [Sample code per country](http://www.id3globalsupport.com/Website/Sample-Code.html)

*Note:* The code below is entirely subject to change. It is primarily focused at the moment around the `AuthenticateSP` method of the ID3Global API, and specifically on NZ, however it should be generic enough to easily support non-NZ systems easily.
*Note:* The code below is entirely subject to change. It is primarily focused at the moment around the `AuthenticateSP` method of the ID3global API, and specifically on New Zealand (Aotearoa), however it should be generic enough to easily support non-NZ systems easily.

```php
/**
Expand Down Expand Up @@ -98,14 +98,20 @@ $documentContainer = new \ID3Global\Identity\Documents\DocumentContainer();
$documentContainer->addIdentityDocument(new \ID3Global\Identity\Documents\NZ\DrivingLicence(), 'New Zealand');

/**
* $result will be one of the following:
* - \ID3Global\Constants\Identity::IDENTITY_BAND_PASS
* - \ID3Global\Constants\Identity::IDENTITY_BAND_REFER
* - \ID3Global\Constants\Identity::IDENTITY_BAND_ALERT
* $result will be a string representing the 'BandText' as returned by the ID3global API. By default, this may be a word
* like 'PASS', 'REFER' or 'ALERT' but could also be any string value e.g. 'Name, Address and DOB Match'. The exact
* string returned is entirely dependent on how the profile is configured within ID3global, and can vary if you adjust
* the profile id and profile version.
*
* It is up to your implementation how these are handled. Note that generally there is only a single value that
* represents an identity that has passed the necessary verification, and multiple BandTexts that represent a failing
* identity. You **must** handle this in your own code, as the ID3Global API does not provide any kind of boolean value
* for whether a given identity passed identity verification or not.
*
* It is up to the implementation how these are handled.
* An exception is thrown if the web service fails or cannot be contacted.
*/
$validIdentityBandText = 'PASS'; // See note above about how this may differ for you

$identity = new \ID3Global\Identity\Identity();
$identity
->setPersonalDetails($personalDetails)
Expand All @@ -116,9 +122,10 @@ $identity
$gateway = new \ID3Global\Gateway\GlobalAuthenticationGateway('username', 'password');
$id3Service = new \ID3Global\Service\GlobalAuthenticationService($gateway);
$result = $id3Service
->verifyIdentity($identity, 'profile-id');
->setProfileId('Profile ID as provided by ID3global interface')
->verifyIdentity($identity, 'Unique customer reference');

if($result === 'PASS') {
if($result === $validIdentityBandText) {
// Identity is verified, continue processing
}
```
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "madmatt/id3global-service",
"description": "Allows a PHP-powered website to communicate with the GBG ID3global API to verify identities. This library is not affiliated with GBG PLC in any way.",
"type": "library",
"keywords": [ "id3global", "GBG", "GBG PLC", "ID3Global", "identity verification", "identity" ],
"keywords": [ "id3global", "GBG", "GBG PLC", "ID3Global", "ID3global", "identity verification", "identity" ],
"homepage": "https://github.com/madmatt/id3global-service/",
"license": "BSD-3-Clause",

Expand Down
2 changes: 1 addition & 1 deletion src/Exceptions/IdentityVerificationFailureException.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class IdentityVerificationFailureException extends Exception
public function __construct($response)
{
$this->response = $response;
$message = sprintf('Invalid Response returned by ID3Global API. Serialized response: %s', serialize($response));
$message = sprintf('Invalid Response returned by ID3global API. Serialized response: %s', serialize($response));
parent::__construct($message);
}

Expand Down
132 changes: 107 additions & 25 deletions src/Service/GlobalAuthenticationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace ID3Global\Service;

use Exception;
use LogicException;
use ID3Global\Exceptions\IdentityVerificationFailureException;
use ID3Global\Gateway\GlobalAuthenticationGateway;
use ID3Global\Identity\Identity;
Expand All @@ -16,6 +17,31 @@ class GlobalAuthenticationService extends ID3BaseService
*/
private GlobalAuthenticationGateway $gateway;

/**
* @var string The Profile ID to be used when verifying identities via $this->verifyIdentity().
* @see self::setProfileId()
*/
private string $profileId = '';

/**
* @var int The version of the Profile ID to be used when verifying identities via $this->verifyIdentity().
* The special value of 0 is treated specially by ID3global and represents the 'most recent version of the profile'.
* @see self::setProfileVersion()
*/
private int $profileVersion = 0;

/**
* @var Identity The most recent Identity object to be verified by the ID3global API (regardless of the outcome of
* the API request).
*/
private Identity $lastIdentity;

/**
* @var string|null The most recent customer reference to be verified by the ID3global API (regardless of the
* outcome of the API request).
*/
private ?string $lastCustomerReference;

/**
* @var stdClass|null The last response, directly from the API gateway. Can be retrieved using
* {@link getLastVerifyIdentityResponse()}.
Expand All @@ -39,39 +65,54 @@ public function __construct(GlobalAuthenticationGateway $gateway, array $soapOpt
}

/**
* @param Identity $identity
* @param string $profileId The Profile ID to be used when verifying a @link \ID3Global\Identity\Identity object
* @param int $profileVersion The Profile Version to be used when verifying a @link \ID3Global\Identity\Identity object. The version
* 0 represents the 'most recent version of the profile', which is generally what is required.
* @param string|null $customerReference A reference stored against this identity request. This is optional, but is recommended to set a
* customer reference and store it against the returned identity verification so it can be later tracked if
* Given an Identity and a profile of checks to perform, query ID3Global and verify the given $identity object. The
* raw response is the output of the 'BandText' as returned directly by the ID3Global API. Per the
* [ID3Global 'Integrate now' documentation](https://www.id3globalsupport.com/integrate-now/), you should use this
* value to determine whether or not to consider the identity to be sufficiently verified for your needs.
*
* If you want to dive deeper (e.g. to look at individual checks that were performed such as whether the identity
* matched on a driver's license or passport record), you can do this by calling
* $service->getLastVerifyIdentityResponse() after calling this method - this will return the full response from the
* API.
*
* Ensure you call at least ->setProfileId() prior to calling this method.
* Optionally call ->setProfileVersion() if you wish to set a specific profile version to query against.
*
* @param Identity $identity The full Identity object that should be verified with the ID3global API
* @param string|null $customerReference A reference stored against this identity request within the ID3global
* interface. This is optional, but is highly recommended to set a reference
* and store it against the identity so that it can be later tracked if
* necessary for compliance purposes.
*
* @throws IdentityVerificationFailureException
* @throws IdentityVerificationFailureException Thrown specifically if the SOAP response was 'valid' according to
* SOAP but does not conform to the expected response (missing BandText or Score elements of the response).
* @throws Exception May throw a generic Exception or SoapFault if any part of the SOAP callstack fails.
*
* @return string One of Identity::IDENTITY_BAND_PASS, Identity::IDENTITY_BAND_REFER, or Identity::IDENTITY_BAND_ALERT
*/
public function verifyIdentity(
Identity $identity,
string $profileId,
int $profileVersion = 0,
?string $customerReference = null
): string {
* @return string The raw BandText as provided by the API.
*/
public function verifyIdentity(Identity $identity, ?string $customerReference = null): string {
$this->lastIdentity = $identity;
$this->lastCustomerReference = $customerReference;

$gateway = $this->getGateway();

if (!$this->profileId) {
$error = 'An ID3global Profile ID must be set by calling setProfileId() before calling verifyIdentity().';
throw new LogicException($error);
}

$profileId = $this->profileId;
$profileVersion = $this->profileVersion;

try {
$response = $gateway->AuthenticateSP(
$profileId,
$profileVersion,
$customerReference,
$identity
);
$response = $gateway->AuthenticateSP($profileId, $profileVersion, $customerReference, $identity);

if ($gateway->getClient() instanceof SoapClient) {
$this->lastRawRequest = $gateway->getClient()->__getLastRequest();
}

$validResult = false;
$this->lastVerifyIdentityResponse = $response;

if (
isset($response) &&
Expand All @@ -82,8 +123,6 @@ public function verifyIdentity(
}

if ($validResult) {
$this->lastVerifyIdentityResponse = $response;

return $response->AuthenticateSPResult->BandText;
} else {
throw new IdentityVerificationFailureException($response);
Expand All @@ -93,9 +132,52 @@ public function verifyIdentity(
}
}

public function setProfileId(string $profileId): self
{
$this->profileId = $profileId;

return $this;
}

public function getProfileId(): string
{
return $this->profileId;
}

public function setProfileVersion(int $profileVersion): self
{
$this->profileVersion = $profileVersion;

return $this;
}

public function getProfileVersion(): int
{
return $this->profileVersion;
}

/**
* @return Identity|null The last Identity object to be verified by the API (regardless of whether it was
* successfully accepted by the ID3global API or not). Returns null if ->verifyIdentity() has not yet been called.
*/
public function getLastVerifiedIdentity(): ?Identity
{
return $this->lastIdentity;
}

/**
* @return string|null The last customer reference value to be verified by the API (regardless of whether it was
* successfully accepted by the ID3global API or not). Returns null if ->verifyIdentity() has not yet been called.
*/
public function getLastCustomerReference(): ?string
{
return $this->lastCustomerReference;
}

/**
* @return stdClass|null Either the full response as returned by ID3Global, or null if no call has been made (or
* if the previous call failed for any reason)
* @return stdClass|null Either the full response as returned by ID3global, or null if no call has been made yet. If
* the request was made but failed to validate (e.g. the ID3global API returned an invalid SOAP object, this will
* still be populated.
*/
public function getLastVerifyIdentityResponse(): ?stdClass
{
Expand Down
19 changes: 12 additions & 7 deletions src/Stubs/Gateway/GlobalAuthenticationGatewayFake.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@
class GlobalAuthenticationGatewayFake extends GlobalAuthenticationGateway
{
/**
* @var string The const returned by the ID3Global API when this identity passed verification, according to the
* ruleset used.
* @var string A BandText value returned by the ID3global API when this identity passed verification, according to
* the selected profile.
*/
const IDENTITY_BAND_PASS = 'PASS';

/**
* @var string The const returned by the ID3Global API when this identity needs additional referral, according to
* the ruleset used.
* @var string A BandText value returned by the ID3global API when this identity needs additional referral,
* according to the selected profile.
*/
const IDENTITY_BAND_REFER = 'REFER';

/**
* The const returned by the ID3Global API when this identity needs additional referral, according to
* the ruleset used.
* @var string A BandText value returned by the ID3global API when this identity has a significant issue, according
* to the selected profile.
*/
const IDENTITY_BAND_ALERT = 'ALERT';

Expand All @@ -32,6 +32,11 @@ public function __construct($username, $password, $soapClientOptions = [], $useP

public function AuthenticateSP($profileID, $profileVersion, $customerReference, Identity $identity)
{
return unserialize('O:8:"stdClass":1:{s:20:"AuthenticateSPResult";O:8:"stdClass":12:{s:16:"AuthenticationID";s:36:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";s:9:"Timestamp";s:33:"2016-01-01T00:00:00.0000000+01:00";s:11:"CustomerRef";s:1:"x";s:9:"ProfileID";s:36:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";s:11:"ProfileName";s:15:"Default Profile";s:14:"ProfileVersion";i:1;s:15:"ProfileRevision";i:1;s:12:"ProfileState";s:9:"Effective";s:11:"ResultCodes";O:8:"stdClass":1:{s:26:"GlobalItemCheckResultCodes";a:0:{}}s:5:"Score";i:3000;s:8:"BandText";s:4:"PASS";s:7:"Country";s:11:"New Zealand";}}');
$bandText = self::IDENTITY_BAND_PASS;

return unserialize(sprintf(
'O:8:"stdClass":1:{s:20:"AuthenticateSPResult";O:8:"stdClass":12:{s:16:"AuthenticationID";s:36:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";s:9:"Timestamp";s:33:"2016-01-01T00:00:00.0000000+01:00";s:11:"CustomerRef";s:1:"x";s:9:"ProfileID";s:36:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";s:11:"ProfileName";s:15:"Default Profile";s:14:"ProfileVersion";i:1;s:15:"ProfileRevision";i:1;s:12:"ProfileState";s:9:"Effective";s:11:"ResultCodes";O:8:"stdClass":1:{s:26:"GlobalItemCheckResultCodes";a:0:{}}s:5:"Score";i:3000;s:8:"BandText";s:4:"%s";s:7:"Country";s:11:"New Zealand";}}',
$bandText
));
}
}
16 changes: 15 additions & 1 deletion tests/Service/GlobalAuthenticationServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use DateTime;
use Exception;
use LogicException;
use ID3Global\Identity\Identity;
use ID3Global\Identity\PersonalDetails;
use ID3Global\Service\GlobalAuthenticationService;
Expand Down Expand Up @@ -36,18 +37,31 @@ public function testSuccessfulResponse()
->setSurname('Huntsman')
->setGender('Female')
->setDateOfBirth(DateTime::createFromFormat('Y-m-d', '1976-03-06'));

$identity = new Identity();
$identity->setPersonalDetails($personalDetails);

$profileId = 'profile-id';

// Act
$bandText = $this->service->verifyIdentity($identity, $profileId, 0, 'x');
$bandText = $this->service
->setProfileId($profileId)
->verifyIdentity($identity, 'customer reference');

// Assert
$this->assertSame(GlobalAuthenticationGatewayFake::IDENTITY_BAND_PASS, $bandText);

$response = $this->service->getLastVerifyIdentityResponse();
$this->assertSame('stdClass', get_class($response));
$this->assertSame(GlobalAuthenticationGatewayFake::IDENTITY_BAND_PASS, $response->AuthenticateSPResult->BandText);
$this->assertSame('Default Profile', $response->AuthenticateSPResult->ProfileName);
}

public function testNotSettingProfileIdThrows()
{
$identity = new Identity();

$this->expectException(LogicException::class);
$this->service->verifyIdentity($identity);
}
}

0 comments on commit 78689c4

Please sign in to comment.