From 57fb98b5280eb80486271819a767405c90fb9f21 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov <vl.homutov@gmail.com> Date: Tue, 23 Oct 2018 18:37:24 +0300 Subject: [PATCH] Added test suite. The testsuite depends on nginx test suite, and requires an OpenLDAP server installed. --- t/README | 22 +++ t/ldap-auth.t | 444 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 466 insertions(+) create mode 100644 t/README create mode 100644 t/ldap-auth.t diff --git a/t/README b/t/README new file mode 100644 index 0000000..9caf5bb --- /dev/null +++ b/t/README @@ -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/ diff --git a/t/ldap-auth.t b/t/ldap-auth.t new file mode 100644 index 0000000..eccd2eb --- /dev/null +++ b/t/ldap-auth.t @@ -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 +} -- GitLab