-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathSSOTokenGenerator.php
More file actions
131 lines (113 loc) · 4.58 KB
/
SSOTokenGenerator.php
File metadata and controls
131 lines (113 loc) · 4.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php
declare(strict_types=1);
/**
* SSO token generator, based on this doc:
* https://developers.staffbase.com/api/plugin-sso/
*
* PHP version 7.4.0
*
* @category Authentication
* @copyright 2017-2022 Staffbase, GmbH.
* @author Daniel Grosse
* @license http://www.apache.org/licenses/LICENSE-2.0
* @link https://github.com/staffbase/plugins-sdk-php
*/
namespace Staffbase\plugins\sdk;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Signer\Rsa\Sha256;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Token\RegisteredClaims;
class SSOTokenGenerator
{
/**
* Create a signed token from an array.
*
* Can be used in development in conjunction with getTokenData.
*
* @param string $privateKey private key
* @param array $tokenData associative array of claims
* @param Signer|null $signer the Signer instance to sign the token, defaults to SHA256
*
* @return string Encoded token.
*/
/**
* @param array<string,mixed> $tokenData
*/
public static function createSignedTokenFromData(string $privateKey, array $tokenData, Signer $signer = null): string
{
if (!trim($privateKey)) {
throw new \InvalidArgumentException('Parameter privateKey for token generation is empty.');
}
// After validation, we know $privateKey is non-empty
/** @var non-empty-string $privateKey */
$config = Configuration::forSymmetricSigner($signer ?: new Sha256(), InMemory::plainText($privateKey));
return self::buildToken($config, $tokenData)->toString();
}
/**
* @param Configuration $config
* @param array $tokenData
* @return Token
*/
/**
* @param array<string,mixed> $tokenData
*/
private static function buildToken(Configuration $config, array $tokenData): Token
{
$builder = $config->builder();
// Validate and coerce required registered claims to the expected types
$audience = $tokenData[SSOData\SharedClaimsInterface::CLAIM_AUDIENCE] ?? '';
if (!is_string($audience) || $audience === '') {
throw new \InvalidArgumentException('aud claim must be a non-empty string for token generation');
}
$issuedAt = $tokenData[SSOData\SharedClaimsInterface::CLAIM_ISSUED_AT] ?? null;
if (!($issuedAt instanceof \DateTimeImmutable)) {
throw new \InvalidArgumentException('iat claim must be a DateTimeImmutable for token generation');
}
$notBefore = $tokenData[SSOData\SharedClaimsInterface::CLAIM_NOT_BEFORE] ?? null;
if (!($notBefore instanceof \DateTimeImmutable)) {
throw new \InvalidArgumentException('nbf claim must be a DateTimeImmutable for token generation');
}
$expiresAt = $tokenData[SSOData\SharedClaimsInterface::CLAIM_EXPIRE_AT] ?? null;
if (!($expiresAt instanceof \DateTimeImmutable)) {
throw new \InvalidArgumentException('exp claim must be a DateTimeImmutable for token generation');
}
$token = $builder
->permittedFor($audience)
->issuedAt($issuedAt)
->canOnlyBeUsedAfter($notBefore)
->expiresAt($expiresAt);
if (isset($tokenData[SSOData\SharedClaimsInterface::CLAIM_ISSUER])) {
$issuer = $tokenData[SSOData\SharedClaimsInterface::CLAIM_ISSUER];
if (is_string($issuer) && $issuer !== '') {
$token = $token->issuedBy($issuer);
}
}
if (isset($tokenData[SSOData\SSODataClaimsInterface::CLAIM_USER_ID])) {
$subject = $tokenData[SSOData\SSODataClaimsInterface::CLAIM_USER_ID];
if (is_string($subject) && $subject !== '') {
$token = $token->relatedTo($subject);
}
}
if (isset($tokenData[SSOData\SharedClaimsInterface::CLAIM_JWT_ID])) {
$jwtId = $tokenData[SSOData\SharedClaimsInterface::CLAIM_JWT_ID];
if (is_string($jwtId) && $jwtId !== '') {
$token = $token->identifiedBy($jwtId);
}
}
// Remove all set keys as they throw an exception when used with withClaim
$claims = array_filter(
$tokenData,
static fn($key) => !in_array($key, RegisteredClaims::ALL, true),
ARRAY_FILTER_USE_KEY,
);
foreach ($claims as $claim => $value) {
if (empty($claim)) {
continue;
}
$token = $token->withClaim($claim, $value);
}
return $token->getToken($config->signer(), $config->signingKey());
}
}