Issues (13)

phpunit/JWTTest.php (4 issues)

1
<?php
2
declare(strict_types=1);
3
use PHPUnit\Framework\TestCase;
0 ignored issues
show
The type PHPUnit\Framework\TestCase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
4
5
class JWTTest extends TestCase {
6
  /**
7
   * Code Igniter Instance.
8
   * @var object
9
   */
10
  private static $ci;
11
  /**
12
   * Package name for simplicity
13
   * @var string
14
   */
15
  private const PACKAGE = "francis94c/ci-jwt";
16
17
  /**
18
   * Prerquisites for the Unit Tests.
19
   *
20
   * @covers JWT::__construct
21
   */
22
  public static function setUpBeforeClass(): void {
23
    self::$ci =& get_instance();
24
    /**
25
     * [$params Config Items.]
26
     *
27
     * @var array
28
     *
29
     * Description:-
30
     *
31
     * secret:  The secret strng used in signing the JWT.
32
     * alg:     Signing Algorithm.
33
     * set_iat: Automatically set issued at time on payloads.
34
     */
35
    $config = [
36
      "secret"     => "GHfsjfblsgo8r84nNOHHdgdgdgdyf758y8hyttjuoljlhkmjhgO8HOHLHLd",
37
      "alg"        => "HS256",
38
      "set_iat"    => true
39
    ];
40
    self::$ci->load->package(self::PACKAGE);
41
    self::$ci->jwt->init($config);
42
  }
43
  /**
44
   * [testHelperMethodsExist Test Helper Method Exist.]
45
   * @testdox Helper Methods.
46
   */
47
  function testHelperMethodsExist() {
48
    $this->assertTrue(function_exists("base64url_encode"));
49
    $this->assertTrue(function_exists("base64url_decode"));
50
  }
51
  /**
52
   * [testHeader test header section of JWT]
53
   *
54
   * @testdox Header Section.
55
   */
56
  function testHeader():void  {
57
    self::$ci->jwt->header("alg", JWT::HS256);
58
    self::$ci->jwt->header("typ", JWT::JWT);
59
    $header = self::$ci->jwt->headerArray();
60
    $this->assertEquals(JWT::HS256, $header["alg"]);
61
    $this->assertEquals(JWT::JWT, $header["typ"]);
62
  }
63
  /**
64
   * [testPayload test payload section.]
65
   *
66
   * RFC7519 Section 4.1
67
   *
68
   * @depends testHeader
69
   *
70
   * @testdox Payload Test.
71
   */
72
  public function testPayload():void  {
73
    self::$ci->jwt->payload("iss", "www.example.com");
74
    self::$ci->jwt->payload("sub", "francis");
75
    self::$ci->jwt->payload("aud", "my_server");
76
    self::$ci->jwt->payload("exp", 23456789967);
77
    self::$ci->jwt->payload("iat", 12345677778);
78
    $payload = self::$ci->jwt->payloadArray();
79
    $this->assertEquals("www.example.com", $payload["iss"]);
80
    $this->assertEquals("francis", $payload["sub"]);
81
    $this->assertEquals("my_server", $payload["aud"]);
82
    $this->assertEquals(23456789967, $payload["exp"]);
83
    $this->assertEquals(12345677778, $payload["iat"]);
84
  }
85
  /**
86
   * [testBase64Methods descriptio]
87
   *
88
   * @depends testHelperMethodsExist
89
   *
90
   * @testdox Test Base64 Function.
91
   */
92
  public function testBase64Functions():void {
93
    $data = "The Quick Brown Fox Jumped over the Lazy Dog.";
94
    $b64 = base64url_encode($data);
95
    $this->assertEquals($data, base64url_decode($b64));
0 ignored issues
show
It seems like $b64 can also be of type false; however, parameter $data of base64url_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
    $this->assertEquals($data, base64url_decode(/** @scrutinizer ignore-type */ $b64));
Loading history...
96
  }
97
  /**
98
   * [testSigning description]
99
   *
100
   * @depends testPayload
101
   *
102
   * @testdox Test Signing.
103
   */
104
  public function testSigning():void {
105
    $jwt = self::$ci->jwt->sign();
106
    $parts = explode(".", $jwt);
107
    $header = json_decode(base64url_decode($parts[0]), true);
108
    $this->assertEquals(JWT::HS256, $header["alg"]);
109
    $this->assertEquals(JWT::JWT, $header["typ"]);
110
    $payload = json_decode(base64url_decode($parts[1]), true);
111
    $this->assertEquals("www.example.com", $payload["iss"]);
112
    $this->assertEquals("francis", $payload["sub"]);
113
    $this->assertEquals("my_server", $payload["aud"]);
114
    $this->assertEquals(23456789967, $payload["exp"]);
115
    $this->assertEquals(12345677778, $payload["iat"]);
116
    // Verify Signature.
117
    $this->assertTrue(self::$ci->jwt->verify($jwt));
118
    // Let's Tamper with the JWT's integrity.
119
    $payload["sub"] = "john";
120
    $jwt = base64url_encode(json_encode($header)) . "." .
0 ignored issues
show
Are you sure base64url_encode(json_encode($header)) of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
    $jwt = /** @scrutinizer ignore-type */ base64url_encode(json_encode($header)) . "." .
Loading history...
121
    base64url_encode(json_encode($payload)) . "." . $parts[2];
0 ignored issues
show
Are you sure base64url_encode(json_encode($payload)) of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

121
    /** @scrutinizer ignore-type */ base64url_encode(json_encode($payload)) . "." . $parts[2];
Loading history...
122
    $this->assertFalse(self::$ci->jwt->verify($jwt));
123
    // Tamper by signing with a different secret.
124
    $signature = hash_hmac(
125
      "sha256",
126
      base64url_encode(json_encode($header)) . "." .
127
      base64url_encode(json_encode($payload)),
128
      "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
129
    $jwt = base64url_encode(json_encode($header)) . "." .
130
    base64url_encode(json_encode($payload)) . "." . $signature;
131
    // Verify with Original Secret.
132
    $this->assertFalse(self::$ci->jwt->verify($jwt));
133
    // Verify with fake Secret.
134
    $this->assertTrue(self::$ci->jwt->verify($jwt, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"));
135
    // Restore integrity.
136
    $payload["sub"] = "francis";
137
    $jwt = base64url_encode(json_encode($header)) . "." .
138
    base64url_encode(json_encode($payload)) . "." . $parts[2];
139
    $this->assertTrue(self::$ci->jwt->verify($jwt));
140
  }
141
  /**
142
   * [testEmpty description]
143
   *
144
   * @depends testSigning
145
   *
146
   * @tesdox Test Empty.
147
   */
148
  public function testEmpty():void {
149
    self::$ci->jwt->create();
150
    $this->assertEmpty(self::$ci->jwt->headerArray());
151
    $this->assertEmpty(self::$ci->jwt->payloadArray());
152
  }
153
  /**
154
   * [testEmptyPayload description]
155
   *
156
   * @depends testEmpty
157
   *
158
   * @tesdox Test Signed Empty Payload.
159
   */
160
  public function testUnsignedToken():void {
161
    $this->assertNull(self::$ci->jwt->token());
162
    self::$ci->jwt->payload("iss", "server");
163
    $jwt = self::$ci->jwt->token();
164
    $this->assertFalse(self::$ci->jwt->verify($jwt));
165
    self::$ci->jwt->init(["allow_unsigned" => true]);
166
    $this->assertTrue(self::$ci->jwt->verify($jwt));
167
    // Test auto-generation of time stamp with unsigned token.
168
    $this->assertIsNumeric(json_decode(base64url_decode(explode(".", $jwt)[1]), true)["iat"]);
169
    self::$ci->jwt->init(["allow_unsigned" => false]);
170
    // Test auto-generation of time stamp with signed token.
171
    self::$ci->jwt->create();
172
    self::$ci->jwt->payload("iss", "server");
173
    $jwt = self::$ci->jwt->sign();
174
    $this->assertIsNumeric(json_decode(base64url_decode(explode(".", $jwt)[1]), true)["iat"]);
175
  }
176
  /**
177
   * [testDecode description]
178
   *
179
   * @depends testUnsignedToken
180
   */
181
  public function testDecode():void {
182
    self::$ci->jwt->create();
183
    self::$ci->jwt->header("alg", JWT::HS256);
184
    self::$ci->jwt->header("typ", JWT::JWT);
185
    self::$ci->jwt->payload("iss", "www.example.com");
186
    self::$ci->jwt->payload("sub", "francis");
187
    self::$ci->jwt->payload("aud", "my_server");
188
    self::$ci->jwt->payload("exp", 23456789967);
189
    self::$ci->jwt->payload("iat", 12345677778);
190
    // Get Token
191
    $jwt = self::$ci->jwt->sign();
192
    self::$ci->jwt->create();
193
    self::$ci->jwt->decode($jwt);
194
    $header = self::$ci->jwt->headerArray();
195
    $this->assertEquals(JWT::HS256, $header["alg"]);
196
    $this->assertEquals(JWT::JWT, $header["typ"]);
197
    $payload = self::$ci->jwt->payloadArray();
198
    $this->assertEquals("www.example.com", $payload["iss"]);
199
    $this->assertEquals("francis", $payload["sub"]);
200
    $this->assertEquals("my_server", $payload["aud"]);
201
    $this->assertEquals(23456789967, $payload["exp"]);
202
    $this->assertEquals(12345677778, $payload["iat"]);
203
  }
204
  /**
205
   * [testExpired Test expiry date of JWTs.]
206
   *
207
   * @depends testDecode
208
   */
209
  public function testExpired():void {
210
    // Internal Check.
211
    self::$ci->jwt->payload("exp", time());
212
    $this->assertTrue(self::$ci->jwt->expired());
213
    self::$ci->jwt->payload("exp", time() + (7 * 24 * 60 * 60));
214
    $this->assertFalse(self::$ci->jwt->expired());
215
216
    // Supplied Token Check.
217
    self::$ci->jwt->payload("exp", time());
218
    $jwt = self::$ci->jwt->sign();
219
    $this->assertTrue(self::$ci->jwt->expired($jwt));
220
    self::$ci->jwt->payload("exp", time() + (7 * 24 * 60 * 60));
221
    $jwt = self::$ci->jwt->sign();
222
    $this->assertFalse(self::$ci->jwt->expired($jwt));
223
    // Empty Expire.
224
    // Absent exp field means token cannot expire.
225
    self::$ci->jwt->create();
226
    $this->assertFalse(self::$ci->jwt->expired());
227
  }
228
  /**
229
   * [testSetExpired description]
230
   *
231
   * @depends testExpired
232
   *
233
   * @testdox Test Set Expiry Date on Token.
234
   */
235
  public function testSetExpired():void {
236
    self::$ci->jwt->expire("+1 Day");
237
    $this->assertFalse(self::$ci->jwt->expired());
238
  }
239
  /**
240
   * [setDefaultExpiryDate description]
241
   *
242
   */
243
  public function testSetDefaultExpiryDateForSignedToken():void {
244
    self::$ci->jwt->create();
245
    self::$ci->jwt->payload("iss", "www.example.com");
246
    self::$ci->jwt->init(["auto_expire" => "+1 Seconds"]);
247
    $jwt = self::$ci->jwt->sign();
248
    $this->assertFalse(self::$ci->jwt->expired($jwt));
249
    sleep(1); // Allow Token to expire.
250
    $this->assertTrue(self::$ci->jwt->expired($jwt));
251
  }
252
  /**
253
   * [testSetDefaultExpiryDateForUnSignedToken description]
254
   */
255
  public function testSetDefaultExpiryDateForUnSignedToken(): void {
256
    self::$ci->jwt->create();
257
    self::$ci->jwt->payload("iss", "www.example.com");
258
    self::$ci->jwt->init(["auto_expire" => "+1 Seconds"]);
259
    $jwt = self::$ci->jwt->token();
260
    $this->assertFalse(self::$ci->jwt->expired($jwt));
261
    sleep(1); // Allow Token to expire.
262
    $this->assertTrue(self::$ci->jwt->expired($jwt));
263
  }
264
}
265
?>
266