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