Skip to content

Commit dc992a4

Browse files
committed
Aud support array
1 parent 761791f commit dc992a4

File tree

5 files changed

+105
-21
lines changed

5 files changed

+105
-21
lines changed

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div align="center">
2-
<p><img src="https://jwt.io/img/logo-asset.svg" /></p>
2+
<p><a target="_blank" href="https://jwt.io"><img src="https://jwt.io/img/logo-asset.svg" /></a></p>
33
<p>A PHP extension for <a target="_blank" href="https://tools.ietf.org/html/rfc7519">RFC 7519 OAuth JSON Web Token (JWT)</a></p>
44
<a target="_blank" href="https://travis-ci.org/cdoco/php-jwt" title="Build Status"><img src="https://travis-ci.org/cdoco/php-jwt.svg"></a>
55
<img src="https://img.shields.io/badge/branch-master-brightgreen.svg?style=flat-square">
@@ -20,7 +20,7 @@ $ phpize && ./configure --with-openssl=/path/to/openssl
2020
$ make && make install
2121
```
2222

23-
## Quick Example
23+
## Quick [Example](https://github.com/cdoco/php-jwt/tree/master/example)
2424

2525
```php
2626
$key = "example-hmac-key";
@@ -55,8 +55,6 @@ $decoded_token = jwt_decode($token, $key);
5555
print_r($decoded_token);
5656
```
5757

58-
## [Example](https://github.com/cdoco/php-jwt/tree/master/example)
59-
6058
## Algorithms and Usage
6159

6260
The JWT supports NONE, HMAC, RSASSA and ECDSA algorithms for cryptographic signing.
@@ -255,12 +253,12 @@ try {
255253
> The `aud` (audience) claim identifies the recipients that the JWT is intended for. Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the `aud` claim when this claim is present, then the JWT MUST be rejected. In the general case, the `aud` value is an array of case-sensitive strings, each containing a **StringOrURI** value. In the special case when the JWT has one audience, the `aud` value MAY be a single case-sensitive string containing a **StringOrURI** value. The interpretation of audience values is generally application specific. Use of this claim is OPTIONAL.
256254
257255
```php
258-
$payload = ['data' => 'data', 'aud' => 'Young Man'];
256+
$payload = ['data' => 'data', 'aud' => ['Young', 'Old']];
259257

260258
$token = jwt_encode($payload, $hmackey, 'HS256');
261259

262260
try {
263-
$decoded_token = jwt_decode($token, $hmackey, ['aud' => 'Young Man', 'algorithm' => 'HS256']);
261+
$decoded_token = jwt_decode($token, $hmackey, ['aud' => ['Young', 'Old'], 'algorithm' => 'HS256']);
264262
} catch (Exception $e) {
265263
// Handle invalid token
266264
}

jwt.c

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -225,49 +225,106 @@ zend_string *jwt_b64_url_decode(const char *src)
225225

226226
char *jwt_hash_str_find_str(zval *arr, char *key)
227227
{
228-
char *str = NULL;
228+
char *str = NULL, err_msg[128];
229229
zval *zv = zend_hash_str_find(Z_ARRVAL_P(arr), key, strlen(key));
230230

231231
if (zv != NULL) {
232-
str = Z_STRVAL_P(zv);
233-
}
232+
if (Z_TYPE_P(zv) == IS_STRING) {
233+
str = Z_STRVAL_P(zv);
234+
} else {
235+
sprintf(err_msg, "%s type must be string", key);
236+
zend_throw_exception(zend_ce_exception, err_msg, 0);
237+
}
238+
}
234239

235240
return str;
236241
}
237242

238243
long jwt_hash_str_find_long(zval *arr, char *key)
239244
{
245+
char err_msg[128];
240246
zval *zv = zend_hash_str_find(Z_ARRVAL_P(arr), key, strlen(key));
241247

242248
if (zv != NULL) {
243-
return Z_LVAL_P(zv);
249+
if (Z_TYPE_P(zv) == IS_LONG) {
250+
return Z_LVAL_P(zv);
251+
} else {
252+
sprintf(err_msg, "%s type must be long", key);
253+
zend_throw_exception(zend_ce_exception, err_msg, 0);
254+
}
244255
}
245256

246257
return 0;
247258
}
248259

260+
zend_array *jwt_hash_str_find_ht(zval *arr, char *key)
261+
{
262+
char err_msg[128];
263+
zval *zv = zend_hash_str_find(Z_ARRVAL_P(arr), key, strlen(key));
264+
265+
if (zv != NULL) {
266+
if (Z_TYPE_P(zv) == IS_ARRAY) {
267+
return Z_ARRVAL_P(zv);
268+
} else {
269+
sprintf(err_msg, "%s type must be array", key);
270+
zend_throw_exception(zend_ce_exception, err_msg, 0);
271+
}
272+
}
273+
274+
return NULL;
275+
}
276+
249277
int jwt_verify_claims(zval *arr, char *key, char *str)
250278
{
251279
char *rs = jwt_hash_str_find_str(arr, key);
252-
if (rs && strcmp(rs, str)) {
280+
if (rs && str && strcmp(rs, str)) {
253281
return FAILURE;
254282
}
255283

256284
return 0;
257285
}
258286

287+
int jwt_array_equals(zend_array *arr1, zend_array *arr2) {
288+
zend_ulong i;
289+
zval *value = NULL;
290+
291+
if (arr1 && arr2) {
292+
if (zend_array_count(arr1) != zend_array_count(arr2)) {
293+
return FAILURE;
294+
}
295+
296+
ZEND_HASH_FOREACH_NUM_KEY_VAL(arr1, i, value) {
297+
zval *tmp = zend_hash_index_find(arr2, i);
298+
299+
if (value && tmp){
300+
if (Z_TYPE_P(value) == IS_STRING && Z_TYPE_P(tmp) == IS_STRING) {
301+
if (strcmp(Z_STRVAL_P(value), Z_STRVAL_P(tmp))) {
302+
return FAILURE;
303+
}
304+
} else {
305+
zend_throw_exception(zend_ce_exception, "Aud each item type must be string", 0);
306+
return FAILURE;
307+
}
308+
}
309+
}ZEND_HASH_FOREACH_END();
310+
}
311+
312+
return 0;
313+
}
314+
259315
int jwt_verify_body(char *body, zval *return_value)
260316
{
261317
char *err_msg = NULL;
262318
time_t curr_time = time((time_t*)NULL);
263319
zend_string *vs = jwt_b64_url_decode(body);
320+
321+
/* decode json to array */
264322
php_json_decode_ex(return_value, ZSTR_VAL(vs), ZSTR_LEN(vs), PHP_JSON_OBJECT_AS_ARRAY, 512);
265323
zend_string_free(vs);
266324

267325
/* Expiration */
268-
if (JWT_G(expiration) && (curr_time - JWT_G(leeway)) >= JWT_G(expiration)) {
326+
if (JWT_G(expiration) && (curr_time - JWT_G(leeway)) >= JWT_G(expiration))
269327
err_msg = "Expired token";
270-
}
271328

272329
/* not before */
273330
if (JWT_G(not_before) && JWT_G(not_before) > (curr_time + JWT_G(leeway))) {
@@ -280,7 +337,7 @@ int jwt_verify_body(char *body, zval *return_value)
280337
}
281338

282339
/* iss */
283-
if (JWT_G(iss) && jwt_verify_claims(return_value, "iss", JWT_G(iss)))
340+
if (jwt_verify_claims(return_value, "iss", JWT_G(iss)))
284341
err_msg = "Iss verify fail";
285342

286343
/* iat */
@@ -294,15 +351,15 @@ int jwt_verify_body(char *body, zval *return_value)
294351
}
295352

296353
/* jti */
297-
if (JWT_G(jti) && jwt_verify_claims(return_value, "jti", JWT_G(jti)))
354+
if (jwt_verify_claims(return_value, "jti", JWT_G(jti)))
298355
err_msg = "Tti verify fail";
299356

300357
/* aud */
301-
if (JWT_G(aud) && jwt_verify_claims(return_value, "aud", JWT_G(aud)))
358+
if (jwt_array_equals(JWT_G(aud), jwt_hash_str_find_ht(return_value, "aud")))
302359
err_msg = "Aud verify fail";
303360

304361
/* sub */
305-
if (JWT_G(sub) && jwt_verify_claims(return_value, "sub", JWT_G(sub)))
362+
if (jwt_verify_claims(return_value, "sub", JWT_G(sub)))
306363
err_msg = "Sub verify fail";
307364

308365
if (err_msg) {
@@ -330,7 +387,7 @@ int jwt_parse_options(zval *options)
330387
JWT_G(leeway) = jwt_hash_str_find_long(options, "leeway");
331388
JWT_G(iss) = jwt_hash_str_find_str(options, "iss");
332389
JWT_G(jti) = jwt_hash_str_find_str(options, "jti");
333-
JWT_G(aud) = jwt_hash_str_find_str(options, "aud");
390+
JWT_G(aud) = jwt_hash_str_find_ht(options, "aud");
334391
JWT_G(sub) = jwt_hash_str_find_str(options, "sub");
335392
}
336393
break;

jwt.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
"admin" => true
1313
],
1414
"sub" => "1234567890",
15-
"nbf" => time() + 100
15+
"nbf" => time() + 1,
16+
"aud" => ['yy'],
1617
);
1718

1819
// default HS256 algorithm
1920
$token = jwt_encode($claims, $key);
2021

2122
echo $token . PHP_EOL;
22-
print_r(jwt_decode($token, $key, ['leeway' => 2, "iss" => "http://example.org"]));
23+
print_r(jwt_decode($token, $key, ["aud" => ['yy'], 'leeway' => 2, "iss" => "http://example.org"]));

php_jwt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ ZEND_BEGIN_MODULE_GLOBALS(jwt)
3838
char *iss;
3939
time_t iat;
4040
char *jti;
41-
char *aud;
41+
zend_array *aud;
4242
char *sub;
4343
size_t leeway;
4444
char *algorithm;

tests/011.phpt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
Check for jwt aud claim name
3+
--SKIPIF--
4+
<?php if (!extension_loaded("jwt")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
$hmackey = "example-hmac-key";
8+
$payload = ['data' => 'data', 'aud' => ['Young', 'Old']];
9+
10+
$token = jwt_encode($payload, $hmackey, 'HS256');
11+
12+
try {
13+
$decoded_token = jwt_decode($token, $hmackey, ['aud' => ['Young', 'Old'], 'algorithm' => 'HS256']);
14+
echo "SUCCESS\n";
15+
} catch (Exception $e) {
16+
// Handle invalid token
17+
}
18+
19+
try {
20+
$decoded_token = jwt_decode($token, $hmackey, ['aud' => ['Young'], 'algorithm' => 'HS256']);
21+
} catch (Exception $e) {
22+
// Handle invalid token
23+
echo "FAIL\n";
24+
}
25+
?>
26+
--EXPECT--
27+
SUCCESS
28+
FAIL

0 commit comments

Comments
 (0)