cirandas.net

ref: master

app/concerns/authenticated_system.rb


  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
module AuthenticatedSystem

  protected

    extend ActiveSupport::Concern

    included do
      if self < ActionController::Base
        around_filter :user_set_current
        before_filter :override_user
        before_filter :login_from_cookie
      end

      # Inclusion hook to make #current_user and #logged_in?
      # available as ActionView helper methods.
      helper_method :current_user, :logged_in?
    end

    # Returns true or false if the user is logged in.
    # Preloads @current_user with the user model if they're logged in.
    def logged_in?
      current_user != nil
    end

    # Accesses the current user from the session.
    def current_user user_id = session[:user]
      @current_user ||= begin
        user = User.find_by id: user_id if user_id
        user.session = session if user
        User.current = user
        user
      end
    end

    # Store the given user in the session.
    def current_user=(new_user)
      if new_user.nil?
        session.delete(:user)
      else
        session[:user] = new_user.id
        new_user.session = session
        new_user.register_login
      end
      @current_user = User.current = new_user
    end

    # See impl. from http://stackoverflow.com/a/2513456/670229
    def user_set_current
      User.current = current_user
      yield
    ensure
      # to address the thread variable leak issues in Puma/Thin webserver
      User.current = nil
    end

    # Check if the user is authorized.
    #
    # Override this method in your controllers if you want to restrict access
    # to only a few actions or if you want to check if the user
    # has the correct rights.
    #
    # Example:
    #
    #  # only allow nonbobs
    #  def authorize?
    #    current_user.login != "bob"
    #  end
    def authorized?
      true
    end

    # Filter method to enforce a login requirement.
    #
    # To require logins for all actions, use this in your controllers:
    #
    #   before_filter :login_required
    #
    # To require logins for specific actions, use this in your controllers:
    #
    #   before_filter :login_required, :only => [ :edit, :update ]
    #
    # To skip this in a subclassed controller:
    #
    #   skip_before_filter :login_required
    #
    def login_required
      username, passwd = get_auth_data
      if username && passwd
        self.current_user ||= User.authenticate(username, passwd) || nil
      end
      if logged_in? && authorized?
        true
      else
        if params[:require_login_popup]
          render :json => { :require_login_popup => true }
        else
          access_denied
        end
      end
    end

    # Redirect as appropriate when an access request fails.
    #
    # The default action is to redirect to the login screen.
    #
    # Override this method in your controllers if you want to have special
    # behavior in case the user is not authorized
    # to access the requested action.  For example, a popup window might
    # simply close itself.
    def access_denied
      respond_to do |accepts|
        accepts.html do
          if request.xhr?
            render :text => _('Access denied'), :status => 401
          else
            store_location
            redirect_to :controller => '/account', :action => 'login'
          end
        end
        accepts.xml do
          headers["Status"]           = "Unauthorized"
          headers["WWW-Authenticate"] = %(Basic realm="Web Password")
          render :text => "Could't authenticate you", :status => '401 Unauthorized'
        end
      end
      false
    end

    # Store the URI of the current request in the session.
    #
    # We can return to this location by calling #redirect_back_or_default.
    def store_location(location = request.url)
      session[:return_to] = location
    end

    # Redirect to the URI stored by the most recent store_location call or
    # to the passed default.
    def redirect_back_or_default(default)
      uri = session.delete(:return_to) || default
      # break cache after login
      if uri.is_a? String
        uri = URI.parse uri
        new_query_ar = URI.decode_www_form(uri.query || '') << ["_", Time.now.to_i.to_s]
        uri.query = URI.encode_www_form new_query_ar
        uri = uri.to_s
      elsif uri.is_a? Hash
        uri.merge! _: Time.now.to_i
      end

      redirect_to uri
    end

    def override_user
      return if params[:override_user].blank?
      return unless logged_in? and user.is_admin? environment
      @current_user = nil
      current_user params[:override_user]
    end

    def override_user
      return if params[:override_user].blank?
      return unless logged_in? and user.is_admin? environment
      @current_user = nil
      current_user params[:override_user]
    end

    # When called with before_filter :login_from_cookie will check for an :auth_token
    # cookie and log the user back in if apropriate
    def login_from_cookie
      return if cookies[:auth_token].blank? or logged_in?
      user = User.where(remember_token: cookies[:auth_token]).first
      self.current_user = user if user and user.remember_token?
    end

  private
    @@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