Passed
Push — master ( 5543a5...653c6a )
by Francis
01:13
created

testSetDefaultExpiryDateForUnSignedToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 8
rs 10
1
<?php
2
declare(strict_types=1);
3
use PHPUnit\Framework\TestCase;
0 ignored issues
show
Bug introduced by
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() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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  {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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
Bug introduced by
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
Bug introduced by
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
Bug introduced by
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
    self::$ci->jwt->create();
225
    $this->assertTrue(self::$ci->jwt->expired());
226
  }
227
  /**
228
   * [testSetExpired description]
229
   *
230
   * @depends testExpired
231
   *
232
   * @testdox Test Set Expiry Date on Token.
233
   */
234
  public function testSetExpired():void {
235
    self::$ci->jwt->expire("+1 Day");
236
    $this->assertFalse(self::$ci->jwt->expired());
237
  }
238
  /**
239
   * [setDefaultExpiryDate description]
240
   *
241
   */
242
  public function testSetDefaultExpiryDateForSignedToken():void {
243
    self::$ci->jwt->create();
244
    self::$ci->jwt->payload("iss", "www.example.com");
245
    self::$ci->jwt->init(["auto_expire" => "+1 Seconds"]);
246
    $jwt = self::$ci->jwt->sign();
247
    $this->assertFalse(self::$ci->jwt->expired($jwt));
248
    sleep(1); // Allow Token to expire.
249
    $this->assertTrue(self::$ci->jwt->expired($jwt));
250
  }
251
  /**
252
   * [testSetDefaultExpiryDateForUnSignedToken description]
253
   */
254
  public function testSetDefaultExpiryDateForUnSignedToken(): void {
255
    self::$ci->jwt->create();
256
    self::$ci->jwt->payload("iss", "www.example.com");
257
    self::$ci->jwt->init(["auto_expire" => "+1 Seconds"]);
258
    $jwt = self::$ci->jwt->token();
259
    $this->assertFalse(self::$ci->jwt->expired($jwt));
260
    sleep(1); // Allow Token to expire.
261
    $this->assertTrue(self::$ci->jwt->expired($jwt));
262
  }
263
}
264
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
265