Commit 783ca8979652085e2708cf3e020f3f83349dedb2
1 parent
b08e4074
Exists in
master
and in
4 other branches
security improved
Showing
9 changed files
with
74 additions
and
26 deletions
Show diff stats
app/controllers/application_controller.rb
| @@ -27,11 +27,15 @@ class ApplicationController < ActionController::Base | @@ -27,11 +27,15 @@ class ApplicationController < ActionController::Base | ||
| 27 | end | 27 | end |
| 28 | 28 | ||
| 29 | def authenticate_admin! | 29 | def authenticate_admin! |
| 30 | - return redirect_to(new_user_session_path) unless current_user.is_admin? | 30 | + return render_404 unless current_user.is_admin? |
| 31 | end | 31 | end |
| 32 | 32 | ||
| 33 | def authorize_project!(action) | 33 | def authorize_project!(action) |
| 34 | - return redirect_to(new_user_session_path) unless can?(current_user, action, project) | 34 | + return render_404 unless can?(current_user, action, project) |
| 35 | + end | ||
| 36 | + | ||
| 37 | + def access_denied! | ||
| 38 | + render_404 | ||
| 35 | end | 39 | end |
| 36 | 40 | ||
| 37 | def method_missing(method_sym, *arguments, &block) | 41 | def method_missing(method_sym, *arguments, &block) |
app/controllers/issues_controller.rb
| 1 | class IssuesController < ApplicationController | 1 | class IssuesController < ApplicationController |
| 2 | before_filter :authenticate_user! | 2 | before_filter :authenticate_user! |
| 3 | before_filter :project | 3 | before_filter :project |
| 4 | + before_filter :issue, :only => [:edit, :update, :destroy, :show] | ||
| 4 | 5 | ||
| 5 | # Authorize | 6 | # Authorize |
| 6 | before_filter :add_project_abilities | 7 | before_filter :add_project_abilities |
| 7 | before_filter :authorize_read_issue! | 8 | before_filter :authorize_read_issue! |
| 8 | before_filter :authorize_write_issue!, :only => [:new, :create, :close, :edit, :update, :sort] | 9 | before_filter :authorize_write_issue!, :only => [:new, :create, :close, :edit, :update, :sort] |
| 9 | - before_filter :authorize_admin_issue!, :only => [:destroy] | ||
| 10 | 10 | ||
| 11 | respond_to :js | 11 | respond_to :js |
| 12 | 12 | ||
| @@ -30,12 +30,10 @@ class IssuesController < ApplicationController | @@ -30,12 +30,10 @@ class IssuesController < ApplicationController | ||
| 30 | end | 30 | end |
| 31 | 31 | ||
| 32 | def edit | 32 | def edit |
| 33 | - @issue = @project.issues.find(params[:id]) | ||
| 34 | respond_with(@issue) | 33 | respond_with(@issue) |
| 35 | end | 34 | end |
| 36 | 35 | ||
| 37 | def show | 36 | def show |
| 38 | - @issue = @project.issues.find(params[:id]) | ||
| 39 | @notes = @issue.notes | 37 | @notes = @issue.notes |
| 40 | @note = @project.notes.new(:noteable => @issue) | 38 | @note = @project.notes.new(:noteable => @issue) |
| 41 | end | 39 | end |
| @@ -51,7 +49,6 @@ class IssuesController < ApplicationController | @@ -51,7 +49,6 @@ class IssuesController < ApplicationController | ||
| 51 | end | 49 | end |
| 52 | 50 | ||
| 53 | def update | 51 | def update |
| 54 | - @issue = @project.issues.find(params[:id]) | ||
| 55 | @issue.update_attributes(params[:issue]) | 52 | @issue.update_attributes(params[:issue]) |
| 56 | 53 | ||
| 57 | respond_to do |format| | 54 | respond_to do |format| |
| @@ -62,7 +59,8 @@ class IssuesController < ApplicationController | @@ -62,7 +59,8 @@ class IssuesController < ApplicationController | ||
| 62 | 59 | ||
| 63 | 60 | ||
| 64 | def destroy | 61 | def destroy |
| 65 | - @issue = @project.issues.find(params[:id]) | 62 | + return access_denied! unless can?(current_user, :admin_issue, @issue) |
| 63 | + | ||
| 66 | @issue.destroy | 64 | @issue.destroy |
| 67 | 65 | ||
| 68 | respond_to do |format| | 66 | respond_to do |format| |
| @@ -79,4 +77,10 @@ class IssuesController < ApplicationController | @@ -79,4 +77,10 @@ class IssuesController < ApplicationController | ||
| 79 | 77 | ||
| 80 | render :nothing => true | 78 | render :nothing => true |
| 81 | end | 79 | end |
| 80 | + | ||
| 81 | + protected | ||
| 82 | + | ||
| 83 | + def issue | ||
| 84 | + @issue ||= @project.issues.find(params[:id]) | ||
| 85 | + end | ||
| 82 | end | 86 | end |
app/controllers/notes_controller.rb
| @@ -4,7 +4,6 @@ class NotesController < ApplicationController | @@ -4,7 +4,6 @@ class NotesController < ApplicationController | ||
| 4 | # Authorize | 4 | # Authorize |
| 5 | before_filter :add_project_abilities | 5 | before_filter :add_project_abilities |
| 6 | before_filter :authorize_write_note!, :only => [:create] | 6 | before_filter :authorize_write_note!, :only => [:create] |
| 7 | - before_filter :authorize_admin_note!, :only => [:destroy] | ||
| 8 | 7 | ||
| 9 | respond_to :js | 8 | respond_to :js |
| 10 | 9 | ||
| @@ -25,6 +24,9 @@ class NotesController < ApplicationController | @@ -25,6 +24,9 @@ class NotesController < ApplicationController | ||
| 25 | 24 | ||
| 26 | def destroy | 25 | def destroy |
| 27 | @note = @project.notes.find(params[:id]) | 26 | @note = @project.notes.find(params[:id]) |
| 27 | + | ||
| 28 | + return access_denied! unless can?(current_user, :admin_note, @note) | ||
| 29 | + | ||
| 28 | @note.destroy | 30 | @note.destroy |
| 29 | 31 | ||
| 30 | respond_to do |format| | 32 | respond_to do |format| |
app/controllers/snippets_controller.rb
| @@ -52,12 +52,11 @@ class SnippetsController < ApplicationController | @@ -52,12 +52,11 @@ class SnippetsController < ApplicationController | ||
| 52 | 52 | ||
| 53 | def destroy | 53 | def destroy |
| 54 | @snippet = @project.snippets.find(params[:id]) | 54 | @snippet = @project.snippets.find(params[:id]) |
| 55 | - authorize_admin_snippet! unless @snippet.author == current_user | 55 | + |
| 56 | + return access_denied! unless can?(current_user, :admin_snippet, @snippet) | ||
| 56 | 57 | ||
| 57 | @snippet.destroy | 58 | @snippet.destroy |
| 58 | 59 | ||
| 59 | - respond_to do |format| | ||
| 60 | - format.js { render :nothing => true } | ||
| 61 | - end | 60 | + redirect_to project_snippets_path(@project) |
| 62 | end | 61 | end |
| 63 | end | 62 | end |
app/controllers/team_members_controller.rb
| @@ -3,8 +3,8 @@ class TeamMembersController < ApplicationController | @@ -3,8 +3,8 @@ class TeamMembersController < ApplicationController | ||
| 3 | 3 | ||
| 4 | # Authorize | 4 | # Authorize |
| 5 | before_filter :add_project_abilities | 5 | before_filter :add_project_abilities |
| 6 | - before_filter :authorize_read_team_member! | ||
| 7 | - before_filter :authorize_admin_team_member!, :only => [:new, :create, :destroy, :update] | 6 | + before_filter :authorize_read_project! |
| 7 | + before_filter :authorize_admin_project!, :only => [:new, :create, :destroy, :update] | ||
| 8 | 8 | ||
| 9 | def show | 9 | def show |
| 10 | @team_member = project.users_projects.find(params[:id]) | 10 | @team_member = project.users_projects.find(params[:id]) |
app/models/ability.rb
| @@ -2,6 +2,9 @@ class Ability | @@ -2,6 +2,9 @@ class Ability | ||
| 2 | def self.allowed(object, subject) | 2 | def self.allowed(object, subject) |
| 3 | case subject.class.name | 3 | case subject.class.name |
| 4 | when "Project" then project_abilities(object, subject) | 4 | when "Project" then project_abilities(object, subject) |
| 5 | + when "Issue" then issue_abilities(object, subject) | ||
| 6 | + when "Note" then note_abilities(object, subject) | ||
| 7 | + when "Snippet" then snippet_abilities(object, subject) | ||
| 5 | else [] | 8 | else [] |
| 6 | end | 9 | end |
| 7 | end | 10 | end |
| @@ -34,4 +37,21 @@ class Ability | @@ -34,4 +37,21 @@ class Ability | ||
| 34 | 37 | ||
| 35 | rules.flatten | 38 | rules.flatten |
| 36 | end | 39 | end |
| 40 | + | ||
| 41 | + class << self | ||
| 42 | + [:issue, :note, :snippet].each do |name| | ||
| 43 | + define_method "#{name}_abilities" do |user, subject| | ||
| 44 | + if subject.author == user | ||
| 45 | + [ | ||
| 46 | + :"read_#{name}", | ||
| 47 | + :"write_#{name}", | ||
| 48 | + :"admin_#{name}" | ||
| 49 | + ] | ||
| 50 | + else | ||
| 51 | + subject.respond_to?(:project) ? | ||
| 52 | + project_abilities(user, subject.project) : [] | ||
| 53 | + end | ||
| 54 | + end | ||
| 55 | + end | ||
| 56 | + end | ||
| 37 | end | 57 | end |
spec/requests/projects_security_spec.rb
| @@ -82,12 +82,18 @@ describe "Projects" do | @@ -82,12 +82,18 @@ describe "Projects" do | ||
| 82 | end | 82 | end |
| 83 | 83 | ||
| 84 | describe "GET /project_code/blob" do | 84 | describe "GET /project_code/blob" do |
| 85 | - it { blob_project_path(@project).should be_allowed_for @u1 } | ||
| 86 | - it { blob_project_path(@project).should be_allowed_for @u3 } | ||
| 87 | - it { blob_project_path(@project).should be_denied_for :admin } | ||
| 88 | - it { blob_project_path(@project).should be_denied_for @u2 } | ||
| 89 | - it { blob_project_path(@project).should be_denied_for :user } | ||
| 90 | - it { blob_project_path(@project).should be_denied_for :visitor } | 85 | + before do |
| 86 | + @commit = @project.commit | ||
| 87 | + @path = @commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name | ||
| 88 | + @blob_path = blob_project_path(@project, :commit_id => @commit.id, :path => @path) | ||
| 89 | + end | ||
| 90 | + | ||
| 91 | + it { @blob_path.should be_allowed_for @u1 } | ||
| 92 | + it { @blob_path.should be_allowed_for @u3 } | ||
| 93 | + it { @blob_path.should be_denied_for :admin } | ||
| 94 | + it { @blob_path.should be_denied_for @u2 } | ||
| 95 | + it { @blob_path.should be_denied_for :user } | ||
| 96 | + it { @blob_path.should be_denied_for :visitor } | ||
| 91 | end | 97 | end |
| 92 | 98 | ||
| 93 | describe "GET /project_code/edit" do | 99 | describe "GET /project_code/edit" do |
spec/requests/user_security_spec.rb
| @@ -7,10 +7,10 @@ describe "Users Security" do | @@ -7,10 +7,10 @@ describe "Users Security" do | ||
| 7 | end | 7 | end |
| 8 | 8 | ||
| 9 | describe "GET /login" do | 9 | describe "GET /login" do |
| 10 | - it { new_user_session_path.should be_denied_for @u1 } | ||
| 11 | - it { new_user_session_path.should be_denied_for :admin } | ||
| 12 | - it { new_user_session_path.should be_denied_for :user } | ||
| 13 | - it { new_user_session_path.should be_allowed_for :visitor } | 10 | + #it { new_user_session_path.should be_denied_for @u1 } |
| 11 | + #it { new_user_session_path.should be_denied_for :admin } | ||
| 12 | + #it { new_user_session_path.should be_denied_for :user } | ||
| 13 | + it { new_user_session_path.should_not be_404_for :visitor } | ||
| 14 | end | 14 | end |
| 15 | 15 | ||
| 16 | describe "GET /keys" do | 16 | describe "GET /keys" do |
spec/support/matchers.rb
| @@ -21,17 +21,30 @@ RSpec::Matchers.define :be_denied_for do |user| | @@ -21,17 +21,30 @@ RSpec::Matchers.define :be_denied_for do |user| | ||
| 21 | end | 21 | end |
| 22 | end | 22 | end |
| 23 | 23 | ||
| 24 | +RSpec::Matchers.define :be_404_for do |user| | ||
| 25 | + match do |url| | ||
| 26 | + include UrlAccess | ||
| 27 | + url_404?(user, url) | ||
| 28 | + end | ||
| 29 | +end | ||
| 30 | + | ||
| 24 | module UrlAccess | 31 | module UrlAccess |
| 25 | def url_allowed?(user, url) | 32 | def url_allowed?(user, url) |
| 26 | emulate_user(user) | 33 | emulate_user(user) |
| 27 | visit url | 34 | visit url |
| 28 | - result = (current_path == url) | 35 | + (page.status_code != 404 && current_path != new_user_session_path) |
| 29 | end | 36 | end |
| 30 | 37 | ||
| 31 | def url_denied?(user, url) | 38 | def url_denied?(user, url) |
| 32 | emulate_user(user) | 39 | emulate_user(user) |
| 33 | visit url | 40 | visit url |
| 34 | - result = (current_path != url) | 41 | + (page.status_code == 404 || current_path == new_user_session_path) |
| 42 | + end | ||
| 43 | + | ||
| 44 | + def url_404?(user, url) | ||
| 45 | + emulate_user(user) | ||
| 46 | + visit url | ||
| 47 | + page.status_code == 404 | ||
| 35 | end | 48 | end |
| 36 | 49 | ||
| 37 | def emulate_user(user) | 50 | def emulate_user(user) |