Skip to content

Commit

Permalink
Add token algorithm encryption configuration support (#113)
Browse files Browse the repository at this point in the history
* Add token algorithm encryption configuration support

* Add test on encryption token algorithm configuration

---------

Co-authored-by: m.sorce <[email protected]>
  • Loading branch information
marwins and m.sorce authored Apr 25, 2024
1 parent 9fee5d5 commit 347a969
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 13 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,13 @@ _Required._

The Keycloak Server realm public key (string).

> How to get realm public key? Click on "Realm Settings" > "Keys" > "Algorithm RS256" Line > "Public Key" Button
> How to get realm public key? Click on "Realm Settings" > "Keys" > "Algorithm RS256 (or defined under token_encryption_algorithm configuration)" Line > "Public Key" Button
✔️ **token_encryption_algorithm**

_Default is `RS256`._

The JWT token encryption algorithm used by Keycloak (string).

✔️ **load_user_from_database**

Expand Down
2 changes: 2 additions & 0 deletions config/keycloak.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
return [
'realm_public_key' => env('KEYCLOAK_REALM_PUBLIC_KEY', null),

'token_encryption_algorithm' => env('KEYCLOAK_TOKEN_ENCRYPTION_ALGORITHM', 'RS256'),

'load_user_from_database' => env('KEYCLOAK_LOAD_USER_FROM_DATABASE', true),

'user_provider_custom_retrieve_method' => null,
Expand Down
2 changes: 1 addition & 1 deletion src/KeycloakGuard.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function __construct(UserProvider $provider, Request $request)
protected function authenticate()
{
try {
$this->decodedToken = Token::decode($this->getTokenForRequest(), $this->config['realm_public_key'], $this->config['leeway']);
$this->decodedToken = Token::decode($this->getTokenForRequest(), $this->config['realm_public_key'], $this->config['leeway'], $this->config['token_encryption_algorithm']);
} catch (\Exception $e) {
throw new TokenException($e->getMessage());
}
Expand Down
4 changes: 2 additions & 2 deletions src/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ class Token
* @param string $publicKey
* @return mixed|null
*/
public static function decode(string $token = null, string $publicKey, int $leeway = 0)
public static function decode(string $token = null, string $publicKey, int $leeway = 0, string $algorithm = 'RS256')
{
JWT::$leeway = $leeway;
$publicKey = self::buildPublicKey($publicKey);

return $token ? JWT::decode($token, new Key($publicKey, 'RS256')) : null;
return $token ? JWT::decode($token, new Key($publicKey, $algorithm)) : null;
}

/**
Expand Down
16 changes: 16 additions & 0 deletions tests/AuthenticateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use KeycloakGuard\KeycloakGuard;
use KeycloakGuard\Tests\Extensions\CustomUserProvider;
use KeycloakGuard\Tests\Models\User;
use KeycloakGuard\Token;

class AuthenticateTest extends TestCase
{
Expand Down Expand Up @@ -425,4 +426,19 @@ public function test_acting_as_keycloak_user_trait_without_user()
$this->assertFalse(Auth::guest());
}

public function test_it_decodes_token_with_the_configured_encryption_algorithm()
{
$this->prepareCredentials('ES256', [
'private_key_type' => OPENSSL_KEYTYPE_EC,
'curve_name' => 'prime256v1'
]);

config([
'keycloak.token_encryption_algorithm' => 'ES256',
'keycloak.realm_public_key' => Token::plainPublicKey($this->publicKey)
]);

$this->withKeycloakToken()->json('GET', '/foo/secret');
$this->assertEquals($this->user->username, Auth::user()->username);
}
}
22 changes: 13 additions & 9 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,18 @@ protected function setUp(): void
]);
}

protected function prepareCredentials()
protected function prepareCredentials(string $encryptionAlgorithm = 'RS256', ?array $openSSLConfig = null)
{
// Prepare private/public keys and a default JWT token, with a simple payload
$this->privateKey = openssl_pkey_new([
'digest_alg' => 'sha256',
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA
]);
if (!$openSSLConfig) {
$openSSLConfig = [
'digest_alg' => 'sha256',
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA
];
}

$this->privateKey = openssl_pkey_new($openSSLConfig);

$this->publicKey = openssl_pkey_get_details($this->privateKey)['key'];

Expand All @@ -54,7 +58,7 @@ protected function prepareCredentials()
'resource_access' => ['myapp-backend' => []]
];

$this->token = JWT::encode($this->payload, $this->privateKey, 'RS256');
$this->token = JWT::encode($this->payload, $this->privateKey, $encryptionAlgorithm);
}

// Default configs to make it running
Expand Down Expand Up @@ -96,11 +100,11 @@ protected function getPackageProviders($app)
}

// Build a different token with custom payload
protected function buildCustomToken(array $payload)
protected function buildCustomToken(array $payload, string $encryptionAlgorithm = 'RS256')
{
$payload = array_replace($this->payload, $payload);

$this->token = JWT::encode($payload, $this->privateKey, 'RS256');
$this->token = JWT::encode($payload, $this->privateKey, $encryptionAlgorithm);
}

// Setup default token, for the default user
Expand Down

0 comments on commit 347a969

Please sign in to comment.