merged cont.
[opensuse:yast-rest-service.git] / webservice / lib / authenticated_system.rb
1 #--
2 # Webyast Webservice framework
3 #
4 # Copyright (C) 2009, 2010 Novell, Inc. 
5 #   This library is free software; you can redistribute it and/or modify
6 # it only under the terms of version 2.1 of the GNU Lesser General Public
7 # License as published by the Free Software Foundation. 
8 #
9 #   This library is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
12 # details. 
13 #
14 #   You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software 
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 #++
18
19 module AuthenticatedSystem
20   protected
21     # Returns true or false if the account is logged in.
22     # Preloads @current_account with the account model if they're logged in.
23     def logged_in?
24       !!current_account
25     end
26
27     # Accesses the current account from the session. 
28     # Future calls avoid the database because nil is not equal to false.
29     def current_account
30       @current_account ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_account == false # RORSCAN_ITL
31     end
32
33     # Store the given account id in the session.
34     def current_account=(new_account)
35       session[:account_id] = new_account ? new_account.id : nil
36       session[:user] = new_account ? new_account.login : nil
37       session[:expires] = new_account ? new_account.remember_token_expires_at : nil
38       @current_account = new_account || false
39     end
40
41     # Check if the account is authorized
42     #
43     # Override this method in your controllers if you want to restrict access
44     # to only a few actions or if you want to check if the account
45     # has the correct rights.
46     #
47     # Example:
48     #
49     #  # only allow nonbobs
50     #  def authorized?
51     #    current_account.login != "bob"
52     #  end
53     def authorized?
54       logged_in?
55     end
56
57     # Filter method to enforce a login requirement.
58     #
59     # To require logins for all actions, use this in your controllers:
60     #
61     #   before_filter :login_required
62     #
63     # To require logins for specific actions, use this in your controllers:
64     #
65     #   before_filter :login_required, :only => [ :edit, :update ]
66     #
67     # To skip this in a subclassed controller:
68     #
69     #   skip_before_filter :login_required
70     #
71     def login_required
72       authorized? || access_denied
73     end
74
75     # Redirect as appropriate when an access request fails.
76     #
77     # The default action is to redirect to the login screen.
78     #
79     # Override this method in your controllers if you want to have special
80     # behavior in case the account is not authorized
81     # to access the requested action.  For example, a popup window might
82     # simply close itself.
83     def access_denied
84        if request.format.html?
85          store_location
86          redirect_to :controller => "session", :action => "new", :hostid => "localhost" #redirect by default to locahost appliance (bnc#602807)
87        else
88          request_http_basic_authentication 'YaST-Webservice Login' # RORSCAN_ITL
89        end
90     end
91
92     # Store the URI of the current request in the session.
93     #
94     # We can return to this location by calling #redirect_back_or_default.
95     def store_location
96       session[:return_to] = request.request_uri
97     end
98
99     # Redirect to the URI stored by the most recent store_location call or
100     # to the passed default.
101     def redirect_back_or_default(default)
102       redirect_to(session[:return_to] || default)
103       session[:return_to] = nil
104     end
105
106     # Inclusion hook to make #current_account and #logged_in?
107     # available as ActionView helper methods.
108     def self.included(base)
109       base.send :helper_method, :current_account, :logged_in?
110     end
111
112     # Called from #current_account.  First attempt to login by the account id stored in the session.
113     def login_from_session
114       self.current_account = Account.find_by_id(session[:account_id]) if session[:account_id]
115     end
116
117     #used for stubbing in the testcases
118     def remote_ip
119       request.remote_ip
120     end
121     # Called from #current_account.  Now, attempt to login by basic authentication information.
122     def login_from_basic_auth
123       authenticate_with_http_basic do |username, password|
124         if username.length > 0
125            self.current_account = Account.authenticate(username, password, remote_ip)
126         else # try it with auth_token
127            account = password && Account[password]
128            if account && account.remember_token?
129               cookies[:auth_token] = { :value => account.remember_token, :expires => account.remember_token_expires_at }
130               self.current_account = account
131            end
132         end 
133       end
134     end
135
136     # Called from #current_account.  Finaly, attempt to login by an expiring token in the cookie.
137     def login_from_cookie
138       account = cookies[:auth_token] && Account.find_by_remember_token(cookies[:auth_token])
139       if account && account.remember_token?
140         auth_token = { :value => account.remember_token, :expires => account.remember_token_expires_at }
141         # make cookie accessible via https only
142         auth_token[:secure] = true if ENV["RAILS_ENV"] == "production"
143         cookies[:auth_token] = auth_token
144         self.current_account = account
145       end
146     end
147 end