github-ldap 1.3.3 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +15 -2
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile +4 -0
  5. data/README.md +15 -1
  6. data/Rakefile +1 -1
  7. data/github-ldap.gemspec +2 -2
  8. data/lib/github/ldap.rb +55 -12
  9. data/lib/github/ldap/domain.rb +6 -2
  10. data/lib/github/ldap/filter.rb +15 -7
  11. data/lib/github/ldap/group.rb +1 -1
  12. data/lib/github/ldap/instrumentation.rb +28 -0
  13. data/lib/github/ldap/membership_validators.rb +18 -0
  14. data/lib/github/ldap/membership_validators/active_directory.rb +56 -0
  15. data/lib/github/ldap/membership_validators/base.rb +37 -0
  16. data/lib/github/ldap/membership_validators/classic.rb +34 -0
  17. data/lib/github/ldap/membership_validators/recursive.rb +93 -0
  18. data/lib/github/ldap/server.rb +2 -0
  19. data/script/changelog +29 -0
  20. data/script/cibuild-apacheds +7 -0
  21. data/script/cibuild-openldap +7 -0
  22. data/script/install-openldap +44 -0
  23. data/script/package +7 -0
  24. data/script/release +16 -0
  25. data/test/domain_test.rb +71 -89
  26. data/test/filter_test.rb +12 -1
  27. data/test/fixtures/common/seed.ldif +369 -0
  28. data/test/fixtures/openldap/memberof.ldif +33 -0
  29. data/test/fixtures/openldap/slapd.conf.ldif +67 -0
  30. data/test/fixtures/posixGroup.schema.ldif +34 -8
  31. data/test/group_test.rb +19 -25
  32. data/test/ldap_test.rb +28 -21
  33. data/test/membership_validators/active_directory_test.rb +68 -0
  34. data/test/membership_validators/classic_test.rb +51 -0
  35. data/test/membership_validators/recursive_test.rb +56 -0
  36. data/test/membership_validators_test.rb +46 -0
  37. data/test/posix_group_test.rb +25 -28
  38. data/test/support/vm/openldap/.gitignore +1 -0
  39. data/test/support/vm/openldap/README.md +32 -0
  40. data/test/support/vm/openldap/Vagrantfile +35 -0
  41. data/test/test_helper.rb +72 -10
  42. metadata +52 -27
  43. data/test/fixtures/github-with-looped-subgroups.ldif +0 -82
  44. data/test/fixtures/github-with-missing-entries.ldif +0 -85
  45. data/test/fixtures/github-with-posixGroups.ldif +0 -50
  46. data/test/fixtures/github-with-subgroups.ldif +0 -146
@@ -1,26 +1,52 @@
1
1
  version: 1
2
2
 
3
- dn: m-oid=1.3.6.1.4.1.18055.0.4.1.2.1001,ou=attributeTypes,cn=other,ou=schema
3
+ # attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber'
4
+ # DESC 'An integer uniquely identifying a group in an administrative domain'
5
+ # EQUALITY integerMatch
6
+ # SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
7
+ dn: m-oid=1.3.6.1.1.1.1.1,ou=attributeTypes,cn=other,ou=schema
8
+ objectClass: metaAttributeType
9
+ objectClass: metaTop
10
+ objectClass: top
11
+ m-collective: FALSE
12
+ m-description: An integer uniquely identifying a group in an administrative domain
13
+ m-equality: integerMatch
14
+ m-name: gidNumber
15
+ m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
16
+ m-usage: USER_APPLICATIONS
17
+ m-oid: 1.3.6.1.1.1.1.1
18
+
19
+ # attributetype ( 1.3.6.1.1.1.1.12 NAME 'memberUid'
20
+ # EQUALITY caseExactIA5Match
21
+ # SUBSTR caseExactIA5SubstringsMatch
22
+ # SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
23
+ dn: m-oid=1.3.6.1.1.1.1.12,ou=attributeTypes,cn=other,ou=schema
4
24
  objectClass: metaAttributeType
5
25
  objectClass: metaTop
6
26
  objectClass: top
7
27
  m-collective: FALSE
8
28
  m-description: memberUid
9
- m-equality: caseExactMatch
29
+ m-equality: caseExactIA5Match
10
30
  m-name: memberUid
11
- m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
31
+ m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
12
32
  m-usage: USER_APPLICATIONS
13
- m-oid: 1.3.6.1.4.1.18055.0.4.1.2.1001
33
+ m-oid: 1.3.6.1.1.1.1.12
14
34
 
15
- dn: m-oid=1.3.6.1.4.1.18055.0.4.1.3.1001,ou=objectClasses,cn=other,ou=schema
35
+ # objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' SUP top STRUCTURAL
36
+ # DESC 'Abstraction of a group of accounts'
37
+ # MUST ( cn $ gidNumber )
38
+ # MAY ( userPassword $ memberUid $ description ) )
39
+ dn: m-oid=1.3.6.1.1.1.2.2,ou=objectClasses,cn=other,ou=schema
16
40
  objectClass: metaObjectClass
17
41
  objectClass: metaTop
18
42
  objectClass: top
19
43
  m-description: posixGroup
20
- m-may: cn
21
- m-may: sn
44
+ m-must: cn
45
+ m-must: gidNumber
22
46
  m-may: memberUid
47
+ m-may: userPassword
48
+ m-may: description
23
49
  m-supobjectclass: top
24
50
  m-name: posixGroup
25
- m-oid: 1.3.6.1.4.1.18055.0.4.1.3.1001
51
+ m-oid: 1.3.6.1.1.1.2.2
26
52
  m-typeobjectclass: STRUCTURAL
data/test/group_test.rb CHANGED
@@ -1,54 +1,56 @@
1
1
  require_relative 'test_helper'
2
2
 
3
3
  class GitHubLdapGroupTest < GitHub::Ldap::Test
4
- def self.test_server_options
5
- {user_fixtures: FIXTURES.join('github-with-subgroups.ldif').to_s}
6
- end
7
-
8
4
  def groups_domain
9
- @ldap.domain("ou=groups,dc=github,dc=com")
5
+ @ldap.domain("ou=Groups,dc=github,dc=com")
10
6
  end
11
7
 
12
8
  def setup
13
9
  @ldap = GitHub::Ldap.new(options)
14
- @group = @ldap.group("cn=enterprise,ou=groups,dc=github,dc=com")
10
+ @group = @ldap.group("cn=ghe-users,ou=Groups,dc=github,dc=com")
15
11
  end
16
12
 
17
13
  def test_group?
14
+ assert @group.group?(%w(group))
15
+ assert @group.group?(%w(groupOfUniqueNames))
16
+ assert @group.group?(%w(posixGroup))
17
+
18
18
  object_classes = %w(groupOfNames)
19
19
  assert @group.group?(object_classes)
20
20
  assert @group.group?(object_classes.map(&:downcase))
21
21
  end
22
22
 
23
23
  def test_subgroups
24
- assert_equal 3, @group.subgroups.size
24
+ group = @ldap.group("cn=deeply-nested-group0.0,ou=Groups,dc=github,dc=com")
25
+ assert_equal 2, group.subgroups.size
25
26
  end
26
27
 
27
28
  def test_members_from_subgroups
28
- assert_equal 4, @group.members.size
29
+ group = @ldap.group("cn=deeply-nested-group0.0,ou=Groups,dc=github,dc=com")
30
+ assert_equal 10, group.members.size
29
31
  end
30
32
 
31
33
  def test_all_domain_groups
32
34
  groups = groups_domain.all_groups
33
- assert_equal 8, groups.size
35
+ assert_equal 27, groups.size
34
36
  end
35
37
 
36
38
  def test_filter_domain_groups
37
- groups = groups_domain.filter_groups('devs')
39
+ groups = groups_domain.filter_groups('ghe-users')
38
40
  assert_equal 1, groups.size
39
41
  end
40
42
 
41
43
  def test_filter_domain_groups_limited
42
44
  groups = []
43
- groups_domain.filter_groups('enter', size: 1) do |entry|
45
+ groups_domain.filter_groups('deeply-nested-group', size: 1) do |entry|
44
46
  groups << entry
45
47
  end
46
48
  assert_equal 1, groups.size
47
49
  end
48
50
 
49
51
  def test_filter_domain_groups_unlimited
50
- groups = groups_domain.filter_groups('ent')
51
- assert_equal 3, groups.size
52
+ groups = groups_domain.filter_groups('deeply-nested-group')
53
+ assert_equal 5, groups.size
52
54
  end
53
55
 
54
56
  def test_unknown_group
@@ -58,33 +60,25 @@ class GitHubLdapGroupTest < GitHub::Ldap::Test
58
60
  end
59
61
 
60
62
  class GitHubLdapLoopedGroupTest < GitHub::Ldap::Test
61
- def self.test_server_options
62
- {user_fixtures: FIXTURES.join('github-with-looped-subgroups.ldif').to_s}
63
- end
64
-
65
63
  def setup
66
- @group = GitHub::Ldap.new(options).group("cn=enterprise,ou=groups,dc=github,dc=com")
64
+ @group = GitHub::Ldap.new(options).group("cn=recursively-nested-groups,ou=Groups,dc=github,dc=com")
67
65
  end
68
66
 
69
67
  def test_members_from_subgroups
70
- assert_equal 4, @group.members.size
68
+ assert_equal 10, @group.members.size
71
69
  end
72
70
  end
73
71
 
74
72
  class GitHubLdapMissingEntriesTest < GitHub::Ldap::Test
75
- def self.test_server_options
76
- {user_fixtures: FIXTURES.join('github-with-missing-entries.ldif').to_s}
77
- end
78
-
79
73
  def setup
80
74
  @ldap = GitHub::Ldap.new(options)
81
75
  end
82
76
 
83
77
  def test_load_right_members
84
- assert_equal 3, @ldap.domain("cn=spaniards,ou=groups,dc=github,dc=com").bind[:member].size
78
+ assert_equal 3, @ldap.domain("cn=missing-users,ou=groups,dc=github,dc=com").bind[:member].size
85
79
  end
86
80
 
87
81
  def test_ignore_missing_member_entries
88
- assert_equal 2, @ldap.group("cn=spaniards,ou=groups,dc=github,dc=com").members.size
82
+ assert_equal 2, @ldap.group("cn=missing-users,ou=groups,dc=github,dc=com").members.size
89
83
  end
90
84
  end
data/test/ldap_test.rb CHANGED
@@ -22,48 +22,55 @@ module GitHubLdapTestCases
22
22
  end
23
23
 
24
24
  def test_search_delegator
25
- @ldap.domain('dc=github,dc=com').valid_login? 'calavera', 'secret'
25
+ assert user = @ldap.domain('dc=github,dc=com').valid_login?('user1', 'passworD1')
26
26
 
27
- result = @ldap.search(
28
- {:base => 'dc=github,dc=com',
29
- :attributes => %w(uid),
30
- :filter => Net::LDAP::Filter.eq('uid', 'calavera')})
27
+ result = @ldap.search \
28
+ :base => 'dc=github,dc=com',
29
+ :attributes => %w(uid),
30
+ :filter => Net::LDAP::Filter.eq('uid', 'user1')
31
31
 
32
32
  refute result.empty?
33
- assert_equal 'calavera', result.first[:uid].first
33
+ assert_equal 'user1', result.first[:uid].first
34
34
  end
35
35
 
36
- def test_virtual_attributes_defaults
37
- @ldap = GitHub::Ldap.new(options.merge(virtual_attributes: true))
38
-
39
- assert @ldap.virtual_attributes.enabled?, "Expected to have virtual attributes enabled with defaults"
40
- assert_equal 'memberOf', @ldap.virtual_attributes.virtual_membership
36
+ def test_virtual_attributes_disabled
37
+ refute @ldap.virtual_attributes.enabled?, "Expected to have virtual attributes disabled"
41
38
  end
42
39
 
43
- def test_virtual_attributes_defaults
40
+ def test_virtual_attributes_configured
44
41
  ldap = GitHub::Ldap.new(options.merge(virtual_attributes: true))
45
42
 
46
- assert ldap.virtual_attributes.enabled?, "Expected to have virtual attributes enabled with defaults"
43
+ assert ldap.virtual_attributes.enabled?,
44
+ "Expected virtual attributes to be enabled"
47
45
  assert_equal 'memberOf', ldap.virtual_attributes.virtual_membership
48
46
  end
49
47
 
50
- def test_virtual_attributes_hash
48
+ def test_virtual_attributes_configured_with_membership_attribute
51
49
  ldap = GitHub::Ldap.new(options.merge(virtual_attributes: {virtual_membership: "isMemberOf"}))
52
50
 
53
- assert ldap.virtual_attributes.enabled?, "Expected to have virtual attributes enabled with defaults"
51
+ assert ldap.virtual_attributes.enabled?,
52
+ "Expected virtual attributes to be enabled"
54
53
  assert_equal 'isMemberOf', ldap.virtual_attributes.virtual_membership
55
54
  end
56
55
 
57
- def test_virtual_attributes_disabled
58
- refute @ldap.virtual_attributes.enabled?, "Expected to have virtual attributes disabled"
59
- end
60
-
61
56
  def test_search_domains
62
57
  ldap = GitHub::Ldap.new(options.merge(search_domains: ['dc=github,dc=com']))
63
- result = ldap.search(filter: Net::LDAP::Filter.eq('uid', 'calavera'))
58
+ result = ldap.search(filter: Net::LDAP::Filter.eq('uid', 'user1'))
64
59
 
65
60
  refute result.empty?
66
- assert_equal 'calavera', result.first[:uid].first
61
+ assert_equal 'user1', result.first[:uid].first
62
+ end
63
+
64
+ def test_instruments_search
65
+ events = @service.subscribe "search.github_ldap"
66
+ result = @ldap.search(filter: "(uid=user1)", :base => "dc=github,dc=com")
67
+ refute_predicate result, :empty?
68
+ payload, event_result = events.pop
69
+ assert payload
70
+ assert event_result
71
+ assert_equal result, event_result
72
+ assert_equal "(uid=user1)", payload[:filter].to_s
73
+ assert_equal "dc=github,dc=com", payload[:base]
67
74
  end
68
75
  end
69
76
 
@@ -0,0 +1,68 @@
1
+ require_relative '../test_helper'
2
+
3
+ # NOTE: Since this strategy is targeted at ActiveDirectory and we don't have
4
+ # AD setup in CI, we stub out actual queries and test against what AD *would*
5
+ # respond with.
6
+
7
+ class GitHubLdapActiveDirectoryMembershipValidatorsTest < GitHub::Ldap::Test
8
+ def setup
9
+ @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com)))
10
+ @domain = @ldap.domain("dc=github,dc=com")
11
+ @entry = @domain.user?('user1')
12
+ @validator = GitHub::Ldap::MembershipValidators::ActiveDirectory
13
+ end
14
+
15
+ def make_validator(groups)
16
+ groups = @domain.groups(groups)
17
+ @validator.new(@ldap, groups)
18
+ end
19
+
20
+ def test_validates_user_in_group
21
+ validator = make_validator(%w(nested-group1))
22
+
23
+ @ldap.stub :search, [@entry] do
24
+ assert validator.perform(@entry)
25
+ end
26
+ end
27
+
28
+ def test_validates_user_in_child_group
29
+ validator = make_validator(%w(n-depth-nested-group1))
30
+
31
+ @ldap.stub :search, [@entry] do
32
+ assert validator.perform(@entry)
33
+ end
34
+ end
35
+
36
+ def test_validates_user_in_grandchild_group
37
+ validator = make_validator(%w(n-depth-nested-group2))
38
+
39
+ @ldap.stub :search, [@entry] do
40
+ assert validator.perform(@entry)
41
+ end
42
+ end
43
+
44
+ def test_validates_user_in_great_grandchild_group
45
+ validator = make_validator(%w(n-depth-nested-group3))
46
+
47
+ @ldap.stub :search, [@entry] do
48
+ assert validator.perform(@entry)
49
+ end
50
+ end
51
+
52
+ def test_does_not_validate_user_not_in_group
53
+ validator = make_validator(%w(ghe-admins))
54
+
55
+ @ldap.stub :search, [] do
56
+ refute validator.perform(@entry)
57
+ end
58
+ end
59
+
60
+ def test_does_not_validate_user_not_in_any_group
61
+ entry = @domain.user?('groupless-user1')
62
+ validator = make_validator(%w(all-users))
63
+
64
+ @ldap.stub :search, [] do
65
+ refute validator.perform(entry)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,51 @@
1
+ require_relative '../test_helper'
2
+
3
+ class GitHubLdapClassicMembershipValidatorsTest < GitHub::Ldap::Test
4
+ def setup
5
+ @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com)))
6
+ @domain = @ldap.domain("dc=github,dc=com")
7
+ @entry = @domain.user?('user1')
8
+ @validator = GitHub::Ldap::MembershipValidators::Classic
9
+ end
10
+
11
+ def make_validator(groups)
12
+ groups = @domain.groups(groups)
13
+ @validator.new(@ldap, groups)
14
+ end
15
+
16
+ def test_validates_user_in_group
17
+ validator = make_validator(%w(nested-group1))
18
+ assert validator.perform(@entry)
19
+ end
20
+
21
+ def test_validates_user_in_child_group
22
+ validator = make_validator(%w(n-depth-nested-group1))
23
+ assert validator.perform(@entry)
24
+ end
25
+
26
+ def test_validates_user_in_grandchild_group
27
+ validator = make_validator(%w(n-depth-nested-group2))
28
+ assert validator.perform(@entry)
29
+ end
30
+
31
+ def test_validates_user_in_great_grandchild_group
32
+ validator = make_validator(%w(n-depth-nested-group3))
33
+ assert validator.perform(@entry)
34
+ end
35
+
36
+ def test_does_not_validate_user_not_in_group
37
+ validator = make_validator(%w(ghe-admins))
38
+ refute validator.perform(@entry)
39
+ end
40
+
41
+ def test_does_not_validate_user_not_in_any_group
42
+ @entry = @domain.user?('groupless-user1')
43
+ validator = make_validator(%w(all-users))
44
+ refute validator.perform(@entry)
45
+ end
46
+
47
+ def test_validates_user_in_posix_group
48
+ validator = make_validator(%w(posix-group1))
49
+ assert validator.perform(@entry)
50
+ end
51
+ end
@@ -0,0 +1,56 @@
1
+ require_relative '../test_helper'
2
+
3
+ class GitHubLdapRecursiveMembershipValidatorsTest < GitHub::Ldap::Test
4
+ def setup
5
+ @ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com)))
6
+ @domain = @ldap.domain("dc=github,dc=com")
7
+ @entry = @domain.user?('user1')
8
+ @validator = GitHub::Ldap::MembershipValidators::Recursive
9
+ end
10
+
11
+ def make_validator(groups)
12
+ groups = @domain.groups(groups)
13
+ @validator.new(@ldap, groups)
14
+ end
15
+
16
+ def test_validates_user_in_group
17
+ validator = make_validator(%w(nested-group1))
18
+ assert validator.perform(@entry)
19
+ end
20
+
21
+ def test_validates_user_in_child_group
22
+ validator = make_validator(%w(n-depth-nested-group1))
23
+ assert validator.perform(@entry)
24
+ end
25
+
26
+ def test_validates_user_in_grandchild_group
27
+ validator = make_validator(%w(n-depth-nested-group2))
28
+ assert validator.perform(@entry)
29
+ end
30
+
31
+ def test_validates_user_in_great_grandchild_group
32
+ validator = make_validator(%w(n-depth-nested-group3))
33
+ assert validator.perform(@entry)
34
+ end
35
+
36
+ def test_does_not_validate_user_in_great_granchild_group_with_depth
37
+ validator = make_validator(%w(n-depth-nested-group3))
38
+ refute validator.perform(@entry, 2)
39
+ end
40
+
41
+ def test_does_not_validate_user_not_in_group
42
+ validator = make_validator(%w(ghe-admins))
43
+ refute validator.perform(@entry)
44
+ end
45
+
46
+ def test_does_not_validate_user_not_in_any_group
47
+ @entry = @domain.user?('groupless-user1')
48
+ validator = make_validator(%w(all-users))
49
+ refute validator.perform(@entry)
50
+ end
51
+
52
+ def test_validates_user_in_posix_group
53
+ validator = make_validator(%w(posix-group1))
54
+ assert validator.perform(@entry)
55
+ end
56
+ end
@@ -0,0 +1,46 @@
1
+ require_relative 'test_helper'
2
+
3
+ module GitHubLdapMembershipValidatorsTestCases
4
+ def make_validator(groups)
5
+ groups = @domain.groups(groups)
6
+ @validator.new(@ldap, groups)
7
+ end
8
+
9
+ def test_validates_user_in_group
10
+ validator = make_validator(%w(ghe-users))
11
+ assert validator.perform(@entry)
12
+ end
13
+
14
+ def test_does_not_validate_user_not_in_group
15
+ validator = make_validator(%w(ghe-admins))
16
+ refute validator.perform(@entry)
17
+ end
18
+
19
+ def test_does_not_validate_user_not_in_any_group
20
+ @entry = @domain.user?('groupless-user1')
21
+ validator = make_validator(%w(ghe-users ghe-admins))
22
+ refute validator.perform(@entry)
23
+ end
24
+ end
25
+
26
+ class GitHubLdapMembershipValidatorsClassicTest < GitHub::Ldap::Test
27
+ include GitHubLdapMembershipValidatorsTestCases
28
+
29
+ def setup
30
+ @ldap = GitHub::Ldap.new(options.merge(search_domains: "dc=github,dc=com"))
31
+ @domain = @ldap.domain("dc=github,dc=com")
32
+ @entry = @domain.user?('user1')
33
+ @validator = GitHub::Ldap::MembershipValidators::Classic
34
+ end
35
+ end
36
+
37
+ class GitHubLdapMembershipValidatorsRecursiveTest < GitHub::Ldap::Test
38
+ include GitHubLdapMembershipValidatorsTestCases
39
+
40
+ def setup
41
+ @ldap = GitHub::Ldap.new(options.merge(search_domains: "dc=github,dc=com"))
42
+ @domain = @ldap.domain("dc=github,dc=com")
43
+ @entry = @domain.user?('user1')
44
+ @validator = GitHub::Ldap::MembershipValidators::Recursive
45
+ end
46
+ end