module Lockdown module Controller#:nodoc: # # Core Controller locking methods # module Core def self.included(base) base.send :include, Lockdown::Controller::Core::InstanceMethods end module InstanceMethods def configure_lock_down check_session_expiry store_location end def set_current_user login_from_basic_auth? unless logged_in? if logged_in? Thread.current[:profile_id] = current_profile_id Thread.current[:client_id] = current_client_id if respond_to? :current_client_id end end def check_request_authorization unless authorized?(path_from_hash(params)) raise SecurityError, "Authorization failed for params #{params.inspect}" end end def redirect_back_or_default(default) session[:prevpage] ? send_to(session[:prevpage]) : send_to(default) end private def path_allowed?(url) req = Lockdown.format_controller_action(url) session[:access_rights] ||= Lockdown::System.public_access session[:access_rights].each do |ar| return true if req == ar end false end def check_session_expiry if session[:expiry_time] && session[:expiry_time] < Time.now nil_lockdown_values end session[:expiry_time] = Time.now + Lockdown::System.fetch(:session_timeout) end def store_location if (request.method == :get) && (session[:thispage] != sent_from_uri) session[:prevpage] = session[:thispage] || '' session[:thispage] = sent_from_uri end end # Called from current_user. Now, attempt to login by # basic authentication information. def login_from_basic_auth? username, passwd = get_auth_data if username && passwd set_session_user User.authenticate(username, passwd) end end @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization) # gets BASIC auth info def get_auth_data auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) } auth_data = request.env[auth_key].to_s.split unless auth_key.blank? return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil] end end # InstanceMethods end # Core # # Merb Controller locking methods # module Merb def self.included(base) base.send :include, Lockdown::Controller::Merb::InstanceMethods base.before :set_current_user base.before :configure_lock_down base.before :check_request_authorization end module InstanceMethods def self.included(base) base.class_eval do alias :send_to :redirect end base.send :include, Lockdown::Controller::Core end def sent_from_uri request.uri end def authorized?(path) return true if current_user_is_admin? # See if path is known if path_allowed?(path) true else false end end # Can log Error => e if desired, I don't desire to now. # For now, just send home, but will probably make this configurable def access_denied(e) send_to Lockdown::Session[:access_denied_path] end def path_from_hash(hsh) return hsh if hsh.is_a?(String) hsh = hsh.to_hash if hsh.is_a?(Mash) hsh['controller'].to_s + "/" + hsh['action'].to_s end end # InstanceMethods end # Merb # # Rails Controller locking methods # module Rails def self.included(base) base.send :include, Lockdown::Controller::Rails::InstanceMethods base.before_filter do |controller| controller.set_current_user controller.configure_lock_down controller.check_request_authorization end base.send :helper_method, :authorized? base.filter_parameter_logging :password, :password_confirmation base.rescue_from SecurityError, :with => proc{|e| access_denied(e)} end module InstanceMethods def self.included(base) base.class_eval do alias :send_to :redirect_to end base.send :include, Lockdown::Controller::Core end def sent_from_uri request.request_uri end def authorized?(url) return true if current_user_is_admin? url_parts = URI::split(url) path = url_parts[5] # See if path is known return true if path_allowed?(path) # Test to see if url contains id parts = path.split("/").collect{|p| p unless p =~ /\A\d+\z/}.compact new_path = parts.join("/") return true if path_allowed?(new_path) # Test for a named routed begin hsh = ActionController::Routing::Routes.recognize_path(url) unless hsh.nil? return true if path_allowed?(path_from_hash(hsh)) end rescue Exception => e # continue on end # Passing in different domain return true if remote_url?(url_parts[2]) false end def access_denied(e) if Lockdown::System.fetch(:logout_on_access_violation) reset_session end respond_to do |accepts| accepts.html do store_location send_to Lockdown::System.fetch(:access_denied_path) end accepts.xml do headers["Status"] = "Unauthorized" headers["WWW-Authenticate"] = %(Basic realm="Web Password") render :text => e.message, :status => "401 Unauthorized" end end false end def path_from_hash(hsh) hsh[:controller].to_s + "/" + hsh[:action].to_s end def remote_url?(domain = nil) return false if domain.nil? || domain.strip.length == 0 request.host.downcase != domain.downcase end end # InstanceMethods end # Rails end # Controller end # Lockdown if Lockdown.merb_app? Merb::Controller.send :include, Lockdown::Controller::Merb elsif Lockdown.rails_app? ActionController::Base.send :include, Lockdown::Controller::Rails end