1. Michael Granger
  2. ruby-openldap

Commits

Michael Granger  committed 10ae7e6

Got the server startup working, added some initial specs.

pair: mahlon

  • Participants
  • Parent commits 8ad7ee7
  • Branches default

Comments (0)

Files changed (8)

File .autotest

-# -*- ruby -*-
-
-require 'autotest/restart'
-
-# Autotest.add_hook :initialize do |at|
-#   at.extra_files << "../some/external/dependency.rb"
-#
-#   at.libs << ":../some/external"
-#
-#   at.add_exception 'vendor'
-#
-#   at.add_mapping(/dependency.rb/) do |f, _|
-#     at.files_matching(/test_.*rb$/)
-#   end
-#
-#   %w(TestA TestB).each do |klass|
-#     at.extra_class_map[klass] = "test/test_misc.rb"
-#   end
-# end
-
-# Autotest.add_hook :run_command do |at|
-#   system "rake build"
-# end

File .hgignore

View file
 ^doc/
 ^pkg/
 ^ChangeLog$
+test_workdir/

File spec/data/DB_CONFIG

View file
+set_cachesize 0 268435456 1
+set_lg_regionmax 262144
+set_lg_bsize 2097152

File spec/data/testdata.ldif

Empty file added.

File spec/lib/constants.rb

View file
 
 	unless defined?( TEST_LDAP_URI )
 
-		TEST_CONFIG_FILE = Pathname( __FILE__ ).dirname.parent.parent + 'test.conf'
-
-		TEST_LOCAL_LDAP_STRING = 'ldap://localhost'
-		TEST_LOCAL_LDAP_URI = URI( TEST_LOCAL_LDAP_STRING )
-
-		TEST_LDAP_STRING = 'ldap://ldap.example.com'
+		TEST_LDAP_STRING = 'ldap://localhost:6363'
 		TEST_LDAP_URI = URI( TEST_LDAP_STRING )
 
-		TEST_LDAPBASE_STRING = 'ldap://ldap.example.com/dc=example,dc=com'
+		TEST_LDAPS_STRING = 'ldaps://localhost:6363'
+		TEST_LDAPS_URI = URI( TEST_LDAPS_STRING )
+
+		TEST_LDAPBASE_STRING = "#{TEST_LDAP_STRING}/dc=example,dc=com"
 		TEST_LDAPBASE_URI = URI( TEST_LDAPBASE_STRING )
 
 		constants.each do |cname|

File spec/lib/helpers.rb

View file
 #!/usr/bin/ruby
 # coding: utf-8
 
+require 'pathname'
+require 'shellwords'
 require 'yaml'
 require 'fileutils'
 require 'loggability/spechelpers'
+require 'openssl'
 
 require 'openldap'
 require 'openldap/mixins'
 
 ### RSpec helper functions.
 module OpenLDAP::SpecHelpers
-	include OpenLDAP::TestConstants
+	include OpenLDAP::TestConstants,
+	        FileUtils
 
-	###############
-	module_function
-	###############
+	include FileUtils::Verbose if $DEBUG || $VERBOSE
 
-	### Load the testing LDAP config options from a YAML file.
-	def load_ldap_config
-		unless defined?( @ldap_config ) && @ldap_config
-			if TEST_CONFIG_FILE.exist?
-				$stderr.puts "Loading LDAP config from #{TEST_CONFIG_FILE}" if $VERBOSE
-				@ldap_config = YAML.load( TEST_CONFIG_FILE.read )
+
+	BASEDIR        = Pathname( __FILE__ ).dirname.parent.parent
+
+	TESTING_SLAPD_URI = 'ldap://localhost:6363'
+	TESTING_SLAPD_SSL_URI = 'ldaps://localhost:6364'
+
+	TEST_WORKDIR   = BASEDIR + 'test_workdir'
+	TEST_DATADIR   = TEST_WORKDIR + 'data'
+
+	SPEC_DIR       = BASEDIR + 'spec'
+	SPEC_DATADIR   = SPEC_DIR + 'data'
+	SPEC_SLAPDCONF = SPEC_DATADIR + 'slapd.conf'
+	SPEC_DBCONFIG  = SPEC_DATADIR + 'DB_CONFIG'
+	SPEC_LDIF      = SPEC_DATADIR + 'testdata.ldif'
+
+
+	### Start a localized slapd daemon for testing.
+	def start_testing_slapd
+
+		self.create_test_directories
+		self.copy_test_files
+		self.generate_ssl_cert
+		self.install_initial_data
+		slapd_pid = self.start_slapd
+
+		return slapd_pid
+	end
+
+
+	### Stop the slapd started by #start_testing_slapd, if it's still alive.
+	def stop_testing_slapd( pid )
+		if pid
+			$stderr.puts "Shutting down slapd at PID %p" % [ pid ]
+			begin
+				Process.kill( :TERM, pid )
+				Process.waitpid2( pid )
+			rescue Errno::ESRCH
+				$stderr.puts "  not running."
+				# Not running
+			rescue Errno::EPERM
+				$stderr.puts "  not allowed (not slapd?)."
 			else
-				$stderr.puts "Skipping tests that require access to a live directory. Copy the ",
-					"#{TEST_CONFIG_FILE}-example file and provide valid values for testing",
-					"with an actual LDAP."
-				@ldap_config = {}
+				$stderr.puts "  killed."
 			end
 		end
 
-		return @ldap_config
+		unless $DEBUG || ENV['MAINTAINER_MODE']
+			$stderr.puts "Cleaning up #{TEST_WORKDIR}..."
+			TEST_WORKDIR.rmtree
+		end
+	end
+
+
+	### Create the directory used for the testing instance of slapd.
+	def create_test_directories
+		TEST_DATADIR.mkpath
+		return TEST_WORKDIR
+	end
+
+
+	### Copy over any files necessary for testing to the testing directory.
+	def copy_test_files
+		install SPEC_SLAPDCONF, TEST_WORKDIR
+		install SPEC_DBCONFIG, TEST_DATADIR
+	end
+
+
+	### Generate a self-signed cert for testing SSL/TlS connections
+	### Mostly stolen from https://gist.github.com/nickyp/886884
+	def generate_ssl_cert
+		key = OpenSSL::PKey::RSA.new( 1024 )
+		public_key = key.public_key
+
+		subject = "/CN=*.example.com"
+
+		cert = OpenSSL::X509::Certificate.new
+		cert.subject = cert.issuer = OpenSSL::X509::Name.parse( subject )
+		cert.not_before = Time.now
+		cert.not_after = Time.now + 365 * 24 * 60 * 60
+		cert.public_key = public_key
+		cert.serial = 0x0
+		cert.version = 2
+
+		ef = OpenSSL::X509::ExtensionFactory.new
+		ef.subject_certificate = cert
+		ef.issuer_certificate = cert
+		cert.extensions = [
+			ef.create_extension( "basicConstraints", "CA:TRUE" , true ),
+			ef.create_extension( "subjectKeyIdentifier", "hash" ),
+			# ef.create_extension("keyUsage", "cRLSign,keyCertSign", true),
+		]
+		ext = ef.create_extension( "authorityKeyIdentifier", "keyid:always,issuer:always" )
+		cert.add_extension( ext )
+
+		cert.sign( key, OpenSSL::Digest::SHA1.new )
+
+		pemfile = TEST_WORKDIR + 'example.pem'
+		pemfile.open( 'w' ) {|io|
+			io.puts(cert.to_pem)
+			io.puts(key.to_pem)
+		}
+	end
+
+
+	### Install the initial testing data into the data dir in +TEST_WORKDIR+.
+	def install_initial_data
+		slapadd = self.find_binary( 'slapadd' )
+		ldiffile = SPEC_LDIF.to_s
+		configfile = TEST_WORKDIR + 'slapd.conf'
+
+		cmd = [
+			slapadd,
+			'-f', configfile.to_s,
+			'-l', ldiffile
+		]
+
+		system( *cmd, chdir: TEST_WORKDIR.to_s ) or
+		raise "Couldn't load initial data: #{Shellwords.join(cmd)}"
+	end
+
+
+	### Start the testing slapd and keep track of its PID.
+	def start_slapd
+		$stderr.print "Starting up testing slapd..."
+		slapd = self.find_binary( 'slapd' )
+		logio = File.open( TEST_WORKDIR + 'slapd.log', 'w' )
+
+		cmd = [
+			slapd,
+			'-f', 'slapd.conf',
+			'-d', '64',
+			'-h', "ldap://localhost:6363 ldaps://localhost:6364"
+		]
+
+		puts( Shellwords.join(cmd) )
+		pid = spawn( *cmd, chdir: TEST_WORKDIR.to_s, [:out,:err] => logio )
+
+		$stderr.puts "started at PID %d" % [ pid ]
+		return pid
+	end
+
+
+	### Attempt to find the path to the binary with the specified +name+, returning it if found,
+	### or +nil+ if not.
+	def find_binary( name )
+		return ENV[name.upcase] if ENV.key?( name.upcase )
+
+		dirs = ENV['PATH'].split( File::PATH_SEPARATOR )
+		dirs += dirs \
+			.find_all {|dir| dir.end_with?('bin') } \
+			.map {|dir| dir[0..-4] + 'libexec' }
+
+		paths = dirs.collect {|dir| File.join(dir, name) }
+		found = paths.find {|path| File.executable?(path) } or
+			raise "Unable to find %p in your PATH, or in corresponding 'libexec' directories." %
+				[name]
+
+		return found
 	end
 
 
 
 ### Mock with Rspec
 RSpec.configure do |config|
+	include OpenLDAP::SpecHelpers
 	include OpenLDAP::TestConstants
 	include Loggability::SpecHelpers
 
 
 	config.filter_run_excluding( :ruby_1_9_only => true ) if RUBY_VERSION >= '1.9.0'
 	config.filter_run_excluding( :ruby_2_0_only => true ) if RUBY_VERSION >= '2.0.0'
-	config.filter_run_excluding( :with_ldap_server => true ) unless TEST_CONFIG_FILE.exist?
+  # config.filter_run_excluding( :with_ldap_server => true ) unless TEST_CONFIG_FILE.exist?
 end
 
 # vim: set nosta noet ts=4 sw=4:

File spec/openldap/connection_spec.rb

View file
 describe OpenLDAP::Connection do
 
 	before( :all ) do
-		setup_logging( :fatal )
+		setup_logging( :debug )
+		@slapd_pid = start_testing_slapd()
 	end
 
 	after( :all ) do
+		stop_testing_slapd( @slapd_pid )
 		reset_logging()
 	end
 
 	end
 
 	it "can be created with several LDAP URIs" do
-		conn = OpenLDAP::Connection.new( TEST_LDAP_URI, TEST_LOCAL_LDAP_URI )
-		conn.uris.should == [ TEST_LDAP_URI, TEST_LOCAL_LDAP_URI ]
+		conn = OpenLDAP::Connection.new( TEST_LDAP_URI, TEST_LDAPS_URI )
+		conn.uris.should == [ TEST_LDAP_URI, TEST_LDAPS_URI ]
 	end
 
 	context "an instance" do
 			@conn.fdno.should be_nil()
 		end
 
+		it "fails to start TLS with strict cert-checking enabled", :with_ldap_server => true do;
+			expect {
+				@conn.start_tls( :tls_require_cert => :demand )
+			}.to raise_error( OpenLDAP::ConnectError, /ldap_start_tls_s/i )
+		end
+
+		it "can start TLS negotiation synchronously", :with_ldap_server => true do;
+			@conn.start_tls( :tls_require_cert => :never )
+		end
+
 	end
 
 
-	it "can start TLS negotiation synchronously", :with_ldap_server => true do
-		config = load_ldap_config()
-		uri = config['uri'] or abort "No 'uri' in the test config!"
-
-		conn = OpenLDAP::Connection.new( uri )
-		conn.start_tls
-	end
-
-	context "a connected instance", :with_ldap_server => true do
-
-		before( :all ) do
-			config = load_ldap_config()
-			@uri = config['uri'] or abort "No 'uri' in the test config!"
-		end
+	context "a connected instance", :if => @slapd_pid do
 
 		before( :each ) do
-			@conn = OpenLDAP::Connection.new( @uri )
+			@conn = OpenLDAP::Connection.new( TEST_LDAP_URI )
 			@conn.start_tls
 		end
 

File test.conf-example

-uri: ldap://ldap.example.com
-base: "dc=example,dc=com"