Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Improved permit! [Brian Langenfeld]

  • Loading branch information...
commit 1940857a1e7cea7f89340387fbeee9621d298707 1 parent fe3ee55
Steffen Bartsch authored
Showing with 40 additions and 4 deletions.
  1. +7 −0 CHANGELOG
  2. +33 −4 lib/authorization.rb
7 CHANGELOG
View
@@ -1,3 +1,10 @@
+* Changed Authorization::Attribute#validate? [Brian Langenfeld]
+ * Encountering a nil value when evaluating an attribute now raises a NilAttributeValueError, instead of an AuthorizationError. We leave it to the caller to decide what to do about it.
+
+* Changed Authorization::Engine#permit! [Brian Langenfeld]
+ * We now convert incoming privileges to symbols (e.g. 'read' is made equivalent to :read). This ensures the privileges will match those defined in the authorization rules file.
+ * The method now properly infers context when checking against an association (e.g. user.posts). We do this by leveraging ActiveRecord builder method 'new' to instantiate a proper object we can work with.
+ * When testing rules for positive results (via Authorization::Attribute#validate?), we now rescue NilAttributeValueError exceptions, simply causing the rule to return a negative result (instead of barfing).
* Changed Authorization::ObligationScope#rebuild_join_options! [Brian Langenfeld]
* If we're dealing with multiple obligations we have to check (i.e. ones that result in OR'd conditions), we now use :include instead of :joins for our generated scope. This does seem like a kludge, but until ActiveRecord scopes support unions (for checking obligations individually and consolidating the results), we don't have much choice. Something to revisit later, for sure.
37 lib/authorization.rb
View
@@ -16,6 +16,9 @@ class AttributeAuthorizationError < NotAuthorized ; end
# in which the application misused the plugin. That is, if, e.g.,
# authorization rules may not be evaluated.
class AuthorizationUsageError < AuthorizationError ; end
+ # NilAttributeValueError is raised by Attribute#validate? when it hits a nil attribute value.
+ # The exception is raised to ensure that the entire rule is invalidated.
+ class NilAttributeValueError < AuthorizationError; end
AUTH_DSL_FILE = "#{RAILS_ROOT}/config/authorization_rules.rb"
@@ -103,6 +106,23 @@ def permit! (privilege, options = {})
:skip_attribute_test => false,
:context => nil
}.merge(options)
+
+ # Make sure we're handling all privileges as symbols.
+ privilege = privilege.is_a?( Array ) ?
+ privilege.flatten.collect { |priv| priv.to_sym } :
+ privilege.to_sym
+
+ #
+ # If the object responds to :new, we're probably working with an association collection. Use
+ # 'new' to leverage ActiveRecord's builder functionality to obtain an object against which we
+ # can check permissions.
+ #
+ # Example: permit!( :edit, user.posts )
+ #
+ if options[:object].respond_to?( :new )
+ options[:object] = options[:object].new
+ end
+
options[:context] ||= options[:object] && options[:object].class.table_name.to_sym rescue NoMethodError
user, roles, privileges = user_roles_privleges_from_options(privilege, options)
@@ -117,10 +137,19 @@ def permit! (privilege, options = {})
"context #{options[:context].inspect})."
end
+ # Test each rule in turn to see whether any one of them is satisfied.
grant_permission = rules.any? do |rule|
- options[:skip_attribute_test] or
- rule.attributes.empty? or
- rule.attributes.any? {|attr| attr.validate? attr_validator }
+ begin
+ options[:skip_attribute_test] or
+ rule.attributes.empty? or
+ rule.attributes.any? do |attr|
+ begin
+ attr.validate?( attr_validator )
+ rescue NilAttributeValueError => e
+ nil # Bumping up against a nil attribute value flunks the rule.
+ end
+ end
+ end
end
unless grant_permission
raise AttributeAuthorizationError, "#{privilege} not allowed for #{user.inspect} on #{options[:object].inspect}."
@@ -317,7 +346,7 @@ def validate? (attr_validator, object = nil, hash = nil)
"on a collection. Cannot use '=>' operator on #{attr.inspect} " +
"(#{attr_value.inspect}) for attributes #{value.inspect}."
elsif attr_value.nil?
- raise AuthorizationError, "Attribute #{attr.inspect} is nil in #{object.inspect}."
+ raise NilAttributeValueError, "Attribute #{attr.inspect} is nil in #{object.inspect}."
end
validate?(attr_validator, attr_value, value)
elsif value.is_a?(Array) and value.length == 2
Please sign in to comment.
Something went wrong with that request. Please try again.