Skip to content

Commit 6c60776

Browse files
authored
Joefitz/optional auth header (TeslaGov#24)
* created more tests, exit if docker fails * copy files to support more tests * Added cookie vs auth header feature, refactored code
1 parent c861b1e commit 6c60776

12 files changed

+347
-152
lines changed

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ RUN wget http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz && \
9999
COPY resources/nginx.conf /etc/nginx/nginx.conf
100100
COPY resources/test-jwt-nginx.conf /etc/nginx/conf.d/test-jwt-nginx.conf
101101
RUN cp -r /usr/share/nginx/html /usr/share/nginx/secure
102+
RUN cp -r /usr/share/nginx/html /usr/share/nginx/secure-auth-header
103+
RUN cp -r /usr/share/nginx/html /usr/share/nginx/secure-no-redirect
102104

103105
ENTRYPOINT ["/usr/sbin/nginx"]
104106
#ENTRYPOINT ["while true; do echo hello world; sleep 1; done"]

build.sh

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,62 @@
11
#!/bin/bash
22

3+
RED='\033[01;31m'
4+
GREEN='\033[01;32m'
5+
NONE='\033[00m'
6+
37
# build
48
DOCKER_IMAGE_NAME=jwt-nginx
59
docker build -t ${DOCKER_IMAGE_NAME} .
10+
if [ $? -ne 0 ]
11+
then
12+
echo -e "${RED}Build Failed${NONE}";
13+
exit 1;
14+
fi
15+
616
CONTAINER_ID=$(docker run --name "${DOCKER_IMAGE_NAME}-cont" -d -p 8000:8000 ${DOCKER_IMAGE_NAME})
717

818
MACHINE_IP=`docker-machine ip`
919

1020
docker cp ${CONTAINER_ID}:/usr/lib64/nginx/modules/ngx_http_auth_jwt_module.so .
1121

12-
RED='\033[01;31m'
13-
GREEN='\033[01;32m'
14-
NONE='\033[00m'
15-
1622
VALIDJWT=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwgImxhc3ROYW1lIjoid29ybGQiLCJlbWFpbEFkZHJlc3MiOiJoZWxsb3dvcmxkQGV4YW1wbGUuY29tIiwgInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwgImlzcyI6Imlzc3VlciIsInBlcnNvbklkIjoiNzViYjNjYzctYjkzMy00NGYwLTkzYzYtMTQ3YjA4MmZhZGI1IiwgImV4cCI6MTkwODgzNTIwMCwiaWF0IjoxNDg4ODE5NjAwLCJ1c2VybmFtZSI6ImhlbGxvLndvcmxkIn0.TvDD63ZOqFKgE-uxPDdP5aGIsbl5xPKz4fMul3Zlti4
1723

18-
TEST_INSECURE_EXPECT_200=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000`
24+
TEST_INSECURE_EXPECT_200=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000 -H 'cache-control: no-cache'`
1925
if [ "$TEST_INSECURE_EXPECT_200" -eq "200" ];then
2026
echo -e "${GREEN}Insecure test pass ${TEST_INSECURE_EXPECT_200}${NONE}";
2127
else
2228
echo -e "${RED}Insecure test fail ${TEST_INSECURE_EXPECT_200}${NONE}";
2329
fi
2430

25-
TEST_SECURE_EXPECT_302=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000/secure/index.html`
26-
if [ "$TEST_SECURE_EXPECT_302" -eq "302" ];then
27-
echo -e "${GREEN}Secure test without jwt pass ${TEST_SECURE_EXPECT_302}${NONE}";
31+
TEST_SECURE_COOKIE_EXPECT_302=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000/secure/index.html -H 'cache-control: no-cache'`
32+
if [ "$TEST_SECURE_COOKIE_EXPECT_302" -eq "302" ];then
33+
echo -e "${GREEN}Secure test without jwt cookie pass ${TEST_SECURE_COOKIE_EXPECT_302}${NONE}";
2834
else
29-
echo -e "${RED}Secure test without jwt fail ${TEST_SECURE_EXPECT_302}${NONE}";
35+
echo -e "${RED}Secure test without jwt cookie fail ${TEST_SECURE_COOKIE_EXPECT_302}${NONE}";
3036
fi
3137

3238
TEST_SECURE_COOKIE_EXPECT_200=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000/secure/index.html -H 'cache-control: no-cache' --cookie "rampartjwt=${VALIDJWT}"`
3339
if [ "$TEST_SECURE_COOKIE_EXPECT_200" -eq "200" ];then
34-
echo -e "${GREEN}Secure test with jwt pass ${TEST_SECURE_COOKIE_EXPECT_200}${NONE}";
40+
echo -e "${GREEN}Secure test with jwt cookie pass ${TEST_SECURE_COOKIE_EXPECT_200}${NONE}";
41+
else
42+
echo -e "${RED}Secure test with jwt cookie fail ${TEST_SECURE_COOKIE_EXPECT_200}${NONE}";
43+
fi
44+
45+
TEST_SECURE_HEADER_EXPECT_200=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000/secure-auth-header/index.html -H 'cache-control: no-cache' --header "Authorization: Bearer ${VALIDJWT}"`
46+
if [ "$TEST_SECURE_HEADER_EXPECT_200" -eq "200" ];then
47+
echo -e "${GREEN}Secure test with jwt auth header pass ${TEST_SECURE_HEADER_EXPECT_200}${NONE}";
48+
else
49+
echo -e "${RED}Secure test with jwt auth header fail ${TEST_SECURE_HEADER_EXPECT_200}${NONE}";
50+
fi
51+
52+
TEST_SECURE_HEADER_EXPECT_302=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000/secure-auth-header/index.html -H 'cache-control: no-cache'`
53+
if [ "$TEST_SECURE_HEADER_EXPECT_302" -eq "200" ];then
54+
echo -e "${GREEN}Secure test without jwt auth header pass ${TEST_SECURE_HEADER_EXPECT_302}${NONE}";
3555
else
36-
echo -e "${RED}Secure test with jwt fail ${TEST_SECURE_COOKIE_EXPECT_200}${NONE}";
56+
echo -e "${RED}Secure test without jwt auth header fail ${TEST_SECURE_HEADER_EXPECT_302}${NONE}";
3757
fi
3858

39-
TEST_SECURE_NO_REDIRECT_EXPECT_401=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000/secure-no-redirect/index.html`
59+
TEST_SECURE_NO_REDIRECT_EXPECT_401=`curl -X GET -o /dev/null --silent --head --write-out '%{http_code}\n' http://${MACHINE_IP}:8000/secure-no-redirect/index.html -H 'cache-control: no-cache'`
4060
if [ "$TEST_SECURE_NO_REDIRECT_EXPECT_401" -eq "401" ];then
4161
echo -e "${GREEN}Secure test without jwt no redirect pass ${TEST_SECURE_NO_REDIRECT_EXPECT_401}${NONE}";
4262
else

config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ ngx_addon_name=ngx_http_auth_jwt_module
22

33
ngx_module_type=HTTP
44
ngx_module_name=ngx_http_auth_jwt_module
5-
ngx_module_srcs="$ngx_addon_dir/src/ngx_http_auth_jwt_module.c"
5+
ngx_module_srcs="$ngx_addon_dir/src/ngx_http_auth_jwt_binary_converters.c $ngx_addon_dir/src/ngx_http_auth_jwt_header_processing.c $ngx_addon_dir/src/ngx_http_auth_jwt_string.c $ngx_addon_dir/src/ngx_http_auth_jwt_module.c"
66
ngx_module_libs="-ljansson -ljwt"
77

88
. auto/module

ngx_http_auth_jwt_module.so

173 KB
Binary file not shown.

resources/test-jwt-nginx.conf

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ server {
1010
___location ~ ^/secure-no-redirect/ {
1111
auth_jwt_enabled on;
1212
auth_jwt_redirect off;
13-
alias /usr/share/nginx/secure/;
13+
root /usr/share/nginx;
14+
index index.html index.htm;
1415
}
1516

1617
___location ~ ^/secure/ {
1718
auth_jwt_enabled on;
18-
root /usr/share/nginx;
19+
auth_jwt_validation_type COOKIE=rampartjwt;
20+
root /usr/share/nginx;
21+
index index.html index.htm;
22+
}
23+
24+
___location ~ ^/secure-auth-header/ {
25+
auth_jwt_enabled on;
26+
root /usr/share/nginx;
1927
index index.html index.htm;
2028
}
2129

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (C) 2018 Tesla Government
3+
*
4+
* This software may be modified and distributed under the terms
5+
* of the MIT license. See the LICENSE file for details.
6+
*
7+
* https://github.com/TeslaGov/ngx-http-auth-jwt-module
8+
*/
9+
10+
#include "ngx_http_auth_jwt_binary_converters.h"
11+
12+
#include <ngx_core.h>
13+
14+
int hex_char_to_binary( char ch, char* ret )
15+
{
16+
ch = tolower( ch );
17+
if( isdigit( ch ) )
18+
*ret = ch - '0';
19+
else if( ch >= 'a' && ch <= 'f' )
20+
*ret = ( ch - 'a' ) + 10;
21+
else if( ch >= 'A' && ch <= 'F' )
22+
*ret = ( ch - 'A' ) + 10;
23+
else
24+
return *ret = 0;
25+
return 1;
26+
}
27+
28+
int hex_to_binary( const char* str, u_char* buf, int len )
29+
{
30+
u_char
31+
*cpy = buf;
32+
char
33+
low,
34+
high;
35+
int
36+
odd = len % 2;
37+
38+
if (odd) {
39+
return -1;
40+
}
41+
42+
for (int i = 0; i < len; i += 2) {
43+
hex_char_to_binary( *(str + i), &high );
44+
hex_char_to_binary( *(str + i + 1 ), &low );
45+
46+
*cpy++ = low | (high << 4);
47+
}
48+
return 0;
49+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (C) 2018 Tesla Government
3+
*
4+
* This software may be modified and distributed under the terms
5+
* of the MIT license. See the LICENSE file for details.
6+
*
7+
* https://github.com/TeslaGov/ngx-http-auth-jwt-module
8+
*/
9+
10+
#ifndef _NGX_HTTP_AUTH_JWT_BINARY_CONVERTERS_H
11+
#define _NGX_HTTP_AUTH_JWT_BINARY_CONVERTERS_H
12+
13+
#include <ngx_core.h>
14+
15+
int hex_char_to_binary( char ch, char* ret );
16+
int hex_to_binary( const char* str, u_char* buf, int len );
17+
18+
#endif /* _NGX_HTTP_AUTH_JWT_BINARY_CONVERTERS_H */
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (C) 2018 Tesla Government
3+
*
4+
* This software may be modified and distributed under the terms
5+
* of the MIT license. See the LICENSE file for details.
6+
*
7+
* https://github.com/TeslaGov/ngx-http-auth-jwt-module
8+
*/
9+
10+
#include <ngx_core.h>
11+
#include <ngx_http.h>
12+
13+
#include "ngx_http_auth_jwt_header_processing.h"
14+
15+
/**
16+
* Sample code from nginx.
17+
* https://www.nginx.com/resources/wiki/start/topics/examples/headers_management/?highlight=http%20settings
18+
*/
19+
ngx_table_elt_t* search_headers_in(ngx_http_request_t *r, u_char *name, size_t len)
20+
{
21+
ngx_list_part_t *part;
22+
ngx_table_elt_t *h;
23+
ngx_uint_t i;
24+
25+
// Get the first part of the list. There is usual only one part.
26+
part = &r->headers_in.headers.part;
27+
h = part->elts;
28+
29+
// Headers list array may consist of more than one part, so loop through all of it
30+
for (i = 0; /* void */ ; i++)
31+
{
32+
if (i >= part->nelts)
33+
{
34+
if (part->next == NULL)
35+
{
36+
/* The last part, search is done. */
37+
break;
38+
}
39+
40+
part = part->next;
41+
h = part->elts;
42+
i = 0;
43+
}
44+
45+
//Just compare the lengths and then the names case insensitively.
46+
if (len != h[i].key.len || ngx_strcasecmp(name, h[i].key.data) != 0)
47+
{
48+
/* This header doesn't match. */
49+
continue;
50+
}
51+
52+
/*
53+
* Ta-da, we got one!
54+
* Note, we've stopped the search at the first matched header
55+
* while more then one header may match.
56+
*/
57+
return &h[i];
58+
}
59+
60+
/* No headers was found */
61+
return NULL;
62+
}
63+
64+
/**
65+
* Sample code from nginx
66+
* https://www.nginx.com/resources/wiki/start/topics/examples/headers_management/#how-can-i-set-a-header
67+
*/
68+
ngx_int_t set_custom_header_in_headers_out(ngx_http_request_t *r, ngx_str_t *key, ngx_str_t *value) {
69+
ngx_table_elt_t *h;
70+
71+
/*
72+
All we have to do is just to allocate the header...
73+
*/
74+
h = ngx_list_push(&r->headers_out.headers);
75+
if (h == NULL) {
76+
return NGX_ERROR;
77+
}
78+
79+
/*
80+
... setup the header key ...
81+
*/
82+
h->key = *key;
83+
84+
/*
85+
... and the value.
86+
*/
87+
h->value = *value;
88+
89+
/*
90+
Mark the header as not deleted.
91+
*/
92+
h->hash = 1;
93+
94+
return NGX_OK;
95+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright (C) 2018 Tesla Government
3+
*
4+
* This software may be modified and distributed under the terms
5+
* of the MIT license. See the LICENSE file for details.
6+
*/
7+
8+
#ifndef _NGX_HTTP_AUTH_JWT_HEADER_PROCESSING_H
9+
#define _NGX_HTTP_AUTH_JWT_HEADER_PROCESSING_H
10+
11+
ngx_table_elt_t* search_headers_in(ngx_http_request_t *r, u_char *name, size_t len);
12+
ngx_int_t set_custom_header_in_headers_out(ngx_http_request_t *r, ngx_str_t *key, ngx_str_t *value);
13+
14+
#endif /* _NGX_HTTP_AUTH_JWT_HEADER_PROCESSING_H */

0 commit comments

Comments
 (0)