1
1
/*
2
2
* Tesla Government
3
3
* @author joefitz
4
+ *
5
+ * To compile you may need to export paths to include openssl:
6
+ *
7
+ * export LIBRARY_PATH=/usr/local/Cellar/openssl/1.0.2j/include
8
+ * export LD_LIBRARY_PATH=/usr/local/Cellar/openssl/1.0.2j/include
9
+ * export C_INCLUDE_PATH=/usr/local/Cellar/openssl/1.0.2j/include
4
10
*/
5
11
6
12
#include <ngx_config.h>
10
16
11
17
#include <jansson.h>
12
18
19
+ #define TOKEN_PERIOD_MINUTES 20
20
+
13
21
typedef struct {
14
22
ngx_str_t auth_jwt_loginurl ;
15
23
ngx_str_t auth_jwt_key ;
16
24
ngx_flag_t auth_jwt_enabled ;
25
+ ngx_str_t auth_jwt_cookie_name ;
26
+ ngx_str_t auth_jwt_cookie_legacy_name ;
27
+ ngx_flag_t auth_jwt_cookie_reissue_enabled ;
28
+ ngx_str_t auth_jwt_cookie_reissue_domain ;
29
+ ngx_flag_t auth_jwt_cookie_reissue_secure ;
30
+ ngx_flag_t auth_jwt_cookie_reissue_httponly ;
31
+
17
32
} ngx_http_auth_jwt_loc_conf_t ;
18
33
19
34
static ngx_int_t ngx_http_auth_jwt_init (ngx_conf_t * cf );
@@ -38,15 +53,57 @@ static ngx_command_t ngx_http_auth_jwt_commands[] = {
38
53
NGX_HTTP_LOC_CONF_OFFSET ,
39
54
offsetof(ngx_http_auth_jwt_loc_conf_t , auth_jwt_key ),
40
55
NULL },
41
-
56
+
42
57
{ ngx_string ("auth_jwt_enabled" ),
43
58
NGX_HTTP_MAIN_CONF |NGX_HTTP_SRV_CONF |NGX_HTTP_LOC_CONF |NGX_CONF_FLAG ,
44
59
ngx_conf_set_flag_slot ,
45
60
NGX_HTTP_LOC_CONF_OFFSET ,
46
61
offsetof(ngx_http_auth_jwt_loc_conf_t , auth_jwt_enabled ),
47
62
NULL },
48
63
49
- ngx_null_command
64
+ { ngx_string ("auth_jwt_cookie_name" ),
65
+ NGX_HTTP_MAIN_CONF |NGX_HTTP_SRV_CONF |NGX_HTTP_LOC_CONF |NGX_CONF_TAKE1 ,
66
+ ngx_conf_set_str_slot ,
67
+ NGX_HTTP_LOC_CONF_OFFSET ,
68
+ offsetof(ngx_http_auth_jwt_loc_conf_t , auth_jwt_cookie_name ),
69
+ NULL },
70
+
71
+ { ngx_string ("auth_jwt_cookie_legacy_name" ),
72
+ NGX_HTTP_MAIN_CONF |NGX_HTTP_SRV_CONF |NGX_HTTP_LOC_CONF |NGX_CONF_TAKE1 ,
73
+ ngx_conf_set_str_slot ,
74
+ NGX_HTTP_LOC_CONF_OFFSET ,
75
+ offsetof(ngx_http_auth_jwt_loc_conf_t , auth_jwt_cookie_legacy_name ),
76
+ NULL },
77
+
78
+ { ngx_string ("auth_jwt_cookie_reissue_enabled" ),
79
+ NGX_HTTP_MAIN_CONF |NGX_HTTP_SRV_CONF |NGX_HTTP_LOC_CONF |NGX_CONF_FLAG ,
80
+ ngx_conf_set_flag_slot ,
81
+ NGX_HTTP_LOC_CONF_OFFSET ,
82
+ offsetof(ngx_http_auth_jwt_loc_conf_t , auth_jwt_cookie_reissue_enabled ),
83
+ NULL },
84
+
85
+ { ngx_string ("auth_jwt_cookie_reissue_domain" ),
86
+ NGX_HTTP_MAIN_CONF |NGX_HTTP_SRV_CONF |NGX_HTTP_LOC_CONF |NGX_CONF_TAKE1 ,
87
+ ngx_conf_set_str_slot ,
88
+ NGX_HTTP_LOC_CONF_OFFSET ,
89
+ offsetof(ngx_http_auth_jwt_loc_conf_t , auth_jwt_cookie_reissue_domain ),
90
+ NULL },
91
+
92
+ { ngx_string ("auth_jwt_cookie_reissue_secure" ),
93
+ NGX_HTTP_MAIN_CONF |NGX_HTTP_SRV_CONF |NGX_HTTP_LOC_CONF |NGX_CONF_FLAG ,
94
+ ngx_conf_set_flag_slot ,
95
+ NGX_HTTP_LOC_CONF_OFFSET ,
96
+ offsetof(ngx_http_auth_jwt_loc_conf_t , auth_jwt_cookie_reissue_secure ),
97
+ NULL },
98
+
99
+ { ngx_string ("auth_jwt_cookie_reissue_httponly" ),
100
+ NGX_HTTP_MAIN_CONF |NGX_HTTP_SRV_CONF |NGX_HTTP_LOC_CONF |NGX_CONF_FLAG ,
101
+ ngx_conf_set_flag_slot ,
102
+ NGX_HTTP_LOC_CONF_OFFSET ,
103
+ offsetof(ngx_http_auth_jwt_loc_conf_t , auth_jwt_cookie_reissue_httponly ),
104
+ NULL },
105
+
106
+ ngx_null_command
50
107
};
51
108
52
109
@@ -84,19 +141,20 @@ ngx_module_t ngx_http_auth_jwt_module = {
84
141
static ngx_int_t ngx_http_auth_jwt_handler (ngx_http_request_t * r )
85
142
{
86
143
ngx_int_t n ;
87
- ngx_str_t jwtCookieName = ngx_string ("rampartjwt" );
88
- ngx_str_t passportKeyCookieName = ngx_string ("PassportKey" );
144
+ // ngx_str_t jwtCookieName = ngx_string("rampartjwt");
145
+ // ngx_str_t passportKeyCookieName = ngx_string("PassportKey");
89
146
ngx_str_t jwtCookieVal ;
90
147
char * jwtCookieValChrPtr ;
91
148
char * return_url ;
92
149
ngx_http_auth_jwt_loc_conf_t * jwtcf ;
93
150
u_char * keyBinary ;
94
- jwt_t * jwt ;
151
+ jwt_t * jwt = NULL ;
95
152
int jwtParseReturnCode ;
96
153
jwt_alg_t alg ;
97
154
time_t exp ;
98
155
time_t now ;
99
-
156
+ double expseconds_from_now ;
157
+
100
158
jwtcf = ngx_http_get_module_loc_conf (r , ngx_http_auth_jwt_module );
101
159
102
160
if (!jwtcf -> auth_jwt_enabled )
@@ -110,11 +168,11 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
110
168
111
169
// get the cookie
112
170
// TODO: the cookie name could be passed in dynamicallly
113
- n = ngx_http_parse_multi_header_lines (& r -> headers_in .cookies , & jwtCookieName , & jwtCookieVal );
171
+ n = ngx_http_parse_multi_header_lines (& r -> headers_in .cookies , & jwtcf -> auth_jwt_cookie_name , & jwtCookieVal );
114
172
if (n == NGX_DECLINED )
115
173
{
116
174
// if we can't find the first cookie, check the legacy ___location
117
- n = ngx_http_parse_multi_header_lines (& r -> headers_in .cookies , & passportKeyCookieName , & jwtCookieVal );
175
+ n = ngx_http_parse_multi_header_lines (& r -> headers_in .cookies , & jwtcf -> auth_jwt_cookie_legacy_name , & jwtCookieVal );
118
176
if (n == NGX_DECLINED )
119
177
{
120
178
ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "failed to obtain a jwt cookie" );
@@ -158,11 +216,78 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
158
216
// validate the exp date of the JWT
159
217
exp = (time_t )jwt_get_grant_int (jwt , "exp" );
160
218
now = time (NULL );
161
- if (exp < now )
219
+ expseconds_from_now = difftime (exp , now );
220
+ if (expseconds_from_now < 0 )
162
221
{
163
222
ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "the jwt has expired" );
164
223
goto redirect ;
165
224
}
225
+
226
+ if (jwtcf -> auth_jwt_cookie_reissue_enabled )
227
+ {
228
+ // if the token is not in the first minute of use, renew it.
229
+ if (expseconds_from_now < ((TOKEN_PERIOD_MINUTES - 1 ) * 60 ))
230
+ {
231
+ struct tm * newexp_tm ;
232
+ time_t newexp ;
233
+ char * newJwtCookieValChrPtr ;
234
+
235
+ // create a new JWT to return for the cookies
236
+ // you could gamble with time arithmetric, but this is the proper way to do it
237
+ newexp_tm = localtime (& now );
238
+ newexp_tm -> tm_min += TOKEN_PERIOD_MINUTES ;
239
+ newexp = mktime (newexp_tm );
240
+ jwt_add_grant_int (jwt , "exp" , newexp );
241
+ newJwtCookieValChrPtr = jwt_encode_str (jwt );
242
+
243
+ u_char * cookie ;
244
+ u_char * p ;
245
+ int len ;
246
+
247
+ len = jwtcf -> auth_jwt_cookie_name .len + sizeof ("=" ) - 1 + strlen (newJwtCookieValChrPtr );
248
+
249
+ // currently we are not expiring our cookies
250
+ // len += sizeof("; expires=") - 1 + sizeof("Mon, 01 Sep 1970 00:00:00 GMT") - 1;
251
+
252
+ len += sizeof ("; Domain=" ) - 1 ;
253
+ len += sizeof (jwtcf -> auth_jwt_cookie_reissue_domain .len );
254
+ len += sizeof ("; Path=/" ); // TODO: Make this configurable
255
+ if (jwtcf -> auth_jwt_cookie_reissue_secure )
256
+ {
257
+ len += sizeof ("; Secure" ) - 1 ;
258
+ }
259
+ if (jwtcf -> auth_jwt_cookie_reissue_httponly )
260
+ {
261
+ len += sizeof ("; HttpOnly" ) - 1 ;
262
+ }
263
+
264
+ cookie = ngx_pnalloc (r -> pool , len );
265
+ p = ngx_copy (cookie , jwtcf -> auth_jwt_cookie_name .data , jwtcf -> auth_jwt_cookie_name .len );
266
+ * p ++ = '=' ;
267
+ p = ngx_copy (p , newJwtCookieValChrPtr , strlen (newJwtCookieValChrPtr ));
268
+
269
+ p = ngx_copy (p , "; Domain=" , sizeof ("; Domain=" ) - 1 );
270
+ p = ngx_copy (p , jwtcf -> auth_jwt_cookie_reissue_domain .data , jwtcf -> auth_jwt_cookie_reissue_domain .len );
271
+
272
+ p = ngx_copy (p , "; Path=/" , sizeof ("; Path=/" ) - 1 );
273
+
274
+ if (jwtcf -> auth_jwt_cookie_reissue_secure )
275
+ {
276
+ p = ngx_copy (p , "; Secure" , sizeof ("; Secure" ) - 1 );
277
+ }
278
+ if (jwtcf -> auth_jwt_cookie_reissue_httponly )
279
+ {
280
+ p = ngx_copy (p , "; HttpOnly" , sizeof ("; HttpOnly" ) - 1 );
281
+ }
282
+
283
+ // this memory was malloc in call to jwt_encode_str
284
+ free (newJwtCookieValChrPtr );
285
+ newJwtCookieValChrPtr = NULL ;
286
+ }
287
+ }
288
+
289
+ jwt_free (jwt );
290
+ jwt = NULL ;
166
291
167
292
return NGX_OK ;
168
293
@@ -201,8 +326,8 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
201
326
if (request_uri_var && !request_uri_var -> not_found && request_uri_var -> valid )
202
327
{
203
328
// ideally we would like the uri with the querystring parameters
204
- uri .data = ngx_palloc (r -> pool , request_uri_var -> len );
205
- uri .len = request_uri_var -> len ;
329
+ uri .data = ngx_palloc (r -> pool , request_uri_var -> len );
330
+ uri .len = request_uri_var -> len ;
206
331
ngx_memcpy (uri .data , request_uri_var -> data , request_uri_var -> len );
207
332
}
208
333
else
@@ -211,21 +336,20 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
211
336
uri = r -> uri ;
212
337
}
213
338
214
- r -> headers_out .___location -> value .len = loginlen + sizeof ("?return_url=" ) - 1 + strlen (scheme ) + sizeof ("://" ) - 1 + server .len + uri .len ;
215
- return_url = ngx_alloc (r -> headers_out .___location -> value .len , r -> connection -> log );
216
- ngx_memcpy (return_url , jwtcf -> auth_jwt_loginurl .data , jwtcf -> auth_jwt_loginurl .len );
217
- int return_url_idx = jwtcf -> auth_jwt_loginurl .len ;
218
- ngx_memcpy (return_url + return_url_idx , "?return_url=" , sizeof ("?return_url=" ) - 1 );
219
- return_url_idx += sizeof ("?return_url=" ) - 1 ;
220
- ngx_memcpy (return_url + return_url_idx , scheme , strlen (scheme ));
221
- return_url_idx += strlen (scheme );
222
- ngx_memcpy (return_url + return_url_idx , "://" , sizeof ("://" ) - 1 );
223
- return_url_idx += sizeof ("://" ) - 1 ;
224
- ngx_memcpy (return_url + return_url_idx , server .data , server .len );
225
- return_url_idx += server .len ;
226
- ngx_memcpy (return_url + return_url_idx , uri .data , uri .len );
227
- return_url_idx += uri .len ;
228
- r -> headers_out .___location -> value .data = (u_char * )return_url ;
339
+ {
340
+ void * return_url_p ;
341
+
342
+ r -> headers_out .___location -> value .len = loginlen + sizeof ("?return_url=" ) - 1 + strlen (scheme ) + sizeof ("://" ) - 1 + server .len + uri .len ;
343
+ return_url = ngx_alloc (r -> headers_out .___location -> value .len , r -> connection -> log );
344
+ return_url_p = return_url ;
345
+ return_url_p = ngx_copy (return_url_p , jwtcf -> auth_jwt_loginurl .data , jwtcf -> auth_jwt_loginurl .len );
346
+ return_url_p = ngx_copy (return_url_p , "?return_url=" , sizeof ("?return_url=" ) - 1 );
347
+ return_url_p = ngx_copy (return_url_p , scheme , strlen (scheme ));
348
+ return_url_p = ngx_copy (return_url_p , "://" , sizeof ("://" ) - 1 );
349
+ return_url_p = ngx_copy (return_url_p , server .data , server .len );
350
+ return_url_p = ngx_copy (return_url_p , uri .data , uri .len );
351
+ r -> headers_out .___location -> value .data = (u_char * )return_url ;
352
+ }
229
353
230
354
ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "redirect for get request" );
231
355
}
@@ -236,6 +360,12 @@ static ngx_int_t ngx_http_auth_jwt_handler(ngx_http_request_t *r)
236
360
r -> headers_out .___location -> value .data = jwtcf -> auth_jwt_loginurl .data ;
237
361
}
238
362
363
+ if (jwt != NULL )
364
+ {
365
+ jwt_free (jwt );
366
+ jwt = NULL ;
367
+ }
368
+
239
369
return NGX_HTTP_MOVED_TEMPORARILY ;
240
370
}
241
371
@@ -269,12 +399,15 @@ ngx_http_auth_jwt_create_loc_conf(ngx_conf_t *cf)
269
399
{
270
400
return NULL ;
271
401
}
272
-
402
+
273
403
// set the flag to unset
274
404
conf -> auth_jwt_enabled = (ngx_flag_t ) - 1 ;
405
+ conf -> auth_jwt_cookie_reissue_enabled = (ngx_flag_t ) - 1 ;
406
+ conf -> auth_jwt_cookie_reissue_secure = (ngx_flag_t ) - 1 ;
407
+ conf -> auth_jwt_cookie_reissue_httponly = (ngx_flag_t ) - 1 ;
275
408
276
409
ngx_conf_log_error (NGX_LOG_DEBUG , cf , 0 , "Created Location Configuration" );
277
-
410
+
278
411
return conf ;
279
412
}
280
413
@@ -285,21 +418,38 @@ ngx_http_auth_jwt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
285
418
ngx_http_auth_jwt_loc_conf_t * prev = parent ;
286
419
ngx_http_auth_jwt_loc_conf_t * conf = child ;
287
420
421
+ ngx_conf_merge_str_value (conf -> auth_jwt_cookie_name , prev -> auth_jwt_cookie_name , "" );
422
+ ngx_conf_merge_str_value (conf -> auth_jwt_cookie_legacy_name , prev -> auth_jwt_cookie_legacy_name , "" );
288
423
ngx_conf_merge_str_value (conf -> auth_jwt_loginurl , prev -> auth_jwt_loginurl , "" );
289
424
ngx_conf_merge_str_value (conf -> auth_jwt_key , prev -> auth_jwt_key , "" );
290
-
291
-
292
- if (conf -> auth_jwt_enabled == ((ngx_flag_t ) - 1 ))
425
+ ngx_conf_merge_str_value ( conf -> auth_jwt_cookie_reissue_domain , prev -> auth_jwt_cookie_reissue_domain , "" );
426
+
427
+ if (conf -> auth_jwt_enabled == ((ngx_flag_t ) - 1 ))
293
428
{
294
- conf -> auth_jwt_enabled = (prev -> auth_jwt_enabled == ((ngx_flag_t ) - 1 )) ? 0 : prev -> auth_jwt_enabled ;
429
+ conf -> auth_jwt_enabled = (prev -> auth_jwt_enabled == ((ngx_flag_t ) - 1 )) ? 0 : prev -> auth_jwt_enabled ;
295
430
}
296
-
431
+
432
+ if (conf -> auth_jwt_cookie_reissue_enabled == ((ngx_flag_t ) - 1 ))
433
+ {
434
+ conf -> auth_jwt_cookie_reissue_enabled = (prev -> auth_jwt_cookie_reissue_enabled == ((ngx_flag_t ) - 1 )) ? 0 : prev -> auth_jwt_cookie_reissue_enabled ;
435
+ }
436
+
437
+ if (conf -> auth_jwt_cookie_reissue_secure == ((ngx_flag_t ) - 1 ))
438
+ {
439
+ conf -> auth_jwt_cookie_reissue_secure = (prev -> auth_jwt_cookie_reissue_secure == ((ngx_flag_t ) - 1 )) ? 0 : prev -> auth_jwt_cookie_reissue_secure ;
440
+ }
441
+
442
+ if (conf -> auth_jwt_cookie_reissue_httponly == ((ngx_flag_t ) - 1 ))
443
+ {
444
+ conf -> auth_jwt_cookie_reissue_httponly = (prev -> auth_jwt_cookie_reissue_httponly == ((ngx_flag_t ) - 1 )) ? 0 : prev -> auth_jwt_cookie_reissue_httponly ;
445
+ }
446
+
297
447
ngx_conf_log_error (NGX_LOG_DEBUG , cf , 0 , "Merged Location Configuration" );
298
448
299
449
// ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "Key: %s, Enabled: %d",
300
450
// conf->auth_jwt_key.data,
301
451
// conf->auth_jwt_enabled);
302
- return NGX_CONF_OK ;
452
+ return NGX_CONF_OK ;
303
453
}
304
454
305
455
static int
@@ -314,13 +464,13 @@ hex_char_to_binary( char ch, char* ret )
314
464
* ret = ( ch - 'A' ) + 10 ;
315
465
else
316
466
return * ret = 0 ;
317
- return 1 ;
467
+ return 1 ;
318
468
}
319
469
320
470
static int
321
471
hex_to_binary ( const char * str , u_char * buf , int len ) {
322
- u_char
323
- * cpy = buf ;
472
+ u_char
473
+ * cpy = buf ;
324
474
char
325
475
low ,
326
476
high ;
@@ -337,6 +487,6 @@ hex_to_binary( const char* str, u_char* buf, int len ) {
337
487
338
488
* cpy ++ = low | (high << 4 );
339
489
}
340
- return 0 ;
490
+ return 0 ;
341
491
}
342
492
0 commit comments