Formatting changes to the DN class.

This commit is contained in:
Austin Ziegler 2011-03-17 22:25:22 -04:00
parent f50ba57e99
commit 393b57405d
2 changed files with 129 additions and 115 deletions

View file

@ -1,12 +1,10 @@
# LDAP DN support classes # -*- ruby encoding: utf-8 -*-
#
## ##
# Objects of this class represent an LDAP DN. # Objects of this class represent an LDAP DN ("Distinguished Name"). A DN
# # ("Distinguished Name") is a unique identifier for an entry within an LDAP
# In LDAP-land, a DN ("Distinguished Name") is a unique identifier for an # directory. It is made up of a number of other attributes strung together,
# entry within an LDAP directory. It is made up of a number of other # to identify the entry in the tree.
# attributes strung together, to identify the entry in the tree.
# #
# Each attribute that makes up a DN needs to have its value escaped so that # Each attribute that makes up a DN needs to have its value escaped so that
# the DN is valid. This class helps take care of that. # the DN is valid. This class helps take care of that.
@ -18,10 +16,10 @@ class Net::LDAP::DN
# Initialize a DN, escaping as required. Pass in attributes in name/value # Initialize a DN, escaping as required. Pass in attributes in name/value
# pairs. If there is a left over argument, it will be appended to the dn # pairs. If there is a left over argument, it will be appended to the dn
# without escaping (useful for a base string). # without escaping (useful for a base string).
# #
# Most uses of this class will be to escape a DN, rather than to parse it, # Most uses of this class will be to escape a DN, rather than to parse it,
# so storing the dn as an escaped String and parsing parts as required with # so storing the dn as an escaped String and parsing parts as required
# a state machine seems sensible. # with a state machine seems sensible.
def initialize(*args) def initialize(*args)
buffer = StringIO.new buffer = StringIO.new
@ -42,7 +40,6 @@ class Net::LDAP::DN
## ##
# Parse a DN into key value pairs using ASN from # Parse a DN into key value pairs using ASN from
# http://tools.ietf.org/html/rfc2253 section 3. # http://tools.ietf.org/html/rfc2253 section 3.
#
def each_pair def each_pair
state = :key state = :key
key = StringIO.new key = StringIO.new
@ -51,118 +48,126 @@ class Net::LDAP::DN
@dn.each_char do |char| @dn.each_char do |char|
case state case state
when :key then
when :key then case char case char
when 'a'..'z','A'..'Z' then when 'a'..'z', 'A'..'Z' then
state = :key_normal state = :key_normal
key << char key << char
when '0'..'9' then when '0'..'9' then
state = :key_oid state = :key_oid
key << char key << char
when ' ' then state = :key when ' ' then state = :key
else raise "DN badly formed" else raise "DN badly formed"
end end
when :key_normal then case char when :key_normal then
when '=' then state = :value case char
when 'a'..'z','A'..'Z','0'..'9','-',' ' then key << char when '=' then state = :value
else raise "DN badly formed" when 'a'..'z', 'A'..'Z', '0'..'9', '-', ' ' then key << char
else raise "DN badly formed"
end end
when :key_oid then case char when :key_oid then
when '=' then state = :value case char
when '0'..'9','.',' ' then key << char when '=' then state = :value
else raise "DN badly formed" when '0'..'9', '.', ' ' then key << char
else raise "DN badly formed"
end end
when :value then
when :value then case char case char
when '\\' then state = :value_normal_escape when '\\' then state = :value_normal_escape
when '"' then state = :value_quoted when '"' then state = :value_quoted
when ' ' then state = :value when ' ' then state = :value
when '#' then when '#' then
state = :value_hexstring state = :value_hexstring
value << char value << char
when ',' then when ',' then
state = :key state = :key
yield key.string.strip, value.string.rstrip yield key.string.strip, value.string.rstrip
key = StringIO.new key = StringIO.new
value = StringIO.new; value = StringIO.new;
else else
state = :value_normal state = :value_normal
value << char value << char
end end
when :value_normal then
when :value_normal then case char case char
when '\\' then state = :value_normal_escape when '\\' then state = :value_normal_escape
when ',' then when ',' then
state = :key state = :key
yield key.string.strip, value.string.rstrip yield key.string.strip, value.string.rstrip
key = StringIO.new key = StringIO.new
value = StringIO.new; value = StringIO.new;
else value << char else value << char
end end
when :value_normal_escape then case char when :value_normal_escape then
when '0'..'9', 'a'..'f', 'A'..'F' then case char
state = :value_normal_escape_hex when '0'..'9', 'a'..'f', 'A'..'F' then
hex_buffer = char state = :value_normal_escape_hex
else state = :value_normal; value << char hex_buffer = char
else state = :value_normal; value << char
end end
when :value_normal_escape_hex then case char when :value_normal_escape_hex then
when '0'..'9', 'a'..'f', 'A'..'F' then case char
state = :value_normal when '0'..'9', 'a'..'f', 'A'..'F' then
value << "#{hex_buffer}#{char}".to_i(16).chr state = :value_normal
else raise "DN badly formed" value << "#{hex_buffer}#{char}".to_i(16).chr
else raise "DN badly formed"
end end
when :value_quoted then
when :value_quoted then case char case char
when '\\' then state = :value_quoted_escape when '\\' then state = :value_quoted_escape
when '"' then state = :value_end when '"' then state = :value_end
else value << char else value << char
end end
when :value_quoted_escape then case char when :value_quoted_escape then
when '0'..'9', 'a'..'f', 'A'..'F' then case char
state = :value_quoted_escape_hex when '0'..'9', 'a'..'f', 'A'..'F' then
hex_buffer = char state = :value_quoted_escape_hex
else state = :value_quoted; value << char hex_buffer = char
else
state = :value_quoted;
value << char
end end
when :value_quoted_escape_hex then case char when :value_quoted_escape_hex then
when '0'..'9', 'a'..'f', 'A'..'F' then case char
state = :value_quoted when '0'..'9', 'a'..'f', 'A'..'F' then
value << "#{hex_buffer}#{char}".to_i(16).chr state = :value_quoted
else raise "DN badly formed" value << "#{hex_buffer}#{char}".to_i(16).chr
else raise "DN badly formed"
end end
when :value_hexstring then
when :value_hexstring then case char case char
when '0'..'9', 'a'..'f', 'A'..'F' then when '0'..'9', 'a'..'f', 'A'..'F' then
state = :value_hexstring_hex state = :value_hexstring_hex
value << char value << char
when ' ' then state = :value_end when ' ' then state = :value_end
when ',' then when ',' then
state = :key state = :key
yield key.string.strip, value.string.rstrip yield key.string.strip, value.string.rstrip
key = StringIO.new key = StringIO.new
value = StringIO.new; value = StringIO.new;
else raise "DN badly formed" else raise "DN badly formed"
end end
when :value_hexstring_hex then case char when :value_hexstring_hex then
when '0'..'9', 'a'..'f', 'A'..'F' then case char
state = :value_hexstring when '0'..'9', 'a'..'f', 'A'..'F' then
value << char state = :value_hexstring
else raise "DN badly formed" value << char
else raise "DN badly formed"
end end
when :value_end then
when :value_end then case char case char
when ' ' then state = :value_end when ' ' then state = :value_end
when ',' then when ',' then
state = :key state = :key
yield key.string.strip, value.string.rstrip yield key.string.strip, value.string.rstrip
key = StringIO.new key = StringIO.new
value = StringIO.new; value = StringIO.new;
else raise "DN badly formed" else raise "DN badly formed"
end end
else raise "Fell out of state machine"
else raise "Fell out of state machine"
end end
end end
# Last pair # Last pair
if [:value, :value_normal, :value_hexstring, :value_end].include? state if [:value, :value_normal, :value_hexstring, :value_end].include? state
yield key.string.strip, value.string.rstrip yield key.string.strip, value.string.rstrip
@ -186,9 +191,8 @@ class Net::LDAP::DN
end end
# http://tools.ietf.org/html/rfc2253 section 2.4 lists these exceptions # http://tools.ietf.org/html/rfc2253 section 2.4 lists these exceptions
# for dn values. All of the following must be escaped in any normal # for dn values. All of the following must be escaped in any normal string
# string using a single backslash ('\') as escape. # using a single backslash ('\') as escape.
#
ESCAPES = { ESCAPES = {
',' => ',', ',' => ',',
'+' => '+', '+' => '+',
@ -198,13 +202,13 @@ class Net::LDAP::DN
'>' => '>', '>' => '>',
';' => ';', ';' => ';',
} }
# Compiled character class regexp using the keys from the above hash, and # Compiled character class regexp using the keys from the above hash, and
# checking for a space or # at the start, or space at the end, of the # checking for a space or # at the start, or space at the end, of the
# string. # string.
ESCAPE_RE = Regexp.new( ESCAPE_RE = Regexp.new("(^ |^#| $|[" +
"(^ |^#| $|[" + ESCAPES.keys.map { |e| Regexp.escape(e) }.join +
ESCAPES.keys.map { |e| Regexp.escape(e) }.join + "])")
"])")
## ##
# Escape a string for use in a DN value # Escape a string for use in a DN value

View file

@ -4,16 +4,20 @@ require 'net/ldap/dn'
describe Net::LDAP::DN do describe Net::LDAP::DN do
describe "<- .construct" do describe "<- .construct" do
attr_reader :dn attr_reader :dn
before(:each) do before(:each) do
@dn = Net::LDAP::DN.new('cn', ',+"\\<>;', 'ou=company') @dn = Net::LDAP::DN.new('cn', ',+"\\<>;', 'ou=company')
end end
it "should construct a Net::LDAP::DN" do it "should construct a Net::LDAP::DN" do
dn.should be_an_instance_of(Net::LDAP::DN) dn.should be_an_instance_of(Net::LDAP::DN)
end end
it "should escape all the required characters" do it "should escape all the required characters" do
dn.to_s.should == 'cn=\\,\\+\\"\\\\\\<\\>\\;,ou=company' dn.to_s.should == 'cn=\\,\\+\\"\\\\\\<\\>\\;,ou=company'
end end
end end
describe "<- .to_a" do describe "<- .to_a" do
context "parsing" do context "parsing" do
{ {
@ -23,12 +27,15 @@ describe Net::LDAP::DN do
}.each do |key, value| }.each do |key, value|
context "(#{key})" do context "(#{key})" do
attr_reader :dn attr_reader :dn
before(:each) do before(:each) do
@dn = Net::LDAP::DN.new(key) @dn = Net::LDAP::DN.new(key)
end end
it "should decode into a Net::LDAP::DN" do it "should decode into a Net::LDAP::DN" do
dn.should be_an_instance_of(Net::LDAP::DN) dn.should be_an_instance_of(Net::LDAP::DN)
end end
it "should return the correct array" do it "should return the correct array" do
dn.to_a.should == value dn.to_a.should == value
end end
@ -48,12 +55,15 @@ describe Net::LDAP::DN do
].each do |value| ].each do |value|
context "(#{value})" do context "(#{value})" do
attr_reader :dn attr_reader :dn
before(:each) do before(:each) do
@dn = Net::LDAP::DN.new(value) @dn = Net::LDAP::DN.new(value)
end end
it "should decode into a Net::LDAP::DN" do it "should decode into a Net::LDAP::DN" do
dn.should be_an_instance_of(Net::LDAP::DN) dn.should be_an_instance_of(Net::LDAP::DN)
end end
it "should raise an error on parsing" do it "should raise an error on parsing" do
lambda { dn.to_a }.should raise_error lambda { dn.to_a }.should raise_error
end end