module AuthorizedPersona::Authorization

Public Instance Methods

authorization_persona() click to toggle source
# File lib/authorized_persona/authorization.rb, line 49
def authorization_persona
  unless authorization_persona_class_name.is_a?(String)
    raise AuthorizedPersona::Error, "you must configure authorization, e.g. `authorize_persona class_name: 'User'`"
  end

  authorization_persona_class_name.constantize
end
authorize_persona(class_name:, current_user_method: nil) click to toggle source

Configure authorization for an authorized persona class

# File lib/authorized_persona/authorization.rb, line 16
def authorize_persona(class_name:, current_user_method: nil) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/LineLength
  raise AuthorizedPersona::Error, "you can only configure authorization once" if authorization_persona_class_name.present?
  raise AuthorizedPersona::Error, "class_name must be a string" unless class_name.is_a?(String)
  raise AuthorizedPersona::Error, "current_user_method must be a symbol" if current_user_method && !current_user_method.is_a?(Symbol)

  self.authorization_persona_class_name = class_name

  unless authorization_persona < AuthorizedPersona::Persona
    raise AuthorizedPersona::Error, "#{class_name} must be an AuthorizedPersona::Persona"
  end

  model_name = if authorization_persona.respond_to?(:model_name)
                 authorization_persona.model_name.singular_route_key
               else
                 authorization_persona.name.underscore
               end
  self.authorization_current_user_method = current_user_method || :"current_#{model_name}"

  before_action :authorize!
end
authorized?(current_user:, action:) click to toggle source
# File lib/authorized_persona/authorization.rb, line 57
def authorized?(current_user:, action:)
  raise AuthorizedPersona::Error, "#{current_user} is not a #{authorization_persona}" unless current_user.is_a?(authorization_persona)

  current_user.authorization_tier_at_or_above?(authorized_tier(action: action))
end
authorized_tier(action:) click to toggle source
# File lib/authorized_persona/authorization.rb, line 63
def authorized_tier(action:)
  action = action.to_sym
  authorization_persona.authorization_tier_names.each do |tier|
    actions = authorized_actions[tier] || []
    return tier if actions == [:all] || actions.include?(action)
  end
  raise AuthorizedPersona::Error, "missing authorization grant for #{name}##{action}"
end
grant(privileges) click to toggle source

Grants replace all previous grants to avoid privilege leakage

# File lib/authorized_persona/authorization.rb, line 38
def grant(privileges) # rubocop:disable Metrics/AbcSize
  self.authorized_actions = Hash[privileges.map { |auth_tier, actions| [auth_tier.to_s, [actions].flatten.map(&:to_sym)] }]

  tier_names = authorization_persona.authorization_tier_names
  extra_keys = authorized_actions.keys - authorization_persona.authorization_tier_names
  if extra_keys.present?
    raise AuthorizedPersona::Error, "invalid grant: #{authorization_persona_class_name} " \
      "has authorization tiers #{tier_names.join(', ')} but received extra keys: #{extra_keys.join(', ')}"
  end
end

Private Instance Methods

authorization_current_user() click to toggle source
# File lib/authorized_persona/authorization.rb, line 79
def authorization_current_user
  unless authorization_current_user_method.is_a?(Symbol)
    raise AuthorizedPersona::Error, "you must configure authorization with a valid current_user method name, " \
      "e.g. `authorize_persona class_name: 'User', current_user_method: :my_custom_current_user`"
  end

  send(self.class.authorization_current_user_method)
end
authorize!() click to toggle source
# File lib/authorized_persona/authorization.rb, line 92
def authorize! # rubocop:disable Metrics/MethodLength
  return if authorized?

  respond_to do |format|
    format.html do
      flash[:error] = 'You are not authorized to perform this action.'
      redirect_back fallback_location: '/', allow_other_host: false
    end
    format.json do
      render json: {}, status: :unauthorized
    end
    format.any do
      head :unauthorized
    end
  end
end