From d9442d5ab255f8752dffb84326b3bd958ba54dbc Mon Sep 17 00:00:00 2001 From: mehmet-yoti <111424390+mehmet-yoti@users.noreply.github.com> Date: Thu, 4 Jul 2024 18:50:09 +0300 Subject: [PATCH] Sdk 2420 php add support for advanced identity profiles to share v 2 and examples (#360) * SDK-2420 Added support for advanced identity profile and examples * SDK-2420 Added test and updated tests for Advanced Identity Profile Share V2 --- .php-cs-fixer.cache | 1 - .../AdvancedIdentityController.php | 71 +++++++++++++++ .../views/advancedidentity.blade.php | 89 +++++++++++++++++++ examples/digitalidentity/routes/web.php | 2 + src/Identity/Policy/Policy.php | 21 ++++- src/Identity/Policy/PolicyBuilder.php | 15 +++- tests/Identity/Policy/PolicyBuilderTest.php | 76 +++++++++++++++- 7 files changed, 268 insertions(+), 7 deletions(-) delete mode 100644 .php-cs-fixer.cache create mode 100644 examples/digitalidentity/app/Http/Controllers/AdvancedIdentityController.php create mode 100644 examples/digitalidentity/resources/views/advancedidentity.blade.php diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache deleted file mode 100644 index f684c0c8..00000000 --- a/.php-cs-fixer.cache +++ /dev/null @@ -1 +0,0 @@ -{"php":"8.1.29","version":"3.59.3:v3.59.3#30ba9ecc2b0e5205e578fe29973c15653d9bfd29","indent":" ","lineEnding":"\n","rules":{"array_syntax":{"syntax":"short"},"no_unused_imports":true,"ordered_imports":{"imports_order":["const","class","function"]},"php_unit_fqcn_annotation":true,"phpdoc_return_self_reference":true,"phpdoc_scalar":true},"hashes":{"\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder861\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"6df4324fbc01516f544e380a2fcdad1d","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder3196\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"81fbf5d555938c2c1693fa70c5d2f06b","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder10280\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"6df4324fbc01516f544e380a2fcdad1d","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder2372\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"81fbf5d555938c2c1693fa70c5d2f06b","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder12059\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"01fd3c6b4102578a5cbe7b9ca5a9620b","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder4216\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"2b29b8fd1369f029fdd2626aff9574a1","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder7923\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"a92ce4d8cf8cba9fc31b0b862a238e7d","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder9888\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"99cf5679ad3fbe693f1318efc4c7562e","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder7837\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"29258793b15beceaafceef4b742beca0","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder5368\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/FailureReasonResponse.php":"9f3471f97753fd479ff323dbab8f8ff8","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder9615\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/FailureReasonResponse.php":"fa7416c72cb9a21e375a580d0711b4a3","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder2220\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/FailureReasonResponse.php":"3f1b675e645966f11d6fe283ff3d1a5c","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder10144\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/FailureReasonResponse.php":"9f3471f97753fd479ff323dbab8f8ff8","\/private\/var\/folders\/hs\/kw0d0_0d2kj8xl5yd5_t2rz40000gn\/T\/PHP CS Fixertemp_folder7956\/src\/DocScan\/Session\/Retrieve\/IdentityProfile\/RequirementNotMetDetails.php":"29258793b15beceaafceef4b742beca0"}} diff --git a/examples/digitalidentity/app/Http/Controllers/AdvancedIdentityController.php b/examples/digitalidentity/app/Http/Controllers/AdvancedIdentityController.php new file mode 100644 index 00000000..cdfda0f6 --- /dev/null +++ b/examples/digitalidentity/app/Http/Controllers/AdvancedIdentityController.php @@ -0,0 +1,71 @@ + [(object)[ + + "trust_framework" => "YOTI_GLOBAL", + "schemes" => [(object)[ + + "label" => "identity-AL-L1", + "type" => "IDENTITY", + "objective"=> "AL_L1" + ], + [ + "label" => "identity-AL-M1", + "type" => "IDENTITY", + "objective" => "AL_M1" + ] + ] + ] + ] + ] + ; + + $policy = (new PolicyBuilder()) + ->withAdvancedIdentityProfileRequirements((object)$advancedIdentityProfileJson) + ->build(); + + $redirectUri = 'https://host/redirect/'; + + $shareSessionRequest = (new ShareSessionRequestBuilder()) + ->withPolicy($policy) + ->withRedirectUri($redirectUri) + ->build(); + $session = $client->createShareSession($shareSessionRequest); + return $session->getId(); + } + catch (\Throwable $e) { + Log::error($e->getTraceAsString()); + throw new BadRequestHttpException($e->getMessage()); + } + } + public function show(DigitalIdentityClient $client) + { + try { + return view('advancedidentity', [ + 'title' => 'Digital Identity(Advanced) Complete Example', + 'sdkId' => $client->id + ]); + } catch (\Throwable $e) { + Log::error($e->getTraceAsString()); + throw new BadRequestHttpException($e->getMessage()); + } + } +} diff --git a/examples/digitalidentity/resources/views/advancedidentity.blade.php b/examples/digitalidentity/resources/views/advancedidentity.blade.php new file mode 100644 index 00000000..289e9e1e --- /dev/null +++ b/examples/digitalidentity/resources/views/advancedidentity.blade.php @@ -0,0 +1,89 @@ + + + + + + + {{ $title }} + + + + + +
+
+
+ + Yoti + +
+

Digital Identity(Advanced) Share Example

+ +
+
+
+ +
+ +
+

The Yoti app is free to download and use:

+ +
+ + Download on the App Store + + + + get it on Google Play + +
+
+
+ + + + diff --git a/examples/digitalidentity/routes/web.php b/examples/digitalidentity/routes/web.php index c592b91f..44933279 100644 --- a/examples/digitalidentity/routes/web.php +++ b/examples/digitalidentity/routes/web.php @@ -16,3 +16,5 @@ Route::get('/generate-share', 'IdentityController@show'); Route::get('/receipt-info', 'ReceiptController@show'); Route::get('/generate-session', 'IdentityController@generateSession'); +Route::get('/generate-advanced-identity-share', 'AdvancedIdentityController@show'); +Route::get('/generate-advanced-identity-session', 'AdvancedIdentityController@generateSession'); diff --git a/src/Identity/Policy/Policy.php b/src/Identity/Policy/Policy.php index 62ade060..a71e1fdc 100644 --- a/src/Identity/Policy/Policy.php +++ b/src/Identity/Policy/Policy.php @@ -26,19 +26,26 @@ class Policy implements \JsonSerializable */ private $identityProfileRequirements; + /** + * @var object|null + */ + private $advancedIdentityProfileRequirements; + /** * @param WantedAttribute[] $wantedAttributes * Array of attributes to be requested. * @param int[] $wantedAuthTypes * Auth types represents the authentication type to be used. * @param object $identityProfileRequirements + * @param object $advancedidentityProfileRequirements */ public function __construct( array $wantedAttributes, array $wantedAuthTypes, bool $wantedRememberMe = false, bool $wantedRememberMeOptional = false, - $identityProfileRequirements = null + $identityProfileRequirements = null, + $advancedIdentityProfileRequirements = null ) { Validation::isArrayOfType($wantedAttributes, [WantedAttribute::class], 'wantedAttributes'); $this->wantedAttributes = $wantedAttributes; @@ -49,6 +56,7 @@ public function __construct( $this->wantedRememberMe = $wantedRememberMe; $this->wantedRememberMeOptional = $wantedRememberMeOptional; $this->identityProfileRequirements = $identityProfileRequirements; + $this->advancedIdentityProfileRequirements = $advancedIdentityProfileRequirements; } @@ -60,6 +68,7 @@ public function jsonSerialize(): stdClass 'wanted_remember_me' => $this->wantedRememberMe, 'wanted_remember_me_optional' => $this->wantedRememberMeOptional, 'identity_profile_requirements' => $this->identityProfileRequirements, + 'advanced_identity_profile_requirements' => $this->advancedIdentityProfileRequirements, ]; } @@ -72,4 +81,14 @@ public function getIdentityProfileRequirements() { return $this->identityProfileRequirements; } + + /** + * AdvancedIdentityProfileRequirements requested in the policy + * + * @return object|null + */ + public function getAdvancedIdentityProfileRequirements() + { + return $this->advancedIdentityProfileRequirements; + } } diff --git a/src/Identity/Policy/PolicyBuilder.php b/src/Identity/Policy/PolicyBuilder.php index e8a8b190..a3b8f479 100644 --- a/src/Identity/Policy/PolicyBuilder.php +++ b/src/Identity/Policy/PolicyBuilder.php @@ -27,6 +27,7 @@ class PolicyBuilder private bool $wantedRememberMeOptional = false; private ?object $identityProfileRequirements = null; + private ?object $advancedIdentityProfileRequirements = null; public function withWantedAttribute(WantedAttribute $wantedAttribute): self { @@ -318,6 +319,17 @@ public function withIdentityProfileRequirements($identityProfileRequirements): s return $this; } + /** + * Use an Advanced Identity Profile Requirement object for the share + * + * @param object $advancedIdentityProfileRequirements + * @return $this + */ + public function withAdvancedIdentityProfileRequirements($advancedIdentityProfileRequirements): self + { + $this->advancedIdentityProfileRequirements = $advancedIdentityProfileRequirements; + return $this; + } public function build(): Policy { @@ -326,7 +338,8 @@ public function build(): Policy array_values($this->wantedAuthTypes), $this->wantedRememberMe, $this->wantedRememberMeOptional, - $this->identityProfileRequirements + $this->identityProfileRequirements, + $this->advancedIdentityProfileRequirements ); } } diff --git a/tests/Identity/Policy/PolicyBuilderTest.php b/tests/Identity/Policy/PolicyBuilderTest.php index d223bd79..58b7968e 100644 --- a/tests/Identity/Policy/PolicyBuilderTest.php +++ b/tests/Identity/Policy/PolicyBuilderTest.php @@ -75,6 +75,7 @@ public function testBuildWithAttributes() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -124,6 +125,7 @@ public function testWithWantedAttributeByNameWithConstraints() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertJsonStringEqualsJsonString( @@ -151,6 +153,7 @@ public function testWithDuplicateAttribute() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -205,6 +208,7 @@ public function testWithWantedAttributeByName() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -238,6 +242,7 @@ public function testWithAttributeObjects() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -269,6 +274,7 @@ public function testWithAgeDerivedAttributes() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -314,6 +320,7 @@ public function testWithAgeDerivedAttributesWithConstraints() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertJsonStringEqualsJsonString( @@ -343,6 +350,7 @@ public function testWithDuplicateAgeDerivedAttributes() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -367,6 +375,7 @@ public function testWithAuthTypes() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -390,7 +399,8 @@ public function testWithAuthTypesTrue() 'wanted_auth_types' => [self::SELFIE_AUTH_TYPE, self::PIN_AUTH_TYPE, 99], 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null + 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -415,6 +425,7 @@ public function testWithAuthTypesFalse() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -439,6 +450,7 @@ public function testWithAuthEnabledThenDisabled() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -461,6 +473,7 @@ public function testWithSameAuthTypeAddedOnlyOnce() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -482,6 +495,7 @@ public function testWithOnlyTwoAuthTypes() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -503,6 +517,7 @@ public function testWithNoSelfieAuthAfterRemoval() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -524,6 +539,7 @@ public function testWithNoPinAuthAfterRemoval() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -545,6 +561,7 @@ public function testWithRememberMe() 'wanted_remember_me' => true, 'wanted_remember_me_optional' => false, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -564,7 +581,8 @@ public function testWithoutRememberMe() 'wanted_auth_types' => [], 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null + 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -585,6 +603,7 @@ public function testWithRememberMeOptional() 'wanted_remember_me' => false, 'wanted_remember_me_optional' => true, 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -604,7 +623,8 @@ public function testWithoutRememberMeOptional() 'wanted_auth_types' => [], 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => null + 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => null ]; $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); @@ -631,7 +651,8 @@ public function testWithIdentityProfileRequirements() 'wanted_auth_types' => [], 'wanted_remember_me' => false, 'wanted_remember_me_optional' => false, - 'identity_profile_requirements' => $identityProfileSample + 'identity_profile_requirements' => $identityProfileSample, + 'advanced_identity_profile_requirements' => null ]; $policy = (new PolicyBuilder()) @@ -641,4 +662,51 @@ public function testWithIdentityProfileRequirements() $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); $this->assertEquals($identityProfileSample, $policy->getIdentityProfileRequirements()); } + + /** + * @covers ::withAdvancedIdentityProfileRequirements + * @covers \Yoti\Identity\Policy\Policy::__construct + * @covers \Yoti\Identity\Policy\Policy::getAdvancedIdentityProfileRequirements + * @covers \Yoti\Identity\Policy\Policy::jsonSerialize + */ + public function testWithAdvancedIdentityProfileRequirements() + { + $advancedIdentityProfileSample = + (object)[ + "profiles" => [(object)[ + + "trust_framework" => "YOTI_GLOBAL", + "schemes" => [(object)[ + + "label" => "identity-AL-L1", + "type" => "IDENTITY", + "objective"=> "AL_L1" + ], + [ + "label" => "identity-AL-M1", + "type" => "IDENTITY", + "objective" => "AL_M1" + ] + ] + ] + ] + ] + ; + + $expectedWantedAttributeData = [ + 'wanted' => [], + 'wanted_auth_types' => [], + 'wanted_remember_me' => false, + 'wanted_remember_me_optional' => false, + 'identity_profile_requirements' => null, + 'advanced_identity_profile_requirements' => $advancedIdentityProfileSample + ]; + + $policy = (new PolicyBuilder()) + ->withAdvancedIdentityProfileRequirements($advancedIdentityProfileSample) + ->build(); + + $this->assertEquals(json_encode($expectedWantedAttributeData), json_encode($policy)); + $this->assertEquals($advancedIdentityProfileSample, $policy->getAdvancedIdentityProfileRequirements()); + } }