@@ -26,7 +26,7 @@ typedef struct
2626{
2727 ngx_str_t loginurl ;
2828 ngx_str_t key ;
29- ngx_flag_t enabled ;
29+ ngx_http_complex_value_t * enabled ;
3030 ngx_flag_t redirect ;
3131 ngx_str_t jwt_location ;
3232 ngx_str_t algorithm ;
@@ -83,8 +83,8 @@ static ngx_command_t auth_jwt_directives[] = {
8383 NULL },
8484
8585 {ngx_string ("auth_jwt_enabled" ),
86- NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_FLAG ,
87- ngx_conf_set_flag_slot ,
86+ NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1 ,
87+ ngx_http_set_complex_value_slot ,
8888 NGX_HTTP_LOC_CONF_OFFSET ,
8989 offsetof(auth_jwt_conf_t , enabled ),
9090 NULL },
@@ -207,9 +207,7 @@ static void *create_conf(ngx_conf_t *cf)
207207 else
208208 {
209209 // ngx_str_t fields are initialized by the ngx_palloc call above -- only need to init flags and arrays here
210- conf -> enabled = NGX_CONF_UNSET ;
211- conf -> redirect = NGX_CONF_UNSET ;
212- conf -> validate_sub = NGX_CONF_UNSET ;
210+ conf -> enabled = NULL ;
213211 conf -> redirect = NGX_CONF_UNSET ;
214212 conf -> validate_sub = NGX_CONF_UNSET ;
215213 conf -> extract_var_claims = NULL ;
@@ -236,20 +234,12 @@ static char *merge_conf(ngx_conf_t *cf, void *parent, void *child)
236234 merge_array (cf -> pool , & conf -> extract_request_claims , prev -> extract_request_claims , sizeof (ngx_str_t ));
237235 merge_array (cf -> pool , & conf -> extract_response_claims , prev -> extract_response_claims , sizeof (ngx_str_t ));
238236
239- if (conf -> enabled == NGX_CONF_UNSET )
240- {
241- conf -> enabled = prev -> enabled == NGX_CONF_UNSET ? 0 : prev -> enabled ;
242- }
243-
244- if (conf -> redirect == NGX_CONF_UNSET )
245- {
246- conf -> redirect = prev -> redirect == NGX_CONF_UNSET ? 0 : prev -> redirect ;
237+ if (conf -> enabled == NULL ) {
238+ conf -> enabled = prev -> enabled ;
247239 }
248240
249- if (conf -> use_keyfile == NGX_CONF_UNSET )
250- {
251- conf -> use_keyfile = prev -> use_keyfile == NGX_CONF_UNSET ? 0 : prev -> use_keyfile ;
252- }
241+ ngx_conf_merge_off_value (conf -> redirect , prev -> redirect , 0 );
242+ ngx_conf_merge_off_value (conf -> use_keyfile , prev -> use_keyfile , 0 );
253243
254244 // If the usage of the keyfile is specified, check if the key_path is also configured
255245 if (conf -> use_keyfile == 1 )
@@ -461,109 +451,138 @@ static auth_jwt_ctx_t *get_or_init_jwt_module_ctx(ngx_http_request_t *r, auth_jw
461451static auth_jwt_ctx_t * get_request_jwt_ctx (ngx_http_request_t * r )
462452{
463453 auth_jwt_conf_t * jwtcf = ngx_http_get_module_loc_conf (r , ngx_http_auth_jwt_module );
454+ ngx_int_t enabled = 1 ;
464455
465- if (!jwtcf -> enabled )
466- {
467- return NULL ;
456+ if (jwtcf -> enabled != NULL ) {
457+ ngx_str_t cv ;
458+ if (ngx_http_complex_value (r , jwtcf -> enabled , & cv ) == NGX_OK && cv .len > 0 ) {
459+ if (ngx_strncmp (cv .data , "off" , 3 ) == 0 ) {
460+ enabled = 0 ;
461+ }
462+ }
468463 }
469464
470- auth_jwt_ctx_t * ctx = get_or_init_jwt_module_ctx (r , jwtcf );
471-
472- if (ctx == NULL )
473- {
465+ if (!enabled ) {
474466 return NULL ;
475467 }
476- else if (ctx -> validation_status != NGX_AGAIN )
477- {
478- // we already validated and extacted everything we care about, so we just return the already-complete context
479- return ctx ;
480- }
481-
482- char * jwtPtr = get_jwt (r , jwtcf -> jwt_location );
468+ else {
469+ auth_jwt_ctx_t * ctx = get_or_init_jwt_module_ctx (r , jwtcf );
483470
484- if (jwtPtr == NULL )
485- {
486- ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "failed to find a JWT" );
487- ctx -> validation_status = NGX_ERROR ;
488- return ctx ;
489- }
490- else
491- {
492- ngx_str_t algorithm = jwtcf -> algorithm ;
493- int keyLength ;
494- u_char * key ;
495- jwt_t * jwt = NULL ;
496-
497- if (algorithm .len == 0 || (algorithm .len == 5 && ngx_strncmp (algorithm .data , "HS" , 2 ) == 0 ))
471+ if (ctx == NULL ) {
472+ return NULL ;
473+ }
474+ else if (ctx -> validation_status != NGX_AGAIN )
498475 {
499- keyLength = jwtcf -> key .len / 2 ;
500- key = ngx_palloc (r -> pool , keyLength );
476+ // we already validated and extacted everything we care about, so we just return the already-complete context
477+ return ctx ;
478+ }
479+ else {
480+ char * jwtPtr = get_jwt (r , jwtcf -> jwt_location );
501481
502- if (0 != hex_to_binary (( char * ) jwtcf -> key . data , key , jwtcf -> key . len ) )
482+ if (jwtPtr == NULL )
503483 {
504- ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "failed to turn hex key into binary " );
484+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "failed to find a JWT " );
505485 ctx -> validation_status = NGX_ERROR ;
486+
506487 return ctx ;
507488 }
508- }
509- else if (algorithm .len == 5 && (ngx_strncmp (algorithm .data , "RS" , 2 ) == 0 || ngx_strncmp (algorithm .data , "ES" , 2 ) == 0 ))
510- {
511- if (jwtcf -> use_keyfile == 1 )
512- {
513- keyLength = jwtcf -> _keyfile .len ;
514- key = (u_char * )jwtcf -> _keyfile .data ;
515- }
516489 else
517490 {
518- keyLength = jwtcf -> key .len ;
519- key = jwtcf -> key .data ;
520- }
521- }
522- else
523- {
524- ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "unsupported algorithm %s" , algorithm );
525- ctx -> validation_status = NGX_ERROR ;
526- return ctx ;
527- }
491+ ngx_str_t algorithm = jwtcf -> algorithm ;
492+ int keyLength ;
493+ u_char * key ;
494+ jwt_t * jwt = NULL ;
528495
529- if (jwt_decode (& jwt , jwtPtr , key , keyLength ) != 0 || !jwt )
530- {
531- ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "failed to parse JWT" );
532- ctx -> validation_status = NGX_ERROR ;
533- }
534- else if (validate_alg (jwtcf , jwt ) != 0 )
535- {
536- ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "invalid algorithm specified" );
537- ctx -> validation_status = NGX_ERROR ;
538- }
539- else if (validate_exp (jwtcf , jwt ) != 0 )
540- {
541- ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "the JWT has expired" );
542- ctx -> validation_status = NGX_ERROR ;
543- }
544- else if (validate_sub (jwtcf , jwt ) != 0 )
545- {
546- ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "the JWT does not contain a subject" );
547- ctx -> validation_status = NGX_ERROR ;
548- }
549- else
550- {
551- extract_request_claims (r , jwtcf , jwt );
552- extract_response_claims (r , jwtcf , jwt );
553- ctx -> validation_status = extract_var_claims (r , jwtcf , jwt , ctx );
554- }
496+ if (algorithm .len == 0 || (algorithm .len == 5 && ngx_strncmp (algorithm .data , "HS" , 2 ) == 0 ))
497+ {
498+ keyLength = jwtcf -> key .len / 2 ;
499+ key = ngx_palloc (r -> pool , keyLength );
555500
556- jwt_free (jwt );
557- return ctx ;
501+ if (0 != hex_to_binary ((char * )jwtcf -> key .data , key , jwtcf -> key .len ))
502+ {
503+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "failed to turn hex key into binary" );
504+ ctx -> validation_status = NGX_ERROR ;
505+
506+ return ctx ;
507+ }
508+ }
509+ else if (algorithm .len == 5 && (ngx_strncmp (algorithm .data , "RS" , 2 ) == 0 || ngx_strncmp (algorithm .data , "ES" , 2 ) == 0 ))
510+ {
511+ if (jwtcf -> use_keyfile == 1 )
512+ {
513+ keyLength = jwtcf -> _keyfile .len ;
514+ key = (u_char * )jwtcf -> _keyfile .data ;
515+ }
516+ else
517+ {
518+ keyLength = jwtcf -> key .len ;
519+ key = jwtcf -> key .data ;
520+ }
521+ }
522+ else
523+ {
524+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "unsupported algorithm %s" , algorithm );
525+ ctx -> validation_status = NGX_ERROR ;
526+
527+ return ctx ;
528+ }
529+
530+ if (jwt_decode (& jwt , jwtPtr , key , keyLength ) != 0 || !jwt )
531+ {
532+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "failed to parse JWT" );
533+ ctx -> validation_status = NGX_ERROR ;
534+ }
535+ else if (validate_alg (jwtcf , jwt ) != 0 )
536+ {
537+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "invalid algorithm specified" );
538+ ctx -> validation_status = NGX_ERROR ;
539+ }
540+ else if (validate_exp (jwtcf , jwt ) != 0 )
541+ {
542+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "the JWT has expired" );
543+ ctx -> validation_status = NGX_ERROR ;
544+ }
545+ else if (validate_sub (jwtcf , jwt ) != 0 )
546+ {
547+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "the JWT does not contain a subject" );
548+ ctx -> validation_status = NGX_ERROR ;
549+ }
550+ else
551+ {
552+ extract_request_claims (r , jwtcf , jwt );
553+ extract_response_claims (r , jwtcf , jwt );
554+ ctx -> validation_status = extract_var_claims (r , jwtcf , jwt , ctx );
555+ }
556+
557+ jwt_free (jwt );
558+
559+ return ctx ;
560+ }
561+ }
558562 }
559563}
560564
561565static ngx_int_t handle_request (ngx_http_request_t * r )
562566{
563567 auth_jwt_conf_t * jwtcf = ngx_http_get_module_loc_conf (r , ngx_http_auth_jwt_module );
568+
569+ // Only activate JWT logic if key or keyfile_path is set
570+ if (jwtcf -> key .len == 0 && jwtcf -> keyfile_path .len == 0 ) {
571+ return NGX_DECLINED ;
572+ }
573+
564574 auth_jwt_ctx_t * ctx = get_request_jwt_ctx (r );
565575
566- if (!jwtcf -> enabled )
576+ ngx_int_t enabled = 1 ;
577+ if (jwtcf -> enabled != NULL ) {
578+ ngx_str_t cv ;
579+ if (ngx_http_complex_value (r , jwtcf -> enabled , & cv ) == NGX_OK && cv .len > 0 ) {
580+ if (ngx_strncmp (cv .data , "off" , 3 ) == 0 ) {
581+ enabled = 0 ;
582+ }
583+ }
584+ }
585+ if (!enabled )
567586 {
568587 return NGX_DECLINED ;
569588 }
0 commit comments