WebauthnLoginControllerTest.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <?php
  2. namespace Tests\Feature\Auth;
  3. use App\Models\User;
  4. use Tests\FeatureTestCase;
  5. use Illuminate\Support\Facades\DB;
  6. use Illuminate\Support\Str;
  7. use Webauthn\TrustPath\EmptyTrustPath;
  8. use DarkGhostHunter\Larapass\Eloquent\WebAuthnCredential;
  9. use DarkGhostHunter\Larapass\WebAuthn\WebAuthnAssertValidator;
  10. class WebAuthnLoginControllerTest extends FeatureTestCase
  11. {
  12. /**
  13. * @var \App\Models\User
  14. */
  15. protected $user;
  16. /**
  17. * @test
  18. */
  19. public function setUp(): void
  20. {
  21. parent::setUp();
  22. }
  23. /**
  24. * @test
  25. */
  26. public function test_user_login_returns_success()
  27. {
  28. $this->user = User::factory()->create([
  29. 'name' => 'john',
  30. 'email' => 'john.doe@mail.com',
  31. 'password' => '$2y$10$FLIykVJWDsYSVMJyaFZZfe4tF5uBTnGsosJBL.ZfAAHsYgc27FSdi',
  32. ]);
  33. $uuid = Str::uuid();
  34. DB::table('web_authn_credentials')->insert([
  35. 'id' => 'dGVzdF9jcmVkZW50aWFsX2lk',
  36. 'user_id' => 1,
  37. 'type' => 'public_key',
  38. 'transports' => json_encode([]),
  39. 'attestation_type' => 'none',
  40. 'trust_path' => json_encode(['type' => EmptyTrustPath::class]),
  41. 'aaguid' => $uuid->toString(),
  42. 'public_key' => 'public_key',
  43. 'counter' => 0,
  44. 'user_handle' => 'test_user_handle',
  45. 'created_at' => now()->toDateTimeString(),
  46. 'updated_at' => now()->toDateTimeString(),
  47. ]);
  48. $data = [
  49. 'id' => 'dGVzdF9jcmVkZW50aWFsX2lk',
  50. 'rawId' => 'ZEdWemRGOWpjbVZrWlc1MGFXRnNYMmxr',
  51. 'type' => 'test_type',
  52. 'response' => [
  53. 'authenticatorData' => 'test',
  54. 'clientDataJSON' => 'test',
  55. 'signature' => 'test',
  56. 'userHandle' => 'test',
  57. ],
  58. ];
  59. $this->mock(WebAuthnAssertValidator::class)
  60. ->shouldReceive('validate')
  61. ->with($data)
  62. ->andReturnUsing(function ($data) {
  63. $credentials = WebAuthnCredential::find($data['id']);
  64. $credentials->setAttribute('counter', 1)->save();
  65. return $credentials->toCredentialSource();
  66. });
  67. $this->json('POST', '/webauthn/login', $data)
  68. ->assertNoContent();
  69. $this->assertAuthenticatedAs($this->user);
  70. }
  71. /**
  72. * @test
  73. */
  74. public function test_user_login_without_userhandle_returns_success()
  75. {
  76. $this->user = User::factory()->create([
  77. 'name' => 'john',
  78. 'email' => 'john.doe@mail.com',
  79. 'password' => '$2y$10$FLIykVJWDsYSVMJyaFZZfe4tF5uBTnGsosJBL.ZfAAHsYgc27FSdi',
  80. ]);
  81. $uuid = Str::uuid();
  82. DB::table('web_authn_credentials')->insert([
  83. 'id' => 'dGVzdF9jcmVkZW50aWFsX2lk',
  84. 'user_id' => 1,
  85. 'type' => 'public_key',
  86. 'transports' => json_encode([]),
  87. 'attestation_type' => 'none',
  88. 'trust_path' => json_encode(['type' => EmptyTrustPath::class]),
  89. 'aaguid' => $uuid->toString(),
  90. 'public_key' => 'public_key',
  91. 'counter' => 0,
  92. 'user_handle' => 'test_user_handle',
  93. 'created_at' => now()->toDateTimeString(),
  94. 'updated_at' => now()->toDateTimeString(),
  95. ]);
  96. $data = [
  97. 'id' => 'dGVzdF9jcmVkZW50aWFsX2lk',
  98. 'rawId' => 'ZEdWemRGOWpjbVZrWlc1MGFXRnNYMmxr',
  99. 'type' => 'test_type',
  100. 'response' => [
  101. 'authenticatorData' => 'test',
  102. 'clientDataJSON' => 'test',
  103. 'signature' => 'test',
  104. 'userHandle' => '',
  105. ],
  106. ];
  107. $this->mock(WebAuthnAssertValidator::class)
  108. ->shouldReceive('validate')
  109. ->with([
  110. 'id' => 'dGVzdF9jcmVkZW50aWFsX2lk',
  111. 'rawId' => 'ZEdWemRGOWpjbVZrWlc1MGFXRnNYMmxr',
  112. 'type' => 'test_type',
  113. 'response' => [
  114. 'authenticatorData' => 'test',
  115. 'clientDataJSON' => 'test',
  116. 'signature' => 'test',
  117. 'userHandle' => 'dGVzdF91c2VyX2hhbmRsZQ==',
  118. ],
  119. ])
  120. ->andReturnUsing(function ($data) {
  121. $credentials = WebAuthnCredential::find($data['id']);
  122. $credentials->setAttribute('counter', 1)->save();
  123. return $credentials->toCredentialSource();
  124. });
  125. $this->json('POST', '/webauthn/login', $data)
  126. ->assertNoContent();
  127. $this->assertAuthenticatedAs($this->user);
  128. }
  129. /**
  130. * @test
  131. */
  132. public function test_user_login_with_missing_data_returns_validation_error()
  133. {
  134. $this->user = User::factory()->create([
  135. 'name' => 'john',
  136. 'email' => 'john.doe@mail.com',
  137. 'password' => '$2y$10$FLIykVJWDsYSVMJyaFZZfe4tF5uBTnGsosJBL.ZfAAHsYgc27FSdi',
  138. ]);
  139. $data = [
  140. 'id' => '',
  141. 'rawId' => '',
  142. 'type' => '',
  143. 'response' => [
  144. 'authenticatorData' => '',
  145. 'clientDataJSON' => '',
  146. 'signature' => '',
  147. 'userHandle' => null,
  148. ],
  149. ];
  150. $response = $this->json('POST', '/webauthn/login', $data)
  151. ->assertStatus(422)
  152. ->assertJsonValidationErrors([
  153. 'id',
  154. 'rawId',
  155. 'type',
  156. 'response.authenticatorData',
  157. 'response.clientDataJSON',
  158. 'response.signature',
  159. ]);
  160. }
  161. /**
  162. * @test
  163. */
  164. public function test_get_options_returns_success()
  165. {
  166. $this->user = User::factory()->create([
  167. 'name' => 'john',
  168. 'email' => 'john.doe@mail.com',
  169. 'password' => '$2y$10$FLIykVJWDsYSVMJyaFZZfe4tF5uBTnGsosJBL.ZfAAHsYgc27FSdi',
  170. ]);
  171. $response = $this->json('POST', '/webauthn/login/options', [])
  172. ->assertOk()
  173. ->assertJsonStructure([
  174. 'challenge',
  175. 'rpId',
  176. 'userVerification',
  177. 'timeout',
  178. ]);
  179. }
  180. /**
  181. * @test
  182. */
  183. public function test_get_options_with_no_registred_user_returns_error()
  184. {
  185. $this->json('POST', '/webauthn/login/options', [])
  186. ->assertStatus(400)
  187. ->assertJsonStructure([
  188. 'message',
  189. ]);
  190. }
  191. }