From 4f79ddca2b084fb76b5ae409281b4adfce996794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Jaussoin?= Date: Tue, 30 Apr 2024 10:10:19 +0000 Subject: [PATCH] Fix FLEXIAPI-167 Add the handling of a custom identifier for the JWT tokens on top of the email one --- CHANGELOG.md | 1 + flexiapi/.env.example | 1 + flexiapi/app/Helpers/Utils.php | 16 +++-- .../Middleware/AuthenticateDigestOrKey.php | 4 +- .../app/Http/Middleware/AuthenticateJWT.php | 23 +++++-- flexiapi/composer.lock | 14 ++-- flexiapi/composer.phar | Bin 2977479 -> 2985953 bytes flexiapi/config/services.php | 3 +- .../Feature/AccountJWTAuthenticationTest.php | 63 +++++++++++++----- 9 files changed, 86 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 646f9fd..2b4ded9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ v1.5 ---- - Fix FLEXIAPI-168 Add POST /accounts/me/email to confirm the email change +- Fix FLEXIAPI-167 Add the handling of a custom identifier for the JWT tokens on top of the email one - Fix FLEXIAPI-166 Reimplement the deprecated email validation URL - Fix FLEXIAPI-165 Remove for now text/vcard header constraint - Fix FLEXIAPI-164 Add vcards-storage endpoints diff --git a/flexiapi/.env.example b/flexiapi/.env.example index 3e4a203..ab60b93 100644 --- a/flexiapi/.env.example +++ b/flexiapi/.env.example @@ -114,3 +114,4 @@ HCAPTCHA_SITEKEY=site-key # JWT JWT_RSA_PUBLIC_KEY_PEM= +JWT_SIP_IDENTIFIER= diff --git a/flexiapi/app/Helpers/Utils.php b/flexiapi/app/Helpers/Utils.php index 6c3ab34..0c4293d 100644 --- a/flexiapi/app/Helpers/Utils.php +++ b/flexiapi/app/Helpers/Utils.php @@ -22,7 +22,6 @@ use Illuminate\Support\Str; use App\Account; use App\DigestNonce; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Schema; use League\CommonMark\CommonMarkConverter; use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension; use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension; @@ -51,23 +50,23 @@ function generateValidNonce(Account $account): string return $nonce->nonce; } -function bchash(string $username, string $domain, string $password, string $algorithm = 'MD5') +function bchash(string $username, string $domain, string $password, string $algorithm = 'MD5'): string { return hash(passwordAlgorithms()[$algorithm], $username . ':' . $domain . ':' . $password); } -function generatePin() +function generatePin(): int { return mt_rand(1000, 9999); } -function percent($value, $max) +function percent($value, $max): float { if ($max == 0) $max = 1; return round(($value * 100) / $max, 2); } -function markdownDocumentationView($view): string +function markdownDocumentationView(string $view): string { $converter = new CommonMarkConverter([ 'heading_permalink' => [ @@ -92,7 +91,12 @@ function markdownDocumentationView($view): string ); } -function isRegularExpression($string): bool +function parseSIP(string $sipAdress): array +{ + return explode('@', \substr($sipAdress, 4)); +} + +function isRegularExpression(string $string): bool { set_error_handler(function () { }, E_WARNING); diff --git a/flexiapi/app/Http/Middleware/AuthenticateDigestOrKey.php b/flexiapi/app/Http/Middleware/AuthenticateDigestOrKey.php index 0930b2c..83913ee 100644 --- a/flexiapi/app/Http/Middleware/AuthenticateDigestOrKey.php +++ b/flexiapi/app/Http/Middleware/AuthenticateDigestOrKey.php @@ -70,7 +70,7 @@ class AuthenticateDigestOrKey ])->validate(); $from = $this->extractFromHeader($request->header('From')); - list($username, $domain) = explode('@', $from); + list($username, $domain) = parseSIP($from); $account = Account::withoutGlobalScopes() ->where('username', $username) @@ -234,7 +234,7 @@ class AuthenticateDigestOrKey private function extractFromHeader(string $string): string { - list($from) = explode(';', \substr($string, 4)); + list($from) = explode(';', $string); return \rawurldecode($from); } diff --git a/flexiapi/app/Http/Middleware/AuthenticateJWT.php b/flexiapi/app/Http/Middleware/AuthenticateJWT.php index 6009c6c..d9e4398 100644 --- a/flexiapi/app/Http/Middleware/AuthenticateJWT.php +++ b/flexiapi/app/Http/Middleware/AuthenticateJWT.php @@ -33,15 +33,15 @@ class AuthenticateJWT switch ($token->headers()->get('alg')) { case 'RS256': - $signer = new Sha256; + $signer = new Sha256(); break; case 'RS384': - $signer = new Sha384; + $signer = new Sha384(); break; case 'RS512': - $signer = new Sha512; + $signer = new Sha512(); break; } @@ -57,9 +57,20 @@ class AuthenticateJWT abort(403, 'Expired JWT token'); } - $account = Account::withoutGlobalScopes() - ->where('email', $token->claims()->get('email')) - ->first(); + $account = null; + + if ($token->claims()->has(config('services.jwt.sip_identifier'))) { + list($username, $domain) = parseSIP($token->claims()->get(config('services.jwt.sip_identifier'))); + + $account = Account::withoutGlobalScopes() + ->where('username', $username) + ->where('domain', $domain) + ->first(); + } elseif ($token->claims()->has('email')) { + $account = Account::withoutGlobalScopes() + ->where('email', $token->claims()->get('email')) + ->first(); + } if (!$account) { abort(403, 'The JWT token is not related to someone in the system'); diff --git a/flexiapi/composer.lock b/flexiapi/composer.lock index e4c5c5e..6b0641c 100644 --- a/flexiapi/composer.lock +++ b/flexiapi/composer.lock @@ -4738,20 +4738,20 @@ }, { "name": "ramsey/uuid", - "version": "4.7.5", + "version": "4.7.6", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e" + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", - "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", "ext-json": "*", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" @@ -4814,7 +4814,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.7.5" + "source": "https://github.com/ramsey/uuid/tree/4.7.6" }, "funding": [ { @@ -4826,7 +4826,7 @@ "type": "tidelift" } ], - "time": "2023-11-08T05:53:05+00:00" + "time": "2024-04-27T21:32:50+00:00" }, { "name": "react/cache", diff --git a/flexiapi/composer.phar b/flexiapi/composer.phar index e6ba7bbadc93b5fc256ac8a80023ae73deacb942..9b28eb4b6535bff6bd912935d34e783c65d3dbaf 100755 GIT binary patch delta 29007 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 [ 'rsa_public_key_pem' => env('JWT_RSA_PUBLIC_KEY_PEM'), - ], + 'sip_identifier' => env('JWT_SIP_IDENTIFIER', 'sip_identity'), + ], ]; diff --git a/flexiapi/tests/Feature/AccountJWTAuthenticationTest.php b/flexiapi/tests/Feature/AccountJWTAuthenticationTest.php index e4162d0..7bd62c2 100644 --- a/flexiapi/tests/Feature/AccountJWTAuthenticationTest.php +++ b/flexiapi/tests/Feature/AccountJWTAuthenticationTest.php @@ -24,6 +24,7 @@ use DateTimeImmutable; use Lcobucci\Clock\FrozenClock; use Lcobucci\JWT\Builder; use Lcobucci\JWT\JwtFacade; +use Lcobucci\JWT\UnencryptedToken; use Lcobucci\JWT\Signer\Key\InMemory; use Lcobucci\JWT\Signer\Rsa\Sha256; use Lcobucci\JWT\Signer\Rsa\Sha512; @@ -68,14 +69,38 @@ class AccountJWTAuthenticationTest extends TestCase ): Builder => $builder->withClaim('email', $password->account->email) ); - $this->withHeaders([ - 'Authorization' => 'Bearer ' . $token->toString(), - 'x-linphone-provisioning' => true, - ]) - ->get($this->accountRoute) - ->assertStatus(200) - ->assertHeader('Content-Type', 'application/xml') - ->assertSee('ha1'); + $this->checkToken($token); + + // SIP identifier + + // This line shoudn't be required, but the pipeline doesn't get the default value somehow + config()->set('services.jwt.sip_identifier', 'sip_identity'); + + $token = (new JwtFacade(null, $clock))->issue( + new Sha256(), + InMemory::plainText($this->serverPrivateKeyPem), + static fn ( + Builder $builder, + DateTimeImmutable $issuedAt + ): Builder => $builder->withClaim('sip_identity', 'sip:' . $password->account->username . '@' . $password->account->domain) + ); + + $this->checkToken($token); + + // Custom SIP identifier + $otherIdentifier = 'sip_other_identifier'; + config()->set('services.jwt.sip_identifier', $otherIdentifier); + + $token = (new JwtFacade(null, $clock))->issue( + new Sha256(), + InMemory::plainText($this->serverPrivateKeyPem), + static fn ( + Builder $builder, + DateTimeImmutable $issuedAt + ): Builder => $builder->withClaim($otherIdentifier, 'sip:' . $password->account->username . '@' . $password->account->domain) + ); + + $this->checkToken($token); // Sha512 $token = (new JwtFacade(null, $clock))->issue( @@ -87,17 +112,9 @@ class AccountJWTAuthenticationTest extends TestCase ): Builder => $builder->withClaim('email', $password->account->email) ); - $this->withHeaders([ - 'Authorization' => 'Bearer ' . $token->toString(), - 'x-linphone-provisioning' => true, - ]) - ->get($this->accountRoute) - ->assertStatus(200) - ->assertHeader('Content-Type', 'application/xml') - ->assertSee('ha1'); + $this->checkToken($token); // Expired token - $oldClock = new FrozenClock(new DateTimeImmutable('2022-06-24 22:51:10')); $token = (new JwtFacade(null, $oldClock))->issue( @@ -155,4 +172,16 @@ class AccountJWTAuthenticationTest extends TestCase ->get($this->accountRoute) ->assertStatus(403); } + + private function checkToken(UnencryptedToken $token): void + { + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $token->toString(), + 'x-linphone-provisioning' => true, + ]) + ->get($this->accountRoute) + ->assertStatus(200) + ->assertHeader('Content-Type', 'application/xml') + ->assertSee('ha1'); + } }