Skip to content

Commit 424caae

Browse files
authored
feat: rewrite for more customizable library (#355)
BREAKING CHANGE: This new version is a rewrite with a lot of breaking changes, see details in https://github.com/asbiin/laravel-webauthn/blob/main/docs/migration-v1-to-v2.md
1 parent 51c23a4 commit 424caae

File tree

80 files changed

+3119
-1635
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+3119
-1635
lines changed

.github/workflows/tests.yml

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,31 @@ on:
1616
workflow_dispatch:
1717

1818
env:
19-
php-version: '8.1'
20-
laravel-version: '8.*'
21-
node-version: 14
19+
default-php-version: '8.1'
20+
default-laravel-version: '8.*'
21+
semantic-node-version: 16
2222

2323
jobs:
2424
tests:
2525
runs-on: ubuntu-latest
26-
name: PHP ${{ matrix.php-version }} | Laravel ${{ matrix.laravel_version }}
26+
name: PHP ${{ matrix.php-version }} | Laravel ${{ matrix.laravel-version }} (${{ matrix.psr7 }})
2727

2828
strategy:
2929
fail-fast: false
3030
matrix:
3131
php-version: ['7.4', '8.0', '8.1']
32-
laravel_version: [6.*, 7.*, 8.*]
32+
laravel-version: [7.*, 8.*]
33+
psr7: ['guzzle']
3334
exclude:
3435
- php-version: '8.1'
35-
laravel_version: '6.*'
36+
laravel-version: '7.*'
37+
include:
3638
- php-version: '8.1'
37-
laravel_version: '7.*'
39+
laravel-version: '8.*'
40+
psr7: 'nyholm'
41+
- php-version: '8.1'
42+
laravel-version: '8.*'
43+
psr7: 'discovery'
3844

3945
steps:
4046
- name: Checkout sources
@@ -63,27 +69,45 @@ jobs:
6369
uses: actions/[email protected]
6470
with:
6571
path: ${{ steps.composer-cache.outputs.dir }}
66-
key: ${{ runner.os }}-composer-v4-${{ hashFiles('**/composer.json') }}-${{ matrix.php-version }}-${{ matrix.laravel_version }}
72+
key: ${{ runner.os }}-composer-v4-${{ hashFiles('**/composer.json') }}-${{ matrix.php-version }}-${{ matrix.laravel-version }}
6773
restore-keys: |
68-
${{ runner.os }}-composer-v4-${{ hashFiles('**/composer.json') }}-${{ matrix.php-version }}-${{ matrix.laravel_version }}
74+
${{ runner.os }}-composer-v4-${{ hashFiles('**/composer.json') }}-${{ matrix.php-version }}-${{ matrix.laravel-version }}
6975
${{ runner.os }}-composer-v4-${{ hashFiles('**/composer.json') }}-${{ matrix.php-version }}
7076
${{ runner.os }}-composer-v4-${{ hashFiles('**/composer.json') }}
7177
${{ runner.os }}-composer-v4-
7278
73-
- name: Install dependencies with Laravel ${{ matrix.laravel_version }}
79+
- name: Update dependencies with Laravel ${{ matrix.laravel-version }}
80+
run: |
81+
export COMPOSER_ROOT_VERSION=dev-main
82+
composer require "illuminate/support:${{ matrix.laravel-version }}" --no-update
83+
84+
- name: Use psr7 variant (nyholm)
85+
if: matrix.psr7 == 'nyholm'
86+
run: |
87+
composer remove psr/http-factory-implementation --no-update
88+
composer remove --dev guzzlehttp/psr7 --no-update
89+
composer require --dev symfony/psr-http-message-bridge nyholm/psr7 --no-update
90+
91+
- name: Use psr7 variant (with php-http/discovery)
92+
if: matrix.psr7 == 'discovery'
7493
run: |
75-
export COMPOSER_ROOT_VERSION=dev-master
76-
composer require "laravel/framework:${{ matrix.laravel_version }}" --no-interaction --no-progress --prefer-stable --prefer-dist
94+
composer remove psr/http-factory-implementation --no-update
95+
composer remove --dev guzzlehttp/psr7 --no-update
96+
composer require --dev symfony/psr-http-message-bridge php-http/discovery laminas/laminas-diactoros php-http/curl-client --no-update
97+
98+
- name: Install dependencies
99+
run: |
100+
composer update --no-interaction --no-progress --prefer-dist
77101
78102
- name: Run test suite
79-
run: phpdbg -dmemory_limit=4G -qrr vendor/bin/phpunit -c phpunit.xml --log-junit ./results/results.xml --coverage-clover ./results/coverage.xml
103+
run: phpdbg -dmemory_limit=4G -qrr vendor/bin/phpunit -c phpunit.xml --log-junit ./results/results_${{ matrix.psr7 }}.xml --coverage-clover ./results/coverage_${{ matrix.psr7 }}.xml
80104

81105
- name: Fix results files
82106
run: sed -i -e "s%$GITHUB_WORKSPACE/%%g" *.xml
83107
working-directory: results
84108

85109
- name: Store results
86-
if: matrix.php-version == '${{ env.php-version }}' && matrix.laravel_version == '${{ env.laravel-version }}'
110+
if: matrix.php-version == env.default-php-version && matrix.laravel-version == env.default-laravel-version
87111
uses: actions/upload-artifact@v2
88112
with:
89113
name: results
@@ -112,12 +136,22 @@ jobs:
112136
name: results
113137
path: results
114138

139+
- name: Set coverage list
140+
id: coverage
141+
run: |
142+
SONAR_COVERAGE=$(ls -m --format=comma results/coverage*.xml | sed -e ':a;N;$!ba;s/\n//g; s/ //g;')
143+
echo "::set-output name=list::$SONAR_COVERAGE"
144+
115145
- name: SonarCloud Scan
116146
if: env.SONAR_TOKEN != ''
117147
uses: SonarSource/[email protected]
118148
env:
119149
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
120150
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
151+
with:
152+
args: |
153+
-Dsonar.php.tests.reportPath=./results/results_guzzle.xml
154+
-Dsonar.php.coverage.reportPaths=${{ steps.coverage.outputs.list }}
121155
122156
123157
####################
@@ -135,10 +169,10 @@ jobs:
135169
with:
136170
fetch-depth: 0 # Get all tags
137171

138-
- name: Use Node.js ${{ env.node-version }}
172+
- name: Setup Node.js
139173
uses: actions/setup-node@v2
140174
with:
141-
node-version: ${{ env.node-version }}
175+
node-version: ${{ env.semantic-node-version }}
142176

143177
- name: Semantic Release
144178
uses: cycjimmy/semantic-release-action@v2
@@ -149,7 +183,7 @@ jobs:
149183
with:
150184
semantic_version: 18
151185
extra_plugins: |
152-
@semantic-release/changelog
186+
@semantic-release/changelog@6
153187
semantic-release-github-pullrequest
154188
155189
- name: New release published

README.md

Lines changed: 128 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Webauthn adapter for Laravel
1+
Webauthn adapter for Laravel <!-- omit in toc -->
22
============================
33

44
LaravelWebauthn is an adapter to use Webauthn as 2FA (second-factor authentication) on Laravel.
@@ -10,6 +10,21 @@ LaravelWebauthn is an adapter to use Webauthn as 2FA (second-factor authenticati
1010
[![Coverage Status](https://img.shields.io/sonar/coverage/asbiin_laravel-webauthn?server=https%3A%2F%2Fsonarcloud.io&style=flat-square&label=Coverage%20Status)](https://sonarcloud.io/dashboard?id=asbiin_laravel-webauthn)
1111

1212

13+
- [Installation](#installation)
14+
- [Configuration](#configuration)
15+
- [Add LaravelWebauthn middleware](#add-laravelwebauthn-middleware)
16+
- [Login via remember](#login-via-remember)
17+
- [Usage](#usage)
18+
- [Authenticate](#authenticate)
19+
- [Register a new key](#register-a-new-key)
20+
- [Important](#important)
21+
- [Homestead](#homestead)
22+
- [Routes](#routes)
23+
- [Events](#events)
24+
- [View response](#view-response)
25+
- [Compatibility](#compatibility)
26+
- [License](#license)
27+
1328
# Installation
1429

1530
You may use Composer to install this package into your Laravel project:
@@ -20,47 +35,14 @@ composer require asbiin/laravel-webauthn
2035

2136
You don't need to add this package to your service providers.
2237

23-
## Support
24-
25-
This package supports Laravel 5.8 and newer, and has been tested with php 7.2 and newer versions.
26-
27-
It's based on [web-auth/webauthn-framework](https://github.com/web-auth/webauthn-framework).
28-
29-
30-
## Important
31-
32-
Your browser will refuse to negotiate a relay to your security device without the following:
33-
34-
- domain (localhost and 127.0.0.1 will be rejected by `webauthn.js`)
35-
- an SSL/TLS certificate trusted by your browser (self-signed is okay)
36-
- connected HTTPS on port 443 (ports other than 443 will be rejected)
37-
38-
### Homestead
39-
If you are a Laravel Homestead user, the default is to forward ports. You can switch from NAT/port forwarding to a private network with similar `Homestead.yaml` options:
40-
41-
```yaml
42-
sites:
43-
- map: homestead.test
44-
networks:
45-
- type: "private_network"
46-
ip: "192.168.254.2"
47-
```
48-
49-
Re-provisioning vagrant will inform your virtual machine of the new network and install self-signed SSL/TLS certificates automatically: `vagrant reload --provision`
50-
51-
If you haven't done so already, describe your site domain and network in your hosts file:
52-
```
53-
192.168.254.2 homestead.test
54-
```
55-
5638

5739
## Configuration
5840

5941
You can publish the LaravelWebauthn configuration in a file named `config/webauthn.php`, and resources.
6042
Just run this artisan command:
6143

6244
```sh
63-
php artisan laravelwebauthn:publish
45+
php artisan vendor:publish --provider="LaravelWebauthn\WebauthnServiceProvider"
6446
```
6547

6648
If desired, you may disable LaravelWebauthn entirely using the `enabled` configuration option:
@@ -87,6 +69,23 @@ Route::middleware(['auth', 'webauthn'])->group(function () {
8769
This way users would have to validate their key on login.
8870

8971

72+
### Login via remember
73+
74+
When session expires, but the user set the `remember` token, you can revalidate webauthn session by adding this in your `App\Providers\EventServiceProvider` file:
75+
76+
```php
77+
use Illuminate\Auth\Events\Login;
78+
use LaravelWebauthn\Listeners\LoginViaRemember;
79+
80+
class EventServiceProvider extends ServiceProvider
81+
{
82+
protected $listen = [
83+
Login::class => [
84+
LoginViaRemember::class,
85+
],
86+
];
87+
...
88+
```
9089

9190
# Usage
9291

@@ -184,35 +183,120 @@ If `postSuccessRedirectRoute` is empty, the return will be JSON form:
184183
}
185184
```
186185

186+
## Important
187+
188+
Your browser will refuse to negotiate a relay to your security device without the following:
189+
190+
- domain (localhost and 127.0.0.1 will be rejected by `webauthn.js`)
191+
- an SSL/TLS certificate trusted by your browser (self-signed is okay)
192+
- connected HTTPS on port 443 (ports other than 443 will be rejected)
193+
194+
### Homestead
195+
If you are a Laravel Homestead user, the default is to forward ports. You can switch from NAT/port forwarding to a private network with similar `Homestead.yaml` options:
196+
197+
```yaml
198+
sites:
199+
- map: homestead.test
200+
networks:
201+
- type: "private_network"
202+
ip: "192.168.254.2"
203+
```
204+
205+
Re-provisioning vagrant will inform your virtual machine of the new network and install self-signed SSL/TLS certificates automatically: `vagrant reload --provision`
206+
207+
If you haven't done so already, describe your site domain and network in your hosts file:
208+
```
209+
192.168.254.2 homestead.test
210+
```
187211

188-
## Urls
189212

190-
These url are used
213+
## Routes
214+
215+
These reoutes are defined:
191216

192217
* GET `/webauthn/auth` / `route('webauthn.login')`
193218
The login page.
194219

195220
* POST `/webauthn/auth` / `route('webauthn.auth')`
196221
Post datas after a WebAuthn login validate.
197222

198-
* GET `/webauthn/register` / `route('webauthn.register')`
223+
* GET `/webauthn/keys/create` / `route('webauthn.create')`
199224
Get datas to register a new key
200225

201-
* POST `/webauthn/register` / `route('webauthn.create')`
226+
* POST `/webauthn/keys` / `route('webauthn.store')`
202227
Post datas after a WebAuthn register check
203228

204-
* DELETE `/webauthn/{id}` / `route('webauthn.destroy')`
205-
Get register datas
229+
* DELETE `/webauthn/keys/{id}` / `route('webauthn.destroy')`
230+
Delete an existing key
231+
232+
* UPDATE `/webauthn/keys/{id}` / `route('webauthn.update')`
233+
Update key properties
206234

207235

236+
You can modify the first part of the url by setting `prefix` value in the config file.
237+
208238
## Events
209239

210240
Events are dispatched by LaravelWebauthn:
211241

212-
* `\LaravelWebauthn\Events\WebauthnLoginData` on creating authentication datas
213-
* `\LaravelWebauthn\Events\WebauthnLogin` on login with WebAuthn check
214-
* `\LaravelWebauthn\Events\WebauthnRegisterData` on creating register datas
242+
* `\LaravelWebauthn\Events\WebauthnLoginData` on preparing authentication data
243+
* `\LaravelWebauthn\Events\WebauthnLogin` on login with Webauthn check
244+
* `\LaravelWebauthn\Events\WebauthnLoginFailed` on a failed login check
245+
* `\LaravelWebauthn\Events\WebauthnRegisterData` on preparing register data
215246
* `\LaravelWebauthn\Events\WebauthnRegister` on registering a new key
247+
* `\LaravelWebauthn\Events\WebauthnRegisterFailed` on failing registering a new key
248+
249+
250+
## View response
251+
252+
You can easily change the view responses with the Webauthn service:
253+
254+
```php
255+
use LaravelWebauthn\Services\Webauthn;
256+
257+
class AppServiceProvider extends ServiceProvider
258+
{
259+
public function register()
260+
{
261+
Webauthn::loginViewResponseUsing(LoginViewResponse::class);
262+
}
263+
}
264+
```
265+
266+
```php
267+
use LaravelWebauthn\Http\Responses\LoginViewResponse as LoginViewResponseBase;
268+
269+
class LoginViewResponse extends LoginViewResponseBase
270+
{
271+
public function toResponse($request)
272+
{
273+
$publicKey = $this->publicKeyRequest($request);
274+
275+
return Inertia::render('Webauthn/WebauthnLogin', [
276+
'publicKey' => $publicKey
277+
]);
278+
}
279+
}
280+
```
281+
282+
List of methods and their expected response contracts:
283+
284+
| Webauthn | LaravelWebauthn\Contracts |
285+
|------------------------------|---------------------------------|
286+
| loginViewResponseUsing | LoginViewResponseContract |
287+
| loginSuccessResponseUsing | LoginSuccessResponseContract |
288+
| registerViewResponseUsing | RegisterViewResponseContract |
289+
| registerSuccessResponseUsing | RegisterSuccessResponseContract |
290+
| destroyViewResponseUsing | DestroyResponseContract |
291+
| updateViewResponseUsing | UpdateResponseContract |
292+
293+
294+
# Compatibility
295+
296+
| Laravel | [asbiin/laravel-webauthn](https://github.com/asbiin/laravel-webauthn) |
297+
|----------|----------|
298+
| 5.8-8.x | <= 1.2.0 |
299+
| 7.x-8.x | 2.0.0 |
216300

217301

218302
# License

0 commit comments

Comments
 (0)