comparison .svn/pristine/60/60a7eaf3b71f4ea5a952f91807abdd540583522f.svn-base @ 909:cbb26bc654de redmine-1.3

Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author Chris Cannam
date Fri, 24 Feb 2012 19:09:32 +0000
parents
children
comparison
equal deleted inserted replaced
908:c6c2cbd0afee 909:cbb26bc654de
1 # $Id: pdu.rb 126 2006-05-31 15:55:16Z blackhedd $
2 #
3 # LDAP PDU support classes
4 #
5 #
6 #----------------------------------------------------------------------------
7 #
8 # Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
9 #
10 # Gmail: garbagecat10
11 #
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #
26 #---------------------------------------------------------------------------
27 #
28
29
30
31 module Net
32
33
34 class LdapPduError < Exception; end
35
36
37 class LdapPdu
38
39 BindResult = 1
40 SearchReturnedData = 4
41 SearchResult = 5
42 ModifyResponse = 7
43 AddResponse = 9
44 DeleteResponse = 11
45 ModifyRDNResponse = 13
46 SearchResultReferral = 19
47
48 attr_reader :msg_id, :app_tag
49 attr_reader :search_dn, :search_attributes, :search_entry
50 attr_reader :search_referrals
51
52 #
53 # initialize
54 # An LDAP PDU always looks like a BerSequence with
55 # at least two elements: an integer (message-id number), and
56 # an application-specific sequence.
57 # Some LDAPv3 packets also include an optional
58 # third element, which is a sequence of "controls"
59 # (See RFC 2251, section 4.1.12).
60 # The application-specific tag in the sequence tells
61 # us what kind of packet it is, and each kind has its
62 # own format, defined in RFC-1777.
63 # Observe that many clients (such as ldapsearch)
64 # do not necessarily enforce the expected application
65 # tags on received protocol packets. This implementation
66 # does interpret the RFC strictly in this regard, and
67 # it remains to be seen whether there are servers out
68 # there that will not work well with our approach.
69 #
70 # Added a controls-processor to SearchResult.
71 # Didn't add it everywhere because it just _feels_
72 # like it will need to be refactored.
73 #
74 def initialize ber_object
75 begin
76 @msg_id = ber_object[0].to_i
77 @app_tag = ber_object[1].ber_identifier - 0x60
78 rescue
79 # any error becomes a data-format error
80 raise LdapPduError.new( "ldap-pdu format error" )
81 end
82
83 case @app_tag
84 when BindResult
85 parse_ldap_result ber_object[1]
86 when SearchReturnedData
87 parse_search_return ber_object[1]
88 when SearchResultReferral
89 parse_search_referral ber_object[1]
90 when SearchResult
91 parse_ldap_result ber_object[1]
92 parse_controls(ber_object[2]) if ber_object[2]
93 when ModifyResponse
94 parse_ldap_result ber_object[1]
95 when AddResponse
96 parse_ldap_result ber_object[1]
97 when DeleteResponse
98 parse_ldap_result ber_object[1]
99 when ModifyRDNResponse
100 parse_ldap_result ber_object[1]
101 else
102 raise LdapPduError.new( "unknown pdu-type: #{@app_tag}" )
103 end
104 end
105
106 #
107 # result_code
108 # This returns an LDAP result code taken from the PDU,
109 # but it will be nil if there wasn't a result code.
110 # That can easily happen depending on the type of packet.
111 #
112 def result_code code = :resultCode
113 @ldap_result and @ldap_result[code]
114 end
115
116 # Return RFC-2251 Controls if any.
117 # Messy. Does this functionality belong somewhere else?
118 def result_controls
119 @ldap_controls || []
120 end
121
122
123 #
124 # parse_ldap_result
125 #
126 def parse_ldap_result sequence
127 sequence.length >= 3 or raise LdapPduError
128 @ldap_result = {:resultCode => sequence[0], :matchedDN => sequence[1], :errorMessage => sequence[2]}
129 end
130 private :parse_ldap_result
131
132 #
133 # parse_search_return
134 # Definition from RFC 1777 (we're handling application-4 here)
135 #
136 # Search Response ::=
137 # CHOICE {
138 # entry [APPLICATION 4] SEQUENCE {
139 # objectName LDAPDN,
140 # attributes SEQUENCE OF SEQUENCE {
141 # AttributeType,
142 # SET OF AttributeValue
143 # }
144 # },
145 # resultCode [APPLICATION 5] LDAPResult
146 # }
147 #
148 # We concoct a search response that is a hash of the returned attribute values.
149 # NOW OBSERVE CAREFULLY: WE ARE DOWNCASING THE RETURNED ATTRIBUTE NAMES.
150 # This is to make them more predictable for user programs, but it
151 # may not be a good idea. Maybe this should be configurable.
152 # ALTERNATE IMPLEMENTATION: In addition to @search_dn and @search_attributes,
153 # we also return @search_entry, which is an LDAP::Entry object.
154 # If that works out well, then we'll remove the first two.
155 #
156 # Provisionally removed obsolete search_attributes and search_dn, 04May06.
157 #
158 def parse_search_return sequence
159 sequence.length >= 2 or raise LdapPduError
160 @search_entry = LDAP::Entry.new( sequence[0] )
161 #@search_dn = sequence[0]
162 #@search_attributes = {}
163 sequence[1].each {|seq|
164 @search_entry[seq[0]] = seq[1]
165 #@search_attributes[seq[0].downcase.intern] = seq[1]
166 }
167 end
168
169 #
170 # A search referral is a sequence of one or more LDAP URIs.
171 # Any number of search-referral replies can be returned by the server, interspersed
172 # with normal replies in any order.
173 # Until I can think of a better way to do this, we'll return the referrals as an array.
174 # It'll be up to higher-level handlers to expose something reasonable to the client.
175 def parse_search_referral uris
176 @search_referrals = uris
177 end
178
179
180 # Per RFC 2251, an LDAP "control" is a sequence of tuples, each consisting
181 # of an OID, a boolean criticality flag defaulting FALSE, and an OPTIONAL
182 # Octet String. If only two fields are given, the second one may be
183 # either criticality or data, since criticality has a default value.
184 # Someday we may want to come back here and add support for some of
185 # more-widely used controls. RFC-2696 is a good example.
186 #
187 def parse_controls sequence
188 @ldap_controls = sequence.map do |control|
189 o = OpenStruct.new
190 o.oid,o.criticality,o.value = control[0],control[1],control[2]
191 if o.criticality and o.criticality.is_a?(String)
192 o.value = o.criticality
193 o.criticality = false
194 end
195 o
196 end
197 end
198 private :parse_controls
199
200
201 end
202
203
204 end # module Net
205