WebAuthnLoginControllerTest.php 6.7 KB

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