Skip to content

Commit

Permalink
Signatures can now be implemented on blueprints through signature a…
Browse files Browse the repository at this point in the history
…nd `generateAndSign` functionality which should make this a more central place for token generation out of the box.
  • Loading branch information
LarsGrevelink committed Jun 10, 2020
1 parent 8943d6d commit 4f419b8
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/Exceptions/Blueprint/JwtBlueprintException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace LGrevelink\SimpleJWT\Exceptions\Blueprint;

use LGrevelink\SimpleJWT\Exceptions\SimpleJwtException;

abstract class JwtBlueprintException extends SimpleJwtException
{
}
7 changes: 7 additions & 0 deletions src/Exceptions/Blueprint/SignatureNotImplementedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace LGrevelink\SimpleJWT\Exceptions\Blueprint;

final class SignatureNotImplementedException extends JwtBlueprintException
{
}
33 changes: 33 additions & 0 deletions src/TokenBlueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace LGrevelink\SimpleJWT;

use LGrevelink\SimpleJWT\Exceptions\Blueprint\SignatureNotImplementedException;

/**
* Blueprint class for JWT tokens. Used to generate a basic token and pre-fill
* registered claims.
Expand Down Expand Up @@ -84,6 +86,37 @@ public static function generate(array $claims = [])
return $token;
}

/**
* Generate a token and sign it based on the blueprint.
*
* @param array $claims
* @param array ...$signatureArguments
*
* @return Token
*/
public static function generateAndSign(array $claims = [])
{
$signatureArguments = array_slice(func_get_args(), 1);

return static::generate($claims)->signature(
forward_static_call_array([static::class, 'signature'], $signatureArguments)
);
}

/**
* Generate a signature for a token.
*
* @throws SignatureNotImplementedException
*
* @return TokenSignature
*/
public static function signature()
{
throw new SignatureNotImplementedException(
sprintf('Missing signature implementation on %s', static::class)
);
}

/**
* Validate a token based on the blueprint.
*
Expand Down
18 changes: 18 additions & 0 deletions tests/Mocks/Blueprints/SignatureBlueprintMock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Tests\Mocks\Blueprints;

use LGrevelink\SimpleJWT\Signing\Hmac\HmacSha256;
use LGrevelink\SimpleJWT\TokenBlueprint;
use LGrevelink\SimpleJWT\TokenSignature;

class SignatureBlueprintMock extends TokenBlueprint
{
/**
* @inheritdoc
*/
public static function signature(string $customKey = null)
{
return new TokenSignature(new HmacSha256(), $customKey ?? 'default-key');
}
}
41 changes: 41 additions & 0 deletions tests/TokenBlueprintTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace Tests;

use LGrevelink\SimpleJWT\Exceptions\Blueprint\SignatureNotImplementedException;
use LGrevelink\SimpleJWT\Signing\Hmac\HmacSha256;
use LGrevelink\SimpleJWT\TokenBlueprint;
use LGrevelink\SimpleJWT\TokenSignature;
use Tests\Mocks\Blueprints\AudienceBlueprintMock;
use Tests\Mocks\Blueprints\EmptyBlueprintMock;
use Tests\Mocks\Blueprints\ExpirationTimeBlueprintMock;
Expand All @@ -11,6 +14,7 @@
use Tests\Mocks\Blueprints\IssuerBlueprintMock;
use Tests\Mocks\Blueprints\JwtIdBlueprintMock;
use Tests\Mocks\Blueprints\NotBeforeBlueprintMock;
use Tests\Mocks\Blueprints\SignatureBlueprintMock;
use Tests\Mocks\Blueprints\SubjectBlueprintMock;

final class TokenBlueprintTest extends TestCase
Expand Down Expand Up @@ -78,6 +82,43 @@ public function testGenerate()
$this->assertSame('claim', $token->getPayload('additional'));
}

public function testGenerateAndSign()
{
$token = SignatureBlueprintMock::generateAndSign([
'additional' => 'claim',
]);

$this->assertSame($token->toString(), 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhZGRpdGlvbmFsIjoiY2xhaW0ifQ.fzZBLQfFRdMzDzJbgNc-0iVOi2UuyTLhFVZqgqUbUU0');

$token = SignatureBlueprintMock::generateAndSign([
'additional' => 'claim',
], 'custom-key');

$this->assertSame($token->toString(), 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhZGRpdGlvbmFsIjoiY2xhaW0ifQ.C7bk4bT1GtU3q8ByI6dqhelAqEEzf4FqOpQjksUgsOo');
}

public function testSignature()
{
$defaultValueSignature = SignatureBlueprintMock::signature();

$this->assertInstanceOf(TokenSignature::class, $defaultValueSignature);
$this->assertSame('default-key', $defaultValueSignature->signatureKey());

$customValueSignature = SignatureBlueprintMock::signature('custom-key');

$this->assertInstanceOf(TokenSignature::class, $customValueSignature);
$this->assertSame('custom-key', $customValueSignature->signatureKey());
}

public function testSignatureWithoutOverride()
{
$this->expectException(SignatureNotImplementedException::class);
$this->expectExceptionMessage(sprintf('Missing signature implementation on %s', EmptyBlueprintMock::class));

EmptyBlueprintMock::signature(new TokenSignature(new HmacSha256(), 'key'));
EmptyBlueprintMock::generateAndSign();
}

public function testValidateAudience()
{
$token = AudienceBlueprintMock::generate();
Expand Down

0 comments on commit 4f419b8

Please sign in to comment.