2
2
3
3
namespace Icinga \Module \Grafana \Helpers ;
4
4
5
- use Firebase \JWT \JWT ;
6
- use Firebase \JWT \Key ;
5
+ use OpenSSLAsymmetricKey ;
6
+ use InvalidArgumentException ;
7
+ use RuntimeException ;
7
8
8
- class JwtToken {
9
+ class JwtToken
10
+ {
9
11
const RSA_KEY_BITS = 2048 ;
10
12
const JWT_PRIVATEKEY_FILE = '/etc/icingaweb2/modules/grafana/jwt.key.priv ' ;
11
13
const JWT_PUBLICKEY_FILE = '/etc/icingaweb2/modules/grafana/jwt.key.pub ' ;
12
14
13
-
14
15
/**
15
16
* Create JWT Token
16
17
*/
17
- public static function create (string $ sub , int $ exp = 0 , string $ iss = null , array $ claims = null ) : string {
18
+ public static function create (string $ sub , int $ exp = 0 , string $ iss = null , array $ claims = null ): string
19
+ {
18
20
$ privateKeyFile = JwtToken::JWT_PRIVATEKEY_FILE ;
19
21
20
22
$ privateKey = openssl_pkey_get_private (
@@ -27,38 +29,80 @@ public static function create(string $sub, int $exp = 0, string $iss = null, arr
27
29
'nbf ' => time (),
28
30
];
29
31
30
- if (isset ($ claims )) {
32
+ if (isset ($ claims )) {
31
33
$ payload = array_merge ($ payload , $ claims );
32
34
}
33
35
34
36
if (!empty ($ iss )) {
35
37
$ payload ['iss ' ] = $ iss ;
36
38
}
37
- if ($ exp > 0 ) {
38
- $ payload ['exp ' ] = $ exp ;
39
- }
40
39
41
- return JWT ::encode ($ payload , $ privateKey , 'RS256 ' );
40
+ return JwtToken ::encode ($ payload , $ privateKey , 'RS256 ' , $ exp );
42
41
}
43
42
44
43
/**
45
44
* Generate Private and Public RSA Keys
46
45
*/
47
46
public static function generateRsaKeys ()
48
47
{
49
- if (!file_exists (JwtToken::JWT_PRIVATEKEY_FILE )) {
50
- $ config = array (
51
- "private_key_bits " => JwtToken::RSA_KEY_BITS ,
52
- "private_key_type " => OPENSSL_KEYTYPE_RSA ,
53
- );
54
-
55
- $ res = openssl_pkey_new ($ config );
56
- openssl_pkey_export ($ res , $ privKey );
57
- $ pubKey = openssl_pkey_get_details ($ res );
58
- $ pubKey = $ pubKey ["key " ];
59
-
60
- file_put_contents (JwtToken::JWT_PRIVATEKEY_FILE , $ privKey );
61
- file_put_contents (JwtToken::JWT_PUBLICKEY_FILE , $ pubKey );
48
+ $ ret = file_exists (JwtToken::JWT_PRIVATEKEY_FILE );
49
+ if ($ ret ) {
50
+ return ;
51
+ }
52
+
53
+ $ config = array (
54
+ "private_key_bits " => JwtToken::RSA_KEY_BITS ,
55
+ "private_key_type " => OPENSSL_KEYTYPE_RSA ,
56
+ );
57
+
58
+ $ res = openssl_pkey_new ($ config );
59
+ openssl_pkey_export ($ res , $ privKey );
60
+ $ pubKey = openssl_pkey_get_details ($ res );
61
+ $ pubKey = $ pubKey ["key " ];
62
+
63
+ file_put_contents (JwtToken::JWT_PRIVATEKEY_FILE , $ privKey );
64
+ file_put_contents (JwtToken::JWT_PUBLICKEY_FILE , $ pubKey );
65
+ }
66
+
67
+ private static function encode (array $ payload , OpenSSLAsymmetricKey $ privateKey , string $ algorithm = 'RS256 ' , int $ expiration = 3600 ): string
68
+ {
69
+ // Verify that the algorithm is compatible with asymmetric keys
70
+ if ($ algorithm !== 'RS256 ' && $ algorithm !== 'RS512 ' ) {
71
+ throw new InvalidArgumentException ("Unsupported algorithm for assymmetric keys: $ algorithm " );
62
72
}
73
+
74
+ // Define the JWT header
75
+ $ header = json_encode ([
76
+ 'alg ' => $ algorithm ,
77
+ 'typ ' => 'JWT '
78
+ ]);
79
+
80
+ // Add expiration time to the payload
81
+ if ($ expiration > 0 ) {
82
+ $ payload ['exp ' ] = time () + $ expiration ;
83
+ }
84
+
85
+ // Encode header and payload to base64 URL
86
+ $ base64Header = JwtToken::base64UrlEncode ($ header );
87
+ $ base64Payload = JwtToken::base64UrlEncode (json_encode ($ payload ));
88
+
89
+ // Create the signature
90
+ $ dataToSign = "$ base64Header. $ base64Payload " ;
91
+ $ signature = '' ;
92
+ $ success = openssl_sign ($ dataToSign , $ signature , $ privateKey , OPENSSL_ALGO_SHA256 );
93
+ if (!$ success ) {
94
+ throw new RuntimeException ("Failed to sign the JWT with the private key. " );
95
+ }
96
+
97
+ // Encode signature to base64 URL
98
+ $ base64Signature = JwtToken::base64UrlEncode ($ signature );
99
+
100
+ // Return the complete token
101
+ return "$ base64Header. $ base64Payload. $ base64Signature " ;
102
+ }
103
+
104
+ private static function base64UrlEncode (string $ data ): string
105
+ {
106
+ return rtrim (strtr (base64_encode ($ data ), '+/ ' , '-_ ' ), '= ' );
63
107
}
64
108
}
0 commit comments