Skip to content

Commit 59be3cc

Browse files
authored
Merge pull request #4 from cdoco/develop
Add aud support array
2 parents b310954 + 5051ba7 commit 59be3cc

File tree

5 files changed

+98
-20
lines changed

5 files changed

+98
-20
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: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,12 @@ char *jwt_hash_str_find_str(zval *arr, char *key)
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+
php_error_docref(NULL, E_WARNING, "%s type must be string", key);
236+
}
237+
}
234238

235239
return str;
236240
}
@@ -240,34 +244,81 @@ long jwt_hash_str_find_long(zval *arr, char *key)
240244
zval *zv = zend_hash_str_find(Z_ARRVAL_P(arr), key, strlen(key));
241245

242246
if (zv != NULL) {
243-
return Z_LVAL_P(zv);
247+
if (Z_TYPE_P(zv) == IS_LONG) {
248+
return Z_LVAL_P(zv);
249+
} else {
250+
php_error_docref(NULL, E_WARNING, "%s type must be long", key);
251+
}
244252
}
245253

246254
return 0;
247255
}
248256

257+
zend_array *jwt_hash_str_find_ht(zval *arr, char *key)
258+
{
259+
zval *zv = zend_hash_str_find(Z_ARRVAL_P(arr), key, strlen(key));
260+
261+
if (zv != NULL) {
262+
if (Z_TYPE_P(zv) == IS_ARRAY) {
263+
return Z_ARRVAL_P(zv);
264+
} else {
265+
php_error_docref(NULL, E_WARNING, "%s type must be array", key);
266+
}
267+
}
268+
269+
return NULL;
270+
}
271+
249272
int jwt_verify_claims(zval *arr, char *key, char *str)
250273
{
251274
char *rs = jwt_hash_str_find_str(arr, key);
252-
if (rs && strcmp(rs, str)) {
275+
if (rs && str && strcmp(rs, str)) {
253276
return FAILURE;
254277
}
255278

256279
return 0;
257280
}
258281

282+
int jwt_array_equals(zend_array *arr1, zend_array *arr2) {
283+
zend_ulong i;
284+
zval *value = NULL;
285+
286+
if (arr1 && arr2) {
287+
if (zend_array_count(arr1) != zend_array_count(arr2)) {
288+
return FAILURE;
289+
}
290+
291+
ZEND_HASH_FOREACH_NUM_KEY_VAL(arr1, i, value) {
292+
zval *tmp = zend_hash_index_find(arr2, i);
293+
294+
if (value && tmp){
295+
if (Z_TYPE_P(value) == IS_STRING && Z_TYPE_P(tmp) == IS_STRING) {
296+
if (strcmp(Z_STRVAL_P(value), Z_STRVAL_P(tmp))) {
297+
return FAILURE;
298+
}
299+
} else {
300+
php_error_docref(NULL, E_WARNING, "Aud each item type must be string");
301+
}
302+
}
303+
}ZEND_HASH_FOREACH_END();
304+
}
305+
306+
return 0;
307+
}
308+
259309
int jwt_verify_body(char *body, zval *return_value)
260310
{
261311
char *err_msg = NULL;
262312
time_t curr_time = time((time_t*)NULL);
263313
zend_string *vs = jwt_b64_url_decode(body);
314+
315+
/* decode json to array */
264316
php_json_decode_ex(return_value, ZSTR_VAL(vs), ZSTR_LEN(vs), PHP_JSON_OBJECT_AS_ARRAY, 512);
265317
zend_string_free(vs);
266318

267319
/* Expiration */
268-
if (JWT_G(expiration) && (curr_time - JWT_G(leeway)) >= JWT_G(expiration)) {
320+
if (JWT_G(expiration) && (curr_time - JWT_G(leeway)) >= JWT_G(expiration))
269321
err_msg = "Expired token";
270-
}
271322

272323
/* not before */
273324
if (JWT_G(not_before) && JWT_G(not_before) > (curr_time + JWT_G(leeway))) {
@@ -280,7 +331,7 @@ int jwt_verify_body(char *body, zval *return_value)
280331
}
281332

282333
/* iss */
283-
if (JWT_G(iss) && jwt_verify_claims(return_value, "iss", JWT_G(iss)))
334+
if (jwt_verify_claims(return_value, "iss", JWT_G(iss)))
284335
err_msg = "Iss verify fail";
285336

286337
/* iat */
@@ -294,15 +345,15 @@ int jwt_verify_body(char *body, zval *return_value)
294345
}
295346

296347
/* jti */
297-
if (JWT_G(jti) && jwt_verify_claims(return_value, "jti", JWT_G(jti)))
348+
if (jwt_verify_claims(return_value, "jti", JWT_G(jti)))
298349
err_msg = "Tti verify fail";
299350

300351
/* aud */
301-
if (JWT_G(aud) && jwt_verify_claims(return_value, "aud", JWT_G(aud)))
352+
if (jwt_array_equals(JWT_G(aud), jwt_hash_str_find_ht(return_value, "aud")))
302353
err_msg = "Aud verify fail";
303354

304355
/* sub */
305-
if (JWT_G(sub) && jwt_verify_claims(return_value, "sub", JWT_G(sub)))
356+
if (jwt_verify_claims(return_value, "sub", JWT_G(sub)))
306357
err_msg = "Sub verify fail";
307358

308359
if (err_msg) {
@@ -330,7 +381,7 @@ int jwt_parse_options(zval *options)
330381
JWT_G(leeway) = jwt_hash_str_find_long(options, "leeway");
331382
JWT_G(iss) = jwt_hash_str_find_str(options, "iss");
332383
JWT_G(jti) = jwt_hash_str_find_str(options, "jti");
333-
JWT_G(aud) = jwt_hash_str_find_str(options, "aud");
384+
JWT_G(aud) = jwt_hash_str_find_ht(options, "aud");
334385
JWT_G(sub) = jwt_hash_str_find_str(options, "sub");
335386
}
336387
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)