From 4f71fc3b17c1fbe6b3c7a734506bfc9eb2e5456d Mon Sep 17 00:00:00 2001 From: Tim Underhay Date: Tue, 17 Apr 2018 10:16:10 -0600 Subject: [PATCH 01/16] First stab at RSA validation. --- src/ngx_http_auth_jwt_module.c | 35 ++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index d217cf5..eb50aa7 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -24,6 +24,7 @@ typedef struct { ngx_flag_t auth_jwt_enabled; ngx_flag_t auth_jwt_redirect; ngx_str_t auth_jwt_validation_type; + ngx_str_t auth_jwt_algorithm; } ngx_http_auth_jwt_loc_conf_t; @@ -70,6 +71,13 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = { offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_validation_type), NULL }, + { ngx_string("auth_jwt_algorithm"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_algorithm), + NULL }, + ngx_null_command }; @@ -122,6 +130,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) ngx_str_t email_t; time_t exp; time_t now; + ngx_str_t auth_jwt_algorithm; jwtcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_jwt_module); @@ -137,15 +146,29 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) goto redirect; } - // convert key from hex to binary - keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len / 2); - if (0 != hex_to_binary((char *)jwtcf->auth_jwt_key.data, keyBinary, jwtcf->auth_jwt_key.len)) + // convert key from hex to binary, if a symmetric key + + auth_jwt_algorithm = jwtcf->auth_jwt_algorithm; + if (auth_jwt_algorithm.len == 0 || (auth_jwt_algorithm.len == sizeof("HS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "HS256", sizeof("HS256") - 1)==0)) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to turn hex key into binary"); - goto redirect; + ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "got to 0"); + keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len / 2); + if (0 != hex_to_binary((char *)jwtcf->auth_jwt_key.data, keyBinary, jwtcf->auth_jwt_key.len)) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to turn hex key into binary"); + goto redirect; + } + } + else if ( auth_jwt_algorithm.len == sizeof("RS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "RS256", sizeof("RS256") - 1) == 0) ) + { + // in this case, 'Binary' is a misnomer, as it is the private key string itself + ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "got to 1"); + keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len); + ngx_str_set(keyBinary, auth_jwt_key.data); } // validate the jwt + ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "trying to decode JWT"); jwtParseReturnCode = jwt_decode(&jwt, jwtCookieValChrPtr, keyBinary, jwtcf->auth_jwt_key.len / 2); if (jwtParseReturnCode != 0) { @@ -155,7 +178,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) // validate the algorithm alg = jwt_get_alg(jwt); - if (alg != JWT_ALG_HS256) + if (alg != JWT_ALG_HS256 && alg != JWT_ALG_RS256) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid algorithm in jwt %d", alg); goto redirect; From 447273bc3f2638432b793ea2cad3662726d481e1 Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 10:54:11 -0600 Subject: [PATCH 02/16] Fix for build errors --- src/ngx_http_auth_jwt_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index eb50aa7..26186ad 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -159,7 +159,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) goto redirect; } } - else if ( auth_jwt_algorithm.len == sizeof("RS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "RS256", sizeof("RS256") - 1) == 0) ) + else if ( auth_jwt_algorithm.len == sizeof("RS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "RS256", sizeof("RS256") - 1) == 0 ) { // in this case, 'Binary' is a misnomer, as it is the private key string itself ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "got to 1"); From acc223656f9bd763264772f9b6c9b355fc64bbce Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 10:55:03 -0600 Subject: [PATCH 03/16] Another build fix --- src/ngx_http_auth_jwt_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index 26186ad..9d1f292 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -164,7 +164,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) // in this case, 'Binary' is a misnomer, as it is the private key string itself ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "got to 1"); keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len); - ngx_str_set(keyBinary, auth_jwt_key.data); + ngx_str_set(keyBinary, jwtcf->auth_jwt_key.data); } // validate the jwt From ae738ddc11adf423fb04f9dd734c2135e6361f3c Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 11:29:19 -0600 Subject: [PATCH 04/16] Fix for key copy --- src/ngx_http_auth_jwt_module.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index 9d1f292..6812482 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -164,7 +164,8 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) // in this case, 'Binary' is a misnomer, as it is the private key string itself ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "got to 1"); keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len); - ngx_str_set(keyBinary, jwtcf->auth_jwt_key.data); + ngx_memcpy(keyBinary, jwtcf->auth_jwt_key.data, jwtcf->auth_jwt_key.len); + } // validate the jwt From 453cb7566609b9f8c14f1be7c07e88ef3759114c Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 12:09:41 -0600 Subject: [PATCH 05/16] Key length fix --- src/ngx_http_auth_jwt_module.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index 6812482..33e0622 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -131,6 +131,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) time_t exp; time_t now; ngx_str_t auth_jwt_algorithm; + int keylen; jwtcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_jwt_module); @@ -151,8 +152,9 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) auth_jwt_algorithm = jwtcf->auth_jwt_algorithm; if (auth_jwt_algorithm.len == 0 || (auth_jwt_algorithm.len == sizeof("HS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "HS256", sizeof("HS256") - 1)==0)) { - ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "got to 0"); - keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len / 2); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "got to 0"); + keylen = jwtcf->auth_jwt_key.len / 2; + keyBinary = ngx_palloc(r->pool, keylen); if (0 != hex_to_binary((char *)jwtcf->auth_jwt_key.data, keyBinary, jwtcf->auth_jwt_key.len)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to turn hex key into binary"); @@ -162,15 +164,16 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) else if ( auth_jwt_algorithm.len == sizeof("RS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "RS256", sizeof("RS256") - 1) == 0 ) { // in this case, 'Binary' is a misnomer, as it is the private key string itself - ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "got to 1"); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "got to 1"); keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len); ngx_memcpy(keyBinary, jwtcf->auth_jwt_key.data, jwtcf->auth_jwt_key.len); - + keylen = jwtcf->auth_jwt_key.len; } // validate the jwt - ngx_log_debug(NGX_LOG_DEBUG, r->connection->log, 0, "trying to decode JWT"); - jwtParseReturnCode = jwt_decode(&jwt, jwtCookieValChrPtr, keyBinary, jwtcf->auth_jwt_key.len / 2); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "trying to decode JWT"); + jwtParseReturnCode = jwt_decode(&jwt, jwtCookieValChrPtr, keyBinary, keylen); + if (jwtParseReturnCode != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to parse jwt"); From 78126e654bc2447dd8c28c88d48432e9a7342f6d Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 12:26:32 -0600 Subject: [PATCH 06/16] Logging --- src/ngx_http_auth_jwt_module.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index 33e0622..fc1c482 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -152,7 +152,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) auth_jwt_algorithm = jwtcf->auth_jwt_algorithm; if (auth_jwt_algorithm.len == 0 || (auth_jwt_algorithm.len == sizeof("HS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "HS256", sizeof("HS256") - 1)==0)) { - ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "got to 0"); + ngx_log_error(NGX_LOG_ERROR, r->connection->log, 0, "got to 0"); keylen = jwtcf->auth_jwt_key.len / 2; keyBinary = ngx_palloc(r->pool, keylen); if (0 != hex_to_binary((char *)jwtcf->auth_jwt_key.data, keyBinary, jwtcf->auth_jwt_key.len)) @@ -164,14 +164,14 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) else if ( auth_jwt_algorithm.len == sizeof("RS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "RS256", sizeof("RS256") - 1) == 0 ) { // in this case, 'Binary' is a misnomer, as it is the private key string itself - ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "got to 1"); + ngx_log_error(NGX_LOG_ERROR, r->connection->log, 0, "got to 1"); keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len); ngx_memcpy(keyBinary, jwtcf->auth_jwt_key.data, jwtcf->auth_jwt_key.len); keylen = jwtcf->auth_jwt_key.len; } // validate the jwt - ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "trying to decode JWT"); + ngx_log_error(NGX_LOG_ERROR, r->connection->log, 0, "trying to decode JWT"); jwtParseReturnCode = jwt_decode(&jwt, jwtCookieValChrPtr, keyBinary, keylen); if (jwtParseReturnCode != 0) From 4d8f9211400a00675d657694e1cf189875682c42 Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 12:37:37 -0600 Subject: [PATCH 07/16] Logging fix --- src/ngx_http_auth_jwt_module.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index fc1c482..dbd8d54 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -152,7 +152,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) auth_jwt_algorithm = jwtcf->auth_jwt_algorithm; if (auth_jwt_algorithm.len == 0 || (auth_jwt_algorithm.len == sizeof("HS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "HS256", sizeof("HS256") - 1)==0)) { - ngx_log_error(NGX_LOG_ERROR, r->connection->log, 0, "got to 0"); + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "got to 0"); keylen = jwtcf->auth_jwt_key.len / 2; keyBinary = ngx_palloc(r->pool, keylen); if (0 != hex_to_binary((char *)jwtcf->auth_jwt_key.data, keyBinary, jwtcf->auth_jwt_key.len)) @@ -164,14 +164,14 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) else if ( auth_jwt_algorithm.len == sizeof("RS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "RS256", sizeof("RS256") - 1) == 0 ) { // in this case, 'Binary' is a misnomer, as it is the private key string itself - ngx_log_error(NGX_LOG_ERROR, r->connection->log, 0, "got to 1"); + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "got to 1"); keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len); ngx_memcpy(keyBinary, jwtcf->auth_jwt_key.data, jwtcf->auth_jwt_key.len); keylen = jwtcf->auth_jwt_key.len; } // validate the jwt - ngx_log_error(NGX_LOG_ERROR, r->connection->log, 0, "trying to decode JWT"); + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "trying to decode JWT"); jwtParseReturnCode = jwt_decode(&jwt, jwtCookieValChrPtr, keyBinary, keylen); if (jwtParseReturnCode != 0) From 82cd5dea961623e37d9a3aa659b3a1245ca22ea8 Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 13:10:40 -0600 Subject: [PATCH 08/16] Remove debug logs. Make validation of email optional with auth_jwt_validate_email --- src/ngx_http_auth_jwt_module.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index dbd8d54..dc62c96 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -25,6 +25,7 @@ typedef struct { ngx_flag_t auth_jwt_redirect; ngx_str_t auth_jwt_validation_type; ngx_str_t auth_jwt_algorithm; + ngx_flag_t auth_jwt_validate_email; } ngx_http_auth_jwt_loc_conf_t; @@ -78,6 +79,13 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = { offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_algorithm), NULL }, + { ngx_string("auth_jwt_validate_email"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_validate_email), + NULL }, + ngx_null_command }; @@ -152,7 +160,6 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) auth_jwt_algorithm = jwtcf->auth_jwt_algorithm; if (auth_jwt_algorithm.len == 0 || (auth_jwt_algorithm.len == sizeof("HS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "HS256", sizeof("HS256") - 1)==0)) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "got to 0"); keylen = jwtcf->auth_jwt_key.len / 2; keyBinary = ngx_palloc(r->pool, keylen); if (0 != hex_to_binary((char *)jwtcf->auth_jwt_key.data, keyBinary, jwtcf->auth_jwt_key.len)) @@ -163,17 +170,14 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) } else if ( auth_jwt_algorithm.len == sizeof("RS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "RS256", sizeof("RS256") - 1) == 0 ) { - // in this case, 'Binary' is a misnomer, as it is the private key string itself - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "got to 1"); + // in this case, 'Binary' is a misnomer, as it is the public key string itself keyBinary = ngx_palloc(r->pool, jwtcf->auth_jwt_key.len); ngx_memcpy(keyBinary, jwtcf->auth_jwt_key.data, jwtcf->auth_jwt_key.len); keylen = jwtcf->auth_jwt_key.len; } // validate the jwt - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "trying to decode JWT"); jwtParseReturnCode = jwt_decode(&jwt, jwtCookieValChrPtr, keyBinary, keylen); - if (jwtParseReturnCode != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to parse jwt"); @@ -209,15 +213,18 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) set_custom_header_in_headers_out(r, &useridHeaderName, &sub_t); } - email = jwt_get_grant(jwt, "emailAddress"); - if (email == NULL) - { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the jwt does not contain an email address"); - } - else + if (jwtcf->auth_jwt_validate_email == NULL || !jwtcf->auth_jwt_validate_email) { - email_t = ngx_char_ptr_to_str_t(r->pool, (char *)email); - set_custom_header_in_headers_out(r, &emailHeaderName, &email_t); + email = jwt_get_grant(jwt, "emailAddress"); + if (email == NULL) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the jwt does not contain an email address"); + } + else + { + email_t = ngx_char_ptr_to_str_t(r->pool, (char *)email); + set_custom_header_in_headers_out(r, &emailHeaderName, &email_t); + } } return NGX_OK; From a71fc75ec1dd76a1ee91a0d4e1964b1c4bd99137 Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 13:22:52 -0600 Subject: [PATCH 09/16] Fix for email validation option, now auth_jwt_email_validation --- src/ngx_http_auth_jwt_module.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index dc62c96..a74809a 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -23,9 +23,9 @@ typedef struct { ngx_str_t auth_jwt_key; ngx_flag_t auth_jwt_enabled; ngx_flag_t auth_jwt_redirect; + ngx_flag_t auth_jwt_email_validation; ngx_str_t auth_jwt_validation_type; ngx_str_t auth_jwt_algorithm; - ngx_flag_t auth_jwt_validate_email; } ngx_http_auth_jwt_loc_conf_t; @@ -65,6 +65,13 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = { offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_redirect), NULL }, + { ngx_string("auth_jwt_email_validation"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_email_validation), + NULL }, + { ngx_string("auth_jwt_validation_type"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -79,13 +86,6 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = { offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_algorithm), NULL }, - { ngx_string("auth_jwt_validate_email"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_validate_email), - NULL }, - ngx_null_command }; @@ -213,7 +213,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) set_custom_header_in_headers_out(r, &useridHeaderName, &sub_t); } - if (jwtcf->auth_jwt_validate_email == NULL || !jwtcf->auth_jwt_validate_email) + if (jwtcf->auth_jwt_email_validation == NULL || !jwtcf->auth_jwt_email_validation) { email = jwt_get_grant(jwt, "emailAddress"); if (email == NULL) From 98b748b9a5e68973997399c1428ff52fc60aa83c Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 13:45:32 -0600 Subject: [PATCH 10/16] Changed back to auth_jwt_validate_email and additional conf merging code --- src/ngx_http_auth_jwt_module.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index a74809a..235d04b 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -23,7 +23,7 @@ typedef struct { ngx_str_t auth_jwt_key; ngx_flag_t auth_jwt_enabled; ngx_flag_t auth_jwt_redirect; - ngx_flag_t auth_jwt_email_validation; + ngx_flag_t auth_jwt_validate_email; ngx_str_t auth_jwt_validation_type; ngx_str_t auth_jwt_algorithm; @@ -65,11 +65,11 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = { offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_redirect), NULL }, - { ngx_string("auth_jwt_email_validation"), + { ngx_string("auth_jwt_validate_email"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_email_validation), + offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_validate_email), NULL }, { ngx_string("auth_jwt_validation_type"), @@ -213,7 +213,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) set_custom_header_in_headers_out(r, &useridHeaderName, &sub_t); } - if (jwtcf->auth_jwt_email_validation == NULL || !jwtcf->auth_jwt_email_validation) + if (jwtcf->auth_jwt_validate_email == NULL || !jwtcf->auth_jwt_validate_email) { email = jwt_get_grant(jwt, "emailAddress"); if (email == NULL) @@ -355,6 +355,7 @@ ngx_http_auth_jwt_create_loc_conf(ngx_conf_t *cf) // set the flag to unset conf->auth_jwt_enabled = (ngx_flag_t) -1; conf->auth_jwt_redirect = (ngx_flag_t) -1; + conf->auth_jwt_validate_email = (ngx_flag_t) -1; ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "Created Location Configuration"); @@ -371,6 +372,7 @@ ngx_http_auth_jwt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->auth_jwt_loginurl, prev->auth_jwt_loginurl, ""); ngx_conf_merge_str_value(conf->auth_jwt_key, prev->auth_jwt_key, ""); ngx_conf_merge_str_value(conf->auth_jwt_validation_type, prev->auth_jwt_validation_type, ""); + ngx_conf_merge_str_value(conf->auth_jwt_algorithm, prev->auth_jwt_algorithm, ""); if (conf->auth_jwt_enabled == ((ngx_flag_t) -1)) { @@ -382,6 +384,11 @@ ngx_http_auth_jwt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->auth_jwt_redirect = (prev->auth_jwt_redirect == ((ngx_flag_t) -1)) ? 0 : prev->auth_jwt_redirect; } + if (conf->auth_jwt_validate_email == ((ngx_flag_t) -1)) + { + conf->auth_jwt_validate_email = (prev->auth_jwt_validate_email == ((ngx_flag_t) -1)) ? 0 : prev->auth_jwt_validate_email; + } + return NGX_CONF_OK; } From 11b80d593353d82b12886499947dae11d77f11c3 Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 13:50:02 -0600 Subject: [PATCH 11/16] One more email validation fix --- src/ngx_http_auth_jwt_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index 235d04b..96bfdee 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -213,7 +213,7 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) set_custom_header_in_headers_out(r, &useridHeaderName, &sub_t); } - if (jwtcf->auth_jwt_validate_email == NULL || !jwtcf->auth_jwt_validate_email) + if (jwtcf->auth_jwt_validate_email == NULL || jwtcf->auth_jwt_validate_email) { email = jwt_get_grant(jwt, "emailAddress"); if (email == NULL) From 62929e8e1dc05aa84da7a36bc85e7d49ec3b1760 Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 14:19:55 -0600 Subject: [PATCH 12/16] More fixes to email validate --- src/ngx_http_auth_jwt_module.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index 96bfdee..f2650fd 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -213,7 +213,8 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) set_custom_header_in_headers_out(r, &useridHeaderName, &sub_t); } - if (jwtcf->auth_jwt_validate_email == NULL || jwtcf->auth_jwt_validate_email) + // if (jwtcf->auth_jwt_validate_email == NULL || jwtcf->auth_jwt_validate_email == 1) + if (jwtcf->auth_jwt_validate_email == 1) { email = jwt_get_grant(jwt, "emailAddress"); if (email == NULL) @@ -355,7 +356,7 @@ ngx_http_auth_jwt_create_loc_conf(ngx_conf_t *cf) // set the flag to unset conf->auth_jwt_enabled = (ngx_flag_t) -1; conf->auth_jwt_redirect = (ngx_flag_t) -1; - conf->auth_jwt_validate_email = (ngx_flag_t) -1; + // conf->auth_jwt_validate_email = (ngx_flag_t) -1; ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "Created Location Configuration"); @@ -372,7 +373,8 @@ ngx_http_auth_jwt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->auth_jwt_loginurl, prev->auth_jwt_loginurl, ""); ngx_conf_merge_str_value(conf->auth_jwt_key, prev->auth_jwt_key, ""); ngx_conf_merge_str_value(conf->auth_jwt_validation_type, prev->auth_jwt_validation_type, ""); - ngx_conf_merge_str_value(conf->auth_jwt_algorithm, prev->auth_jwt_algorithm, ""); + ngx_conf_merge_str_value(conf->auth_jwt_algorithm, prev->auth_jwt_algorithm, "HS256"); + ngx_conf_merge_off_value(conf->auth_jwt_validate_email, prev->auth_jwt_validate_email, 1); if (conf->auth_jwt_enabled == ((ngx_flag_t) -1)) { @@ -384,11 +386,6 @@ ngx_http_auth_jwt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->auth_jwt_redirect = (prev->auth_jwt_redirect == ((ngx_flag_t) -1)) ? 0 : prev->auth_jwt_redirect; } - if (conf->auth_jwt_validate_email == ((ngx_flag_t) -1)) - { - conf->auth_jwt_validate_email = (prev->auth_jwt_validate_email == ((ngx_flag_t) -1)) ? 0 : prev->auth_jwt_validate_email; - } - return NGX_CONF_OK; } From 89d9830bc373397b91ca0557e5d08af152375d8f Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 14:23:46 -0600 Subject: [PATCH 13/16] Another fix --- src/ngx_http_auth_jwt_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index f2650fd..1ee7fed 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -356,7 +356,7 @@ ngx_http_auth_jwt_create_loc_conf(ngx_conf_t *cf) // set the flag to unset conf->auth_jwt_enabled = (ngx_flag_t) -1; conf->auth_jwt_redirect = (ngx_flag_t) -1; - // conf->auth_jwt_validate_email = (ngx_flag_t) -1; + conf->auth_jwt_validate_email = (ngx_flag_t) -1; ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "Created Location Configuration"); From da07bc2d8554c53245055af72406e17da913c799 Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 15:35:49 -0600 Subject: [PATCH 14/16] Set getJwt logs to NGX_LOG_DEBUG --- src/ngx_http_auth_jwt_module.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index 1ee7fed..f68d034 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -398,7 +398,7 @@ static char * getJwt(ngx_http_request_t *r, ngx_str_t auth_jwt_validation_type) ngx_int_t n; ngx_str_t authorizationHeaderStr; - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "auth_jwt_validation_type.len %d", auth_jwt_validation_type.len); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "auth_jwt_validation_type.len %d", auth_jwt_validation_type.len); if (auth_jwt_validation_type.len == 0 || (auth_jwt_validation_type.len == sizeof("AUTHORIZATION") - 1 && ngx_strncmp(auth_jwt_validation_type.data, "AUTHORIZATION", sizeof("AUTHORIZATION") - 1)==0)) { @@ -406,14 +406,14 @@ static char * getJwt(ngx_http_request_t *r, ngx_str_t auth_jwt_validation_type) authorizationHeader = search_headers_in(r, authorizationHeaderName.data, authorizationHeaderName.len); if (authorizationHeader != NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Found authorization header len %d", authorizationHeader->value.len); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Found authorization header len %d", authorizationHeader->value.len); authorizationHeaderStr.data = authorizationHeader->value.data + sizeof("Bearer ") - 1; authorizationHeaderStr.len = authorizationHeader->value.len - (sizeof("Bearer ") - 1); jwtCookieValChrPtr = ngx_str_t_to_char_ptr(r->pool, authorizationHeaderStr); - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Authorization header: %s", jwtCookieValChrPtr); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Authorization header: %s", jwtCookieValChrPtr); } } else if (auth_jwt_validation_type.len > sizeof("COOKIE=") && ngx_strncmp(auth_jwt_validation_type.data, "COOKIE=", sizeof("COOKIE=") - 1)==0) From 4822be39285191ae677cfdecc4df0b8ad0196508 Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Tue, 17 Apr 2018 15:54:44 -0600 Subject: [PATCH 15/16] Updated README. Rearranged some code. --- README.md | 30 ++++++++++++++++++++++++++++++ src/ngx_http_auth_jwt_module.c | 17 ++++++++--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7e07429..7de9088 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ This module requires several new nginx.conf directives, which can be specified i auth_jwt_key "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF"; auth_jwt_loginurl "https://yourdomain.com/loginpage"; auth_jwt_enabled on; +auth_jwt_algorithm HS256; # or RS256 +auth_jwt_validate_email on; # or off ``` So, a typical use would be to specify the key and loginurl on the main level and then only turn on the locations that you want to secure (not the login page). Unauthorized requests are given 302 "Moved Temporarily" responses with a location of the specified loginurl. @@ -28,6 +30,34 @@ auth_jwt_validation_type COOKIE=rampartjwt; ``` By default the authorization header is used to provide a JWT for validation. However, you may use the `auth_jwt_validation_type` configuration to specify the name of a cookie that provides the JWT. + + +The default algorithm is 'HS256', for symmetric key validation. Also supported is 'RS256', for RSA 256-bit public key validation. + +If using "auth_jwt_algorithm RS256;", then the 'auth_jwt_key' field must be set to your public key. That is the public key, rather than a PEM certificate. I.e.: + +``` +auth_jwt_key "-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0aPPpS7ufs0bGbW9+OFQ +RvJwb58fhi2BuHMd7Ys6m8D1jHW/AhDYrYVZtUnA60lxwSJ/ZKreYOQMlNyZfdqA +rhYyyUkedDn8e0WsDvH+ocY0cMcxCCN5jItCwhIbIkTO6WEGrDgWTY57UfWDqbMZ +4lMn42f77OKFoxsOA6CVvpsvrprBPIRPa25H2bJHODHEtDr/H519Y681/eCyeQE/ +1ibKL2cMN49O7nRAAaUNoFcO89Uc+GKofcad1TTwtTIwmSMbCLVkzGeExBCrBTQo +wO6AxLijfWV/JnVxNMUiobiKGc/PP6T5PI70Uv67Y4FzzWTuhqmREb3/BlcbPwtM +oQIDAQAB +-----END PUBLIC KEY-----"; +``` + + + +By default, the module will attempt to validate the email address field of the JWT, then set the x-email header of the session, and will log an error if it isn't found. To disable this behavior, for instance if you are using a different user identifier property such as 'sub', set: + +``` +auth_jwt_validate_email off; +``` + + + The Dockerfile builds all of the dependencies as well as the module, downloads a binary version of nginx, and runs the module as a dynamic module. Have a look at build.sh, which creates the docker image and container and executes some test requests to illustrate that some pages are secured by the module and requre a valid JWT. diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index f68d034..ae0ea82 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -23,9 +23,9 @@ typedef struct { ngx_str_t auth_jwt_key; ngx_flag_t auth_jwt_enabled; ngx_flag_t auth_jwt_redirect; - ngx_flag_t auth_jwt_validate_email; ngx_str_t auth_jwt_validation_type; ngx_str_t auth_jwt_algorithm; + ngx_flag_t auth_jwt_validate_email; } ngx_http_auth_jwt_loc_conf_t; @@ -65,13 +65,6 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = { offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_redirect), NULL }, - { ngx_string("auth_jwt_validate_email"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_validate_email), - NULL }, - { ngx_string("auth_jwt_validation_type"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -86,6 +79,13 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = { offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_algorithm), NULL }, + { ngx_string("auth_jwt_validate_email"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_auth_jwt_loc_conf_t, auth_jwt_validate_email), + NULL }, + ngx_null_command }; @@ -213,7 +213,6 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) set_custom_header_in_headers_out(r, &useridHeaderName, &sub_t); } - // if (jwtcf->auth_jwt_validate_email == NULL || jwtcf->auth_jwt_validate_email == 1) if (jwtcf->auth_jwt_validate_email == 1) { email = jwt_get_grant(jwt, "emailAddress"); From f054f11eb46476bdeda7875d65d18916810b048b Mon Sep 17 00:00:00 2001 From: Tim Underhay <15734900+citizentim@users.noreply.github.com> Date: Thu, 19 Apr 2018 16:53:53 -0600 Subject: [PATCH 16/16] Added else error condition to avert compiler warning. --- src/ngx_http_auth_jwt_module.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ngx_http_auth_jwt_module.c b/src/ngx_http_auth_jwt_module.c index ae0ea82..b64c12b 100644 --- a/src/ngx_http_auth_jwt_module.c +++ b/src/ngx_http_auth_jwt_module.c @@ -175,6 +175,11 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r) ngx_memcpy(keyBinary, jwtcf->auth_jwt_key.data, jwtcf->auth_jwt_key.len); keylen = jwtcf->auth_jwt_key.len; } + else + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unsupported algorithm"); + goto redirect; + } // validate the jwt jwtParseReturnCode = jwt_decode(&jwt, jwtCookieValChrPtr, keyBinary, keylen);