diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,3 +1,5 @@ +require 'ipaddr' + class ApplicationController < ActionController::Base protect_from_forgery @@ -5,6 +7,8 @@ SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode' MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login' + ALLOW_WHITELIST_IP_ONLY_CONF_KEY = 'right.allow_whitelist_ip_only' + WHITELIST_IP_CONF_KEY = 'right.whitelist_ip' #report and redirect for unauthorized activities def unauthorized_redirect @@ -46,8 +50,11 @@ unauthorized_redirect unless GraderConfiguration["right.view_testcase"] end + protected + #redirect to root (and also force logout) + #if the user is not logged_in or the system is in "ADMIN ONLY" mode def authenticate unless session[:user_id] flash[:notice] = 'You need to login' @@ -58,24 +65,30 @@ return false end - # check if run in single user mode if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY] - if @current_user==nil or (not @current_user.admin?) + if @current_user==nil || (not @current_user.admin?) flash[:notice] = 'You cannot log in at this time' redirect_to :controller => 'main', :action => 'login' return false end - return true end # check if the user is enabled - unless @current_user.enabled? or @current_user.admin? + unless @current_user.enabled? || @current_user.admin? flash[:notice] = 'Your account is disabled' redirect_to :controller => 'main', :action => 'login' return false end + # check if user ip is allowed + unless @current_user.admin? || !GraderConfiguration[ALLOW_WHITELIST_IP_ONLY_CONF_KEY] + unless is_request_ip_allowed? + flash[:notice] = 'Your IP is not allowed' + redirect_to root_path + end + end + if GraderConfiguration.multicontests? return true if @current_user.admin? begin @@ -89,11 +102,14 @@ return true end + #redirect to root (and also force logout) + #if the user use different ip from the previous connection + # only applicable when MULTIPLE_IP_LOGIN options is false only def authenticate_by_ip_address #this assume that we have already authenticate normally unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY] user = User.find(session[:user_id]) - if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip) + if (not @current_user.admin? && user.last_ip && user.last_ip != request.remote_ip) flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}" redirect_to :controller => 'main', :action => 'login' puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}" @@ -113,7 +129,7 @@ unless user.roles.detect { |role| role.rights.detect{ |right| right.controller == self.class.controller_name and - (right.action == 'all' or right.action == action_name) + (right.action == 'all' || right.action == action_name) } } flash[:notice] = 'You are not authorized to view the page you requested' @@ -126,7 +142,7 @@ def verify_time_limit return true if session[:user_id]==nil user = User.find(session[:user_id], :include => :site) - return true if user==nil or user.site == nil + return true if user==nil || user.site == nil if user.contest_finished? flash[:notice] = 'Error: the contest you are participating is over.' redirect_to :back @@ -135,4 +151,17 @@ return true end + def is_request_ip_allowed? + if GraderConfiguration[ALLOW_WHITELIST_IP_ONLY_CONF_KEY] + user_ip = IPAddr.new(request.remote_ip) + GraderConfiguration[WHITELIST_IP_LIST_CONF_KEY].delete(' ').split(',').each do |ips| + allow_ips = IPAddr.new(ips) + unless allow_ips.includes(user_ip) + return false + end + end + end + return true + end + end diff --git a/db/seeds.rb b/db/seeds.rb --- a/db/seeds.rb +++ b/db/seeds.rb @@ -173,15 +173,28 @@ }, + { + :key => 'right.whitelist_ip_only', + :value_type => 'boolean', + :default_value => 'false', + :description => "If true, non-admin user will be able to use the system only when their ip is in the 'whitelist_ip'." + }, + + { + :key => 'right.whitelist_ip', + :value_type => 'string', + :default_value => '0.0.0.0/0', + :description => "list of whitelist ip, given in comma separated CIDR notation. For example '161.200.92.0/23, 161.200.80.1/32'" + }, ] -def create_configuration_key(key, - value_type, - default_value, +def create_configuration_key(key, + value_type, + default_value, description='') - conf = (GraderConfiguration.find_by_key(key) || + conf = (GraderConfiguration.find_by_key(key) || GraderConfiguration.new(:key => key, :value_type => value_type, :value => default_value)) @@ -196,7 +209,7 @@ else desc = '' end - create_configuration_key(conf[:key], + create_configuration_key(conf[:key], conf[:value_type], conf[:default_value], desc) @@ -217,7 +230,7 @@ graders_right = Right.create(:name => 'graders_admin', :controller => 'graders', :action => 'all') - + role.rights << user_admin_right; role.rights << problem_admin_right; role.rights << graders_right;