File: validations.rb

package info (click to toggle)
ruby-activeldap 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 1,588 kB
  • sloc: ruby: 18,143; sh: 12; makefile: 5
file content (223 lines) | stat: -rw-r--r-- 7,081 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
module ActiveLdap
  module Validations
    extend ActiveSupport::Concern
    include ActiveModel::Validations

    module ClassMethods
      def attribute_method?(attribute)
        normalized_attribute = entry_attribute.normalize(attribute)
        normalized_attribute and normalized_attribute != "objectClass"
      end

      private
      def entry_attribute
        @entry_attribute ||=
          connection.entry_attribute(classes.collect(&:name))
      end
    end

    included do
      alias_method :new_record?, :new_entry?
      class << self
        unless method_defined?(:human_attribute_name_with_gettext)
          def human_attribute_name_with_gettext(attribute_key_name, options={})
            logger.warn("options was ignored.") unless options.empty?
            s_("#{self}|#{attribute_key_name.to_s.humanize}")
          end
        end
      end

      class_local_attr_accessor true, :validation_skip_attributes
      remove_method :validation_skip_attributes
      self.validation_skip_attributes = []

      validate :validate_duplicated_dn_creation, :on => :create
      validate :validate_duplicated_dn_rename, :on => :update
      validate :validate_dn
      validate :validate_excluded_classes
      validate :validate_required_ldap_values
      validate :validate_ldap_values
    end

    def validation_skip_attributes
      @validation_skip_attributes ||= []
    end

    def validation_skip_attributes=(attributes)
      @validation_skip_attributes = attributes
    end

    def valid?(context = nil)
      context ||= (new_entry? ? :create : :update)
      output = super(context)
      errors.empty? && output
    end

    def save(**options)
      perform_validations(options) ? super : false
    end

    def save!(**options)
      perform_validations(options) ? super : raise(EntryInvalid.new(self))
    end

    private
    def perform_validations(options)
      if options[:validate] == false
        true
      else
        valid?(options[:context])
      end
    end

    def format_validation_message(format, parameters)
      format % parameters
    end

    def validate_duplicated_dn_creation
      _dn = nil
      begin
        _dn = dn
      rescue DistinguishedNameInvalid, DistinguishedNameNotSetError
        return
      end
      if _dn and exist?
        format = _("is duplicated: %s")
        message = format_validation_message(format, _dn)
        errors.add("distinguishedName", message)
      end
    end

    def validate_duplicated_dn_rename
      _dn_attribute = dn_attribute_with_fallback
      original_dn_value = @ldap_data[_dn_attribute]
      current_dn_value = @data[_dn_attribute]
      return if original_dn_value == current_dn_value
      return if original_dn_value == [current_dn_value]

      _dn = nil
      begin
        _dn = dn
      rescue DistinguishedNameInvalid, DistinguishedNameNotSetError
        return
      end
      if _dn and exist?
        format = _("is duplicated: %s")
        message = format_validation_message(format, _dn)
        errors.add("distinguishedName", message)
      end
    end

    def validate_dn
      dn
    rescue DistinguishedNameInvalid
      format = _("is invalid: %s")
      message = format_validation_message(format, $!.message)
      errors.add("distinguishedName", message)
    rescue DistinguishedNameNotSetError
      format = _("isn't set: %s")
      message = format_validation_message(format, $!.message)
      errors.add("distinguishedName", message)
    end

    def validate_excluded_classes
      excluded_classes = self.class.excluded_classes
      return if excluded_classes.empty?

      _schema = schema
      _classes = classes.collect do |name|
        _schema.object_class(name)
      end
      unexpected_classes = excluded_classes.inject([]) do |classes, name|
        excluded_class = _schema.object_class(name)
        if _classes.include?(excluded_class)
          classes << excluded_class
        end
        classes
      end
      return if unexpected_classes.empty?

      names = unexpected_classes.collect do |object_class|
        self.class.human_object_class_name(object_class)
      end
      format = n_("has excluded value: %s",
                  "has excluded values: %s",
                  names.size)
      message = format_validation_message(format, names.join(", "))
      errors.add("objectClass", message)
    end

    # validate_required_ldap_values
    #
    # Basic validation:
    # - Verify that every 'MUST' specified in the schema has a value defined
    def validate_required_ldap_values
      _schema = nil
      @validation_skip_attributes ||= []
      _validation_skip_attributes =
        @validation_skip_attributes +
        (self.class.validation_skip_attributes || [])
      # Make sure all MUST attributes have a value
      entry_attribute.object_classes.each do |object_class|
        object_class.must.each do |required_attribute|
          # Normalize to ensure we catch schema problems
          # needed?
          real_name = to_real_attribute_name(required_attribute.name, true)
          raise UnknownAttribute.new(required_attribute) if real_name.nil?

          next if required_attribute.read_only?
          next if _validation_skip_attributes.include?(real_name)

          value = @data[real_name]
          next unless self.class.blank_value?(value)

          _schema ||= schema
          aliases = required_attribute.aliases.collect do |name|
            self.class.human_attribute_name(name)
          end
          args = [self.class.human_object_class_name(object_class)]
          if aliases.empty?
            format = _("is required attribute by objectClass '%s'")
          else
            format = _("is required attribute by objectClass " \
                       "'%s': aliases: %s")
            args << aliases.join(', ')
          end
          message = format_validation_message(format, args)
          errors.add(real_name, message)
        end
      end
    end

    def validate_ldap_values
      entry_attribute.schemata.each do |name, attribute|
        value = self[name]
        # Is it really proper location for setting encoding?
        attribute.apply_encoding(value)
        next if self.class.blank_value?(value)
        validate_ldap_value(attribute, name, value)
      end
    end

    def validate_ldap_value(attribute, name, value)
      failed_reason, option = attribute.validate(value)
      return if failed_reason.nil?
      if attribute.binary?
        inspected_value = _("<binary-value>")
      else
        inspected_value = self.class.human_readable_format(value)
      end
      params = [inspected_value,
                self.class.human_syntax_description(attribute.syntax),
                failed_reason]
      if option
        format = _("(%s) has invalid format: %s: required syntax: %s: %s")
      else
        format = _("has invalid format: %s: required syntax: %s: %s")
      end
      params.unshift(option) if option
      message = format_validation_message(format, params)
      errors.add(name, message)
    end
  end
end