diff --git a/.travis.yml b/.travis.yml index 8f17123..09e4709 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,20 @@ language: ruby rvm: - - 1.9.3 - - 2.1.0 + - 1.9.3 + - 2.1.0 +env: + - TESTENV=openldap + - TESTENV=apacheds + +install: + - if [ "$TESTENV" = "openldap" ]; then ./script/install-openldap; fi + - bundle install + +script: + - ./script/cibuild-$TESTENV + +matrix: + fast_finish: true notifications: email: false diff --git a/Gemfile b/Gemfile index ab76291..4abbfe8 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,7 @@ source 'https://rubygems.org' # Specify your gem's dependencies in github-ldap.gemspec gemspec + +group :test, :development do + gem "byebug", :platforms => [:mri_20, :mri_21] +end diff --git a/lib/github/ldap.rb b/lib/github/ldap.rb index 9844ceb..1484bec 100644 --- a/lib/github/ldap.rb +++ b/lib/github/ldap.rb @@ -9,6 +9,7 @@ class Ldap require 'github/ldap/virtual_group' require 'github/ldap/virtual_attributes' require 'github/ldap/instrumentation' + require 'github/ldap/membership_validators' include Instrumentation diff --git a/lib/github/ldap/domain.rb b/lib/github/ldap/domain.rb index 8085c44..aa2066b 100644 --- a/lib/github/ldap/domain.rb +++ b/lib/github/ldap/domain.rb @@ -110,11 +110,15 @@ def valid_login?(login, password) # Check if a user exists based in the `uid`. # # login: is the user's login + # search_options: Net::LDAP#search compatible options to pass through # # Returns the user if the login matches any `uid`. # Returns nil if there are no matches. - def user?(login) - search(filter: login_filter(@uid, login), size: 1).first + def user?(login, search_options = {}) + options = search_options.merge \ + filter: login_filter(@uid, login), + size: 1 + search(options).first end # Check if a user can be bound with a password. diff --git a/lib/github/ldap/filter.rb b/lib/github/ldap/filter.rb index a238642..64f5aa3 100644 --- a/lib/github/ldap/filter.rb +++ b/lib/github/ldap/filter.rb @@ -20,16 +20,18 @@ def group_filter(group_names) # Filter to check group membership. # - # entry: finds groups this Net::LDAP::Entry is a member of (optional) + # entry: finds groups this entry is a member of (optional) + # Expects a Net::LDAP::Entry or String DN. # # Returns a Net::LDAP::Filter. def member_filter(entry = nil) if entry + entry = entry.dn if entry.respond_to?(:dn) MEMBERSHIP_NAMES. - map {|n| Net::LDAP::Filter.eq(n, entry.dn) }.reduce(:|) + map {|n| Net::LDAP::Filter.eq(n, entry) }.reduce(:|) else MEMBERSHIP_NAMES. - map {|n| Net::LDAP::Filter.pres(n) }. reduce(:|) + map {|n| Net::LDAP::Filter.pres(n) }. reduce(:|) end end @@ -41,10 +43,16 @@ def member_filter(entry = nil) # uid_attr: specifies the memberUid attribute to match with # # Returns a Net::LDAP::Filter or nil if no entry has no UID set. - def posix_member_filter(entry, uid_attr) - if !entry[uid_attr].empty? - entry[uid_attr].map { |uid| Net::LDAP::Filter.eq("memberUid", uid) }. - reduce(:|) + def posix_member_filter(entry_or_uid, uid_attr = nil) + case entry_or_uid + when Net::LDAP::Entry + entry = entry_or_uid + if !entry[uid_attr].empty? + entry[uid_attr].map { |uid| Net::LDAP::Filter.eq("memberUid", uid) }. + reduce(:|) + end + when String + Net::LDAP::Filter.eq("memberUid", entry_or_uid) end end diff --git a/lib/github/ldap/membership_validators.rb b/lib/github/ldap/membership_validators.rb new file mode 100644 index 0000000..c355589 --- /dev/null +++ b/lib/github/ldap/membership_validators.rb @@ -0,0 +1,17 @@ +require 'github/ldap/membership_validators/base' +require 'github/ldap/membership_validators/classic' +require 'github/ldap/membership_validators/recursive' + +module GitHub + class Ldap + # Provides various strategies for validating membership. + # + # For example: + # + # groups = domain.groups(%w(Engineering)) + # validator = GitHub::Ldap::MembershipValidators::Classic.new(ldap, groups) + # validator.perform(entry) #=> true + # + module MembershipValidators; end + end +end diff --git a/lib/github/ldap/membership_validators/base.rb b/lib/github/ldap/membership_validators/base.rb new file mode 100644 index 0000000..3c47853 --- /dev/null +++ b/lib/github/ldap/membership_validators/base.rb @@ -0,0 +1,37 @@ +module GitHub + class Ldap + module MembershipValidators + class Base + + # Internal: The GitHub::Ldap object to search domains with. + attr_reader :ldap + + # Internal: an Array of Net::LDAP::Entry group objects to validate with. + attr_reader :groups + + # Public: Instantiate new validator. + # + # - ldap: GitHub::Ldap object + # - groups: Array of Net::LDAP::Entry group objects + def initialize(ldap, groups) + @ldap = ldap + @groups = groups + end + + # Abstract: Performs the membership validation check. + # + # Returns Boolean whether the entry's membership is validated or not. + # def perform(entry) + # end + + # Internal: Domains to search through. + # + # Returns an Array of GitHub::Ldap::Domain objects. + def domains + @domains ||= ldap.search_domains.map { |base| ldap.domain(base) } + end + private :domains + end + end + end +end diff --git a/lib/github/ldap/membership_validators/classic.rb b/lib/github/ldap/membership_validators/classic.rb new file mode 100644 index 0000000..f1cda3e --- /dev/null +++ b/lib/github/ldap/membership_validators/classic.rb @@ -0,0 +1,33 @@ +module GitHub + class Ldap + module MembershipValidators + # Validates membership using `GitHub::Ldap::Domain#membership`. + # + # This is a simple wrapper for existing functionality in order to expose + # it consistently with the new approach. + class Classic < Base + def perform(entry) + return true if groups.empty? + + domains.each do |domain| + membership = domain.membership(entry, group_names) + + if !membership.empty? + entry[:groups] = membership + return true + end + end + + false + end + + # Internal: the group names to look up membership for. + # + # Returns an Array of String group names (CNs). + def group_names + @group_names ||= groups.map { |g| g[:cn].first } + end + end + end + end +end diff --git a/lib/github/ldap/membership_validators/recursive.rb b/lib/github/ldap/membership_validators/recursive.rb new file mode 100644 index 0000000..7d4936c --- /dev/null +++ b/lib/github/ldap/membership_validators/recursive.rb @@ -0,0 +1,90 @@ +module GitHub + class Ldap + module MembershipValidators + # Validates membership recursively. + # + # The first step checks whether the entry is a direct member of the given + # groups. If they are, then we've validated membership successfully. + # + # If not, query for all of the groups that have our groups as members, + # then we check if the entry is a member of any of those. + # + # This is repeated until the entry is found, recursing and requesting + # groups in bulk each iteration until we hit the maximum depth allowed + # and have to give up. + # + # This results in a maximum of `depth` queries (per domain) to validate + # membership in a list of groups. + class Recursive < Base + include Filter + + DEFAULT_MAX_DEPTH = 9 + ATTRS = %w(dn cn) + + def perform(entry, depth = DEFAULT_MAX_DEPTH) + domains.each do |domain| + # find groups entry is an immediate member of + membership = domain.search(filter: member_filter(entry), attributes: ATTRS) + + # success if any of these groups match the restricted auth groups + return true if membership.any? { |entry| group_dns.include?(entry.dn) } + + # give up if the entry has no memberships to recurse + next if membership.empty? + + # recurse to at most `depth` + depth.times do |n| + # find groups whose members include membership groups + membership = domain.search(filter: membership_filter(membership), attributes: ATTRS) + + # success if any of these groups match the restricted auth groups + return true if membership.any? { |entry| group_dns.include?(entry.dn) } + + # give up if there are no more membersips to recurse + break if membership.empty? + end + + # give up on this base if there are no memberships to test + next if membership.empty? + end + + false + end + + # Internal: Construct a filter to find groups this entry is a direct + # member of. + # + # Overloads the included `GitHub::Ldap::Filters#member_filter` method + # to inject `posixGroup` handling. + # + # Returns a Net::LDAP::Filter object. + def member_filter(entry_or_uid, uid = ldap.uid) + filter = super(entry_or_uid) + + if ldap.posix_support_enabled? + if posix_filter = posix_member_filter(entry_or_uid, uid) + filter |= posix_filter + end + end + + filter + end + + # Internal: Construct a filter to find groups whose members are the + # Array of String group DNs passed in. + # + # Returns a String filter. + def membership_filter(groups) + groups.map { |entry| member_filter(entry, :cn) }.reduce(:|) + end + + # Internal: the group DNs to check against. + # + # Returns an Array of String DNs. + def group_dns + @group_dns ||= groups.map(&:dn) + end + end + end + end +end diff --git a/lib/github/ldap/server.rb b/lib/github/ldap/server.rb index c2cf10c..c7f624a 100644 --- a/lib/github/ldap/server.rb +++ b/lib/github/ldap/server.rb @@ -38,6 +38,8 @@ def self.start_server(options = {}) @server_options[:domain] = @server_options[:user_domain] @server_options[:tmpdir] ||= server_tmp + @server_options[:quiet] = false if @server_options[:verbose] + @ldap_server = Ladle::Server.new(@server_options) @ldap_server.start end diff --git a/script/cibuild-apacheds b/script/cibuild-apacheds new file mode 100755 index 0000000..6e02fa0 --- /dev/null +++ b/script/cibuild-apacheds @@ -0,0 +1,7 @@ +#!/usr/bin/env sh +set -e +set -x + +cd `dirname $0`/.. + +bundle exec rake diff --git a/script/cibuild-openldap b/script/cibuild-openldap new file mode 100755 index 0000000..6e02fa0 --- /dev/null +++ b/script/cibuild-openldap @@ -0,0 +1,7 @@ +#!/usr/bin/env sh +set -e +set -x + +cd `dirname $0`/.. + +bundle exec rake diff --git a/script/install-openldap b/script/install-openldap new file mode 100755 index 0000000..bb0033f --- /dev/null +++ b/script/install-openldap @@ -0,0 +1,44 @@ +#!/usr/bin/env sh +set -e +set -x + +BASE_PATH="$( cd `dirname $0`/../test/fixtures/openldap && pwd )" +SEED_PATH="$( cd `dirname $0`/../test/fixtures/common && pwd )" + +DEBIAN_FRONTEND=noninteractive sudo -E apt-get install -y --force-yes slapd time ldap-utils + +sudo /etc/init.d/slapd stop + +TMPDIR=$(mktemp -d) +cd $TMPDIR + +# Delete data and reconfigure. +sudo cp -v /var/lib/ldap/DB_CONFIG ./DB_CONFIG +sudo rm -rf /etc/ldap/slapd.d/* +sudo rm -rf /var/lib/ldap/* +sudo cp -v ./DB_CONFIG /var/lib/ldap/DB_CONFIG +sudo slapadd -F /etc/ldap/slapd.d -b "cn=config" -l $BASE_PATH/slapd.conf.ldif +# Load memberof and ref-int overlays and configure them. +sudo slapadd -F /etc/ldap/slapd.d -b "cn=config" -l $BASE_PATH/memberof.ldif + +# Add base domain. +sudo slapadd -F /etc/ldap/slapd.d < [:cn]) + assert_equal [:dn, :cn], entry.attribute_names end def test_auth_binds - user = @domain.user?('calavera') - assert @domain.auth(user, 'passworD1'), 'Expected user to be bound.' + assert user = @domain.user?('user1') + assert @domain.auth(user, 'passworD1'), 'Expected user to bind' end def test_auth_does_not_bind - user = @domain.user?('calavera') - assert !@domain.auth(user, 'foo'), 'Expected user not to be bound.' + assert user = @domain.user?('user1') + refute @domain.auth(user, 'foo'), 'Expected user not not bind' end end @@ -143,48 +151,37 @@ class GitHubLdapDomainUnauthenticatedTest < GitHub::Ldap::UnauthenticatedTest end class GitHubLdapDomainNestedGroupsTest < GitHub::Ldap::Test - def self.test_server_options - {user_fixtures: FIXTURES.join('github-with-subgroups.ldif').to_s} - end - def setup @ldap = GitHub::Ldap.new(options) @domain = @ldap.domain("dc=github,dc=com") end def test_membership_in_subgroups - user = @ldap.domain('uid=rubiojr,ou=users,dc=github,dc=com').bind + user = @ldap.domain('uid=user1,ou=People,dc=github,dc=com').bind - assert @domain.is_member?(user, %w(enterprise-ops)), - "Expected `enterprise-ops` to include the member `#{user.dn}`" + assert @domain.is_member?(user, %w(nested-groups)), + "Expected `nested-groups` to include the member `#{user.dn}`" end def test_membership_in_deeply_nested_subgroups - assert user = @ldap.domain('uid=user1.1.1.1,ou=users,dc=github,dc=com').bind + assert user = @ldap.domain('uid=user1,ou=People,dc=github,dc=com').bind - assert @domain.is_member?(user, %w(group1)), - "Expected `group1` to include the member `#{user.dn}` via deep recursion" + assert @domain.is_member?(user, %w(n-depth-nested-group4)), + "Expected `n-depth-nested-group4` to include the member `#{user.dn}` via deep recursion" end end class GitHubLdapPosixGroupsWithRecursionFallbackTest < GitHub::Ldap::Test - def self.test_server_options - { - custom_schemas: FIXTURES.join('posixGroup.schema.ldif'), - user_fixtures: FIXTURES.join('github-with-posixGroups.ldif').to_s, - # so we exercise the recursive group search fallback - recursive_group_search_fallback: true - } - end - def setup - @ldap = GitHub::Ldap.new(options) + opts = options.merge \ + recursive_group_search_fallback: true + @ldap = GitHub::Ldap.new(opts) @domain = @ldap.domain("dc=github,dc=com") - @cn = "enterprise-posix-devs" + @cn = "posix-group1" end def test_membership_for_posixGroups - assert user = @ldap.domain('uid=mtodd,ou=users,dc=github,dc=com').bind + assert user = @ldap.domain('uid=user1,ou=People,dc=github,dc=com').bind assert @domain.is_member?(user, [@cn]), "Expected `#{@cn}` to include the member `#{user.dn}`" @@ -192,23 +189,16 @@ def test_membership_for_posixGroups end class GitHubLdapPosixGroupsWithoutRecursionTest < GitHub::Ldap::Test - def self.test_server_options - { - custom_schemas: FIXTURES.join('posixGroup.schema.ldif'), - user_fixtures: FIXTURES.join('github-with-posixGroups.ldif').to_s, - # so we test the test the non-recursive group membership search - recursive_group_search_fallback: false - } - end - def setup - @ldap = GitHub::Ldap.new(options) + opts = options.merge \ + recursive_group_search_fallback: false + @ldap = GitHub::Ldap.new(opts) @domain = @ldap.domain("dc=github,dc=com") - @cn = "enterprise-posix-devs" + @cn = "posix-group1" end def test_membership_for_posixGroups - assert user = @ldap.domain('uid=mtodd,ou=users,dc=github,dc=com').bind + assert user = @ldap.domain('uid=user1,ou=People,dc=github,dc=com').bind assert @domain.is_member?(user, [@cn]), "Expected `#{@cn}` to include the member `#{user.dn}`" @@ -218,25 +208,17 @@ def test_membership_for_posixGroups # Specifically testing that this doesn't break when posixGroups are not # supported. class GitHubLdapWithoutPosixGroupsTest < GitHub::Ldap::Test - def self.test_server_options - { - custom_schemas: FIXTURES.join('posixGroup.schema.ldif'), - user_fixtures: FIXTURES.join('github-with-posixGroups.ldif').to_s, - # so we test the test the non-recursive group membership search - recursive_group_search_fallback: false, - # explicitly disable posixGroup support (even if the schema supports it) - posix_support: false - } - end - def setup - @ldap = GitHub::Ldap.new(options) + opts = options.merge \ + recursive_group_search_fallback: false, # test non-recursive group membership search + posix_support: false # disable posixGroup support + @ldap = GitHub::Ldap.new(opts) @domain = @ldap.domain("dc=github,dc=com") - @cn = "enterprise-posix-devs" + @cn = "posix-group1" end def test_membership_for_posixGroups - assert user = @ldap.domain('uid=mtodd,ou=users,dc=github,dc=com').bind + assert user = @ldap.domain('uid=user1,ou=People,dc=github,dc=com').bind refute @domain.is_member?(user, [@cn]), "Expected `#{@cn}` to not include the member `#{user.dn}`" diff --git a/test/filter_test.rb b/test/filter_test.rb index 8fc6ba2..58992a8 100644 --- a/test/filter_test.rb +++ b/test/filter_test.rb @@ -20,7 +20,8 @@ def setup @subject = Subject.new(@ldap) @me = 'uid=calavera,dc=github,dc=com' @uid = "calavera" - @entry = Entry.new(@me, @uid) + @entry = Net::LDAP::Entry.new(@me) + @entry[:uid] = @uid end def test_member_present @@ -32,6 +33,11 @@ def test_member_equal @subject.member_filter(@entry).to_s end + def test_member_equal_with_string + assert_equal "(|(member=#{@me})(uniqueMember=#{@me}))", + @subject.member_filter(@entry.dn).to_s + end + def test_posix_member_without_uid @entry.uid = nil assert_nil @subject.posix_member_filter(@entry, @ldap.uid) @@ -42,6 +48,11 @@ def test_posix_member_equal @subject.posix_member_filter(@entry, @ldap.uid).to_s end + def test_posix_member_equal_string + assert_equal "(memberUid=#{@uid})", + @subject.posix_member_filter(@uid).to_s + end + def test_groups_reduced assert_equal "(|(cn=Enterprise)(cn=People))", @subject.group_filter(%w(Enterprise People)).to_s diff --git a/test/fixtures/common/seed.ldif b/test/fixtures/common/seed.ldif new file mode 100644 index 0000000..29284bb --- /dev/null +++ b/test/fixtures/common/seed.ldif @@ -0,0 +1,369 @@ +dn: ou=People,dc=github,dc=com +objectClass: top +objectClass: organizationalUnit +ou: People + +dn: ou=Groups,dc=github,dc=com +objectClass: top +objectClass: organizationalUnit +ou: Groups + +# Directory Superuser +dn: uid=admin,dc=github,dc=com +uid: admin +cn: system administrator +sn: administrator +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +displayName: Directory Superuser +userPassword: passworD1 + +# Users 1-10 + +dn: uid=user1,ou=People,dc=github,dc=com +uid: user1 +cn: user1 +sn: user1 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user1@github.com + +dn: uid=user2,ou=People,dc=github,dc=com +uid: user2 +cn: user2 +sn: user2 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user2@github.com + +dn: uid=user3,ou=People,dc=github,dc=com +uid: user3 +cn: user3 +sn: user3 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user3@github.com + +dn: uid=user4,ou=People,dc=github,dc=com +uid: user4 +cn: user4 +sn: user4 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user4@github.com + +dn: uid=user5,ou=People,dc=github,dc=com +uid: user5 +cn: user5 +sn: user5 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user5@github.com + +dn: uid=user6,ou=People,dc=github,dc=com +uid: user6 +cn: user6 +sn: user6 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user6@github.com + +dn: uid=user7,ou=People,dc=github,dc=com +uid: user7 +cn: user7 +sn: user7 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user7@github.com + +dn: uid=user8,ou=People,dc=github,dc=com +uid: user8 +cn: user8 +sn: user8 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user8@github.com + +dn: uid=user9,ou=People,dc=github,dc=com +uid: user9 +cn: user9 +sn: user9 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user9@github.com + +dn: uid=user10,ou=People,dc=github,dc=com +uid: user10 +cn: user10 +sn: user10 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: user10@github.com + +# Emailless User + +dn: uid=emailless-user1,ou=People,dc=github,dc=com +uid: emailless-user1 +cn: emailless-user1 +sn: emailless-user1 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 + +# Groupless User + +dn: uid=groupless-user1,ou=People,dc=github,dc=com +uid: groupless-user1 +cn: groupless-user1 +sn: groupless-user1 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 + +# Admin User + +dn: uid=admin1,ou=People,dc=github,dc=com +uid: admin1 +cn: admin1 +sn: admin1 +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +userPassword: passworD1 +mail: admin1@github.com + +# Groups + +dn: cn=ghe-users,ou=Groups,dc=github,dc=com +cn: ghe-users +objectClass: groupOfNames +member: uid=user1,ou=People,dc=github,dc=com +member: uid=emailless-user1,ou=People,dc=github,dc=com + +dn: cn=all-users,ou=Groups,dc=github,dc=com +cn: all-users +objectClass: groupOfNames +member: cn=ghe-users,ou=Groups,dc=github,dc=com +member: uid=user1,ou=People,dc=github,dc=com +member: uid=user2,ou=People,dc=github,dc=com +member: uid=user3,ou=People,dc=github,dc=com +member: uid=user4,ou=People,dc=github,dc=com +member: uid=user5,ou=People,dc=github,dc=com +member: uid=user6,ou=People,dc=github,dc=com +member: uid=user7,ou=People,dc=github,dc=com +member: uid=user8,ou=People,dc=github,dc=com +member: uid=user9,ou=People,dc=github,dc=com +member: uid=user10,ou=People,dc=github,dc=com +member: uid=emailless-user1,ou=People,dc=github,dc=com + +dn: cn=ghe-admins,ou=Groups,dc=github,dc=com +cn: ghe-admins +objectClass: groupOfNames +member: uid=admin1,ou=People,dc=github,dc=com + +dn: cn=all-admins,ou=Groups,dc=github,dc=com +cn: all-admins +objectClass: groupOfNames +member: cn=ghe-admins,ou=Groups,dc=github,dc=com +member: uid=admin1,ou=People,dc=github,dc=com + +dn: cn=n-member-group10,ou=Groups,dc=github,dc=com +cn: n-member-group10 +objectClass: groupOfNames +member: uid=user1,ou=People,dc=github,dc=com +member: uid=user2,ou=People,dc=github,dc=com +member: uid=user3,ou=People,dc=github,dc=com +member: uid=user4,ou=People,dc=github,dc=com +member: uid=user5,ou=People,dc=github,dc=com +member: uid=user6,ou=People,dc=github,dc=com +member: uid=user7,ou=People,dc=github,dc=com +member: uid=user8,ou=People,dc=github,dc=com +member: uid=user9,ou=People,dc=github,dc=com +member: uid=user10,ou=People,dc=github,dc=com + +dn: cn=nested-group1,ou=Groups,dc=github,dc=com +cn: nested-group1 +objectClass: groupOfNames +member: uid=user1,ou=People,dc=github,dc=com +member: uid=user2,ou=People,dc=github,dc=com +member: uid=user3,ou=People,dc=github,dc=com +member: uid=user4,ou=People,dc=github,dc=com +member: uid=user5,ou=People,dc=github,dc=com +member: uid=user6,ou=People,dc=github,dc=com +member: uid=user7,ou=People,dc=github,dc=com +member: uid=user8,ou=People,dc=github,dc=com +member: uid=user9,ou=People,dc=github,dc=com +member: uid=user10,ou=People,dc=github,dc=com + +dn: cn=nested-groups,ou=Groups,dc=github,dc=com +cn: nested-groups +objectClass: groupOfNames +member: cn=nested-group1,ou=Groups,dc=github,dc=com + +dn: cn=n-member-nested-group1,ou=Groups,dc=github,dc=com +cn: n-member-nested-group1 +objectClass: groupOfNames +member: cn=nested-group1,ou=Groups,dc=github,dc=com + +dn: cn=deeply-nested-group0.0.0,ou=Groups,dc=github,dc=com +cn: deeply-nested-group0.0.0 +objectClass: groupOfNames +member: uid=user1,ou=People,dc=github,dc=com +member: uid=user2,ou=People,dc=github,dc=com +member: uid=user3,ou=People,dc=github,dc=com +member: uid=user4,ou=People,dc=github,dc=com +member: uid=user5,ou=People,dc=github,dc=com + +dn: cn=deeply-nested-group0.0.1,ou=Groups,dc=github,dc=com +cn: deeply-nested-group0.0.1 +objectClass: groupOfNames +member: uid=user6,ou=People,dc=github,dc=com +member: uid=user7,ou=People,dc=github,dc=com +member: uid=user8,ou=People,dc=github,dc=com +member: uid=user9,ou=People,dc=github,dc=com +member: uid=user10,ou=People,dc=github,dc=com + +dn: cn=deeply-nested-group0.0,ou=Groups,dc=github,dc=com +cn: deeply-nested-group0.0 +objectClass: groupOfNames +member: cn=deeply-nested-group0.0.0,ou=Groups,dc=github,dc=com +member: cn=deeply-nested-group0.0.1,ou=Groups,dc=github,dc=com + +dn: cn=deeply-nested-group0,ou=Groups,dc=github,dc=com +cn: deeply-nested-group0 +objectClass: groupOfNames +member: cn=deeply-nested-group0.0,ou=Groups,dc=github,dc=com + +dn: cn=deeply-nested-groups,ou=Groups,dc=github,dc=com +cn: deeply-nested-groups +objectClass: groupOfNames +member: cn=deeply-nested-group0,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group1,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group1 +objectClass: groupOfNames +member: cn=nested-group1,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group2,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group2 +objectClass: groupOfNames +member: cn=n-depth-nested-group1,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group3,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group3 +objectClass: groupOfNames +member: cn=n-depth-nested-group2,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group4,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group4 +objectClass: groupOfNames +member: cn=n-depth-nested-group3,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group5,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group5 +objectClass: groupOfNames +member: cn=n-depth-nested-group4,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group6,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group6 +objectClass: groupOfNames +member: cn=n-depth-nested-group5,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group7,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group7 +objectClass: groupOfNames +member: cn=n-depth-nested-group6,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group8,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group8 +objectClass: groupOfNames +member: cn=n-depth-nested-group7,ou=Groups,dc=github,dc=com + +dn: cn=n-depth-nested-group9,ou=Groups,dc=github,dc=com +cn: n-depth-nested-group9 +objectClass: groupOfNames +member: cn=n-depth-nested-group8,ou=Groups,dc=github,dc=com + +dn: cn=head-group,ou=Groups,dc=github,dc=com +cn: head-group +objectClass: groupOfNames +member: cn=tail-group,ou=Groups,dc=github,dc=com +member: uid=user1,ou=People,dc=github,dc=com +member: uid=user2,ou=People,dc=github,dc=com +member: uid=user3,ou=People,dc=github,dc=com +member: uid=user4,ou=People,dc=github,dc=com +member: uid=user5,ou=People,dc=github,dc=com + +dn: cn=tail-group,ou=Groups,dc=github,dc=com +cn: tail-group +objectClass: groupOfNames +member: cn=head-group,ou=Groups,dc=github,dc=com +member: uid=user6,ou=People,dc=github,dc=com +member: uid=user7,ou=People,dc=github,dc=com +member: uid=user8,ou=People,dc=github,dc=com +member: uid=user9,ou=People,dc=github,dc=com +member: uid=user10,ou=People,dc=github,dc=com + +dn: cn=recursively-nested-groups,ou=Groups,dc=github,dc=com +cn: recursively-nested-groups +objectClass: groupOfNames +member: cn=head-group,ou=Groups,dc=github,dc=com +member: cn=tail-group,ou=Groups,dc=github,dc=com + +# posixGroup + +dn: cn=posix-group1,ou=Groups,dc=github,dc=com +cn: posix-group1 +objectClass: posixGroup +gidNumber: 1001 +memberUid: user1 +memberUid: user2 +memberUid: user3 +memberUid: user4 +memberUid: user5 + +# missing members + +dn: cn=missing-users,ou=Groups,dc=github,dc=com +cn: missing-users +objectClass: groupOfNames +member: uid=user1,ou=People,dc=github,dc=com +member: uid=user2,ou=People,dc=github,dc=com +member: uid=nonexistent-user,ou=People,dc=github,dc=com diff --git a/test/fixtures/github-with-looped-subgroups.ldif b/test/fixtures/github-with-looped-subgroups.ldif deleted file mode 100644 index 02868fe..0000000 --- a/test/fixtures/github-with-looped-subgroups.ldif +++ /dev/null @@ -1,82 +0,0 @@ -version: 1 - -# Admin user - -dn: uid=admin,dc=github,dc=com -objectClass: top -objectClass: person -objectClass: organizationalPerson -objectClass: inetOrgPerson -cn: system administrator -sn: administrator -displayName: Directory Superuser -uid: admin -userPassword: secret - -# Groups - -dn: ou=groups,dc=github,dc=com -objectclass: organizationalUnit - -dn: cn=enterprise,ou=groups,dc=github,dc=com -cn: Enterprise -objectClass: groupOfNames -member: uid=calavera,ou=users,dc=github,dc=com -member: cn=enterprise-devs,ou=groups,dc=github,dc=com -member: cn=enterprise-ops,ou=groups,dc=github,dc=com - -dn: cn=enterprise-devs,ou=groups,dc=github,dc=com -cn: enterprise-devs -objectClass: groupOfNames -member: uid=benburkert,ou=users,dc=github,dc=com -member: cn=enterprise,ou=groups,dc=github,dc=com - -dn: cn=enterprise-ops,ou=groups,dc=github,dc=com -cn: enterprise-ops -objectClass: groupOfNames -member: uid=sbryant,ou=users,dc=github,dc=com -member: cn=spaniards,ou=groups,dc=github,dc=com - -dn: cn=spaniards,ou=groups,dc=github,dc=com -cn: spaniards -objectClass: groupOfNames -member: uid=calavera,ou=users,dc=github,dc=com -member: uid=rubiojr,ou=users,dc=github,dc=com - -# Users - -dn: ou=users,dc=github,dc=com -objectclass: organizationalUnit - -dn: uid=calavera,ou=users,dc=github,dc=com -cn: David Calavera -cn: David -sn: Calavera -uid: calavera -userPassword: passworD1 -mail: calavera@github.com -objectClass: inetOrgPerson - -dn: uid=benburkert,ou=users,dc=github,dc=com -cn: benburkert -sn: benburkert -uid: benburkert -userPassword: passworD1 -mail: benburkert@github.com -objectClass: inetOrgPerson - -dn: uid=sbryant,ou=users,dc=github,dc=com -cn: sbryant -sn: sbryant -uid: sbryant -userPassword: passworD1 -mail: sbryant@github.com -objectClass: inetOrgPerson - -dn: uid=rubiojr,ou=users,dc=github,dc=com -cn: rubiojr -sn: rubiojr -uid: rubiojr -userPassword: passworD1 -mail: rubiojr@github.com -objectClass: inetOrgPerson diff --git a/test/fixtures/github-with-missing-entries.ldif b/test/fixtures/github-with-missing-entries.ldif deleted file mode 100644 index be8d316..0000000 --- a/test/fixtures/github-with-missing-entries.ldif +++ /dev/null @@ -1,85 +0,0 @@ -version: 1 - -# Admin user - -dn: uid=admin,dc=github,dc=com -objectClass: top -objectClass: person -objectClass: organizationalPerson -objectClass: inetOrgPerson -cn: system administrator -sn: administrator -displayName: Directory Superuser -uid: admin -userPassword: secret - -# Groups - -dn: ou=groups,dc=github,dc=com -objectclass: organizationalUnit - -dn: cn=enterprise,ou=groups,dc=github,dc=com -cn: Enterprise -objectClass: groupOfNames -member: uid=calavera,ou=users,dc=github,dc=com -member: cn=enterprise-devs,ou=groups,dc=github,dc=com -member: cn=enterprise-ops,ou=groups,dc=github,dc=com - -dn: cn=enterprise-devs,ou=groups,dc=github,dc=com -cn: enterprise-devs -objectClass: groupOfNames -member: uid=benburkert,ou=users,dc=github,dc=com -member: cn=enterprise,ou=groups,dc=github,dc=com - -dn: cn=enterprise-ops,ou=groups,dc=github,dc=com -cn: enterprise-ops -objectClass: groupOfNames -member: uid=sbryant,ou=users,dc=github,dc=com -member: cn=spaniards,ou=groups,dc=github,dc=com - -# The last member of this group is missing on purpose. -# See: https://github.com/github/github-ldap/pull/18 -dn: cn=spaniards,ou=groups,dc=github,dc=com -cn: spaniards -objectClass: groupOfNames -member: uid=calavera,ou=users,dc=github,dc=com -member: uid=rubiojr,ou=users,dc=github,dc=com -member: uid=felipe,ou=users,dc=github,dc=com - -# Users - -dn: ou=users,dc=github,dc=com -objectclass: organizationalUnit - -dn: uid=calavera,ou=users,dc=github,dc=com -cn: David Calavera -cn: David -sn: Calavera -uid: calavera -userPassword: passworD1 -mail: calavera@github.com -objectClass: inetOrgPerson - -dn: uid=benburkert,ou=users,dc=github,dc=com -cn: benburkert -sn: benburkert -uid: benburkert -userPassword: passworD1 -mail: benburkert@github.com -objectClass: inetOrgPerson - -dn: uid=sbryant,ou=users,dc=github,dc=com -cn: sbryant -sn: sbryant -uid: sbryant -userPassword: passworD1 -mail: sbryant@github.com -objectClass: inetOrgPerson - -dn: uid=rubiojr,ou=users,dc=github,dc=com -cn: rubiojr -sn: rubiojr -uid: rubiojr -userPassword: passworD1 -mail: rubiojr@github.com -objectClass: inetOrgPerson diff --git a/test/fixtures/github-with-posixGroups.ldif b/test/fixtures/github-with-posixGroups.ldif deleted file mode 100644 index ac8b3a0..0000000 --- a/test/fixtures/github-with-posixGroups.ldif +++ /dev/null @@ -1,50 +0,0 @@ -version: 1 - -# Admin user - -dn: uid=admin,dc=github,dc=com -objectClass: top -objectClass: person -objectClass: organizationalPerson -objectClass: inetOrgPerson -cn: system administrator -sn: administrator -displayName: Directory Superuser -uid: admin -userPassword: secret - -# Groups - -dn: ou=groups,dc=github,dc=com -objectclass: organizationalUnit -ou: groups - -# Posix Groups - -dn: cn=enterprise-posix-devs,ou=groups,dc=github,dc=com -cn: enterprise-posix-devs -objectClass: posixGroup -memberUid: benburkert -memberUid: mtodd - -# Users - -dn: ou=users,dc=github,dc=com -objectclass: organizationalUnit -ou: users - -dn: uid=benburkert,ou=users,dc=github,dc=com -cn: benburkert -sn: benburkert -uid: benburkert -userPassword: passworD1 -mail: benburkert@github.com -objectClass: inetOrgPerson - -dn: uid=mtodd,ou=users,dc=github,dc=com -cn: mtodd -sn: mtodd -uid: mtodd -userPassword: passworD1 -mail: mtodd@github.com -objectClass: inetOrgPerson diff --git a/test/fixtures/github-with-subgroups.ldif b/test/fixtures/github-with-subgroups.ldif deleted file mode 100644 index 00dc929..0000000 --- a/test/fixtures/github-with-subgroups.ldif +++ /dev/null @@ -1,146 +0,0 @@ -version: 1 - -# Admin user - -dn: uid=admin,dc=github,dc=com -objectClass: top -objectClass: person -objectClass: organizationalPerson -objectClass: inetOrgPerson -cn: system administrator -sn: administrator -displayName: Directory Superuser -uid: admin -userPassword: secret - -# Groups - -dn: ou=groups,dc=github,dc=com -objectclass: organizationalUnit -ou: groups - -dn: cn=enterprise,ou=groups,dc=github,dc=com -cn: Enterprise -objectClass: groupOfNames -member: uid=calavera,ou=users,dc=github,dc=com -member: cn=enterprise-devs,ou=groups,dc=github,dc=com -member: cn=enterprise-ops,ou=groups,dc=github,dc=com - -dn: cn=enterprise-devs,ou=groups,dc=github,dc=com -cn: enterprise-devs -objectClass: groupOfNames -member: uid=benburkert,ou=users,dc=github,dc=com - -dn: cn=enterprise-ops,ou=groups,dc=github,dc=com -cn: enterprise-ops -objectClass: groupOfNames -member: uid=sbryant,ou=users,dc=github,dc=com -member: cn=spaniards,ou=groups,dc=github,dc=com - -dn: cn=spaniards,ou=groups,dc=github,dc=com -cn: spaniards -objectClass: groupOfNames -member: uid=calavera,ou=users,dc=github,dc=com -member: uid=rubiojr,ou=users,dc=github,dc=com - -dn: cn=group1,ou=groups,dc=github,dc=com -cn: group1 -objectClass: groupOfNames -member: uid=user1,ou=users,dc=github,dc=com -member: cn=group1.1,ou=groups,dc=github,dc=com - -dn: cn=group1.1,ou=groups,dc=github,dc=com -cn: group1 -objectClass: groupOfNames -member: uid=user1.1,ou=users,dc=github,dc=com -member: cn=group1.1.1,ou=groups,dc=github,dc=com - -dn: cn=group1.1.1,ou=groups,dc=github,dc=com -cn: group1 -objectClass: groupOfNames -member: uid=user1.1.1,ou=users,dc=github,dc=com -member: cn=group1.1.1.1,ou=groups,dc=github,dc=com - -dn: cn=group1.1.1.1,ou=groups,dc=github,dc=com -cn: group1 -objectClass: groupOfNames -member: uid=user1.1.1.1,ou=users,dc=github,dc=com - -# Users - -dn: ou=users,dc=github,dc=com -objectclass: organizationalUnit -ou: users - -dn: uid=calavera,ou=users,dc=github,dc=com -cn: David Calavera -cn: David -sn: Calavera -uid: calavera -userPassword: passworD1 -mail: calavera@github.com -objectClass: inetOrgPerson - -dn: uid=benburkert,ou=users,dc=github,dc=com -cn: benburkert -sn: benburkert -uid: benburkert -userPassword: passworD1 -mail: benburkert@github.com -objectClass: inetOrgPerson - -dn: uid=sbryant,ou=users,dc=github,dc=com -cn: sbryant -sn: sbryant -uid: sbryant -userPassword: passworD1 -mail: sbryant@github.com -objectClass: inetOrgPerson - -dn: uid=rubiojr,ou=users,dc=github,dc=com -cn: rubiojr -sn: rubiojr -uid: rubiojr -userPassword: passworD1 -mail: rubiojr@github.com -objectClass: inetOrgPerson - -dn: uid=mtodd,ou=users,dc=github,dc=com -cn: mtodd -sn: mtodd -uid: mtodd -userPassword: passworD1 -mail: mtodd@github.com -objectClass: inetOrgPerson - -dn: uid=user1,ou=users,dc=github,dc=com -uid: user1 -sn: user1 -cn: user1 -userPassword: passworD1 -mail: user1@github.com -objectClass: inetOrgPerson - -dn: uid=user1.1,ou=users,dc=github,dc=com -uid: user1.1 -sn: user1.1 -cn: user1.1 -userPassword: passworD1 -mail: user1.1@github.com -objectClass: inetOrgPerson - -dn: uid=user1.1.1,ou=users,dc=github,dc=com -uid: user1.1.1 -sn: user1.1.1 -cn: user1.1.1 -userPassword: passworD1 -mail: user1.1.1@github.com -objectClass: inetOrgPerson - -dn: uid=user1.1.1.1,ou=users,dc=github,dc=com -uid: user1.1.1.1 -sn: user1.1.1.1 -cn: user1.1.1.1 -userPassword: passworD1 -mail: user1.1.1.1@github.com -objectClass: inetOrgPerson diff --git a/test/fixtures/openldap/memberof.ldif b/test/fixtures/openldap/memberof.ldif new file mode 100644 index 0000000..dac7c6b --- /dev/null +++ b/test/fixtures/openldap/memberof.ldif @@ -0,0 +1,33 @@ +dn: cn=module,cn=config +cn: module +objectClass: olcModuleList +objectClass: top +olcModulePath: /usr/lib/ldap +olcModuleLoad: memberof.la + +dn: olcOverlay={0}memberof,olcDatabase={1}hdb,cn=config +objectClass: olcConfig +objectClass: olcMemberOf +objectClass: olcOverlayConfig +objectClass: top +olcOverlay: memberof +olcMemberOfDangling: ignore +olcMemberOfRefInt: TRUE +olcMemberOfGroupOC: groupOfNames +olcMemberOfMemberAD: member +olcMemberOfMemberOfAD: memberOf + +dn: cn=module,cn=config +cn: module +objectclass: olcModuleList +objectclass: top +olcmoduleload: refint.la +olcmodulepath: /usr/lib/ldap + +dn: olcOverlay={1}refint,olcDatabase={1}hdb,cn=config +objectClass: olcConfig +objectClass: olcOverlayConfig +objectClass: olcRefintConfig +objectClass: top +olcOverlay: {1}refint +olcRefintAttribute: memberof member manager owner diff --git a/test/fixtures/openldap/slapd.conf.ldif b/test/fixtures/openldap/slapd.conf.ldif new file mode 100644 index 0000000..7d88769 --- /dev/null +++ b/test/fixtures/openldap/slapd.conf.ldif @@ -0,0 +1,67 @@ +dn: cn=config +objectClass: olcGlobal +cn: config +olcPidFile: /var/run/slapd/slapd.pid +olcArgsFile: /var/run/slapd/slapd.args +olcLogLevel: none +olcToolThreads: 1 + +dn: olcDatabase={-1}frontend,cn=config +objectClass: olcDatabaseConfig +objectClass: olcFrontendConfig +olcDatabase: {-1}frontend +olcSizeLimit: 500 +olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break +olcAccess: {1}to dn.exact="" by * read +olcAccess: {2}to dn.base="cn=Subschema" by * read + +dn: olcDatabase=config,cn=config +objectClass: olcDatabaseConfig +olcDatabase: config +olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break + +dn: cn=schema,cn=config +objectClass: olcSchemaConfig +cn: schema + +include: file:///etc/ldap/schema/core.ldif +include: file:///etc/ldap/schema/cosine.ldif +include: file:///etc/ldap/schema/nis.ldif +include: file:///etc/ldap/schema/inetorgperson.ldif + +dn: cn=module{0},cn=config +objectClass: olcModuleList +cn: module{0} +olcModulePath: /usr/lib/ldap +olcModuleLoad: back_hdb + +dn: olcBackend=hdb,cn=config +objectClass: olcBackendConfig +olcBackend: hdb + +dn: olcDatabase=hdb,cn=config +objectClass: olcDatabaseConfig +objectClass: olcHdbConfig +olcDatabase: hdb +olcDbCheckpoint: 512 30 +olcDbConfig: set_cachesize 1 0 0 +olcDbConfig: set_lk_max_objects 1500 +olcDbConfig: set_lk_max_locks 1500 +olcDbConfig: set_lk_max_lockers 1500 +olcLastMod: TRUE +olcSuffix: dc=github,dc=com +olcDbDirectory: /var/lib/ldap +olcRootDN: cn=admin,dc=github,dc=com +# admin's password: "passworD1" +olcRootPW: {SHA}LFSkM9eegU6j3PeGG7UuHrT/KZM= +olcDbIndex: objectClass eq +olcAccess: to attrs=userPassword,shadowLastChange + by self write + by anonymous auth + by dn="cn=admin,dc=github,dc=com" write + by * none +olcAccess: to dn.base="" by * read +olcAccess: to * + by self write + by dn="cn=admin,dc=github,dc=com" write + by * read diff --git a/test/fixtures/posixGroup.schema.ldif b/test/fixtures/posixGroup.schema.ldif index 94dd488..3ba04e0 100644 --- a/test/fixtures/posixGroup.schema.ldif +++ b/test/fixtures/posixGroup.schema.ldif @@ -1,26 +1,52 @@ version: 1 -dn: m-oid=1.3.6.1.4.1.18055.0.4.1.2.1001,ou=attributeTypes,cn=other,ou=schema +# attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber' +# DESC 'An integer uniquely identifying a group in an administrative domain' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +dn: m-oid=1.3.6.1.1.1.1.1,ou=attributeTypes,cn=other,ou=schema +objectClass: metaAttributeType +objectClass: metaTop +objectClass: top +m-collective: FALSE +m-description: An integer uniquely identifying a group in an administrative domain +m-equality: integerMatch +m-name: gidNumber +m-syntax: 1.3.6.1.4.1.1466.115.121.1.27 +m-usage: USER_APPLICATIONS +m-oid: 1.3.6.1.1.1.1.1 + +# attributetype ( 1.3.6.1.1.1.1.12 NAME 'memberUid' +# EQUALITY caseExactIA5Match +# SUBSTR caseExactIA5SubstringsMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +dn: m-oid=1.3.6.1.1.1.1.12,ou=attributeTypes,cn=other,ou=schema objectClass: metaAttributeType objectClass: metaTop objectClass: top m-collective: FALSE m-description: memberUid -m-equality: caseExactMatch +m-equality: caseExactIA5Match m-name: memberUid -m-syntax: 1.3.6.1.4.1.1466.115.121.1.15 +m-syntax: 1.3.6.1.4.1.1466.115.121.1.26 m-usage: USER_APPLICATIONS -m-oid: 1.3.6.1.4.1.18055.0.4.1.2.1001 +m-oid: 1.3.6.1.1.1.1.12 -dn: m-oid=1.3.6.1.4.1.18055.0.4.1.3.1001,ou=objectClasses,cn=other,ou=schema +# objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' SUP top STRUCTURAL +# DESC 'Abstraction of a group of accounts' +# MUST ( cn $ gidNumber ) +# MAY ( userPassword $ memberUid $ description ) ) +dn: m-oid=1.3.6.1.1.1.2.2,ou=objectClasses,cn=other,ou=schema objectClass: metaObjectClass objectClass: metaTop objectClass: top m-description: posixGroup -m-may: cn -m-may: sn +m-must: cn +m-must: gidNumber m-may: memberUid +m-may: userPassword +m-may: description m-supobjectclass: top m-name: posixGroup -m-oid: 1.3.6.1.4.1.18055.0.4.1.3.1001 +m-oid: 1.3.6.1.1.1.2.2 m-typeobjectclass: STRUCTURAL diff --git a/test/group_test.rb b/test/group_test.rb index 6f1714d..1ed5f82 100644 --- a/test/group_test.rb +++ b/test/group_test.rb @@ -1,17 +1,13 @@ require_relative 'test_helper' class GitHubLdapGroupTest < GitHub::Ldap::Test - def self.test_server_options - {user_fixtures: FIXTURES.join('github-with-subgroups.ldif').to_s} - end - def groups_domain - @ldap.domain("ou=groups,dc=github,dc=com") + @ldap.domain("ou=Groups,dc=github,dc=com") end def setup @ldap = GitHub::Ldap.new(options) - @group = @ldap.group("cn=enterprise,ou=groups,dc=github,dc=com") + @group = @ldap.group("cn=ghe-users,ou=Groups,dc=github,dc=com") end def test_group? @@ -25,34 +21,36 @@ def test_group? end def test_subgroups - assert_equal 3, @group.subgroups.size + group = @ldap.group("cn=deeply-nested-group0.0,ou=Groups,dc=github,dc=com") + assert_equal 2, group.subgroups.size end def test_members_from_subgroups - assert_equal 4, @group.members.size + group = @ldap.group("cn=deeply-nested-group0.0,ou=Groups,dc=github,dc=com") + assert_equal 10, group.members.size end def test_all_domain_groups groups = groups_domain.all_groups - assert_equal 8, groups.size + assert_equal 27, groups.size end def test_filter_domain_groups - groups = groups_domain.filter_groups('devs') + groups = groups_domain.filter_groups('ghe-users') assert_equal 1, groups.size end def test_filter_domain_groups_limited groups = [] - groups_domain.filter_groups('enter', size: 1) do |entry| + groups_domain.filter_groups('deeply-nested-group', size: 1) do |entry| groups << entry end assert_equal 1, groups.size end def test_filter_domain_groups_unlimited - groups = groups_domain.filter_groups('ent') - assert_equal 3, groups.size + groups = groups_domain.filter_groups('deeply-nested-group') + assert_equal 5, groups.size end def test_unknown_group @@ -62,33 +60,25 @@ def test_unknown_group end class GitHubLdapLoopedGroupTest < GitHub::Ldap::Test - def self.test_server_options - {user_fixtures: FIXTURES.join('github-with-looped-subgroups.ldif').to_s} - end - def setup - @group = GitHub::Ldap.new(options).group("cn=enterprise,ou=groups,dc=github,dc=com") + @group = GitHub::Ldap.new(options).group("cn=recursively-nested-groups,ou=Groups,dc=github,dc=com") end def test_members_from_subgroups - assert_equal 4, @group.members.size + assert_equal 10, @group.members.size end end class GitHubLdapMissingEntriesTest < GitHub::Ldap::Test - def self.test_server_options - {user_fixtures: FIXTURES.join('github-with-missing-entries.ldif').to_s} - end - def setup @ldap = GitHub::Ldap.new(options) end def test_load_right_members - assert_equal 3, @ldap.domain("cn=spaniards,ou=groups,dc=github,dc=com").bind[:member].size + assert_equal 3, @ldap.domain("cn=missing-users,ou=groups,dc=github,dc=com").bind[:member].size end def test_ignore_missing_member_entries - assert_equal 2, @ldap.group("cn=spaniards,ou=groups,dc=github,dc=com").members.size + assert_equal 2, @ldap.group("cn=missing-users,ou=groups,dc=github,dc=com").members.size end end diff --git a/test/ldap_test.rb b/test/ldap_test.rb index 27861d3..40fcb95 100644 --- a/test/ldap_test.rb +++ b/test/ldap_test.rb @@ -22,59 +22,54 @@ def test_start_tls end def test_search_delegator - @ldap.domain('dc=github,dc=com').valid_login? 'calavera', 'secret' + assert user = @ldap.domain('dc=github,dc=com').valid_login?('user1', 'passworD1') - result = @ldap.search( - {:base => 'dc=github,dc=com', - :attributes => %w(uid), - :filter => Net::LDAP::Filter.eq('uid', 'calavera')}) + result = @ldap.search \ + :base => 'dc=github,dc=com', + :attributes => %w(uid), + :filter => Net::LDAP::Filter.eq('uid', 'user1') refute result.empty? - assert_equal 'calavera', result.first[:uid].first + assert_equal 'user1', result.first[:uid].first end - def test_virtual_attributes_defaults - @ldap = GitHub::Ldap.new(options.merge(virtual_attributes: true)) - - assert @ldap.virtual_attributes.enabled?, "Expected to have virtual attributes enabled with defaults" - assert_equal 'memberOf', @ldap.virtual_attributes.virtual_membership + def test_virtual_attributes_disabled + refute @ldap.virtual_attributes.enabled?, "Expected to have virtual attributes disabled" end - def test_virtual_attributes_defaults + def test_virtual_attributes_configured ldap = GitHub::Ldap.new(options.merge(virtual_attributes: true)) - assert ldap.virtual_attributes.enabled?, "Expected to have virtual attributes enabled with defaults" + assert ldap.virtual_attributes.enabled?, + "Expected virtual attributes to be enabled" assert_equal 'memberOf', ldap.virtual_attributes.virtual_membership end - def test_virtual_attributes_hash + def test_virtual_attributes_configured_with_membership_attribute ldap = GitHub::Ldap.new(options.merge(virtual_attributes: {virtual_membership: "isMemberOf"})) - assert ldap.virtual_attributes.enabled?, "Expected to have virtual attributes enabled with defaults" + assert ldap.virtual_attributes.enabled?, + "Expected virtual attributes to be enabled" assert_equal 'isMemberOf', ldap.virtual_attributes.virtual_membership end - def test_virtual_attributes_disabled - refute @ldap.virtual_attributes.enabled?, "Expected to have virtual attributes disabled" - end - def test_search_domains ldap = GitHub::Ldap.new(options.merge(search_domains: ['dc=github,dc=com'])) - result = ldap.search(filter: Net::LDAP::Filter.eq('uid', 'calavera')) + result = ldap.search(filter: Net::LDAP::Filter.eq('uid', 'user1')) refute result.empty? - assert_equal 'calavera', result.first[:uid].first + assert_equal 'user1', result.first[:uid].first end def test_instruments_search events = @service.subscribe "search.github_ldap" - result = @ldap.search(filter: "(uid=calavera)", :base => "dc=github,dc=com") + result = @ldap.search(filter: "(uid=user1)", :base => "dc=github,dc=com") refute_predicate result, :empty? payload, event_result = events.pop assert payload assert event_result assert_equal result, event_result - assert_equal "(uid=calavera)", payload[:filter].to_s + assert_equal "(uid=user1)", payload[:filter].to_s assert_equal "dc=github,dc=com", payload[:base] end end diff --git a/test/membership_validators/classic_test.rb b/test/membership_validators/classic_test.rb new file mode 100644 index 0000000..9b2c32b --- /dev/null +++ b/test/membership_validators/classic_test.rb @@ -0,0 +1,51 @@ +require_relative '../test_helper' + +class GitHubLdapClassicMembershipValidatorsTest < GitHub::Ldap::Test + def setup + @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com))) + @domain = @ldap.domain("dc=github,dc=com") + @entry = @domain.user?('user1') + @validator = GitHub::Ldap::MembershipValidators::Classic + end + + def make_validator(groups) + groups = @domain.groups(groups) + @validator.new(@ldap, groups) + end + + def test_validates_user_in_group + validator = make_validator(%w(nested-group1)) + assert validator.perform(@entry) + end + + def test_validates_user_in_child_group + validator = make_validator(%w(n-depth-nested-group1)) + assert validator.perform(@entry) + end + + def test_validates_user_in_grandchild_group + validator = make_validator(%w(n-depth-nested-group2)) + assert validator.perform(@entry) + end + + def test_validates_user_in_great_grandchild_group + validator = make_validator(%w(n-depth-nested-group3)) + assert validator.perform(@entry) + end + + def test_does_not_validate_user_not_in_group + validator = make_validator(%w(ghe-admins)) + refute validator.perform(@entry) + end + + def test_does_not_validate_user_not_in_any_group + @entry = @domain.user?('groupless-user1') + validator = make_validator(%w(all-users)) + refute validator.perform(@entry) + end + + def test_validates_user_in_posix_group + validator = make_validator(%w(posix-group1)) + assert validator.perform(@entry) + end +end diff --git a/test/membership_validators/recursive_test.rb b/test/membership_validators/recursive_test.rb new file mode 100644 index 0000000..e351532 --- /dev/null +++ b/test/membership_validators/recursive_test.rb @@ -0,0 +1,56 @@ +require_relative '../test_helper' + +class GitHubLdapRecursiveMembershipValidatorsTest < GitHub::Ldap::Test + def setup + @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com))) + @domain = @ldap.domain("dc=github,dc=com") + @entry = @domain.user?('user1') + @validator = GitHub::Ldap::MembershipValidators::Recursive + end + + def make_validator(groups) + groups = @domain.groups(groups) + @validator.new(@ldap, groups) + end + + def test_validates_user_in_group + validator = make_validator(%w(nested-group1)) + assert validator.perform(@entry) + end + + def test_validates_user_in_child_group + validator = make_validator(%w(n-depth-nested-group1)) + assert validator.perform(@entry) + end + + def test_validates_user_in_grandchild_group + validator = make_validator(%w(n-depth-nested-group2)) + assert validator.perform(@entry) + end + + def test_validates_user_in_great_grandchild_group + validator = make_validator(%w(n-depth-nested-group3)) + assert validator.perform(@entry) + end + + def test_does_not_validate_user_in_great_granchild_group_with_depth + validator = make_validator(%w(n-depth-nested-group3)) + refute validator.perform(@entry, 2) + end + + def test_does_not_validate_user_not_in_group + validator = make_validator(%w(ghe-admins)) + refute validator.perform(@entry) + end + + def test_does_not_validate_user_not_in_any_group + @entry = @domain.user?('groupless-user1') + validator = make_validator(%w(all-users)) + refute validator.perform(@entry) + end + + def test_validates_user_in_posix_group + validator = make_validator(%w(posix-group1)) + assert validator.perform(@entry) + end +end diff --git a/test/membership_validators_test.rb b/test/membership_validators_test.rb new file mode 100644 index 0000000..e1a981f --- /dev/null +++ b/test/membership_validators_test.rb @@ -0,0 +1,46 @@ +require_relative 'test_helper' + +module GitHubLdapMembershipValidatorsTestCases + def make_validator(groups) + groups = @domain.groups(groups) + @validator.new(@ldap, groups) + end + + def test_validates_user_in_group + validator = make_validator(%w(ghe-users)) + assert validator.perform(@entry) + end + + def test_does_not_validate_user_not_in_group + validator = make_validator(%w(ghe-admins)) + refute validator.perform(@entry) + end + + def test_does_not_validate_user_not_in_any_group + @entry = @domain.user?('groupless-user1') + validator = make_validator(%w(ghe-users ghe-admins)) + refute validator.perform(@entry) + end +end + +class GitHubLdapMembershipValidatorsClassicTest < GitHub::Ldap::Test + include GitHubLdapMembershipValidatorsTestCases + + def setup + @ldap = GitHub::Ldap.new(options.merge(search_domains: "dc=github,dc=com")) + @domain = @ldap.domain("dc=github,dc=com") + @entry = @domain.user?('user1') + @validator = GitHub::Ldap::MembershipValidators::Classic + end +end + +class GitHubLdapMembershipValidatorsRecursiveTest < GitHub::Ldap::Test + include GitHubLdapMembershipValidatorsTestCases + + def setup + @ldap = GitHub::Ldap.new(options.merge(search_domains: "dc=github,dc=com")) + @domain = @ldap.domain("dc=github,dc=com") + @entry = @domain.user?('user1') + @validator = GitHub::Ldap::MembershipValidators::Recursive + end +end diff --git a/test/posix_group_test.rb b/test/posix_group_test.rb index a71e252..e21b3ac 100644 --- a/test/posix_group_test.rb +++ b/test/posix_group_test.rb @@ -1,54 +1,51 @@ require_relative 'test_helper' class GitHubLdapPosixGroupTest < GitHub::Ldap::Test - def self.test_server_options - {user_fixtures: FIXTURES.join('github-with-subgroups.ldif').to_s} - end - def setup @simple_group = Net::LDAP::Entry._load(""" -dn: cn=enterprise-posix-devs,ou=groups,dc=github,dc=com -cn: enterprise-posix-devs +dn: cn=simple-group,ou=Groups,dc=github,dc=com +cn: simple-group objectClass: posixGroup -memberUid: benburkert -memberUid: mtodd""") +memberUid: user1 +memberUid: user2""") @one_level_deep_group = Net::LDAP::Entry._load(""" -dn: cn=enterprise-posix-ops,ou=groups,dc=github,dc=com -cn: enterprise-posix-ops +dn: cn=one-level-deep-group,ou=Groups,dc=github,dc=com +cn: one-level-deep-group objectClass: posixGroup objectClass: groupOfNames -memberUid: sbryant -member: cn=spaniards,ou=groups,dc=github,dc=com""") +memberUid: user6 +member: cn=ghe-users,ou=Groups,dc=github,dc=com""") @two_levels_deep_group = Net::LDAP::Entry._load(""" -dn: cn=enterprise-posix,ou=groups,dc=github,dc=com -cn: Enterprise Posix +dn: cn=two-levels-deep-group,ou=Groups,dc=github,dc=com +cn: two-levels-deep-group objectClass: posixGroup objectClass: groupOfNames -memberUid: calavera -member: cn=enterprise-devs,ou=groups,dc=github,dc=com -member: cn=enterprise-ops,ou=groups,dc=github,dc=com""") +memberUid: user6 +member: cn=n-depth-nested-group2,ou=Groups,dc=github,dc=com +member: cn=posix-group1,ou=Groups,dc=github,dc=com""") @empty_group = Net::LDAP::Entry._load(""" -dn: cn=enterprise-posix-empty,ou=groups,dc=github,dc=com -cn: enterprise-posix-empty +dn: cn=empty-group,ou=Groups,dc=github,dc=com +cn: empty-group objectClass: posixGroup""") @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com))) end def test_posix_group - assert GitHub::Ldap::PosixGroup.valid?(@simple_group), + entry = @ldap.search(filter: "(cn=posix-group1)").first + assert GitHub::Ldap::PosixGroup.valid?(entry), "Expected entry to be a valid posixGroup" end def test_posix_simple_members - group = GitHub::Ldap::PosixGroup.new(@ldap, @simple_group) + assert group = @ldap.group("cn=posix-group1,ou=Groups,dc=github,dc=com") members = group.members - assert_equal 2, members.size - assert_equal %w(benburkert mtodd), members.map(&:uid).flatten.sort + assert_equal 5, members.size + assert_equal %w(user1 user2 user3 user4 user5), members.map(&:uid).flatten.sort end def test_posix_combined_group @@ -62,7 +59,7 @@ def test_posix_combined_group_unique_members group = GitHub::Ldap::PosixGroup.new(@ldap, @two_levels_deep_group) members = group.members - assert_equal 4, members.size + assert_equal 10, members.size end def test_empty_subgroups @@ -81,7 +78,7 @@ def test_posix_combined_group_subgroups def test_is_member_simple_group group = GitHub::Ldap::PosixGroup.new(@ldap, @simple_group) - user = @ldap.domain("uid=benburkert,ou=users,dc=github,dc=com").bind + user = @ldap.domain("uid=user1,ou=People,dc=github,dc=com").bind assert group.is_member?(user), "Expected user in the memberUid list to be a member of the posixgroup" @@ -89,7 +86,7 @@ def test_is_member_simple_group def test_is_member_combined_group group = GitHub::Ldap::PosixGroup.new(@ldap, @one_level_deep_group) - user = @ldap.domain("uid=calavera,ou=users,dc=github,dc=com").bind + user = @ldap.domain("uid=user1,ou=People,dc=github,dc=com").bind assert group.is_member?(user), "Expected user in a subgroup to be a member of the posixgroup" @@ -97,7 +94,7 @@ def test_is_member_combined_group def test_is_not_member_simple_group group = GitHub::Ldap::PosixGroup.new(@ldap, @simple_group) - user = @ldap.domain("uid=calavera,ou=users,dc=github,dc=com").bind + user = @ldap.domain("uid=user10,ou=People,dc=github,dc=com").bind refute group.is_member?(user), "Expected user to not be member when her uid is not in the list of memberUid" @@ -105,7 +102,7 @@ def test_is_not_member_simple_group def test_is_member_combined_group group = GitHub::Ldap::PosixGroup.new(@ldap, @one_level_deep_group) - user = @ldap.domain("uid=benburkert,ou=users,dc=github,dc=com").bind + user = @ldap.domain("uid=user10,ou=People,dc=github,dc=com").bind refute group.is_member?(user), "Expected user to not be member when she's not member of any subgroup" diff --git a/test/test_helper.rb b/test/test_helper.rb index d996c5f..feee10f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -12,7 +12,20 @@ require 'minitest/autorun' +if ENV.fetch('TESTENV', "apacheds") == "apacheds" + # Make sure we clean up running test server + # NOTE: We need to do this manually since its internal `at_exit` hook + # collides with Minitest's autorun at_exit handling, hence this hook. + Minitest.after_run do + GitHub::Ldap.stop_server + end +end + class GitHub::Ldap::Test < Minitest::Test + def self.test_env + ENV.fetch("TESTENV", "apacheds") + end + def self.run(reporter, options = {}) start_server super @@ -20,28 +33,56 @@ def self.run(reporter, options = {}) end def self.stop_server - GitHub::Ldap.stop_server + if test_env == "apacheds" + # see Minitest.after_run hook above. + # GitHub::Ldap.stop_server + end + end + + def self.test_server_options + { + custom_schemas: FIXTURES.join('posixGroup.schema.ldif').to_s, + user_fixtures: FIXTURES.join('common/seed.ldif').to_s, + allow_anonymous: true, + verbose: ENV.fetch("VERBOSE", "0") == "1" + } end def self.start_server - server_opts = respond_to?(:test_server_options) ? test_server_options : {} - GitHub::Ldap.start_server(server_opts) + if test_env == "apacheds" + # skip this if a server has already been started + return if GitHub::Ldap.ldap_server + + GitHub::Ldap.start_server(test_server_options) + end end def options @service = MockInstrumentationService.new - @options ||= GitHub::Ldap.server_options.merge \ - host: 'localhost', - uid: 'uid', - :instrumentation_service => @service + @options ||= + case self.class.test_env + when "apacheds" + GitHub::Ldap.server_options.merge \ + admin_user: 'uid=admin,dc=github,dc=com', + admin_password: 'passworD1', + host: 'localhost', + uid: 'uid', + instrumentation_service: @service + when "openldap" + { + host: 'localhost', + port: 389, + admin_user: 'uid=admin,dc=github,dc=com', + admin_password: 'passworD1', + search_domains: %w(dc=github,dc=com), + uid: 'uid', + instrumentation_service: @service + } + end end end class GitHub::Ldap::UnauthenticatedTest < GitHub::Ldap::Test - def self.start_server - GitHub::Ldap.start_server(:allow_anonymous => true) - end - def options @options ||= begin super.delete_if {|k, _| [:admin_user, :admin_password].include?(k)} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy