Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add test suite with 100% line/branch coverage
- Loading branch information
1 parent
c053bb9
commit cf65eb4
Showing
6 changed files
with
459 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
/rdoc | ||
/simple_ldap_authenticator-*.gem | ||
/coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,35 @@ | ||
require 'rake' | ||
require 'rake/clean' | ||
begin | ||
require 'hanna/rdoctask' | ||
rescue LoadError | ||
require 'rake/rdoctask' | ||
end | ||
|
||
Rake::RDocTask.new do |rdoc| | ||
rdoc.rdoc_dir = "rdoc" | ||
rdoc.options += ["--quiet", "--line-numbers", "--inline-source"] | ||
rdoc.main = "README" | ||
rdoc.title = "simple_ldap_authenticator: Easy authentication to an LDAP server(s)" | ||
rdoc.rdoc_files.add ["README", "LICENSE", "lib/simple_ldap_authenticator.rb"] | ||
end | ||
CLEAN.include %w'*.gem coverage rdoc' | ||
|
||
desc "Package simple_ldap_authenticator" | ||
task :package do | ||
sh %{gem build simple_ldap_authenticator.gemspec} | ||
end | ||
|
||
### Specs | ||
|
||
desc "Run tests" | ||
task :test do | ||
ruby = ENV['RUBY'] ||= FileUtils::RUBY | ||
sh "#{ruby} #{"-w" if RUBY_VERSION >= '3'} test/simple_ldap_authenticator_test.rb" | ||
end | ||
|
||
task :default => :test | ||
|
||
desc "Run tests with coverage" | ||
task :test_cov do | ||
ruby = ENV['RUBY'] ||= FileUtils::RUBY | ||
ENV['COVERAGE'] = '1' | ||
sh "#{ruby} test/simple_ldap_authenticator_test.rb" | ||
end | ||
|
||
### RDoc | ||
|
||
require "rdoc/task" | ||
|
||
RDoc::Task.new do |rdoc| | ||
rdoc.rdoc_dir = "rdoc" | ||
rdoc.options += ['--inline-source', '--line-numbers', '--title', 'simple_ldap_authenticator: Easy authentication to an LDAP server(s)', '--main', 'README', '-f', 'hanna'] | ||
rdoc.rdoc_files.add %w"README LICENSE lib/simple_ldap_authenticator.rb" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,291 @@ | ||
# $Id$ | ||
# | ||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. | ||
# Gmail account: garbagecat10. | ||
# | ||
# This is an LDAP server intended for unit testing of Net::LDAP. | ||
# It implements as much of the protocol as we have the stomach | ||
# to implement but serves static data. Use ldapsearch to test | ||
# this server! | ||
# | ||
# To make this easier to write, we use the Ruby/EventMachine | ||
# reactor library. | ||
# | ||
|
||
#------------------------------------------------ | ||
|
||
module LdapServer | ||
LdapServerAsnSyntaxTemplate = { | ||
:application => { | ||
:constructed => { | ||
0 => :array, # LDAP BindRequest | ||
3 => :array # LDAP SearchRequest | ||
}, | ||
:primitive => { | ||
2 => :string, # ldapsearch sends this to unbind | ||
}, | ||
}, | ||
:context_specific => { | ||
:primitive => { | ||
0 => :string, # simple auth (password) | ||
7 => :string # present filter | ||
}, | ||
:constructed => { | ||
3 => :array # equality filter | ||
}, | ||
}, | ||
} | ||
|
||
def post_init | ||
#$logger.info "Accepted LDAP connection" | ||
@authenticated = false | ||
end | ||
|
||
def receive_data data | ||
@data ||= ""; @data << data | ||
while pdu = @data.read_ber!(LdapServerAsnSyntax) | ||
begin | ||
handle_ldap_pdu pdu | ||
rescue | ||
#$logger.error "closing connection due to error #{$!}" | ||
close_connection | ||
end | ||
end | ||
end | ||
|
||
def handle_ldap_pdu pdu | ||
tag_id = pdu[1].ber_identifier | ||
case tag_id | ||
when 0x60 | ||
handle_bind_request pdu | ||
when 0x63 | ||
handle_search_request pdu | ||
when 0x42 | ||
# bizarre thing, it's a null object (primitive application-2) | ||
# sent by ldapsearch to request an unbind (or a kiss-off, not sure which) | ||
close_connection_after_writing | ||
else | ||
#$logger.error "received unknown packet-type #{tag_id}" | ||
close_connection_after_writing | ||
end | ||
end | ||
|
||
def handle_bind_request pdu | ||
# TODO, return a proper LDAP error instead of blowing up on version error | ||
if pdu[1][0] != 3 || pdu[1][1] == "bad_version" | ||
send_ldap_response 1, pdu[0].to_i, 2, "", "We only support version 3" | ||
elsif pdu[1][1] != "user" | ||
send_ldap_response 1, pdu[0].to_i, 48, "", "Who are you?" | ||
elsif pdu[1][2].ber_identifier != 0x80 | ||
send_ldap_response 1, pdu[0].to_i, 7, "", "Keep it simple, man" | ||
elsif pdu[1][2] != "password" | ||
send_ldap_response 1, pdu[0].to_i, 49, "", "Make my day" | ||
else | ||
@authenticated = true | ||
send_ldap_response 1, pdu[0].to_i, 0, pdu[1][1], "I'll take it" | ||
end | ||
end | ||
|
||
# -- | ||
# Search Response ::= | ||
# CHOICE { | ||
# entry [APPLICATION 4] SEQUENCE { | ||
# objectName LDAPDN, | ||
# attributes SEQUENCE OF SEQUENCE { | ||
# AttributeType, | ||
# SET OF AttributeValue | ||
# } | ||
# }, | ||
# resultCode [APPLICATION 5] LDAPResult | ||
# } | ||
def handle_search_request pdu | ||
unless @authenticated | ||
# NOTE, early exit. | ||
send_ldap_response 5, pdu[0].to_i, 50, "", "Who did you say you were?" | ||
return | ||
end | ||
|
||
treebase = pdu[1][0] | ||
if treebase != "dc=bayshorenetworks,dc=com" | ||
send_ldap_response 5, pdu[0].to_i, 32, "", "unknown treebase" | ||
return | ||
end | ||
|
||
msgid = pdu[0].to_i.to_ber | ||
|
||
# pdu[1][7] is the list of requested attributes. | ||
# If it's an empty array, that means that *all* attributes were requested. | ||
requested_attrs = if pdu[1][7].length > 0 | ||
pdu[1][7].map(&:downcase) | ||
else | ||
:all | ||
end | ||
|
||
filters = pdu[1][6] | ||
if filters.length == 0 | ||
# NOTE, early exit. | ||
send_ldap_response 5, pdu[0].to_i, 53, "", "No filter specified" | ||
end | ||
|
||
# TODO, what if this returns nil? | ||
filter = Net::LDAP::Filter.parse_ldap_filter(filters) | ||
|
||
$ldif.each do |dn, entry| | ||
if filter.match(entry) | ||
attrs = [] | ||
entry.each do |k, v| | ||
if requested_attrs == :all || requested_attrs.include?(k.downcase) | ||
attrvals = v.map(&:to_ber).to_ber_set | ||
attrs << [k.to_ber, attrvals].to_ber_sequence | ||
end | ||
end | ||
|
||
appseq = [dn.to_ber, attrs.to_ber_sequence].to_ber_appsequence(4) | ||
pkt = [msgid.to_ber, appseq].to_ber_sequence | ||
send_data pkt | ||
end | ||
end | ||
|
||
send_ldap_response 5, pdu[0].to_i, 0, "", "Was that what you wanted?" | ||
end | ||
|
||
def send_ldap_response pkt_tag, msgid, code, dn, text | ||
send_data([msgid.to_ber, [code.to_ber, dn.to_ber, text.to_ber].to_ber_appsequence(pkt_tag)].to_ber) | ||
end | ||
end | ||
|
||
#------------------------------------------------ | ||
|
||
# Rather bogus, a global method, which reads a HARDCODED filename | ||
# parses out LDIF data. It will be used to serve LDAP queries out of this server. | ||
# | ||
def load_test_data | ||
ary = (<<END).split("\n") | ||
dn: dc=bayshorenetworks,dc=com | ||
objectClass: dcObject | ||
objectClass: organization | ||
o: Bayshore Networks LLC | ||
dc: bayshorenetworks | ||
dn: cn=Manager,dc=bayshorenetworks,dc=com | ||
objectClass: organizationalrole | ||
cn: Manager | ||
dn: ou=people,dc=bayshorenetworks,dc=com | ||
objectClass: organizationalunit | ||
ou: people | ||
dn: ou=privileges,dc=bayshorenetworks,dc=com | ||
objectClass: organizationalunit | ||
ou: privileges | ||
dn: ou=roles,dc=bayshorenetworks,dc=com | ||
objectClass: organizationalunit | ||
ou: roles | ||
dn: ou=office,dc=bayshorenetworks,dc=com | ||
objectClass: organizationalunit | ||
ou: office | ||
dn: mail=nogoodnik@steamheat.net,ou=people,dc=bayshorenetworks,dc=com | ||
cn: Bob Fosse | ||
mail: nogoodnik@steamheat.net | ||
sn: Fosse | ||
ou: people | ||
objectClass: top | ||
objectClass: inetorgperson | ||
objectClass: authorizedperson | ||
hasAccessRole: uniqueIdentifier=engineer,ou=roles | ||
hasAccessRole: uniqueIdentifier=ldapadmin,ou=roles | ||
hasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles | ||
hasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=ogilvy_eagle_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=greenplug_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=brandplace_logging_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=brandplace_report_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=workorder_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=bayshore_eagle_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=bayshore_eagle_superuser,ou=roles | ||
hasAccessRole: uniqueIdentifier=kledaras_user,ou=roles | ||
dn: mail=elephant@steamheat.net,ou=people,dc=bayshorenetworks,dc=com | ||
cn: Gwen Verdon | ||
mail: elephant@steamheat.net | ||
sn: Verdon | ||
ou: people | ||
objectClass: top | ||
objectClass: inetorgperson | ||
objectClass: authorizedperson | ||
hasAccessRole: uniqueIdentifier=brandplace_report_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=engineer,ou=roles | ||
hasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles | ||
hasAccessRole: uniqueIdentifier=ldapadmin,ou=roles | ||
dn: uniqueIdentifier=engineering,ou=privileges,dc=bayshorenetworks,dc=com | ||
uniqueIdentifier: engineering | ||
ou: privileges | ||
objectClass: accessPrivilege | ||
dn: uniqueIdentifier=engineer,ou=roles,dc=bayshorenetworks,dc=com | ||
uniqueIdentifier: engineer | ||
ou: roles | ||
objectClass: accessRole | ||
hasAccessPrivilege: uniqueIdentifier=engineering,ou=privileges | ||
dn: uniqueIdentifier=ldapadmin,ou=roles,dc=bayshorenetworks,dc=com | ||
uniqueIdentifier: ldapadmin | ||
ou: roles | ||
objectClass: accessRole | ||
dn: uniqueIdentifier=ldapsuperadmin,ou=roles,dc=bayshorenetworks,dc=com | ||
uniqueIdentifier: ldapsuperadmin | ||
ou: roles | ||
objectClass: accessRole | ||
dn: mail=catperson@steamheat.net,ou=people,dc=bayshorenetworks,dc=com | ||
cn: Sid Sorokin | ||
mail: catperson@steamheat.net | ||
sn: Sorokin | ||
ou: people | ||
objectClass: top | ||
objectClass: inetorgperson | ||
objectClass: authorizedperson | ||
hasAccessRole: uniqueIdentifier=engineer,ou=roles | ||
hasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles | ||
hasAccessRole: uniqueIdentifier=ogilvy_eagle_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=greenplug_user,ou=roles | ||
hasAccessRole: uniqueIdentifier=workorder_user,ou=roles | ||
END | ||
hash = {} | ||
while (line = ary.shift) && line.chomp! | ||
if line =~ /^dn:[\s]*/i | ||
dn = $' | ||
hash[dn] = {} | ||
while (attr = ary.shift) && attr.chomp! && attr =~ /^([\w]+)[\s]*:[\s]*/ | ||
hash[dn][$1.downcase] ||= [] | ||
hash[dn][$1.downcase] << $' | ||
end | ||
end | ||
end | ||
hash | ||
end | ||
|
||
#------------------------------------------------ | ||
|
||
if __FILE__ == $0 | ||
require 'eventmachine' | ||
require 'logger' | ||
#$logger = Logger.new $stderr | ||
$ldif = load_test_data | ||
|
||
require 'net/ldap' | ||
LdapServerAsnSyntax = Net::BER.compile_syntax(LdapServer::LdapServerAsnSyntaxTemplate) | ||
EventMachine.run do | ||
port = (ENV['PORT'] || 3890).to_i | ||
EventMachine.start_server "127.0.0.1", port, LdapServer | ||
#EventMachine.add_periodic_timer 60, proc { $logger.info "heartbeat" } | ||
#$logger.info "started LDAP server on 127.0.0.1 port #{port}" | ||
end | ||
end |
Oops, something went wrong.