activedirectory 0.9.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ #-- license
2
+ #
3
+ # This file is part of the Ruby Active Directory Project
4
+ # on the web at http://rubyforge.org/projects/activedirectory
5
+ #
6
+ # Copyright (c) 2008, James Hunt <filefrog@gmail.com>
7
+ # based on original code by Justin Mecham
8
+ #
9
+ # This program is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # This program is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
21
+ #
22
+ #++ license
23
+
24
+ module ActiveDirectory
25
+ class Computer < Base
26
+ def self.filter # :nodoc:
27
+ Net::LDAP::Filter.eq(:objectClass,'computer')
28
+ end
29
+
30
+ def self.required_attributes # :nodoc:
31
+ { :objectClass => [ 'top', 'person', 'organizationalPerson', 'user', 'computer' ] }
32
+ end
33
+
34
+ def hostname
35
+ dNSHostName || name
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,117 @@
1
+ #-- license
2
+ #
3
+ # This file is part of the Ruby Active Directory Project
4
+ # on the web at http://rubyforge.org/projects/activedirectory
5
+ #
6
+ # Copyright (c) 2008, James Hunt <filefrog@gmail.com>
7
+ # based on original code by Justin Mecham
8
+ #
9
+ # This program is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # This program is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
21
+ #
22
+ #++ license
23
+
24
+ module ActiveDirectory
25
+ #
26
+ # The ActiveDirectory::Container class represents a more malleable way
27
+ # of dealing with LDAP Distinguished Names (dn), like
28
+ # "cn=UserName,ou=Users,dc=example,dc=org".
29
+ #
30
+ # The following two representations of the above dn are identical:
31
+ #
32
+ # dn = "cn=UserName,ou=Users,dc=example,dc=org"
33
+ # dn = ActiveDirectory::Container.dc('org').dc('example').ou('Users').cn('UserName').to_s
34
+ #
35
+ class Container
36
+ attr_reader :type
37
+ attr_reader :name
38
+ attr_reader :parent
39
+
40
+ def initialize(type, name, node = nil) #:nodoc:
41
+ @type = type
42
+ @name = name
43
+ @node = node
44
+ end
45
+
46
+ #
47
+ # Creates a starting OU (Organizational Unit) dn part.
48
+ #
49
+ # # ou_part = "ou=OrganizationalUnit"
50
+ # ou_part = ActiveDirectory::Container.ou('OrganizationalUnit').to_s
51
+ #
52
+ def self.ou(name)
53
+ new(:ou, name, nil)
54
+ end
55
+
56
+ #
57
+ # Creates a starting DC (Domain Component) dn part.
58
+ #
59
+ # # dc_part = "dc=net"
60
+ # dc_part = ActiveDirectory::Container.dc('net').to_s
61
+ #
62
+ def self.dc(name)
63
+ new(:dc, name, nil)
64
+ end
65
+
66
+ #
67
+ # Creates a starting CN (Canonical Name) dn part.
68
+ #
69
+ # # cn_part = "cn=CanonicalName"
70
+ # cn_part = ActiveDirectory::Container.cn('CanonicalName').to_s
71
+ #
72
+ def self.cn(name)
73
+ new(:cn, name, nil)
74
+ end
75
+
76
+ #
77
+ # Appends an OU (Organizational Unit) dn part to another Container.
78
+ #
79
+ # # ou = "ou=InfoTech,dc=net"
80
+ # ou = ActiveDirectory::Container.dc("net").ou("InfoTech").to_s
81
+ #
82
+ def ou(name)
83
+ self.class.new(:ou, name, self)
84
+ end
85
+
86
+ #
87
+ # Appends a DC (Domain Component) dn part to another Container.
88
+ #
89
+ # # base = "dc=example,dc=net"
90
+ # base = ActiveDirectory::Container.dc("net").dc("example").to_s
91
+ #
92
+ def dc(name)
93
+ self.class.new(:dc, name, self)
94
+ end
95
+
96
+ #
97
+ # Appends a CN (Canonical Name) dn part to another Container.
98
+ #
99
+ # # user = "cn=UID,ou=Users"
100
+ # user = ActiveDirectory::Container.ou("Users").cn("UID")
101
+ #
102
+ def cn(name)
103
+ self.class.new(:cn, name, self)
104
+ end
105
+
106
+ #
107
+ # Converts the Container object to its String representation.
108
+ #
109
+ def to_s
110
+ @node ? "#{@type}=#{name},#{@node.to_s}" : "#{@type}=#{name}"
111
+ end
112
+
113
+ def ==(other) #:nodoc:
114
+ to_s.downcase == other.to_s.downcase
115
+ end
116
+ end
117
+ end
@@ -1,109 +1,162 @@
1
- #--
2
- # Active Directory Module for Ruby
1
+ #-- license
3
2
  #
4
- # Copyright (c) 2005-2006 Justin Mecham
3
+ # This file is part of the Ruby Active Directory Project
4
+ # on the web at http://rubyforge.org/projects/activedirectory
5
5
  #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the "Software"), to
8
- # deal in the Software without restriction, including without limitation the
9
- # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
- # sell copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
6
+ # Copyright (c) 2008, James Hunt <filefrog@gmail.com>
7
+ # based on original code by Justin Mecham
12
8
  #
13
- # The above copyright notice and this permission notice shall be included in
14
- # all copies or substantial portions of the Software.
9
+ # This program is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
15
13
  #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
- # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
- # IN THE SOFTWARE.
23
- #++
14
+ # This program is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
21
+ #
22
+ #++ license
24
23
 
25
24
  module ActiveDirectory
26
-
27
- #
28
- # Represents a Group object within an Active Directory instance.
29
- #
30
- class Group < Base
31
-
32
- # Distinguished Name (DN)
33
- attr_accessor :dn
34
-
35
- # Description
36
- attr_accessor :description
37
-
38
- # Common Name (CN)
39
- attr_accessor :name
40
-
41
- # Users who are members of this Group
42
- attr :members
43
-
44
- #
45
- # Attributes that we wish to pull from Active Directory for any Group that
46
- # can be located within the directory.
47
- #
48
- ATTRIBUTES = ["distinguishedName", # DN of Group
49
- "name", # Group Name
50
- "member", # DN References to Members
51
- "description"] #:nodoc: # Description
52
-
53
- #
54
- # Attempts to load a Group by a Distinguished Name (DN).
55
- #
56
- def initialize(identifier)
57
-
58
- identifier = identifier.delete("\\")
59
-
60
- load_by_dn(identifier)
61
-
62
- end
63
-
64
- #
65
- # Proxy for loading and returning the members of this group.
66
- #
67
- def members #:nodoc:
68
- members = Array.new
69
- unless @members.nil?
70
- for user_dn in @members
71
- members << User.new(user_dn)
72
- end
73
- end
74
- members
75
- end
76
-
77
- private
78
-
79
- #
80
- # Attempt to load a Group by its Distinguished Name (DN).
81
- #
82
- def load_by_dn(dn)
83
-
84
- if dn.nil? or dn.length == 0
85
- raise ArgumentError, "No distinguished name provided."
86
- end
87
-
88
- # De-escape the DN
89
- dn = dn.gsub(/"/, "\\\"")
90
-
91
- entries = Base.search(dn, LDAP::LDAP_SCOPE_BASE,
92
- "(&(objectClass=group))", ATTRIBUTES)
93
-
94
- raise UnknownGroupError if (entries.nil? or entries.length != 1)
95
-
96
- parse_ldap_entry(entries[0])
97
-
98
- end
99
-
100
- def parse_ldap_entry(entry)
101
- @dn = entry['distinguishedName'][0].delete("\\")
102
- @name = entry['name'][0].delete("\\")
103
- @description = entry['description'][0] unless entry['description'].nil?
104
- @members = entry['member']
105
- end
106
-
107
- end
108
-
109
- end
25
+ class Group < Base
26
+ include Member
27
+
28
+ def self.filter # :nodoc:
29
+ Net::LDAP::Filter.eq(:objectClass,'group')
30
+ end
31
+
32
+ def self.required_attributes # :nodoc:
33
+ { :objectClass => [ 'top', 'group' ] }
34
+ end
35
+
36
+ def reload # :nodoc:
37
+ @member_users_non_r = nil
38
+ @member_users_r = nil
39
+ @member_groups_non_r = nil
40
+ @member_groups_r = nil
41
+ @groups = nil
42
+ super
43
+ end
44
+
45
+ #
46
+ # Returns true if the passed User or Group object belongs to
47
+ # this group. For performance reasons, the check is handled
48
+ # by the User or Group object passed.
49
+ #
50
+ def has_member?(user)
51
+ user.member_of?(self)
52
+ end
53
+
54
+ #
55
+ # Add the passed User or Group object to this Group. Returns true if
56
+ # the User or Group is already a member of the group, or if the operation
57
+ # to add them succeeds.
58
+ #
59
+ def add(new_member)
60
+ return false unless new_member.is_a?(User) || new_member.is_a?(Group)
61
+ if @@ldap.modify(:dn => distinguishedName, :operations => [
62
+ [ :add, :member, new_member.distinguishedName ]
63
+ ])
64
+ return true
65
+ else
66
+ return has_member?(new_member)
67
+ end
68
+ end
69
+
70
+ #
71
+ # Remove a User or Group from this Group. Returns true if the User or
72
+ # Group does not belong to this Group, or if the oepration to remove them
73
+ # succeeds.
74
+ #
75
+ def remove(member)
76
+ return false unless member.is_a?(User) || member.is_a?(Group)
77
+ if @@ldap.modify(:dn => distinguishedName, :operations => [
78
+ [ :delete, :member, member.distinguishedName ]
79
+ ])
80
+ return true
81
+ else
82
+ return !has_member?(member)
83
+ end
84
+ end
85
+
86
+ def has_members?
87
+ begin
88
+ return (@entry.member.nil? || @entry.member.empty?) ? false : true
89
+ rescue NoMethodError
90
+ return false
91
+ end
92
+ end
93
+
94
+ #
95
+ # Returns an array of all User objects that belong to this group.
96
+ #
97
+ # If the recursive argument is passed as false, then only Users who
98
+ # belong explicitly to this Group are returned.
99
+ #
100
+ # If the recursive argument is passed as true, then all Users who
101
+ # belong to this Group, or any of its subgroups, are returned.
102
+ #
103
+ def member_users(recursive = false)
104
+ return [] unless has_members?
105
+ if recursive
106
+ if @member_users_r.nil?
107
+ @member_users_r = []
108
+ @entry.member.each do |member_dn|
109
+ subuser = User.find_by_distinguishedName(member_dn)
110
+ if subuser
111
+ @member_users_r << subuser
112
+ else
113
+ subgroup = Group.find_by_distinguishedName(member_dn)
114
+ if subgroup
115
+ @member_users_r = @member_users_r.concat(subgroup.member_users(true))
116
+ end
117
+ end
118
+ end
119
+ end
120
+ return @member_users_r
121
+ else
122
+ @member_users_non_r ||= @entry.member.collect { |dn| User.find_by_distinguishedName(dn) }.delete_if { |u| u.nil? }
123
+ end
124
+ end
125
+
126
+ #
127
+ # Returns an array of all Group objects that belong to this group.
128
+ #
129
+ # If the recursive argument is passed as false, then only Groups that
130
+ # belong explicitly to this Group are returned.
131
+ #
132
+ # If the recursive argument is passed as true, then all Groups that
133
+ # belong to this Group, or any of its subgroups, are returned.
134
+ #
135
+ def member_groups(recursive = false)
136
+ return [] unless has_members?
137
+ if recursive
138
+ if @member_groups_r.nil?
139
+ @member_groups_r = []
140
+ @entry.member.each do |member_dn|
141
+ subgroup = Group.find_by_distinguishedName(member_dn)
142
+ if subgroup
143
+ @member_groups_r << subgroup
144
+ @member_groups_r = @member_groups_r.concat(subgroup.member_groups(true))
145
+ end
146
+ end
147
+ end
148
+ return @member_groups_r
149
+ else
150
+ @member_groups_non_r ||= @entry.member.collect { |dn| Group.find_by_distinguishedName(dn) }.delete_if { |g| g.nil? }
151
+ end
152
+ end
153
+
154
+ #
155
+ # Returns an array of Group objects that this Group belongs to.
156
+ #
157
+ def groups
158
+ return [] if memberOf.nil?
159
+ @groups ||= memberOf.collect { |group_dn| Group.find_by_distinguishedName(group_dn) }
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,56 @@
1
+ #-- license
2
+ #
3
+ # This file is part of the Ruby Active Directory Project
4
+ # on the web at http://rubyforge.org/projects/activedirectory
5
+ #
6
+ # Copyright (c) 2008, James Hunt <filefrog@gmail.com>
7
+ # based on original code by Justin Mecham
8
+ #
9
+ # This program is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # This program is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
21
+ #
22
+ #++ license
23
+
24
+ module ActiveDirectory
25
+ module Member
26
+ #
27
+ # Returns true if this member (User or Group) is a member of
28
+ # the passed Group object.
29
+ #
30
+ def member_of?(usergroup)
31
+ group_dns = memberOf
32
+ return false if group_dns.nil? || group_dns.empty?
33
+ #group_dns = [group_dns] unless group_dns.is_a?(Array)
34
+ group_dns.include?(usergroup.dn)
35
+ end
36
+
37
+ #
38
+ # Add the member to the passed Group object. Returns true if this object
39
+ # is already a member of the Group, or if the operation to add it succeeded.
40
+ #
41
+ def join(group)
42
+ return false unless group.is_a?(Group)
43
+ group.add(self)
44
+ end
45
+
46
+ #
47
+ # Remove the member from the passed Group object. Returns true if this
48
+ # object is not a member of the Group, or if the operation to remove it
49
+ # succeeded.
50
+ #
51
+ def unjoin(group)
52
+ return false unless group.is_a?(Group)
53
+ group.remove(self)
54
+ end
55
+ end
56
+ end