Get rid of custom CSRF protection for user role changes

By restricting role changes to POST requests, which they should be
anyway, we get all the rails CSRF protection for free.
This commit is contained in:
Tom Hughes 2012-03-20 16:22:07 +00:00
parent 0b87b003ee
commit 5f33656c8d
8 changed files with 10 additions and 50 deletions

View file

@ -8,7 +8,6 @@ class UserRolesController < ApplicationController
before_filter :require_valid_role before_filter :require_valid_role
before_filter :not_in_role, :only => [:grant] before_filter :not_in_role, :only => [:grant]
before_filter :in_role, :only => [:revoke] before_filter :in_role, :only => [:revoke]
around_filter :setup_nonce
def grant def grant
@this_user.roles.create({ @this_user.roles.create({
@ -38,22 +37,6 @@ class UserRolesController < ApplicationController
redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] unless @this_user redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] unless @this_user
end end
##
# the random nonce here which isn't predictable, making an CSRF
# procedure much, much more difficult. setup the nonce. if the given
# nonce matches the session nonce then yield into the actual method.
# otherwise, just sets up the nonce for the form.
def setup_nonce
if params[:nonce] and params[:nonce] == session[:nonce]
@nonce = params[:nonce]
yield
else
@nonce = OAuth::Helper.generate_nonce
session[:nonce] = @nonce
render
end
end
## ##
# require that the given role is valid. the role is a URL # require that the given role is valid. the role is a URL
# parameter, so should always be present. # parameter, so should always be present.

View file

@ -5,9 +5,9 @@
<% UserRole::ALL_ROLES.each do |role| %> <% UserRole::ALL_ROLES.each do |role| %>
<% if @user and @user.administrator? %> <% if @user and @user.administrator? %>
<% if @this_user.has_role? role %> <% if @this_user.has_role? role %>
<%= link_to(image_tag("roles/#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.revoke.#{role}"), :title => t("user.view.role.revoke.#{role}")), :controller => 'user_roles', :action => 'revoke', :display_name => @this_user.display_name, :role => role) %> <%= link_to image_tag("roles/#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.revoke.#{role}"), :title => t("user.view.role.revoke.#{role}")), revoke_role_path(:display_name => @this_user.display_name, :role => role), :method => :post, :confirm => t('user_role.revoke.are_you_sure', :name => @this_user.display_name, :role => role) %>
<% else %> <% else %>
<%= link_to(image_tag("roles/blank_#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.grant.#{role}"), :title => t("user.view.role.grant.#{role}")), :controller => 'user_roles', :action => 'grant', :display_name => @this_user.display_name, :role => role) %> <%= link_to image_tag("roles/blank_#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.grant.#{role}"), :title => t("user.view.role.grant.#{role}")), grant_role_path(:display_name => @this_user.display_name, :role => role), :method => :post, :confirm => t('user_role.grant.are_you_sure', :name => @this_user.display_name, :role => role) %>
<% end %> <% end %>
<% elsif @this_user.has_role? role %> <% elsif @this_user.has_role? role %>
<%= image_tag("roles/#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.#{role}"), :title => t("user.view.role.#{role}")) %> <%= image_tag("roles/#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.#{role}"), :title => t("user.view.role.#{role}")) %>

View file

@ -1,7 +0,0 @@
<%= form_tag request.fullpath do %>
<%= hidden_field_tag 'nonce', @nonce %>
<% @title = t('user_role.grant.heading') %>
<h1><%= t('user_role.grant.heading') %></h1>
<p><%= t('user_role.grant.are_you_sure', :name => params[:display_name], :role => params[:role]) %></p>
<p><%= submit_tag t('user_role.grant.confirm') %></p>
<% end %>

View file

@ -1,7 +0,0 @@
<%= form_tag request.fullpath do %>
<%= hidden_field_tag 'nonce', @nonce %>
<% @title = t('user_role.revoke.heading') %>
<h1><%= t('user_role.revoke.heading') %></h1>
<p><%= t('user_role.revoke.are_you_sure', :name => params[:display_name], :role => params[:role]) %></p>
<p><%= submit_tag t'user_role.revoke.confirm' %></p>
<% end %>

View file

@ -219,8 +219,8 @@ OpenStreetMap::Application.routes.draw do
match '/oauth/test_request' => 'oauth#test_request', :as => :test_request match '/oauth/test_request' => 'oauth#test_request', :as => :test_request
# roles and banning pages # roles and banning pages
match '/user/:display_name/role/:role/grant' => 'user_roles#grant', :via => [:get, :post] match '/user/:display_name/role/:role/grant' => 'user_roles#grant', :via => :post, :as => "grant_role"
match '/user/:display_name/role/:role/revoke' => 'user_roles#revoke', :via => [:get, :post] match '/user/:display_name/role/:role/revoke' => 'user_roles#revoke', :via => :post, :as => "revoke_role"
match '/user/:display_name/blocks' => 'user_blocks#blocks_on', :via => :get match '/user/:display_name/blocks' => 'user_blocks#blocks_on', :via => :get
match '/user/:display_name/blocks_by' => 'user_blocks#blocks_by', :via => :get match '/user/:display_name/blocks_by' => 'user_blocks#blocks_by', :via => :get
match '/blocks/new/:display_name' => 'user_blocks#new', :via => :get, :as => "new_user_block" match '/blocks/new/:display_name' => 'user_blocks#new', :via => :get, :as => "new_user_block"

View file

@ -44,7 +44,8 @@ SET search_path = public, pg_catalog;
CREATE TYPE format_enum AS ENUM ( CREATE TYPE format_enum AS ENUM (
'html', 'html',
'markdown' 'markdown',
'text'
); );

View file

@ -4,18 +4,10 @@ class UserRolesControllerTest < ActionController::TestCase
## ##
# test all routes which lead to this controller # test all routes which lead to this controller
def test_routes def test_routes
assert_routing(
{ :path => "/user/username/role/rolename/grant", :method => :get },
{ :controller => "user_roles", :action => "grant", :display_name => "username", :role => "rolename" }
)
assert_routing( assert_routing(
{ :path => "/user/username/role/rolename/grant", :method => :post }, { :path => "/user/username/role/rolename/grant", :method => :post },
{ :controller => "user_roles", :action => "grant", :display_name => "username", :role => "rolename" } { :controller => "user_roles", :action => "grant", :display_name => "username", :role => "rolename" }
) )
assert_routing(
{ :path => "/user/username/role/rolename/revoke", :method => :get },
{ :controller => "user_roles", :action => "revoke", :display_name => "username", :role => "rolename" }
)
assert_routing( assert_routing(
{ :path => "/user/username/role/rolename/revoke", :method => :post }, { :path => "/user/username/role/rolename/revoke", :method => :post },
{ :controller => "user_roles", :action => "revoke", :display_name => "username", :role => "rolename" } { :controller => "user_roles", :action => "revoke", :display_name => "username", :role => "rolename" }

View file

@ -16,6 +16,8 @@ class UserRolesTest < ActionController::IntegrationTest
check_fail(:revoke, :administrator_user, :moderator) check_fail(:revoke, :administrator_user, :moderator)
end end
private
def check_fail(action, user, role) def check_fail(action, user, role)
get '/login' get '/login'
assert_response :redirect assert_response :redirect
@ -27,8 +29,7 @@ class UserRolesTest < ActionController::IntegrationTest
follow_redirect! follow_redirect!
assert_response :success assert_response :success
get "/user/#{users(:second_public_user).display_name}/role/#{role}/#{action}" post "/user/#{users(:second_public_user).display_name}/role/#{role}/#{action}"
assert_response :redirect
assert_redirected_to :controller => 'user', :action => 'view', :display_name => users(:second_public_user).display_name assert_redirected_to :controller => 'user', :action => 'view', :display_name => users(:second_public_user).display_name
reset! reset!
@ -45,10 +46,7 @@ class UserRolesTest < ActionController::IntegrationTest
follow_redirect! follow_redirect!
assert_response :success assert_response :success
get "/user/#{users(:second_public_user).display_name}/role/#{role}/#{action}" post "/user/#{users(:second_public_user).display_name}/role/#{role}/#{action}"
assert_response :success
post "/user/#{users(:second_public_user).display_name}/role/#{role}/#{action}", {:confirm => "yes", :nonce => session[:nonce]}
assert_response :redirect
assert_redirected_to :controller => 'user', :action => 'view', :display_name => users(:second_public_user).display_name assert_redirected_to :controller => 'user', :action => 'view', :display_name => users(:second_public_user).display_name
reset! reset!