Added test suite.
The testsuite depends on nginx test suite, and requires an OpenLDAP server installed.
This commit is contained in:
		
							parent
							
								
									850f5ea5ca
								
							
						
					
					
						commit
						57fb98b528
					
				|  | @ -0,0 +1,22 @@ | ||||||
|  | Test suite is available at http://hg.nginx.org/nginx-tests. | ||||||
|  | Check the http://hg.nginx.org/nginx-tests/file/tip/README file | ||||||
|  | for instructions on how to use it. | ||||||
|  | 
 | ||||||
|  | Additionally, the test requires a working installation | ||||||
|  | of OpenLDAP server and utilities (http://www.openldap.org/), | ||||||
|  | and python's coverage tool (https://coverage.readthedocs.io) | ||||||
|  | 
 | ||||||
|  | copy ldap-auth.t into testsuite, setup environment variables: | ||||||
|  | 
 | ||||||
|  | $ export TEST_LDAP_DAEMON=/usr/lib64/openldap/slapd | ||||||
|  | $ export TEST_LDAP_AUTH_DAEMON=/path/to/nginx-ldap-auth-daemon.py | ||||||
|  | $ prove 'ldap-auth.t' | ||||||
|  | 
 | ||||||
|  | to get coverage report: | ||||||
|  | 
 | ||||||
|  | $ export TEST_NGINX_LEAVE=1 | ||||||
|  | $ prove 'ldap-auth.t' | ||||||
|  | $ cd /tmp/nginx-test-xxxx | ||||||
|  | $ coverage2 html | ||||||
|  | 
 | ||||||
|  | report is now generated in htmlcov/ | ||||||
|  | @ -0,0 +1,444 @@ | ||||||
|  | #!/usr/bin/perl | ||||||
|  | 
 | ||||||
|  | # (C) Nginx, Inc. | ||||||
|  | 
 | ||||||
|  | # Test for nginx-ldap-auth daemon with OpenLDAP. | ||||||
|  | 
 | ||||||
|  | ############################################################################### | ||||||
|  | 
 | ||||||
|  | use warnings; | ||||||
|  | use strict; | ||||||
|  | 
 | ||||||
|  | use Test::More; | ||||||
|  | 
 | ||||||
|  | use MIME::Base64; | ||||||
|  | 
 | ||||||
|  | BEGIN { use FindBin; chdir($FindBin::Bin); } | ||||||
|  | 
 | ||||||
|  | use lib 'lib'; | ||||||
|  | use Test::Nginx; | ||||||
|  | 
 | ||||||
|  | ############################################################################### | ||||||
|  | 
 | ||||||
|  | select STDERR; $| = 1; | ||||||
|  | select STDOUT; $| = 1; | ||||||
|  | 
 | ||||||
|  | my $t = Test::Nginx->new()->has(qw/http proxy rewrite auth_request/) | ||||||
|  | 	->write_file_expand('nginx.conf', <<'EOF'); | ||||||
|  | 
 | ||||||
|  | %%TEST_GLOBALS%% | ||||||
|  | 
 | ||||||
|  | events { } | ||||||
|  | 
 | ||||||
|  | daemon off; | ||||||
|  | 
 | ||||||
|  | http { | ||||||
|  | 
 | ||||||
|  |     %%TEST_GLOBALS_HTTP%% | ||||||
|  | 
 | ||||||
|  |     #proxy_cache_path cache/  keys_zone=auth_cache:10m; | ||||||
|  | 
 | ||||||
|  |     server { | ||||||
|  |         listen 127.0.0.1:8082; | ||||||
|  | 
 | ||||||
|  |         location / { | ||||||
|  |             return 200 "ACCESS GRANTED\n"; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location /login { | ||||||
|  |             return 200 "LOGIN PAGE\n"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     upstream backend { | ||||||
|  |         server 127.0.0.1:8082; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     server { | ||||||
|  |         listen 127.0.0.1:8080; | ||||||
|  | 
 | ||||||
|  |         location / { | ||||||
|  |             auth_request /auth-proxy; | ||||||
|  | 
 | ||||||
|  |             error_page 401 =200 /login; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://backend/; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location /ssl { | ||||||
|  |             auth_request /auth-proxy-ssl; | ||||||
|  | 
 | ||||||
|  |             error_page 401 =200 /login; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://backend/; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location /starttls { | ||||||
|  |             auth_request /auth-proxy-starttls; | ||||||
|  | 
 | ||||||
|  |             error_page 401 =200 /login; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://backend/; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location /nodn { | ||||||
|  |             auth_request /auth-nodn; | ||||||
|  | 
 | ||||||
|  |             error_page 401 =200 /login; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://backend/; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location /nourl { | ||||||
|  |             auth_request /auth-nourl; | ||||||
|  | 
 | ||||||
|  |             error_page 401 =200 /login; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://backend/; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location /login { | ||||||
|  |             proxy_pass http://backend/login; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-Target $request_uri; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location = /auth-proxy { | ||||||
|  |             internal; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://127.0.0.1:8888; | ||||||
|  | 
 | ||||||
|  |             proxy_pass_request_body off; | ||||||
|  |             proxy_set_header Content-Length ""; | ||||||
|  | 
 | ||||||
|  |             #proxy_cache auth_cache; | ||||||
|  |             #proxy_cache_valid 200 10m; | ||||||
|  |             #proxy_cache_key "$http_authorization$cookie_nginxauth"; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-Ldap-URL      "ldap://127.0.0.1:8083"; | ||||||
|  |             proxy_set_header X-Ldap-BaseDN   "ou=Users,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindDN   "cn=root,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindPass "secret"; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-CookieName "nginxauth"; | ||||||
|  |             proxy_set_header Cookie nginxauth=$cookie_nginxauth; | ||||||
|  | 
 | ||||||
|  |             #proxy_set_header X-Ldap-Starttls "true"; | ||||||
|  | 
 | ||||||
|  |             #proxy_set_header X-Ldap-Template "(sAMAccountName=%(username)s)"; | ||||||
|  |             #proxy_set_header X-Ldap-DisableReferrals "true"; | ||||||
|  | 
 | ||||||
|  |             #proxy_set_header X-Ldap-Template "(cn=%(username)s)"; | ||||||
|  |             #proxy_set_header X-Ldap-Realm    "Restricted"; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location = /auth-proxy-ssl { | ||||||
|  |             internal; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://127.0.0.1:8888; | ||||||
|  | 
 | ||||||
|  |             proxy_pass_request_body off; | ||||||
|  |             proxy_set_header Content-Length ""; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-Ldap-URL      "ldaps://127.0.0.1:8084"; | ||||||
|  |             proxy_set_header X-Ldap-BaseDN   "ou=Users,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindDN   "cn=root,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindPass "secret"; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-CookieName "nginxauth"; | ||||||
|  |             proxy_set_header Cookie nginxauth=$cookie_nginxauth; | ||||||
|  | 
 | ||||||
|  |             #proxy_set_header X-Ldap-Starttls "true"; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |        location = /auth-proxy-starttls { | ||||||
|  |             internal; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://127.0.0.1:8888; | ||||||
|  | 
 | ||||||
|  |             proxy_pass_request_body off; | ||||||
|  |             proxy_set_header Content-Length ""; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-Ldap-URL      "ldap://127.0.0.1:8083"; | ||||||
|  |             proxy_set_header X-Ldap-BaseDN   "ou=Users,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindDN   "cn=root,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindPass "secret"; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-CookieName "nginxauth"; | ||||||
|  |             proxy_set_header Cookie nginxauth=$cookie_nginxauth; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-Ldap-Starttls "true"; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location = /auth-nodn { | ||||||
|  |             internal; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://127.0.0.1:8888; | ||||||
|  | 
 | ||||||
|  |             proxy_pass_request_body off; | ||||||
|  |             proxy_set_header Content-Length ""; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-Ldap-URL      "ldap://127.0.0.1:8083"; | ||||||
|  |             proxy_set_header X-Ldap-BindDN   "cn=root,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindPass "secret"; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         location = /auth-nourl { | ||||||
|  |             internal; | ||||||
|  | 
 | ||||||
|  |             proxy_pass http://127.0.0.1:8888; | ||||||
|  | 
 | ||||||
|  |             proxy_pass_request_body off; | ||||||
|  |             proxy_set_header Content-Length ""; | ||||||
|  | 
 | ||||||
|  |             proxy_set_header X-Ldap-BaseDN   "ou=Users,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindDN   "cn=root,dc=test,dc=local"; | ||||||
|  |             proxy_set_header X-Ldap-BindPass "secret"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  | my $d = $t->testdir(); | ||||||
|  | 
 | ||||||
|  | $t->write_file('openssl.conf', <<EOF); | ||||||
|  | [ req ] | ||||||
|  | default_bits = 1024 | ||||||
|  | encrypt_key = no | ||||||
|  | distinguished_name = req_distinguished_name | ||||||
|  | [ req_distinguished_name ] | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  | foreach my $name ('localhost') { | ||||||
|  | 	system('openssl req -x509 -new ' | ||||||
|  | 		. "-config $d/openssl.conf -subj /CN=$name/ " | ||||||
|  | 		. "-out $d/$name.crt -keyout $d/$name.key " | ||||||
|  | 		. ">>$d/openssl.out 2>&1") == 0 | ||||||
|  | 		or die "Can't create certificate for $name: $!\n"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | $t->write_file_expand("slapd.conf", <<"EOF"); | ||||||
|  | include /etc/openldap/schema/core.schema | ||||||
|  | include /etc/openldap/schema/cosine.schema | ||||||
|  | include /etc/openldap/schema/inetorgperson.schema | ||||||
|  | include /etc/openldap/schema/nis.schema | ||||||
|  | include /etc/openldap/schema/misc.schema | ||||||
|  | 
 | ||||||
|  | pidfile  $d/slapd.pid | ||||||
|  | argsfile $d/slapd.args | ||||||
|  | logfile $d/slapd.log | ||||||
|  | 
 | ||||||
|  | loglevel 256 64 | ||||||
|  | 
 | ||||||
|  | access to dn.base="" by * read | ||||||
|  | access to dn.base="cn=Subschema" by * read | ||||||
|  | access to * | ||||||
|  |   by self write | ||||||
|  |   by users read | ||||||
|  |   by anonymous read | ||||||
|  | 
 | ||||||
|  | database hdb | ||||||
|  | suffix "dc=test,dc=local" | ||||||
|  | rootdn "cn=root,dc=test,dc=local" | ||||||
|  | rootpw secret | ||||||
|  | directory $d/openldap-data | ||||||
|  | index objectClass eq | ||||||
|  | 
 | ||||||
|  | TLSCipherSuite HIGH:MEDIUM:+SSLv2 | ||||||
|  | TLSCACertificateFile $d/localhost.crt | ||||||
|  | TLSCertificateFile $d/localhost.crt | ||||||
|  | TLSCertificateKeyFile $d/localhost.key | ||||||
|  | 
 | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | $t->write_file_expand("initial.ldif", <<'EOF'); | ||||||
|  | dn: dc=test,dc=local | ||||||
|  | dc: test | ||||||
|  | description: BlaBlaBla | ||||||
|  | objectClass: dcObject | ||||||
|  | objectClass: organization | ||||||
|  | o: Example, Inc. | ||||||
|  | 
 | ||||||
|  | dn: ou=Users, dc=test,dc=local | ||||||
|  | ou: Users | ||||||
|  | description: All people in organisation | ||||||
|  | objectclass: organizationalunit | ||||||
|  | 
 | ||||||
|  | dn: cn=user1,ou=Users,dc=test,dc=local | ||||||
|  | objectclass: inetOrgPerson | ||||||
|  | cn: User number one | ||||||
|  | sn: u1 | ||||||
|  | uid: user1 | ||||||
|  | userpassword: user1secret | ||||||
|  | mail: user1@example.com | ||||||
|  | description: user1 | ||||||
|  | ou: Users | ||||||
|  | 
 | ||||||
|  | dn: cn=user2,ou=Users,dc=test,dc=local | ||||||
|  | objectclass: inetOrgPerson | ||||||
|  | cn: User number one | ||||||
|  | sn: u2 | ||||||
|  | uid: user2 | ||||||
|  | userpassword: user2secret | ||||||
|  | mail: user2@example.com | ||||||
|  | description: user2 | ||||||
|  | ou: Users | ||||||
|  | 
 | ||||||
|  | dn: cn=user3,ou=Users,dc=test,dc=local | ||||||
|  | objectclass: inetOrgPerson | ||||||
|  | cn: User number one | ||||||
|  | sn: u3 | ||||||
|  | uid: user3 | ||||||
|  | userpassword: user3secret | ||||||
|  | mail: user3@example.com | ||||||
|  | description: user3 | ||||||
|  | ou: Users | ||||||
|  | 
 | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  | # -u ldap -g ldap | ||||||
|  | my $SLAPD = defined $ENV{TEST_LDAP_DAEMON} ? $ENV{TEST_LDAP_DAEMON} | ||||||
|  | 	: '/usr/lib64/openldap/slapd'; | ||||||
|  | 
 | ||||||
|  | my $AUTHD = defined $ENV{TEST_LDAP_AUTH_DAEMON} ? $ENV{TEST_LDAP_AUTH_DAEMON} | ||||||
|  | 	: 'nginx-ldap-auth-daemon.py'; | ||||||
|  | 
 | ||||||
|  | $t->has_daemon($SLAPD); | ||||||
|  | $t->has_daemon($AUTHD); | ||||||
|  | 
 | ||||||
|  | mkdir("$d/openldap-data"); | ||||||
|  | 
 | ||||||
|  | my $p3 = port(8083); | ||||||
|  | my $p4 = port(8084); | ||||||
|  | 
 | ||||||
|  | # change '0' to '1' or more to get debug from slapd | ||||||
|  | $t->run_daemon($SLAPD, '-d', '0', '-f', "$d/slapd.conf", | ||||||
|  | 		'-h', "ldap://127.0.0.1:$p3 ldaps://127.0.0.1:$p4"); | ||||||
|  | 
 | ||||||
|  | $t->waitforsocket("127.0.0.1:$p3") or die "Can't start slapd"; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | system("ldapadd -H ldap://127.0.0.1:$p3 -x -D \"cn=root,dc=test,dc=local\"" | ||||||
|  |        . " -f $d/initial.ldif -w secret >> $d/ldif.log 2>&1") == 0 | ||||||
|  | 		or die "Can't import initial LDIF\n"; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | $t->write_file_expand("auth_daemon.sh", <<"EOF"); | ||||||
|  | AUTHBIN=\$(realpath $AUTHD) | ||||||
|  | cd $d | ||||||
|  | exec coverage2 run \$AUTHBIN --host 127.0.0.1 \\ | ||||||
|  |     -p %%PORT_8888%% >$d/nginx-ldap-auth-dameon.stdlog 2>&1 | ||||||
|  | EOF | ||||||
|  | 
 | ||||||
|  | $t->run_daemon('/bin/sh', "$d/auth_daemon.sh"); | ||||||
|  | $t->waitforsocket('127.0.0.1:' . port(8888)) | ||||||
|  | 	or die "Can't start auth daemon"; | ||||||
|  | 
 | ||||||
|  | $t->plan(19); | ||||||
|  | 
 | ||||||
|  | $t->run(); | ||||||
|  | 
 | ||||||
|  | ############################################################################### | ||||||
|  | 
 | ||||||
|  | like(http_get_auth('/', 'user1', 'user1secret'), qr!ACCESS GRANTED!, | ||||||
|  | 	'proper user with proper pass'); | ||||||
|  | like(http_get_auth('/', 'user1', 'randompass'), qr!LOGIN PAGE!, | ||||||
|  | 	'proper user with incorrect pass'); | ||||||
|  | like(http_get_auth('/', 'user111', 'user1secret'), qr!LOGIN PAGE!, | ||||||
|  | 	'similar user with user1 pass'); | ||||||
|  | like(http_get_auth('/', 'randomuser', 'randompass'), qr!LOGIN PAGE!, | ||||||
|  | 	'random user with random pass'); | ||||||
|  | like(http_get_auth('/', 'user2', 'user2secret'), qr!ACCESS GRANTED!, | ||||||
|  | 	'user2 with proper pass'); | ||||||
|  | like(http_get_auth('/', 'user3', 'user3secret'), qr!ACCESS GRANTED!, | ||||||
|  | 	'user3 with proper pass'); | ||||||
|  | like(http_get_auth('/', '', ''), qr!LOGIN PAGE!, 'empty user no password'); | ||||||
|  | like(http_get('/'), qr!LOGIN PAGE!, 'no auth header'); | ||||||
|  | 
 | ||||||
|  | like(http_get_cookie('/', 'user1', 'user1secret'), qr!ACCESS GRANTED!, | ||||||
|  | 	'proper user with proper pass cookie'); | ||||||
|  | like(http_get_cookie('/', 'user1', 'randompasz'), qr!LOGIN PAGE!, | ||||||
|  | 	'proper user with incorrect pass cookie'); | ||||||
|  | like(http_get_cookie('/', 'randomuser', 'randompass'), qr!LOGIN PAGE!, | ||||||
|  | 	'random user with random pass cookie'); | ||||||
|  | like(http_get_cookie('/', 'user2', 'user2secret'), qr!ACCESS GRANTED!, | ||||||
|  | 	'user2 with proper pass cookie'); | ||||||
|  | like(http_get_cookie('/', 'user3', 'user3secret'), qr!ACCESS GRANTED!, | ||||||
|  | 	'user3 with proper pass cookie'); | ||||||
|  | 
 | ||||||
|  | like(http_get_auth_broken_base64('/', 'user3', 'user3secret'), qr!LOGIN PAGE!, | ||||||
|  | 	'user3 with proper pass broken base64'); | ||||||
|  | like(http_get_cookie_broken_base64('/', 'user3', 'user3secret'), qr!LOGIN PAGE!, | ||||||
|  | 	'user3 with proper pass broken cookie'); | ||||||
|  | 
 | ||||||
|  | like(http_get_auth('/ssl', 'user1', 'user1secret'), qr!ACCESS GRANTED!, | ||||||
|  | 	'proper user with proper pass with ssl'); | ||||||
|  | 
 | ||||||
|  | like(http_get_auth('/starttls', 'user1', 'user1secret'), qr!ACCESS GRANTED!, | ||||||
|  | 	'proper user with proper pass with starttls'); | ||||||
|  | 
 | ||||||
|  | # dn is not set, no default, daemon error => 502 | ||||||
|  | like(http_get_auth('/nodn', 'user1', 'user1secret'), qr!Internal Server Error!, | ||||||
|  | 	'dn must be set'); | ||||||
|  | 
 | ||||||
|  | # url is not set, default is used, which is not accessible => login page | ||||||
|  | like(http_get_auth('/nourl', 'user1', 'user1secret'), qr!LOGIN PAGE!, | ||||||
|  | 	'url must be set'); | ||||||
|  | 
 | ||||||
|  | ############################################################################### | ||||||
|  | 
 | ||||||
|  | sub http_get_auth { | ||||||
|  | 	my ($url, $user, $password) = @_; | ||||||
|  | 
 | ||||||
|  | 	my $auth = encode_base64($user . ':' . $password, ''); | ||||||
|  | 
 | ||||||
|  | 	return http(<<EOF); | ||||||
|  | GET $url HTTP/1.0 | ||||||
|  | Host: localhost | ||||||
|  | Authorization: Basic $auth | ||||||
|  | 
 | ||||||
|  | EOF | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # do not encode auth with base64, send plain | ||||||
|  | sub http_get_auth_broken_base64 { | ||||||
|  | 	my ($url, $user, $password) = @_; | ||||||
|  | 
 | ||||||
|  | 	my $auth = $user . ':' . $password; | ||||||
|  | 
 | ||||||
|  | 	return http(<<EOF); | ||||||
|  | GET $url HTTP/1.0 | ||||||
|  | Host: localhost | ||||||
|  | Authorization: Basic $auth | ||||||
|  | 
 | ||||||
|  | EOF | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | sub http_get_cookie { | ||||||
|  | 	my ($url, $user, $password) = @_; | ||||||
|  | 
 | ||||||
|  | 	my $auth = encode_base64($user . ':' . $password, ''); | ||||||
|  | 
 | ||||||
|  | 	return http(<<EOF); | ||||||
|  | GET $url HTTP/1.0 | ||||||
|  | Host: localhost | ||||||
|  | Cookie: nginxauth=$auth | ||||||
|  | 
 | ||||||
|  | EOF | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub http_get_cookie_broken_base64 { | ||||||
|  | 	my ($url, $user, $password) = @_; | ||||||
|  | 
 | ||||||
|  | 	my $auth = $user . ':' . $password; | ||||||
|  | 
 | ||||||
|  | 	return http(<<EOF); | ||||||
|  | GET $url HTTP/1.0 | ||||||
|  | Host: localhost | ||||||
|  | Cookie: nginxauth=$auth | ||||||
|  | 
 | ||||||
|  | EOF | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue