annotate vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldap/pdu.rb @ 880:067c526a505e feature_74

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