SPNEGO For nginx - a start, at least
I've been posting on the nginx mailing lists for a while that I've had a developer working on SPNEGO (Kerberos/GSSAPI/etc.) module for authentication for nginx. I never produced any code though, because I was constantly waiting for a bit more of a matured module before giving it out.
For now though, it might just be best to throw out there what I have, explain my findings, and let the community start testing it, hacking it, improving it, etc.
Download
ngx_http_auth_sso_module-0.3.zip
Opens for the developer still
- He said he'd like to remove the dependency on the bundled spnegohelp library (apparently it's not needed or it can be filled with a system package)
- Needs some more documentation
My questions, comments
- Should it be called "mod_auth_sso" or something like "mod_auth_gssapi" - I believe Apache's equivalent has "gssapi" in the title somewhere. It was hard to determine which was the most up to date version - mod_auth_kerb, modgssapache, etc.
- I cannot verify this still using my corporate domain setup. I did have to make a minor tweak in the source to change the principal name it was using (see below) and I still got access denied. I have no clue if the module is to blame, the machine's setup with the domain, or what.
A possible required tweak... around line 474 or so in ngx_http_auth_sso_module.c
- host_name = r->headers_in.host->value; + host_name = alcf->realm;
How to compile - yes, it's a bit messy, mainly due to the spnegohelp library dependency
wget http://sysoev.ru/nginx/nginx-0.8.31.tar.gz tar xvfz nginx-0.8.31.tar.gz cd nginx-0.8.31 ./configure --conf-path=/etc/nginx/nginx.conf --prefix=/usr --user=www-data --group=www-data --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx.lock --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/body --http-proxy-temp-path=/var/lib/nginx/proxy --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --with-http_stub_status_module --with-http_gzip_static_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_flv_module --with-http_ssl_module --with-http_dav_module --with-http_realip_module --with-http_xslt_module --with-debug --add-module=/usr/src/build/ngx_http_auth_sso_module-current --with-ld-opt="-L/usr/src/build/ngx_http_auth_sso_module-current/spnegohelp" cp -f /usr/src/build/ngx_http_auth_sso_module-0.3/spnegohelp/libspnegohelp.so /usr/lib64/libspnegohelp.so ... make, make install, whatever ...
I copied the libspnegohelp.so into the system so nginx can use it without any special runtime LD_LIBRARY_PATH crap.
How to configure (again, I could not validate this 100%)
location /test {
auth_gss on;
auth_gss_realm YOUR.KERBEROS.REALM;
auth_gss_keytab /etc/krb5.keytab;
auth_gss_service_name YOURMACHINENAMEIBELIEVE;
}
Conclusion
Your mileage will definitely vary but hopefully some people with more experience with Kerberos, C, nginx modules, or anything else helpful can pick it apart. I will post updates as I get them and I do want to post this on github or something... unless someone else wants to take ownership over it who will actually actively maintain/keep it up to date with nginx internals and maintain the github/whatever repository for it.
This was self-funded personally with no company sponsorship or anything, part of the terms of the project were also to keep it BSD licensed. Feel free to do whatever you want with it. If you want to send me any money to reimburse, I'll never say no to that - paypal AT mike2k.com. Or, pay a developer who can ensure it works end-to-end, if there is something missing.
Sadly, it does require the machine to be on the domain, I was hoping I could get away with it not having to be on the domain. I confirmed with Sam Hartman, who was a chief technologist at the MIT Kerberos Consortium - you can't really get more knowledgeable than that. I would have hired Sam for the project but it would have been too expensive. However if a company is willing to take this initial coding and have Sam add his magic to it, he knows C and was able to give me a real quick estimate and check how nginx modules work. He could possibly do it for cheaper now since the initial work might be done, and he would definitely be able to confirm all the logic is intact.
Thanks to YoctoPetaBorg at RentACoder.com for the initial work (and for hopefully soon finishing up the last bits of this :p) - it will be exciting to be able to use this at work and be able to have a fully functional module out there that people find useful.
Nice writeup. Keep us posted on the corporate domain progress. That would be really big and welcome news.
Many thanks! It is a very useful module.
I hope you will put the source code in a sourceforge/github/... repository.
Regards
Matteo
I could make it
make -f objs/Makefile
make[1]: Entering directory `/root/nginx-0.8.31'
gcc -c -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Wunused-function -Wunused-variable -Wunused-value -Werror -g -I src/core -I src/event -I src/event/modules -I src/os/unix -I objs -I src/http -I src/http/modules -I src/mail \
-o objs/addon/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.o \
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c
/root/ngx_http_auth_sso_mod ule-0.3/ngx_http_auth_sso_module.c:15:27: error: gssapi/gssapi.h: No such file or directory
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:17:18: error: krb5.h: No such file or directory
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:39: error: expected declaration specifiers or '...' before 'OM_uint32'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c: In function 'get_gss_error':
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:42: error: 'OM_uint32' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:42: error: (Each undeclared identifier is reported only once
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:42: error: for each function it appears in.)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:42: error: expected ';' before 'maj_stat'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:43: error: expected ';' before 'msg_ctx'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:44: error: 'gss_buffer_desc' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:44: error: expected ';' before 'status_string'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:53: error: 'maj_stat' undeclared (first use in this function)
cc1: warnings being treated as errors
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:53: error: implicit declaration of function 'gss_display_status'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:53: error: 'min_stat' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:54: error: 'error_status' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:55: error: 'GSS_C_MECH_CODE' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:56: error: 'GSS_C_NO_OID' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:57: error: 'msg_ctx' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:58: error: 'status_string' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:66: error: implicit declaration of function 'gss_release_buffer'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:67: error: implicit declaration of function 'GSS_ERROR'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c: In function 'ngx_http_auth_sso_auth_user_gss':
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_m odule.c:423: error: 'krb5_context' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:423: error: expected ';' before 'krb_ctx'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:438: error: 'OM_uint32' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:438: error: expected ';' before 'major_status'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:439: error: 'gss_buffer_desc' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:439: error: expected ';' before 'service'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:440: error: 'gss_name_t' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:440: error: expected ';' before 'my_gss_name'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:441: error: 'gss_cred_id_t' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:441: error: expected ';' before 'my_gss_creds'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:442: error: expected ';' before 'input_token'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:443: error: 'gss_ctx_id_t' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:443: error: expected ';' before 'gss_context'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:444: error: expected ';' before 'client_name'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:445: error: expected ';' before 'output_token'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:446: error: expected ';' before 'ret_flags'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:447: error: expected ';' before 'delegated_cred'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:459: error: implicit declaration of function 'krb5_init_context'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:459: error: 'krb_ctx' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:476: error: 'service' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:489: error: 'major_status' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:489: error: implicit declaration of function 'gss_import_name'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:489: error: 'minor_status' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:490: error: 'GSS_C_NT_HOSTBASED_SERVICE' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:490: error: 'my_gss_name' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:492: error: too many arguments to function 'get_gss_error'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:501: error: implicit declaration of function 'gss_acquire_cred'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:503: error: 'GSS_C_INDEFINITE' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:504: error: 'GSS_C_NO_OID_SET' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:505: error: 'GSS_C_ACCEPT' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:506: error: 'my_gss_creds' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:510: error: too many arguments to function 'get_gss_error'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:520: error: 'input_token' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:561: error: implicit declaration of function 'gss_accept_sec_context'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:56 2: error: 'gss_context' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:565: error: 'GSS_C_NO_CHANNEL_BINDINGS' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:566: error: 'client_name' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:568: error: 'output_token' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:569: error: 'ret_flags' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:571: error: 'delegated_cred' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:598: error: 'minor_status2' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:618: error: too many arguments to function 'get_gss_error'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:627: error: 'GSS_S_CONTINUE_NEEDED' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:635: error: 'GSS_C_REPLAY_FLAG' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:635: error: 'GSS_C_SEQUENCE_FLAG' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:645: error: implicit declaration of function 'gss_display_name'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:649: error: implicit declaration of function 'gss_release_name'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:653: error: too many arguments to function 'get_gss_error'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:663: error: missing initializer
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:663: error: (near initialization for 'user.len')
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:689: error: 'GSS_C_NO_CREDENTIAL' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:700: error: implicit declaration of function 'gss_release_cred'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:705: error: 'GSS_C_NO_NAME' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:708: error: 'GSS_C_NO_CONTEXT' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:709: error: implicit declaration of function 'gss_delete_sec_context'
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:70 9: error: 'GSS_C_NO_BUFFER' undeclared (first use in this function)
/root/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.c:711: error: implicit declaration of function 'krb5_free_context'
make[1]: *** [objs/addon/ngx_http_auth_sso_module-0.3/ngx_http_auth_sso_module.o] Error 1
make[1]: Leaving directory `/root/nginx-0.8.31'
make: *** [build] Error 2
@Zl0
You must be missing a library or something. What distro, is it 32 or 64 bit, etc?
It works nice, but I don't get basic headers when my browser not support gssapi (like opera), and It will be very nice if it can be configure that my auth login will not "login@REALM" but simple "login"
@Polo
There's a lot of things that are not fully working with it. That's why I put it up on github. I am hoping some people might be able to help improve it. I believe that it is supposed to fall back to digest, not basic auth (which would still present the same HTTP auth prompt box either way) if Kerberos negotiation fails.
I could not figure out how to get the realm stuff working at my work (only place with a proper Windows domain setup that I know of) - I tried my hardest but I don't know enough about how to set it up.
I am all for someone helping extend this and fix bugs. I just wanted to get the project started and sponsored the initial development.
Here's the project on github -
https://github.com/mike503/spnego-http-auth-nginx-module
I am more than happy to adjust settings as needed for people to be able to do development.
@mike
Nice the github repository...
Has someone already been using this module in production?
@Matteo
Odd, I'm not sure why I didn't see the email notification for this reply. As far as I know, no, nobody is. I tried to get some exposure for it (and hopefully someone to validate it works properly, contribute anything to it, etc.) - but even though I had two or three emails offline from the nginx list saying they were interested, I never got a single line of feedback about it.
I'm more than happy to work with someone if someone wants to help maintain, extend, etc.
I highly recommend posting a bounty on gun.io if any further bugs need addressing.
I'm using this module for an intranet and it does enforce Kerberos, and it appears NTLM is not an option, which is fine. Now I want to retrieve the authenticated user name, but not sure how. I'll keep researching, but if anyone has a tip please let me know.
I figured this out. I'm using Passenger so I just set set the cgi parameter as follows in the nginx.conf file:
passenger_set_cgi_param REMOTE_USER $remote_user;
Then I use this in my rails app by looking at request.env['REMOTE_USER']
@John
Would you be able to post your configuration?
Server OS, distro, kernel version, nginx version, libraries or package list, nginx configuration?
Obviously you can rename the specifics to your implementation, I would just love to know how you got a working configuration going as I have yet to be able to, however, the only network I have access to might be so complex that it might be impossible to "test" on to begin with
If you don't want to make it public, feel free to email me - mike@mike2k.com
I haven't really had any feedback on the module yet and would really like to try to get it matured more to be usable (especially in my own company's network)
Thanks!
Hi Mike. Sorry I just saw your post. When I get to work today I'll post my configuration.
nginx-version is as follows:
CentOS release 5.7 (Final)
nginx: nginx version: nginx/1.0.10
nginx: built by gcc 4.1.2 20080704 (Red Hat 4.1.2-51)
nginx: TLS SNI support disabled
nginx: configure arguments: --prefix=/opt/nginx --with-http_ssl_module --with-cc-opt=-Wno-error
--without-http_rewrite_module --add-module=/usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11/ext/nginx
-------- -------------------------------------------------------------------------
I created a text file with the configure parameters, but can't seem to find it. I see the following in the /opt/nginx-1.0.10/objs/Makefile though (I had to put the module @ /usr/local/lib64/spnego-http-auth-nginx-module):
objs/addon/spnego-http-auth-nginx-module/ngx_http_auth_spnego_module.o \
objs/addon/spnego-http-auth-nginx-module/ngx_http_auth_spnego_module.o \
objs/ngx_modules.o \
-lpthread -lcrypt /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11/ext/nginx/../common/libpassenger _common.a /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11/ext/nginx/../c
ommon/libboost_o xt.a -lstdc++ -lpthread -lm -lspnegohelp -lgssapi_krb5 -lssl -lcrypto -ldl -lz
objs/addon/spnego-http-auth-nginx-module/ngx_http_auth_spnego_module.o: $(ADDON_DEPS) \
/usr/local/lib64/spnego-http-auth-nginx-module/ngx_http_auth_spnego_module.c
$(CC) -c $(CFLAGS) $(ALL_INCS) \
-o objs/addon/spnego-http-auth-nginx-module/ngx_http_auth_spnego_module.o \
/usr/local/lib64/spnego-http-auth-nginx-module/ngx_http_auth_spnego_module.c
---------- ------------------------------------------------------------------------
My nginx.conf file has the following:
user appidentity;
worker_processes 2;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
passenger_root /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11;
passenger_ruby /usr/local/rvm/wrappers/ruby-1.9.2-p290/ruby;
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types text/plain text/css
application/x-javascript text/xml
application/xml application/xml+rss
text/javascript;
server {
listen 80;
listen 443 ssl;
server_name servername.sub.domain.com;
ssl_certificate /etc/ssl/servername.sub.domain.com.crt;
ssl_certificate_key /etc/ssl/servername.sub.domain.com.key;
root /home/appidentity/apps/ticketee/current/public;
passenger_enabled on;
passenger_set_cgi_param HTTP_X_FORWARDED_PROTO $scheme;
auth_gss on;
auth_gss_realm sub.domain.com;
auth_gss_keytab /home/ticketeeapp.com/apps/ticketee/shared/http_servername.keytab;
auth_gss_service_name HTTP;
passenger_set_cgi_param REMOTE_USER $remote_user;
#charset koi8-r;
#access_log logs/host.access.log main;
location /admin/incomings {
#root html;
#index index.html index.htm;
auth_gss off;
allow 127.0.0.1;
deny all;
passenger_enabled on;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
#error_page 500 502 503 504 /50x.html;
#location = /50x.html {
# root html;
#}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443;
# server_name localhost;
# ssl on;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_timeout 5m;
# ssl_protocols SSLv2 SSLv3 TLSv1;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}