diff options
author | Michael Kozono <mkozono@gmail.com> | 2017-10-04 01:15:23 +0300 |
---|---|---|
committer | Michael Kozono <mkozono@gmail.com> | 2017-10-07 20:28:13 +0300 |
commit | 3d460af091e7241e4bca7c8ae2880ef0fd2f12b3 (patch) | |
tree | 8769612b53e96fa400ed8c9b4f91393a3ceaa41e /db | |
parent | 6b9229466dc84d3d2b4ed002807d28960bfd1a84 (diff) |
Update DN class in migration
Diffstat (limited to 'db')
-rw-r--r-- | db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb | 101 |
1 files changed, 60 insertions, 41 deletions
diff --git a/db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb b/db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb index aa95fa49e48..234e8a3270b 100644 --- a/db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb +++ b/db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb @@ -19,6 +19,12 @@ class NormalizeLdapExternUids < ActiveRecord::Migration UnsupportedDnFormatError = Class.new(StandardError) class DN + def self.normalize_value(given_value) + dummy_dn = "placeholder=#{given_value}" + normalized_dn = new(*dummy_dn).to_normalized_s + normalized_dn.sub(/\Aplaceholder=/, '') + end + ## # 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 @@ -28,22 +34,31 @@ class NormalizeLdapExternUids < ActiveRecord::Migration # so storing the dn as an escaped String and parsing parts as required # with a state machine seems sensible. def initialize(*args) - buffer = StringIO.new - - args.each_index do |index| - buffer << "=" if index.odd? - buffer << "," if index.even? && index != 0 + @dn = if args.length > 1 + initialize_array(args) + else + initialize_string(args[0]) + end + end - arg = args[index].downcase + def initialize_array(args) + buffer = StringIO.new - buffer << if index < args.length - 1 || index.odd? - self.class.escape(arg) - else - arg - end + args.each_with_index do |arg, index| + if index.even? # key + buffer << "," if index > 0 + buffer << arg + else # value + buffer << "=" + buffer << self.class.escape(arg) + end end - @dn = buffer.string + buffer.string + end + + def initialize_string(arg) + arg.to_s end ## @@ -58,11 +73,11 @@ class NormalizeLdapExternUids < ActiveRecord::Migration value = StringIO.new hex_buffer = "" - @dn.each_char do |char| + @dn.each_char.with_index do |char, dn_index| case state when :key then case char - when 'a'..'z' then + when 'a'..'z', 'A'..'Z' then state = :key_normal key << char when '0'..'9' then @@ -74,7 +89,7 @@ class NormalizeLdapExternUids < ActiveRecord::Migration when :key_normal then case char when '=' then state = :value - when 'a'..'z', '0'..'9', '-', ' ' then key << char + when 'a'..'z', 'A'..'Z', '0'..'9', '-', ' ' then key << char else raise(MalformedDnError, "Unrecognized RDN attribute type name character \"#{char}\"") end when :key_oid then @@ -93,7 +108,7 @@ class NormalizeLdapExternUids < ActiveRecord::Migration value << char when ',' then state = :key - yield key.string.strip, value.string.rstrip + yield key.string.strip, rstrip_except_escaped(value.string, dn_index) key = StringIO.new value = StringIO.new else @@ -105,7 +120,7 @@ class NormalizeLdapExternUids < ActiveRecord::Migration when '\\' then state = :value_normal_escape when ',' then state = :key - yield key.string.strip, value.string.rstrip + yield key.string.strip, rstrip_except_escaped(value.string, dn_index) key = StringIO.new value = StringIO.new when '+' then raise(UnsupportedDnFormatError, "Multivalued RDNs are not supported") @@ -113,34 +128,20 @@ class NormalizeLdapExternUids < ActiveRecord::Migration end when :value_normal_escape then case char - when '0'..'9', 'a'..'f' then + when '0'..'9', 'a'..'f', 'A'..'F' then state = :value_normal_escape_hex hex_buffer = char - when /\s/ then - state = :value_normal_escape_whitespace - value << char else state = :value_normal value << char end when :value_normal_escape_hex then case char - when '0'..'9', 'a'..'f' then + when '0'..'9', 'a'..'f', 'A'..'F' then state = :value_normal value << "#{hex_buffer}#{char}".to_i(16).chr else raise(MalformedDnError, "Invalid escaped hex code \"\\#{hex_buffer}#{char}\"") end - when :value_normal_escape_whitespace then - case char - when '\\' then state = :value_normal_escape - when ',' then - state = :key - yield key.string.strip, value.string # Don't strip trailing escaped space! - key = StringIO.new - value = StringIO.new - when '+' then raise(UnsupportedDnFormatError, "Multivalued RDNs are not supported") - else value << char - end when :value_quoted then case char when '\\' then state = :value_quoted_escape @@ -149,7 +150,7 @@ class NormalizeLdapExternUids < ActiveRecord::Migration end when :value_quoted_escape then case char - when '0'..'9', 'a'..'f' then + when '0'..'9', 'a'..'f', 'A'..'F' then state = :value_quoted_escape_hex hex_buffer = char else @@ -158,27 +159,27 @@ class NormalizeLdapExternUids < ActiveRecord::Migration end when :value_quoted_escape_hex then case char - when '0'..'9', 'a'..'f' then + when '0'..'9', 'a'..'f', 'A'..'F' then state = :value_quoted value << "#{hex_buffer}#{char}".to_i(16).chr else raise(MalformedDnError, "Expected the second character of a hex pair inside a double quoted value, but got \"#{char}\"") end when :value_hexstring then case char - when '0'..'9', 'a'..'f' then + when '0'..'9', 'a'..'f', 'A'..'F' then state = :value_hexstring_hex value << char when ' ' then state = :value_end when ',' then state = :key - yield key.string.strip, value.string.rstrip + yield key.string.strip, rstrip_except_escaped(value.string, dn_index) key = StringIO.new value = StringIO.new else raise(MalformedDnError, "Expected the first character of a hex pair, but got \"#{char}\"") end when :value_hexstring_hex then case char - when '0'..'9', 'a'..'f' then + when '0'..'9', 'a'..'f', 'A'..'F' then state = :value_hexstring value << char else raise(MalformedDnError, "Expected the second character of a hex pair, but got \"#{char}\"") @@ -188,7 +189,7 @@ class NormalizeLdapExternUids < ActiveRecord::Migration when ' ' then state = :value_end when ',' then state = :key - yield key.string.strip, value.string.rstrip + yield key.string.strip, rstrip_except_escaped(value.string, dn_index) key = StringIO.new value = StringIO.new else raise(MalformedDnError, "Expected the end of an attribute value, but got \"#{char}\"") @@ -201,7 +202,25 @@ class NormalizeLdapExternUids < ActiveRecord::Migration raise(MalformedDnError, 'DN string ended unexpectedly') unless [:value, :value_normal, :value_hexstring, :value_end].include? state - yield key.string.strip, value.string.rstrip + yield key.string.strip, rstrip_except_escaped(value.string, @dn.length) + end + + def rstrip_except_escaped(str, dn_index) + str_ends_with_whitespace = str.match(/\s\z/) + + if str_ends_with_whitespace + dn_part_ends_with_escaped_whitespace = @dn[0, dn_index].match(/\\(\s+)\z/) + + if dn_part_ends_with_escaped_whitespace + dn_part_rwhitespace = dn_part_ends_with_escaped_whitespace[1] + num_chars_to_remove = dn_part_rwhitespace.length - 1 + str = str[0, str.length - num_chars_to_remove] + else + str.rstrip! + end + end + + str end ## @@ -221,7 +240,7 @@ class NormalizeLdapExternUids < ActiveRecord::Migration ## # Return the DN as an escaped and normalized string. def to_normalized_s - self.class.new(*to_a).to_s + self.class.new(*to_a).to_s.downcase end # https://tools.ietf.org/html/rfc4514 section 2.4 lists these exceptions |