Passed
Push — master ( e758dd...5543a5 )
by Francis
01:04
created

JWTTest::testSetExpired()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 0
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.
168
    $this->assertIsNumeric(json_decode(base64url_decode(explode(".", $jwt)[1]), true)["iat"]);
169
    self::$ci->jwt->init(["allow_unsigned" => false]);
170
  }
171
  /**
172
   * [testDecode description]
173
   *
174
   * @depends testUnsignedToken
175
   */
176
  public function testDecode():void {
177
    self::$ci->jwt->create();
178
    self::$ci->jwt->header("alg", JWT::HS256);
179
    self::$ci->jwt->header("typ", JWT::JWT);
180
    self::$ci->jwt->payload("iss", "www.example.com");
181
    self::$ci->jwt->payload("sub", "francis");
182
    self::$ci->jwt->payload("aud", "my_server");
183
    self::$ci->jwt->payload("exp", 23456789967);
184
    self::$ci->jwt->payload("iat", 12345677778);
185
    // Get Token
186
    $jwt = self::$ci->jwt->sign();
187
    self::$ci->jwt->create();
188
    self::$ci->jwt->decode($jwt);
189
    $header = self::$ci->jwt->headerArray();
190
    $this->assertEquals(JWT::HS256, $header["alg"]);
191
    $this->assertEquals(JWT::JWT, $header["typ"]);
192
    $payload = self::$ci->jwt->payloadArray();
193
    $this->assertEquals("www.example.com", $payload["iss"]);
194
    $this->assertEquals("francis", $payload["sub"]);
195
    $this->assertEquals("my_server", $payload["aud"]);
196
    $this->assertEquals(23456789967, $payload["exp"]);
197
    $this->assertEquals(12345677778, $payload["iat"]);
198
  }
199
  /**
200
   * [testExpired Test expiry date of JWTs.]
201
   *
202
   * @depends testDecode
203
   */
204
  public function testExpired():void {
205
    // Internal Check.
206
    self::$ci->jwt->payload("exp", time());
207
    $this->assertTrue(self::$ci->jwt->expired());
208
    self::$ci->jwt->payload("exp", time() + (7 * 24 * 60 * 60));
209
    $this->assertFalse(self::$ci->jwt->expired());
210
211
    // Supplied Token Check.
212
    self::$ci->jwt->payload("exp", time());
213
    $jwt = self::$ci->jwt->sign();
214
    $this->assertTrue(self::$ci->jwt->expired($jwt));
215
    self::$ci->jwt->payload("exp", time() + (7 * 24 * 60 * 60));
216
    $jwt = self::$ci->jwt->sign();
217
    $this->assertFalse(self::$ci->jwt->expired($jwt));
218
    // Empty Expire.
219
    self::$ci->jwt->create();
220
    $this->assertTrue(self::$ci->jwt->expired());
221
  }
222
  /**
223
   * [testSetExpired description]
224
   *
225
   * @depends testExpired
226
   *
227
   * @testdox Test Set Expired.
228
   */
229
  public function testSetExpired():void {
230
    self::$ci->jwt->expire("+1 Day");
231
    $this->assertFalse(self::$ci->jwt->expired());
232
  }
233
}
234
?>
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...
235