Skip to content

Commit ea7412d

Browse files
authored
Merge pull request #5 from cdoco/develop
Add exception handling
2 parents 59be3cc + 930386d commit ea7412d

File tree

8 files changed

+106
-42
lines changed

8 files changed

+106
-42
lines changed

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ $payload = array(
3636
// default HS256 algorithm
3737
$token = jwt_encode($payload, $key);
3838

39-
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7Im5hbWUiOiJaaUhhbmcgR2FvIiwiYWRtaW4iOnRydWV9LCJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsInN1YiI6IjEyMzQ1Njc4OTAifQ.UcrCt9o9rz38kKMTa-nCrm7JNQRNAId5Xg9C7EIl2Zc
39+
// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7Im5hbWUiOiJaaUhhbmcgR2FvIiwiYWRtaW4iOnRydWV9LCJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsInN1YiI6IjEyMzQ1Njc4OTAifQ.UcrCt9o9rz38kKMTa-nCrm7JNQRNAId5Xg9C7EIl2Zc
4040
echo $token;
4141

4242
$decoded_token = jwt_decode($token, $key);
@@ -178,9 +178,8 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
178178

179179
try {
180180
$decoded_token = jwt_decode($token, $hmackey, ['algorithm' => 'HS256']);
181-
} catch (Exception $e) {
181+
} catch (ExpiredSignatureException $e) {
182182
// Expired token
183-
$e->getMessage();
184183
}
185184
```
186185

@@ -194,7 +193,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
194193

195194
try {
196195
$decoded_token = jwt_decode($token, $hmackey, ['leeway' => 30, 'algorithm' => 'HS256']);
197-
} catch (Exception $e) {
196+
} catch (ExpiredSignatureException $e) {
198197
// Expired token
199198
}
200199
```
@@ -212,7 +211,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
212211

213212
try {
214213
$decoded_token = jwt_decode($token, $hmackey, ['algorithm' => 'HS256']);
215-
} catch (Exception $e) {
214+
} catch (BeforeValidException $e) {
216215
// Handle invalid token
217216
}
218217
```
@@ -227,7 +226,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
227226

228227
try {
229228
$decoded_token = jwt_decode($token, $hmackey, ['leeway' => 30, 'algorithm' => 'HS256']);
230-
} catch (Exception $e) {
229+
} catch (BeforeValidException $e) {
231230
// Handle invalid token
232231
}
233232
```
@@ -243,7 +242,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
243242

244243
try {
245244
$decoded_token = jwt_decode($token, $hmackey, ['iss' => 'http://example.org', 'algorithm' => 'HS256']);
246-
} catch (Exception $e) {
245+
} catch (InvalidIssuerException $e) {
247246
// Handle invalid token
248247
}
249248
```
@@ -259,7 +258,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
259258

260259
try {
261260
$decoded_token = jwt_decode($token, $hmackey, ['aud' => ['Young', 'Old'], 'algorithm' => 'HS256']);
262-
} catch (Exception $e) {
261+
} catch (InvalidAudException $e) {
263262
// Handle invalid token
264263
}
265264
```
@@ -275,7 +274,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
275274

276275
try {
277276
$decoded_token = jwt_decode($token, $hmackey, ['jti' => md5('id'), 'algorithm' => 'HS256']);
278-
} catch (Exception $e) {
277+
} catch (InvalidJtiException $e) {
279278
// Handle invalid token
280279
}
281280
```
@@ -291,7 +290,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
291290

292291
try {
293292
$decoded_token = jwt_decode($token, $hmackey, ['algorithm' => 'HS256']);
294-
} catch (Exception $e) {
293+
} catch (InvalidIatException $e) {
295294
// Handle invalid token
296295
}
297296
```
@@ -307,7 +306,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
307306

308307
try {
309308
$decoded_token = jwt_decode($token, $hmackey, ['sub' => 'Subject', 'algorithm' => 'HS256']);
310-
} catch (Exception $e) {
309+
} catch (InvalidSubException $e) {
311310
// Handle invalid token
312311
}
313312
```

jwt.c

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "zend_smart_str.h"
2929
#include "zend_exceptions.h"
30+
#include "ext/spl/spl_exceptions.h"
3031
#include "ext/json/php_json.h"
3132
#include "ext/standard/base64.h"
3233
#include "ext/standard/info.h"
@@ -37,6 +38,16 @@
3738

3839
#include "php_jwt.h"
3940

41+
/* Exceptions */
42+
PHP_JWT_API zend_class_entry *jwt_signature_invalid_cex;
43+
PHP_JWT_API zend_class_entry *jwt_before_valid_cex;
44+
PHP_JWT_API zend_class_entry *jwt_expired_signature_cex;
45+
PHP_JWT_API zend_class_entry *jwt_invalid_issuer_cex;
46+
PHP_JWT_API zend_class_entry *jwt_invalid_aud_cex;
47+
PHP_JWT_API zend_class_entry *jwt_invalid_jti_cex;
48+
PHP_JWT_API zend_class_entry *jwt_invalid_iat_cex;
49+
PHP_JWT_API zend_class_entry *jwt_invalid_sub_cex;
50+
4051
ZEND_DECLARE_MODULE_GLOBALS(jwt)
4152

4253
/* string to algorithm */
@@ -300,14 +311,15 @@ int jwt_array_equals(zend_array *arr1, zend_array *arr2) {
300311
php_error_docref(NULL, E_WARNING, "Aud each item type must be string");
301312
}
302313
}
303-
}ZEND_HASH_FOREACH_END();
314+
} ZEND_HASH_FOREACH_END();
304315
}
305316

306317
return 0;
307318
}
308319

309320
int jwt_verify_body(char *body, zval *return_value)
310321
{
322+
zend_class_entry *ce;
311323
char *err_msg = NULL;
312324
time_t curr_time = time((time_t*)NULL);
313325
zend_string *vs = jwt_b64_url_decode(body);
@@ -317,8 +329,10 @@ int jwt_verify_body(char *body, zval *return_value)
317329
zend_string_free(vs);
318330

319331
/* Expiration */
320-
if (JWT_G(expiration) && (curr_time - JWT_G(leeway)) >= JWT_G(expiration))
332+
if (JWT_G(expiration) && (curr_time - JWT_G(leeway)) >= JWT_G(expiration)) {
333+
ce = jwt_expired_signature_cex;
321334
err_msg = "Expired token";
335+
}
322336

323337
/* not before */
324338
if (JWT_G(not_before) && JWT_G(not_before) > (curr_time + JWT_G(leeway))) {
@@ -327,12 +341,15 @@ int jwt_verify_body(char *body, zval *return_value)
327341

328342
timeinfo = localtime(&JWT_G(not_before));
329343
strftime(buf, sizeof(buf), "Cannot handle token prior to %Y-%m-%d %H:%M:%S", timeinfo);
344+
ce = jwt_before_valid_cex;
330345
err_msg = buf;
331346
}
332347

333348
/* iss */
334-
if (jwt_verify_claims(return_value, "iss", JWT_G(iss)))
335-
err_msg = "Iss verify fail";
349+
if (jwt_verify_claims(return_value, "iss", JWT_G(iss))) {
350+
ce = jwt_invalid_issuer_cex;
351+
err_msg = "Invalid Issuer";
352+
}
336353

337354
/* iat */
338355
if (JWT_G(iat) && JWT_G(iat) > (curr_time + JWT_G(leeway))) {
@@ -341,23 +358,30 @@ int jwt_verify_body(char *body, zval *return_value)
341358

342359
timeinfo = localtime(&JWT_G(iat));
343360
strftime(buf, sizeof(buf), "Cannot handle token prior to %Y-%m-%d %H:%M:%S", timeinfo);
361+
ce = jwt_invalid_iat_cex;
344362
err_msg = buf;
345363
}
346364

347365
/* jti */
348-
if (jwt_verify_claims(return_value, "jti", JWT_G(jti)))
349-
err_msg = "Tti verify fail";
366+
if (jwt_verify_claims(return_value, "jti", JWT_G(jti))) {
367+
ce = jwt_invalid_jti_cex;
368+
err_msg = "Invalid Jti";
369+
}
350370

351371
/* aud */
352-
if (jwt_array_equals(JWT_G(aud), jwt_hash_str_find_ht(return_value, "aud")))
353-
err_msg = "Aud verify fail";
372+
if (jwt_array_equals(JWT_G(aud), jwt_hash_str_find_ht(return_value, "aud"))) {
373+
ce = jwt_invalid_aud_cex;
374+
err_msg = "Invalid Aud";
375+
}
354376

355377
/* sub */
356-
if (jwt_verify_claims(return_value, "sub", JWT_G(sub)))
357-
err_msg = "Sub verify fail";
378+
if (jwt_verify_claims(return_value, "sub", JWT_G(sub))) {
379+
ce = jwt_invalid_sub_cex;
380+
err_msg = "Invalid Sub";
381+
}
358382

359383
if (err_msg) {
360-
zend_throw_exception(zend_ce_exception, err_msg, 0);
384+
zend_throw_exception(ce, err_msg, 0);
361385
return FAILURE;
362386
}
363387

@@ -419,7 +443,7 @@ PHP_FUNCTION(jwt_encode)
419443
jwt->alg = jwt_str_alg(alg);
420444

421445
if (jwt->alg == JWT_ALG_INVAL) {
422-
zend_throw_exception(zend_ce_exception, "Algorithm not supported", 0);
446+
zend_throw_exception(spl_ce_UnexpectedValueException, "Algorithm not supported", 0);
423447
goto encode_done;
424448
}
425449

@@ -451,16 +475,16 @@ PHP_FUNCTION(jwt_encode)
451475

452476
/* sign */
453477
if (jwt->alg == JWT_ALG_NONE) {
454-
// alg none.
455-
smart_str_appendl(&segments, ".", 1);
478+
/* alg none */
479+
smart_str_appendl(&segments, ".", 1);
456480
} else {
457481
/* set jwt struct */
458482
jwt->key = key;
459483
jwt->str = segments.s;
460484

461485
/* sign */
462486
if (jwt_sign(jwt, &sig, &sig_len)) {
463-
zend_throw_exception(zend_ce_exception, "Signature error", 0);
487+
zend_throw_exception(spl_ce_DomainException, "OpenSSL unable to sign data", 0);
464488
goto encode_done;
465489
}
466490

@@ -506,15 +530,15 @@ PHP_FUNCTION(jwt_decode)
506530

507531
/* Parse options */
508532
if (jwt_parse_options(options) == FAILURE) {
509-
zend_throw_exception(zend_ce_exception, "Options parse error", 0);
533+
zend_throw_exception(spl_ce_UnexpectedValueException, "Options parse error", 0);
510534
goto decode_done;
511535
}
512536

513537
/* Algorithm */
514538
jwt->alg = jwt_str_alg(JWT_G(algorithm));
515539

516540
if (jwt->alg == JWT_ALG_INVAL) {
517-
zend_throw_exception(zend_ce_exception, "Algorithm not supported", 0);
541+
zend_throw_exception(spl_ce_UnexpectedValueException, "Algorithm not supported", 0);
518542
goto decode_done;
519543
}
520544

@@ -542,7 +566,7 @@ PHP_FUNCTION(jwt_decode)
542566
zend_string *json_h = jwt_b64_url_decode(head);
543567

544568
if (!json_h) {
545-
zend_throw_exception(zend_ce_exception, "Base64 decode error", 0);
569+
zend_throw_exception(spl_ce_UnexpectedValueException, "Base64 decode error", 0);
546570
goto decode_done;
547571
}
548572

@@ -555,11 +579,11 @@ PHP_FUNCTION(jwt_decode)
555579
zval_ptr_dtor(&zv);
556580

557581
if (strcmp(Z_STRVAL_P(zalg), JWT_G(algorithm))) {
558-
zend_throw_exception(zend_ce_exception, "Algorithm not allowed", 0);
582+
zend_throw_exception(spl_ce_UnexpectedValueException, "Algorithm not allowed", 0);
559583
goto decode_done;
560584
}
561585
} else {
562-
zend_throw_exception(zend_ce_exception, "Json decode error", 0);
586+
zend_throw_exception(spl_ce_UnexpectedValueException, "Json decode error", 0);
563587
goto decode_done;
564588
}
565589

@@ -582,7 +606,7 @@ PHP_FUNCTION(jwt_decode)
582606
jwt->str = segments.s;
583607

584608
if (jwt_verify(jwt, sig)) {
585-
zend_throw_exception(zend_ce_exception, "Signature verification failed", 0);
609+
zend_throw_exception(jwt_signature_invalid_cex, "Signature verification failed", 0);
586610
}
587611
}
588612

@@ -614,6 +638,40 @@ PHP_GINIT_FUNCTION(jwt) {
614638

615639
PHP_MINIT_FUNCTION(jwt)
616640
{
641+
zend_class_entry ce;
642+
643+
/* SignatureInvalidException */
644+
INIT_CLASS_ENTRY(ce, "SignatureInvalidException", NULL);
645+
jwt_signature_invalid_cex = zend_register_internal_class_ex(&ce, zend_ce_exception);
646+
647+
/* BeforeValidException */
648+
INIT_CLASS_ENTRY(ce, "BeforeValidException", NULL);
649+
jwt_before_valid_cex = zend_register_internal_class_ex(&ce, zend_ce_exception);
650+
651+
/* ExpiredSignatureException */
652+
INIT_CLASS_ENTRY(ce, "ExpiredSignatureException", NULL);
653+
jwt_expired_signature_cex = zend_register_internal_class_ex(&ce, zend_ce_exception);
654+
655+
/* InvalidIssuerException */
656+
INIT_CLASS_ENTRY(ce, "InvalidIssuerException", NULL);
657+
jwt_invalid_issuer_cex = zend_register_internal_class_ex(&ce, zend_ce_exception);
658+
659+
/* InvalidAudException */
660+
INIT_CLASS_ENTRY(ce, "InvalidAudException", NULL);
661+
jwt_invalid_aud_cex = zend_register_internal_class_ex(&ce, zend_ce_exception);
662+
663+
/* InvalidJtiException */
664+
INIT_CLASS_ENTRY(ce, "InvalidJtiException", NULL);
665+
jwt_invalid_jti_cex = zend_register_internal_class_ex(&ce, zend_ce_exception);
666+
667+
/* InvalidIatException */
668+
INIT_CLASS_ENTRY(ce, "InvalidIatException", NULL);
669+
jwt_invalid_iat_cex = zend_register_internal_class_ex(&ce, zend_ce_exception);
670+
671+
/* InvalidSubException */
672+
INIT_CLASS_ENTRY(ce, "InvalidSubException", NULL);
673+
jwt_invalid_sub_cex = zend_register_internal_class_ex(&ce, zend_ce_exception);
674+
617675
return SUCCESS;
618676
}
619677

php_jwt.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ extern zend_module_entry jwt_module_entry;
2626

2727
#define PHP_JWT_VERSION "0.2.1" /* Replace with version number for your extension */
2828

29+
#ifdef PHP_WIN32
30+
# define PHP_JWT_API __declspec(dllexport)
31+
#elif defined(__GNUC__) && __GNUC__ >= 4
32+
# define PHP_JWT_API __attribute__ ((visibility("default")))
33+
#else
34+
# define PHP_JWT_API
35+
#endif
36+
2937
#ifdef ZTS
3038
#include "TSRM.h"
3139
#endif

tests/006.phpt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
1010

1111
try {
1212
$decoded_token = jwt_decode($token, $hmackey, ['algorithm' => 'HS256']);
13-
} catch (Exception $e) {
13+
} catch (ExpiredSignatureException $e) {
1414
// Expired token
1515
echo $e->getMessage() . "\n";
1616
}
1717

1818
try {
1919
$decoded_token = jwt_decode($token, $hmackey, ['leeway' => 30, 'algorithm' => 'HS256']);
2020
echo "Success\n";
21-
} catch (Exception $e) {
21+
} catch (ExpiredSignatureException $e) {
2222
// Expired token
23-
echo $e->getMessage() . "\n";
2423
}
2524
?>
2625
--EXPECT--

tests/007.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
1010

1111
try {
1212
$decoded_token = jwt_decode($token, $hmackey, ['algorithm' => 'HS256']);
13-
} catch (Exception $e) {
13+
} catch (BeforeValidException $e) {
1414
// Expired token
1515
echo "FAIL\n";
1616
}
1717

1818
try {
1919
$decoded_token = jwt_decode($token, $hmackey, ['leeway' => 30, 'algorithm' => 'HS256']);
2020
echo "SUCCESS\n";
21-
} catch (Exception $e) {
21+
} catch (BeforeValidException $e) {
2222
// Expired token
2323
}
2424
?>

tests/008.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
1111
try {
1212
$decoded_token = jwt_decode($token, $hmackey, ['algorithm' => 'HS256']);
1313
echo "SUCCESS\n";
14-
} catch (Exception $e) {
14+
} catch (InvalidIatException $e) {
1515
// Handle invalid token
1616
}
1717
?>

tests/009.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ $token = jwt_encode($payload, $hmackey, 'HS256');
1212
try {
1313
$decoded_token = jwt_decode($token, $hmackey, ['iss' => 'http://example.org', 'algorithm' => 'HS256']);
1414
echo "SUCCESS\n";
15-
} catch (Exception $e) {
15+
} catch (InvalidIssuerException $e) {
1616
// Handle invalid token
1717
}
1818

1919
try {
2020
$decoded_token = jwt_decode($token, $hmackey, ['iss' => 'test', 'algorithm' => 'HS256']);
21-
} catch (Exception $e) {
21+
} catch (InvalidIssuerException $e) {
2222
// Handle invalid token
2323
echo "FAIL\n";
2424
}

0 commit comments

Comments
 (0)