| Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
|---|---|---|---|---|
| app/controllers/main_controller.rb | 376 | 234 | 82.71%
|
76.92%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 |
2 # Controller responsible for providing login and logout processes |
3 # as well as displaying main page |
4 class MainController < ApplicationController |
5 |
6 include MainHelper |
7 protect_from_forgery :except => [:login, :page_not_found] |
8 |
9 # check for authorization |
10 before_filter :authorize_for_user, |
11 :except => [:login, |
12 :page_not_found] |
13 before_filter :authorize_only_for_admin, :only => [:login_as] |
14 |
15 ######################################################################### |
16 # Authentication |
17 |
18 # Handles login requests; usually redirected here when trying to access |
19 # the website and has not logged in yet, or session has expired. User |
20 # is redirected to main page if session is still active and valid. |
21 |
22 def login |
23 # external auth has been done, skip markus authorization |
24 if MarkusConfigurator.markus_config_remote_user_auth |
25 if @markus_auth_remote_user.nil? |
26 render :file => "#{::Rails.root.to_s}/public/403.html", |
27 :status => 403 |
28 return |
29 else |
30 login_success = login_without_authentication(@markus_auth_remote_user) |
31 if login_success |
32 uri = session[:redirect_uri] |
33 session[:redirect_uri] = nil |
34 refresh_timeout |
35 current_user.set_api_key # set api key in DB for user if not yet set |
36 # redirect to last visited page or to main page |
37 redirect_to( uri || { :action => 'index' } ) |
38 return |
39 else |
40 @login_error = flash[:login_notice] |
41 render :remote_user_auth_login_fail |
42 return |
43 end |
44 end |
45 end |
46 |
47 @current_user = current_user |
48 # redirect to main page if user is already logged in. |
49 if logged_in? && !request.post? |
50 redirect_to :action => 'index' |
51 return |
52 end |
53 return unless request.post? |
54 |
55 # strip username |
56 params[:user_login].strip! |
57 |
58 # Get information of the user that is trying to login if his or her |
59 # authentication is valid |
60 validation_result = validate_user(params[:user_login], params[:user_login], params[:user_password]) |
61 if !validation_result[:error].nil? |
62 flash[:login_notice] = validation_result[:error] |
63 redirect_to :action => 'login' |
64 return |
65 end |
66 # validation worked |
67 found_user = validation_result[:user] |
68 if found_user.nil? |
69 return |
70 end |
71 |
72 # Has this student been hidden? |
73 if found_user.student? && found_user.hidden |
74 flash[:login_notice] = I18n.t("account_disabled") |
75 redirect_to(:action => 'login') && return |
76 end |
77 |
78 self.current_user = found_user |
79 |
80 if logged_in? |
81 uri = session[:redirect_uri] |
82 session[:redirect_uri] = nil |
83 refresh_timeout |
84 current_user.set_api_key # set api key in DB for user if not yet set |
85 # redirect to last visited page or to main page |
86 redirect_to( uri || { :action => 'index' } ) |
87 else |
88 flash[:login_notice] = I18n.t(:login_failed) |
89 end |
90 end |
91 |
92 |
93 # Clear the sesssion for current user and redirect to login page |
94 def logout |
95 logout_redirect = MarkusConfigurator.markus_config_logout_redirect |
96 if logout_redirect == "NONE" |
97 page_not_found |
98 return |
99 end |
100 m_logger = MarkusLogger.instance |
101 |
102 # The real_uid field of session keeps track of the uid of the original |
103 # user that is logged in if there is a role switch |
104 if !session[:real_uid].nil? && !session[:uid].nil? |
105 #An admin was logged in as a student or grader |
106 m_logger.log("Admin '#{User.find_by_id(session[:real_uid]).user_name}' logged out from '#{User.find_by_id(session[:uid]).user_name}'.") |
107 else |
108 #The user was not assuming another role |
109 m_logger.log("User '#{current_user.user_name}' logged out.") |
110 end |
111 clear_session |
112 cookies.delete :auth_token |
113 reset_session |
114 if logout_redirect == 'DEFAULT' |
115 redirect_to :action => 'login' |
116 return |
117 else |
118 redirect_to logout_redirect |
119 return |
120 end |
121 end |
122 |
123 def index |
124 @current_user = current_user |
125 if @current_user.student? or @current_user.ta? |
126 redirect_to :controller => 'assignments', :action => 'index' |
127 return |
128 end |
129 @assignments = Assignment.find(:all) |
130 render :action => 'index', :layout => 'content' |
131 end |
132 |
133 def about |
134 # dummy action for remote rjs calls |
135 # triggered by clicking on the about icon |
136 end |
137 |
138 def reset_api_key |
139 render :file => "#{::Rails.root.to_s}/public/404.html", :status => 404 and return unless request.post? |
140 # Students shouldn't be able to change their API key |
141 if !@current_user.student? |
142 @current_user.reset_api_key |
143 @current_user.save |
144 else |
145 render :file => "#{::Rails.root.to_s}/public/404.html", :status => 404 and return |
146 end |
147 render :action => 'api_key_replace', :locals => {:user => @current_user } |
148 end |
149 |
150 # Render 404 error (page not found) if no other route matches. |
151 # See config/routes.rb |
152 def page_not_found |
153 render :file => "#{::Rails.root.to_s}/public/404.html", :status => 404 |
154 end |
155 |
156 # Authenticates the admin (i.e. validates her password). Given the user, that |
157 # the admin would like to login as and the admin's password switch to the |
158 # desired user on success. |
159 # |
160 # If the current user already recorded, matches the password entered in the |
161 # form, grant the current user (an admin) access to the account of the user |
162 # name entered in the form. |
163 # |
164 # Relevant partials: |
165 # role_switch_handler |
166 # role_switch_error |
167 # role_switch_content |
168 # role_switch |
169 def login_as |
170 validation_result = nil |
171 if MarkusConfigurator.markus_config_remote_user_auth |
172 validation_result = validate_user_without_login(params[:effective_user_login], |
173 params[:user_login]) |
174 else |
175 validation_result = validate_user(params[:effective_user_login], |
176 params[:user_login], |
177 params[:admin_password]) |
178 end |
179 if !validation_result[:error].nil? |
180 # There were validation errors |
181 render :partial => "role_switch_handler", |
182 :locals => { :error => validation_result[:error], :success => false } |
183 return |
184 end |
185 |
186 found_user = validation_result[:user] |
187 if found_user.nil? |
188 return |
189 end |
190 |
191 # Check if an admin is trying to login as another admin. Should not be allowed |
192 if found_user.admin? |
193 # error |
194 render :partial => "role_switch_handler", :locals => |
195 { :error => I18n.t(:cannot_login_as_another_admin), :success => false } |
196 return |
197 end |
198 |
199 # Log the admin that assumed the role of another user together with the time |
200 # and date that the role switch occurred |
201 m_logger = MarkusLogger.instance |
202 m_logger.log("Admin '#{current_user.user_name}' logged in as '#{params[:effective_user_login]}'.") |
203 |
204 # Save the uid of the admin that is switching roles |
205 session[:real_uid] = session[:uid] |
206 # Change the uid of the current user |
207 self.current_user = found_user |
208 |
209 if logged_in? |
210 uri = session[:redirect_uri] |
211 session[:redirect_uri] = nil |
212 refresh_timeout |
213 current_user.set_api_key # set api key in DB for user if not yet set |
214 # All good, redirect to the main page of the viewer, discard |
215 # role switch modal |
216 render :partial => "role_switch_handler", :locals => |
217 { :success => true } |
218 return |
219 else |
220 render :partial => "role_switch_handler", :locals => |
221 { :error => I18n.t(:login_failed), :success => false } |
222 return |
223 end |
224 end |
225 |
226 def role_switch |
227 # dummy action for remote rjs calls |
228 # triggered by clicking on the "Switch role" link |
229 # please keep. |
230 end |
231 |
232 # Action only relevant if REMOTE_USER config is on and if an |
233 # admin switched role. Since there might not be a logout link |
234 # provide a vehicle to expire the session (I.e. cancel the |
235 # role switch). |
236 def clear_role_switch_session |
237 m_logger = MarkusLogger.instance |
238 |
239 # The real_uid field of session keeps track of the uid of the original |
240 # user that is logged in if there is a role switch |
241 if !session[:real_uid].nil? && !session[:uid].nil? |
242 # An admin was logged in as a student or grader |
243 m_logger.log("Admin '#{User.find_by_id(session[:real_uid]).user_name}' logged out from '#{User.find_by_id(session[:uid]).user_name}'.") |
244 else |
245 #The user was not assuming another role |
246 m_logger.log("WARNING: Possible break in attempt from '#{current_user.user_name}'.") |
247 end |
248 clear_session |
249 cookies.delete :auth_token |
250 reset_session |
251 redirect_to :action => 'login' |
252 return |
253 end |
254 |
255 private |
256 |
257 def login_without_authentication(markus_auth_remote_user) |
258 found_user = User.authorize(markus_auth_remote_user) |
259 # if not nil, user authorized to enter MarkUs |
260 if found_user.nil? |
261 # This message actually means "User not allowed to use MarkUs", |
262 # but it's from a security-perspective |
263 # not a good idea to report this to the outside world. It makes it |
264 # easier for attempted break-ins |
265 # if one can distinguish between existent and non-existent users. |
266 flash[:login_notice] = I18n.t(:login_failed) |
267 return false |
268 end |
269 |
270 # Has this student been hidden? |
271 if found_user.student? && found_user.hidden |
272 flash[:login_notice] = I18n.t("account_disabled") |
273 return false |
274 end |
275 |
276 # For admins we have a possibility of role switches, |
277 # so check if the real_uid is set in the session. |
278 if found_user.admin? && !session[:real_uid].nil? && |
279 session[:real_uid] != session[:uid] |
280 self.current_user = User.find_by_id(session[:uid]) |
281 m_logger = MarkusLogger.instance |
282 m_logger.log("Admin '#{found_user.user_name}' logged in as '#{current_user.user_name}'.") |
283 else |
284 self.current_user = found_user |
285 end |
286 |
287 if logged_in? |
288 return true |
289 else |
290 flash[:login_notice] = I18n.t(:login_failed) |
291 return false |
292 end |
293 end |
294 |
295 # Returns the user with user name "effective_user" from the database given that the user |
296 # with user name "real_user" is authenticated. Effective and real users might be the |
297 # same for regular logins and are different on an assume role call. |
298 # |
299 # This function is called both by the login and login_as actions. |
300 def validate_user(effective_user, real_user, password) |
301 validation_result = Hash.new |
302 validation_result[:user] = nil # Let's be explicit |
303 # check for blank username and password |
304 blank_login = effective_user.blank? |
305 blank_pwd = password.blank? |
306 validation_result[:error] = get_blank_message(blank_login, blank_pwd) |
307 return validation_result if blank_login || blank_pwd |
308 |
309 # Two stage user verification: authentication and authorization |
310 authenticate_response = User.authenticate(real_user, |
311 password) |
312 if authenticate_response == User::AUTHENTICATE_BAD_PLATFORM |
313 validation_result[:error] = I18n.t("external_authentication_not_supported") |
314 return validation_result |
315 end |
316 if authenticate_response == User::AUTHENTICATE_SUCCESS |
317 # Username/password combination is valid. Check if user is |
318 # allowed to use MarkUs. |
319 # |
320 # sets this user as logged in if effective_user is a user in MarkUs |
321 found_user = User.authorize(effective_user) |
322 # if not nil, user authorized to enter MarkUs |
323 if found_user.nil? |
324 # This message actually means "User not allowed to use MarkUs", |
325 # but it's from a security-perspective |
326 # not a good idea to report this to the outside world. It makes it |
327 # easier for attempted break-ins |
328 # if one can distinguish between existent and non-existent users. |
329 validation_result[:error] = I18n.t(:login_failed) |
330 return validation_result |
331 end |
332 else |
333 validation_result[:error] = I18n.t(:login_failed) |
334 return validation_result |
335 end |
336 |
337 # All good, set error to nil. Let's be explicit. |
338 # Also, set the user key to found_user |
339 validation_result[:error] = nil |
340 validation_result[:user] = found_user |
341 return validation_result |
342 end |
343 |
344 # Returns the user with user name "effective_user" from the database given that the user |
345 # with user name "real_user" is authenticated. Effective and real users must be |
346 # different. |
347 def validate_user_without_login(effective_user, real_user) |
348 validation_result = Hash.new |
349 validation_result[:user] = nil # Let's be explicit |
350 # check for blank username |
351 blank_login = effective_user.blank? |
352 validation_result[:error] = get_blank_message(blank_login, false) |
353 return validation_result if blank_login |
354 |
355 # Can't do user authentication, for a remote user setup, so |
356 # only do authorization (i.e. valid user) checks. |
357 found_user = User.authorize(effective_user) |
358 # if not nil, user authorized to enter MarkUs |
359 if found_user.nil? |
360 # This message actually means "User not allowed to use MarkUs", |
361 # but it's from a security-perspective |
362 # not a good idea to report this to the outside world. It makes it |
363 # easier for attempted break-ins |
364 # if one can distinguish between existent and non-existent users. |
365 validation_result[:error] = I18n.t(:login_failed) |
366 return validation_result |
367 end |
368 |
369 # All good, set error to nil. Let's be explicit. |
370 # Also, set the user key to found_user |
371 validation_result[:error] = nil |
372 validation_result[:user] = found_user |
373 return validation_result |
374 end |
375 |
376 end |
Generated on Tue Feb 07 00:07:35 -0500 2012 with rcov 0.9.10