From bcfa571b0328a4b3e94479a31c027621ceb86ad5 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 4 Apr 2014 20:35:16 -0400 Subject: Implement the new security mechanism --- app/controllers/alerts_controller.rb | 13 +---- app/controllers/application_controller.rb | 45 +++++++++++++++ app/controllers/games_controller.rb | 2 - app/controllers/matches_controller.rb | 54 +---------------- app/controllers/pms_controller.rb | 2 - app/controllers/servers_controller.rb | 2 - app/controllers/sessions_controller.rb | 8 ++- app/controllers/teams_controller.rb | 5 +- app/controllers/tournaments_controller.rb | 96 ++++++++++++++----------------- app/controllers/users_controller.rb | 21 +------ app/helpers/sessions_helper.rb | 2 + app/models/alert.rb | 2 +- app/models/tournament.rb | 2 +- app/models/user.rb | 71 +++++++++++------------ config/routes.rb | 3 +- 15 files changed, 146 insertions(+), 182 deletions(-) diff --git a/app/controllers/alerts_controller.rb b/app/controllers/alerts_controller.rb index d2b1558..333022a 100644 --- a/app/controllers/alerts_controller.rb +++ b/app/controllers/alerts_controller.rb @@ -1,7 +1,4 @@ class AlertsController < ApplicationController - before_action :set_alert, only: [:show, :edit, :update, :destroy] - before_action :check_perms, only: [:new, :create, :edit, :update, :destroy] - # GET /alerts # GET /alerts.json def index @@ -63,18 +60,14 @@ class AlertsController < ApplicationController end private + # Use callbacks to share common setup or constraints between actions. def set_alert @alert = Alert.find(params[:id]) end - def check_perms - unless (signed_in? and (current_user.in_group?(:admin) or current_user.in_group?(:host))) - respond_to do |format| - format.html { render action: 'permission_denied', status: :forbidden } - format.json { render json: "Permission denied", status: :forbidden } - end - end + def is_owner?(object) + object.author == current_user end # Never trust parameters from the scary internet, only allow the white list through. diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0ac3486..85fc5b0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,8 +1,53 @@ class ApplicationController < ActionController::Base + before_action :set_object, only: [:show] + before_action :check_create, only: [:new, :create] + before_action :check_edit, only: [:edit, :update] + before_action :check_delete, only: [:destroy] + # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception #include sessionhelper for the session controller and view include SessionsHelper + + def check_permission(verb, object=nil) + unless current_user.can?((verb.to_s+"_"+noun).to_sym) or (!object.nil? and is_owner?(object)) + respond_to do |format| + format.html do + if object.nil? + redirect_to send(noun.pluralize+"_url"), notice: "You don't have permission to #{verb} #{noun.pluralize}." + else + redirect_to object, notice: "You don't have permission to #{verb} this #{noun}." + end + end + format.json { render json: "Permission denied", status: :forbidden } + end + end + end + + def noun + @noun ||= self.class.name.underscore.sub(/_controller$/, '').singularize + end + + def set_object + object = send("set_"+noun) + end + + def check_create + check_permission(:create) + end + def check_edit + object = send("set_"+noun) + check_permission(:edit, object) + end + def check_delete + object = send("set_"+noun) + check_permission(:edit, object) + end + + # Override this + def is_owner?(object) + return false + end end diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index e9620b4..f18a5ad 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -1,6 +1,4 @@ class GamesController < ApplicationController - before_action :set_game, only: [:show, :edit, :update, :destroy] - # GET /games # GET /games.json def index diff --git a/app/controllers/matches_controller.rb b/app/controllers/matches_controller.rb index ba6ab16..474ae04 100644 --- a/app/controllers/matches_controller.rb +++ b/app/controllers/matches_controller.rb @@ -1,6 +1,6 @@ class MatchesController < ApplicationController - before_action :set_tournament, only: [:index, :new, :create] - before_action :set_match, only: [:show, :edit, :update, :destroy] + before_action :set_tournament, only: [:index] + # GET /matches # GET /matches.json def index @@ -12,58 +12,10 @@ class MatchesController < ApplicationController def show end - # GET /matches/new - def new - end - - # GET /matches/1/edit - def edit - end - - # POST /matches - # POST /matches.json - def create - @match = @tournament.matches.build(match_params) - - respond_to do |format| - if @match.save - format.html { redirect_to tournament_matches_path, notice: 'Match was successfully created.' } - format.json { render action: 'show', status: :created, location: @match } - else - format.html { render action: 'new' } - format.json { render json: @match.errors, status: :unprocessable_entity } - end - end - end - - # PATCH/PUT /matches/1 - # PATCH/PUT /matches/1.json - def update - respond_to do |format| - if @match.update(match_params) - format.html { redirect_to [@tournament, @match], notice: 'Match was successfully updated.' } - format.json { head :no_content } - else - format.html { render action: 'edit' } - format.json { render json: @match.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /matches/1 - # DELETE /matches/1.json - def destroy - @match.destroy - respond_to do |format| - format.html { redirect_to tournament_matches_path } - format.json { head :no_content } - end - end - private # Use callbacks to share common setup or constraints between actions. def set_match - @tournament = Tournament.find(params[:tournament_id]) + set_tournament @match = @tournament.matches.find(params[:id]); end def set_tournament diff --git a/app/controllers/pms_controller.rb b/app/controllers/pms_controller.rb index b62a6ef..af112d1 100644 --- a/app/controllers/pms_controller.rb +++ b/app/controllers/pms_controller.rb @@ -1,6 +1,4 @@ class PmsController < ApplicationController - before_action :set_pm, only: [:show, :edit, :update, :destroy] - # GET /pms # GET /pms.json def index diff --git a/app/controllers/servers_controller.rb b/app/controllers/servers_controller.rb index f23f2bf..3f11075 100644 --- a/app/controllers/servers_controller.rb +++ b/app/controllers/servers_controller.rb @@ -1,6 +1,4 @@ class ServersController < ApplicationController - before_action :set_server, only: [:show, :edit, :update, :destroy] - before_action :check_perms # GET /servers # GET /servers.json diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 1bae258..a0390ad 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,5 +1,4 @@ class SessionsController < ApplicationController - before_action :set_session, only: [:destroy] # GET /sessions/new def new @@ -41,11 +40,16 @@ class SessionsController < ApplicationController private # Use callbacks to share common setup or constraints between actions. def set_session - #@session = Session.find(cookies[:remember_token]) + @token = Session.hash_token(cookies[:remember_token]) + @session = Session.find_by(token: @token) end # Never trust parameters from the scary internet, only allow the white list through. def session_params params.require(:session).permit(:session_email, :session_user_name, :session_password) end + + def is_owner?(object) + object.user == current_user + end end diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 05e7a12..57ae256 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -1,5 +1,4 @@ class TeamsController < ApplicationController - before_action :set_team, only: [:show, :edit, :update, :destroy] # GET /teams # GET /teams.json @@ -71,4 +70,8 @@ class TeamsController < ApplicationController def team_params params.require(:team).permit(:match_id) end + + def is_owner?(object) + object.users.include?(current_user) + end end diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index 9cf3404..2d63068 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -1,6 +1,4 @@ class TournamentsController < ApplicationController - before_action :set_tournament, only: [:show, :edit, :update, :destroy, :join] - before_action :check_perms, only: [:new, :create, :edit, :destroy] # GET /tournaments # GET /tournaments.json @@ -36,12 +34,7 @@ class TournamentsController < ApplicationController # GET /tournaments/1/edit def edit - if params['close_action'] == 'close' - @tournament.status = 1 - @tournament.save - @tournament.setup(@tournament) - redirect_to "/tournaments" - end + check_permission(:edit, @tournament) end # POST /tournaments @@ -64,9 +57,9 @@ class TournamentsController < ApplicationController # PATCH/PUT /tournaments/1 # PATCH/PUT /tournaments/1.json def update - - if params[:update_action].nil? - check_perms + case params[:update_action] + when nil + check_permission(:edit, @tournament) respond_to do |format| if @tournament.update(tournament_params) format.html { redirect_to @tournament, notice: 'Tournament was successfully updated.' } @@ -76,42 +69,40 @@ class TournamentsController < ApplicationController format.json { render json: @tournament.errors, status: :unprocessable_entity } end end - else - case params[:update_action] - when "join" - respond_to do |format| - if @tournament.join(current_user) - format.html { render action: 'show', notice: 'You have joined this tournament.' } - format.json { head :no_content } - end - format.html { render action: 'permission_denied', status: :forbidden } - format.json { render json: "Permission denied", status: :forbidden } + + when "join" + check_permission(:join) + respond_to do |format| + if @tournament.join(current_user) + format.html { render action: 'show', notice: 'You have joined this tournament.' } + format.json { head :no_content } end - when "leave" - respond_to do |format| - if @tournament.leave(current_user) - format.html {redirect_to tournaments_url, notice: 'You have left the tournament.' } - format.json { head :no_content } - end - format.html {redirect_to @tournament, notice: 'You were\'t a part of this tournament.' } - format.json { render json: "Permission denied", status: :forbidden } - end - when "open" - respond_to do |format| - if @tournament.setup - format.html { render action: 'show', notice: 'You have joined this tournament.' } - format.json { head :no_content } - end - format.html { render action: 'permission_denied', status: :forbidden } - format.json { render json: "Permission denied", status: :forbidden } + format.html { render action: 'permission_denied', status: :forbidden } + format.json { render json: "Permission denied", status: :forbidden } + end + when "leave" + respond_to do |format| + if @tournament.leave(current_user) + format.html {redirect_to tournaments_url, notice: 'You have left the tournament.' } + format.json { head :no_content } end - #when "close" - # TODO - else - respond_to do |format| - format.html { render action: 'show', notice: "Invalid action", status: :unprocessable_entity } - format.json { render json: @tournament.errors, status: :unprocessable_entity } + format.html {redirect_to @tournament, notice: 'You were\'t a part of this tournament.' } + format.json { render json: "Permission denied", status: :forbidden } + end + when "open" + check_permission(:edit, @tournament) + respond_to do |format| + if @tournament.setup + format.html { render action: 'show', notice: 'You have joined this tournament.' } + format.json { head :no_content } end + format.html { render action: 'permission_denied', status: :forbidden } + format.json { render json: "Permission denied", status: :forbidden } + end + else + respond_to do |format| + format.html { render action: 'show', notice: "Invalid action", status: :unprocessable_entity } + format.json { render json: @tournament.errors, status: :unprocessable_entity } end end end @@ -132,17 +123,16 @@ class TournamentsController < ApplicationController @tournament = Tournament.find(params[:id]) end - def check_perms - unless (signed_in? and current_user.in_group?(:host)) - respond_to do |format| - format.html { render action: 'permission_denied', status: :forbidden } - format.json { render json: "Permission denied", status: :forbidden } - end - end - end - # Never trust parameters from the scary internet, only allow the white list through. def tournament_params params.require(:tournament).permit(:game, :name, :game_id, :status, :min_players_per_team, :max_players_per_team, :min_teams_per_match, :max_teams_per_match, :set_rounds, :randomized_teams) end + + def is_owner?(object) + object.hosts.include?(current_user) + end + + # Turn of check_edit, since our #update is flexible + def check_edit + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 60857f1..82edae7 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,7 +1,4 @@ class UsersController < ApplicationController - before_action :set_user, only: [:show, :edit, :update, :destroy] - before_action :perms_edit, only: [:edit, :update, :destroy] - before_action :perms_create, only: [:new, :create] # GET /users # GET /users.json @@ -69,22 +66,8 @@ class UsersController < ApplicationController @user = User.find(params[:id]) end - def perms_edit - unless (current_user == @user) or (signed_in? and current_user.in_group? :admin) - respond_to do |format| - format.html { render action: 'permission_denied', status: :forbidden } - format.json { render json: "Permission denied", status: :forbidden } - end - end - end - - def perms_create - if signed_in? - respond_to do |format| - format.html { render action: 'already_signed_in', status: :unprocessable_entity } - format.json { render json: "Already signed in", status: :unprocessable_entity } - end - end + def is_owner?(object) + object == current_user end # Never trust parameters from the scary internet, only allow the white list through. diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb index 89e5ef3..05a29f1 100644 --- a/app/helpers/sessions_helper.rb +++ b/app/helpers/sessions_helper.rb @@ -1,3 +1,5 @@ +require 'user' + module SessionsHelper def sign_in(user) @session = Session.new(user: user) diff --git a/app/models/alert.rb b/app/models/alert.rb index 0516355..9876711 100644 --- a/app/models/alert.rb +++ b/app/models/alert.rb @@ -1,3 +1,3 @@ class Alert < ActiveRecord::Base - belongs_to :author + belongs_to :author, class_name: "User" end diff --git a/app/models/tournament.rb b/app/models/tournament.rb index 4483535..ecd551b 100644 --- a/app/models/tournament.rb +++ b/app/models/tournament.rb @@ -9,7 +9,7 @@ class Tournament < ActiveRecord::Base end def joinable_by?(user) - return ((not user.nil?) and user.in_group?(:player) and open? and !players.include?(user)) + return (open? and user.can?(:join_tournament) and !players.include?(user)) end def join(user) diff --git a/app/models/user.rb b/app/models/user.rb index 016c155..1d0879b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -11,44 +11,36 @@ class User < ActiveRecord::Base self.permissions = 0 end - def in_group?(group) - case group - when :admin - return ((groups & 2) != 0) - when :host - return true #((groups & 1) != 0) - when :player - return true - when :specator - return true - else + def can?(action) + case action + when :create_tournament + when :edit_tournament + when :join_tournament + when :delete_tournament + + when :create_game + when :edit_game + when :delete_game + + when :create_user return false - end - end + when :edit_user + when :delete_user - def join_groups(join=[]) - # FIXME: race condition - join.each do |group| - case group - when :admin - groups |= 2 - when :host - groups |= 1 - else - end - end - end + when :create_alert + when :edit_alert + when :delete_alert - def leave_groups(leave=[]) - # FIXME: race condition - leave.each do |group| - case group - when :admin - groups &= ~ 2 - when :host - groups &= ~ 1 - else - end + when :create_pm + when :edit_pm + when :delete_pm + + when :create_session + return false + when :delete_session + + else + return false end end @@ -96,7 +88,14 @@ class NilUser return true end def can?(action) - return false + case action + when :create_user + return true + when :create_session + return true + else + return false + end end def method_missing(name, *args) # Throw an error if User doesn't have this method diff --git a/config/routes.rb b/config/routes.rb index 571e629..45694aa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,10 +15,9 @@ Leaguer::Application.routes.draw do resources :teams resources :tournaments do - resources :matches + resources :matches, only: [:index, :show] end - root to: 'static#homepage' get '/testsvg', to: 'static#test' -- cgit v1.2.3-54-g00ecf