Skip to content

Commit aa024c5

Browse files
add option to not extract sub -- fixes #66 (#70)
* add option to not extract sub * move email variables into block where they are used * cleanup
1 parent 60b6f4b commit aa024c5

File tree

3 files changed

+46
-29
lines changed

3 files changed

+46
-29
lines changed

README.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ which can be specified in on the `main` `server` or `location` level.
4141
auth_jwt_key "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF"; # see docs for format based on algorithm
4242
auth_jwt_loginurl "https://yourdomain.com/loginpage";
4343
auth_jwt_enabled on;
44-
auth_jwt_algorithm HS256; # or RS256
44+
auth_jwt_algorithm HS256; # or RS256
45+
auth_jwt_extract_sub on; # or off
4546
auth_jwt_validate_email on; # or off
46-
auth_jwt_use_keyfile off; # or on
47+
auth_jwt_use_keyfile off; # or on
4748
auth_jwt_keyfile_path "/app/pub_key";
4849
```
4950

@@ -87,9 +88,17 @@ auth_jwt_validation_type COOKIE=rampartjwt;
8788
By default the authorization header is used to provide a JWT for validation.
8889
However, you may use the `auth_jwt_validation_type` configuration to specify the name of a cookie that provides the JWT.
8990

91+
```
92+
auth_jwt_extract_sub
93+
```
94+
By default, the module will attempt to extract the `sub` claim (e.g. the user's id) from the JWT. If successful, the
95+
value will be set in the `x-userid` HTTP header. An error will be logged if this option is enabled and the JWT does not
96+
contain the `sub` claim.
97+
9098
```
9199
auth_jwt_validate_email off;
92100
```
93101
By default, the module will attempt to validate the email address field of the JWT, then set the x-email header of the
94102
session, and will log an error if it isn't found. To disable this behavior, for instance if you are using a different
95-
user identifier property such as 'sub', set `auth_jwt_validate_email` to the value `off`.
103+
user identifier property such as `sub`, set `auth_jwt_validate_email` to the value `off`. _Note that this flag may be
104+
renamed to `auth_jwt_extract_email` in a future release._

src/ngx_http_auth_jwt_module.c

+32-23
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ typedef struct {
2727
ngx_flag_t auth_jwt_redirect;
2828
ngx_str_t auth_jwt_validation_type;
2929
ngx_str_t auth_jwt_algorithm;
30+
ngx_flag_t auth_jwt_extract_sub;
3031
ngx_flag_t auth_jwt_validate_email;
3132
ngx_str_t auth_jwt_keyfile_path;
3233
ngx_flag_t auth_jwt_use_keyfile;
@@ -84,6 +85,13 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = {
8485
offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_algorithm),
8586
NULL },
8687

88+
{ ngx_string("auth_jwt_extract_sub"),
89+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
90+
ngx_conf_set_flag_slot,
91+
NGX_HTTP_LOC_CONF_OFFSET,
92+
offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_extract_sub),
93+
NULL },
94+
8795
{ ngx_string("auth_jwt_validate_email"),
8896
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
8997
ngx_conf_set_flag_slot,
@@ -152,10 +160,6 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
152160
jwt_t *jwt = NULL;
153161
int jwtParseReturnCode;
154162
jwt_alg_t alg;
155-
const char* sub;
156-
const char* email;
157-
ngx_str_t sub_t;
158-
ngx_str_t email_t;
159163
time_t exp;
160164
time_t now;
161165
ngx_str_t auth_jwt_algorithm;
@@ -175,6 +179,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
175179
}
176180

177181
jwtCookieValChrPtr = getJwt(r, jwtcf->auth_jwt_validation_type);
182+
178183
if (jwtCookieValChrPtr == NULL)
179184
{
180185
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to find a jwt");
@@ -184,6 +189,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
184189
// convert key from hex to binary, if a symmetric key
185190

186191
auth_jwt_algorithm = jwtcf->auth_jwt_algorithm;
192+
187193
if (auth_jwt_algorithm.len == 0 || (auth_jwt_algorithm.len == sizeof("HS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "HS256", sizeof("HS256") - 1)==0))
188194
{
189195
keylen = jwtcf->auth_jwt_key.len / 2;
@@ -218,6 +224,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
218224

219225
// validate the jwt
220226
jwtParseReturnCode = jwt_decode(&jwt, jwtCookieValChrPtr, keyBinary, keylen);
227+
221228
if (jwtParseReturnCode != 0)
222229
{
223230
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to parse jwt");
@@ -226,6 +233,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
226233

227234
// validate the algorithm
228235
alg = jwt_get_alg(jwt);
236+
229237
if (alg != JWT_ALG_HS256 && alg != JWT_ALG_RS256)
230238
{
231239
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid algorithm in jwt %d", alg);
@@ -235,45 +243,51 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
235243
// validate the exp date of the JWT
236244
exp = (time_t)jwt_get_grant_int(jwt, "exp");
237245
now = time(NULL);
246+
238247
if (exp < now)
239248
{
240249
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the jwt has expired");
241250
goto redirect;
242251
}
243252

244253
// extract the userid
245-
sub = jwt_get_grant(jwt, "sub");
246-
if (sub == NULL)
254+
if (jwtcf->auth_jwt_extract_sub == 1)
247255
{
248-
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the jwt does not contain a subject");
249-
}
250-
else
251-
{
252-
sub_t = ngx_char_ptr_to_str_t(r->pool, (char *)sub);
253-
set_custom_header_in_headers_out(r, &useridHeaderName, &sub_t);
256+
const char* sub = jwt_get_grant(jwt, "sub");
257+
258+
if (sub == NULL)
259+
{
260+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the jwt does not contain a subject");
261+
}
262+
else
263+
{
264+
ngx_str_t sub_t = ngx_char_ptr_to_str_t(r->pool, (char *)sub);
265+
266+
set_custom_header_in_headers_out(r, &useridHeaderName, &sub_t);
267+
}
254268
}
255269

256270
if (jwtcf->auth_jwt_validate_email == 1)
257271
{
258-
email = jwt_get_grant(jwt, "emailAddress");
272+
const char* email = jwt_get_grant(jwt, "emailAddress");
273+
259274
if (email == NULL)
260275
{
261276
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the jwt does not contain an email address");
262277
}
263278
else
264279
{
265-
email_t = ngx_char_ptr_to_str_t(r->pool, (char *)email);
280+
ngx_str_t email_t = ngx_char_ptr_to_str_t(r->pool, (char *)email);
281+
266282
set_custom_header_in_headers_out(r, &emailHeaderName, &email_t);
267283
}
268284
}
269285

270286
jwt_free(jwt);
271-
272287

273288
return NGX_OK;
274289

275290
redirect:
276-
277291
if (jwt)
278292
{
279293
jwt_free(jwt);
@@ -303,7 +317,6 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
303317
uintptr_t escaped_len;
304318

305319
loginlen = jwtcf->auth_jwt_loginurl.len;
306-
307320
scheme = (r->connection->ssl) ? "https" : "http";
308321
server = r->headers_in.server;
309322

@@ -318,15 +331,11 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
318331
uri.data = ngx_palloc(r->pool, request_uri_var->len);
319332
uri.len = request_uri_var->len;
320333
ngx_memcpy(uri.data, request_uri_var->data, request_uri_var->len);
321-
322-
// ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "found uri with querystring %s", ngx_str_t_to_char_ptr(r->pool, uri));
323334
}
324335
else
325336
{
326337
// fallback to the querystring without params
327338
uri = r->uri;
328-
329-
// ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "fallback to querystring without params");
330339
}
331340

332341
// escape the URI
@@ -350,8 +359,6 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
350359
ngx_memcpy(return_url+return_url_idx, uri_escaped.data, uri_escaped.len);
351360
return_url_idx += uri_escaped.len;
352361
r->headers_out.location->value.data = (u_char *)return_url;
353-
354-
// ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "return_url: %s", ngx_str_t_to_char_ptr(r->pool, r->headers_out.location->value));
355362
}
356363
else
357364
{
@@ -403,6 +410,7 @@ ngx_http_auth_jwt_create_loc_conf(ngx_conf_t *cf)
403410
// set the flag to unset
404411
conf->auth_jwt_enabled = (ngx_flag_t) -1;
405412
conf->auth_jwt_redirect = (ngx_flag_t) -1;
413+
conf->auth_jwt_extract_sub = (ngx_flag_t) -1;
406414
conf->auth_jwt_validate_email = (ngx_flag_t) -1;
407415
conf->auth_jwt_use_keyfile = (ngx_flag_t) -1;
408416

@@ -453,6 +461,7 @@ ngx_http_auth_jwt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
453461
ngx_conf_merge_str_value(conf->auth_jwt_validation_type, prev->auth_jwt_validation_type, "");
454462
ngx_conf_merge_str_value(conf->auth_jwt_algorithm, prev->auth_jwt_algorithm, "HS256");
455463
ngx_conf_merge_str_value(conf->auth_jwt_keyfile_path, prev->auth_jwt_keyfile_path, "");
464+
ngx_conf_merge_off_value(conf->auth_jwt_extract_sub, prev->auth_jwt_extract_sub, 1);
456465
ngx_conf_merge_off_value(conf->auth_jwt_validate_email, prev->auth_jwt_validate_email, 1);
457466

458467
if (conf->auth_jwt_enabled == ((ngx_flag_t) -1))

test.sh

+2-3
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ test_jwt () {
1111
local extra=$4
1212

1313
cmd="curl -X GET -o /dev/null --silent --head --write-out '%{http_code}' http://nginx:8000$path -H 'cache-control: no-cache' $extra"
14-
15-
1614
test=$( eval ${cmd} )
17-
if [ "$test" -eq "$expect" ];then
15+
16+
if [ "$test" -eq "$expect" ]; then
1817
echo -e "${GREEN}${name}: passed (${test})${NONE}";
1918
else
2019
echo -e "${RED}${name}: failed (${test})${NONE}";

0 commit comments

Comments
 (0)