-
Notifications
You must be signed in to change notification settings - Fork 128
PEM key file support #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add loading RS256 key from file
# for compiling for epel7 | ||
RUN yum -y install libxml2 libxslt libxml2-devel libxslt-devel gd gd-devel perl-ExtUtils-Embed geoip geoip-devel google-perftools google-perftools-devel | ||
|
||
# Jansson requires new cmake | ||
RUN yum -y install cmake3 && \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed this as the Jansson build passes with cmake
installed from previous step (I can return it, but it works also without it)
Dockerfile
Outdated
@@ -85,7 +69,7 @@ RUN wget http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz && \ | |||
rm nginx-$NGINX_VERSION.tar.gz && \ | |||
ln -sf nginx-$NGINX_VERSION nginx && \ | |||
cd /root/dl/nginx && \ | |||
./configure --add-dynamic-module=../ngx-http-auth-jwt-module --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-stream_ssl_preread_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-http_auth_request_module --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic -std=gnu99' --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E' && \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I've just added -Wno-unused-variable -Wno-error=unused-but-set-variable
to suppress errors regarding unused variables (return value of fread
isn't used)
@@ -45,11 +45,13 @@ auth_jwt_loginurl "https://yourdomain.com/loginpage"; | |||
auth_jwt_enabled on; | |||
auth_jwt_algorithm HS256; # or RS256 | |||
auth_jwt_validate_email on; # or off | |||
auth_jwt_use_keyfile off; # or on | |||
auth_jwt_keyfile_path "/app/pub_key"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a valid default path? All my docker images are inside /app
working directory, just a habit 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there perhaps shouldn't be a default, and it would be an error case to have auth_jwt_use_keyfile on
and auth_jwt_keyfile_path
not supplied (e.g. force the user to supply a path).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, but there could also be a auth_jwt_key
together with the auth_jwt_keyfile_path
which adds ambiguity to what key is being used. Maybe an enum field auth_jwt_key_location
(with values inline
or file
) would solve it also for future situations (for example having a remote keystore where the key is located).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much @penumbra23 for the PR! Sorry it has taken me so long to get around to reviewing it. I think it would be an excellent addition to be able to refer to a PEM file instead of including the key's text in the nginx.conf. I left some comments below... I'm most concerned that your PR reads the key from the file every request. I think this would be best handled during the loading of the configuration instead. Also, I each new scenario needs a test in test.sh - maybe something like this:
test_jwt "Secure test with rs256 file" "/secure-rs256-file/" "200" "--header \"Authorization: Bearer ${VALID_RS256_JWT}\""
test_jwt "Secure test with rs256 file and invalid JWT" "/secure-rs256-file/" "401" "--header \"Authorization: Bearer ${INVALID_RS256_JWT}\""
src/ngx_http_auth_jwt_module.c
Outdated
@@ -177,8 +199,45 @@ 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 public key string itself | |||
keyBinary = jwtcf->auth_jwt_key.data; | |||
keylen = jwtcf->auth_jwt_key.len; | |||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to find a jwt"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you might have left this debug statement in by mistake... this message will get printed even if a JWT is present.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, by mistake while I was testing something. Gonna remove it 👍
src/ngx_http_auth_jwt_module.c
Outdated
} | ||
|
||
// Read file length | ||
fseek(file, 0, SEEK_END); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to read the public key from a file for every request that NGINX receives. I'm afraid that this would offer poor performance. I think we would need to read from a file when the configuration is loaded instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Until this I've never worked with custom Nginx plugins, it's definitely poor performance as the key won't change frequently (changing the key would require a server restart, which makes sense).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried the init_module
and postconfiguration
hooks, but it seems they don't load the blocks at that time (since when logging the values from the config it displays the default -1 value). I'll try to put it in the merge_location
hook, since it gets called once (maybe a better idea?).
src/ngx_http_auth_jwt_module.c
Outdated
{ | ||
char err[100]; | ||
strcpy(err, "failed to open pub key file: "); | ||
strcat(err, KEY_FILE_PATH); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't necessarily the value that was specified for the location of the public key... this error outputs the default location of the file.
src/ngx_http_auth_jwt_module.c
Outdated
} | ||
|
||
// Read pub key | ||
pub_key = malloc(key_size + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this memory free'd? I think you need to use the ngx_* wrapped versions of malloc to allocate memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw this mem leak before and changed it on some internal branch, gonna merge it
@fitzyjoe I've updated the code and refactored (a bit). Now the location config has a (kinda) private Hope it's okay now, leave more comments because we're using this plugin heavily! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good @penumbra23. Thanks for the contribution!
auth_jwt_use_keyfile
andauth_jwt_keyfile_path
for loading the PEM encoded public key from file (defaults to"/app/pub_key"
)