2 # Copyright (C) 2012-2014 Gitorious AS
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module AuthenticatedSystem
20 # Returns true or false if the user is logged in.
21 # Preloads @current_user with the user model if they're logged in.
26 # Accesses the current user from the session.
28 return @current_user if instance_variable_defined?(:@current_user)
29 @current_user = login_from_session || login_from_basic_auth || login_from_cookie
32 # Store the given user in the session.
33 def current_user=(user)
35 session[:user_id] = user.id
36 set_varnish_auth_cookie
38 session.delete(:user_id)
39 cookies.delete(:auth_token)
40 clear_varnish_auth_cookie
46 def set_varnish_auth_cookie
47 cookies["_logged_in"] = {
49 :domain => ".#{Gitorious.host}",
50 :expires => 3.weeks.from_now,
56 def clear_varnish_auth_cookie
57 cookies.delete "_logged_in", :domain => ".#{Gitorious.host}"
60 # Check if the user is authorized
62 # Override this method in your controllers if you want to restrict access
63 # to only a few actions or if you want to check if the user
64 # has the correct rights.
68 # # only allow nonbobs
70 # current_user.login != "bob"
76 # Filter method to enforce a login requirement.
78 # To require logins for all actions, use this in your controllers:
80 # before_filter :login_required
82 # To require logins for specific actions, use this in your controllers:
84 # before_filter :login_required, :only => [ :edit, :update ]
86 # To skip this in a subclassed controller:
88 # skip_before_filter :login_required
91 authorized? || access_denied
94 # Redirect as appropriate when an access request fails.
96 # The default action is to redirect to the login screen.
98 # Override this method in your controllers if you want to have special
99 # behavior in case the user is not authorized
100 # to access the requested action. For example, a popup window might
101 # simply close itself.
103 respond_to do |accepts|
106 flash[:error] = "Action requires login"
107 redirect_to(main_app.new_sessions_path)
110 headers["Status"] = "Unauthorized"
111 headers["WWW-Authenticate"] = %(Basic realm="Web Password")
112 render :text => "Could't authenticate you", :status => '401 Unauthorized'
118 # Store the URI of the current request in the session.
120 # We can return to this location by calling #redirect_back_or_default.
121 def store_location(location = request.fullpath)
122 session[:return_to] = location
125 # Redirect to the URI stored by the most recent store_location call or
126 # to the passed default.
127 def redirect_back_or_default(default)
128 session[:return_to] ? redirect_to(session[:return_to]) : redirect_to(default)
129 session[:return_to] = nil
132 # Inclusion hook to make #current_user and #logged_in?
133 # available as ActionView helper methods.
134 def self.included(base)
135 if base.respond_to?(:helper_method)
136 base.send(:helper_method, :current_user, :logged_in?)
140 # Called from #current_user. First attempt to login by the user id stored in the session.
141 def login_from_session
142 self.current_user = User.find_by_id(session[:user_id], :conditions => { :suspended_at => nil }) if session[:user_id]
145 # Called from #current_user. Now, attempt to login by basic authentication information.
146 def login_from_basic_auth
147 username, passwd = get_auth_data
148 self.current_user = User.authenticate(username, passwd) if username && passwd
151 # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie.
152 def login_from_cookie
153 user = cookies[:auth_token] && User.find_by_remember_token(cookies[:auth_token])
154 if user && user.remember_token?
156 cookies[:auth_token] = {
157 :value => user.remember_token,
158 :expires => user.remember_token_expires_at,
161 self.current_user = user
166 @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
167 # gets BASIC auth info
169 auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
170 auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
171 return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]