Skip to content

Instantly share code, notes, and snippets.

@cmer
Forked from jamesbebbington/application_controller.rb
Created September 13, 2012 19:13

Revisions

  1. cmer revised this gist Sep 13, 2012. 1 changed file with 21 additions and 10 deletions.
    31 changes: 21 additions & 10 deletions form_tag_helper.rb
    Original file line number Diff line number Diff line change
    @@ -1,22 +1,33 @@
    # From http://www.jarrodspillers.com/2010/02/06/trying-to-use-rails-csrf-protection-on-cached-actions-rack-middleware-to-the-rescue/
    # From http://www.jarrodspillers.com/2010/02/06/trying-to-use-rails-csrf-protection-on-cached-actions-rack-middleware-to-the-rescue/ and https://gist.github.com/1124982/632f1fcbe0981424128b3088ddb27a322c369cc1
    module ActionView
    module Helpers
    module FormTagHelper
    alias_method :token_tag_rails, :token_tag

    # Make all forms generate the same forgery_protection_token so that
    # they can be replaced by Rack before being sent back to the user.
    def token_tag
    if protect_against_forgery?
    tag(
    :input, :type => "hidden",
    :name => request_forgery_protection_token.to_s,
    :value => ApplicationController::TOKEN_PLACEHOLDER
    )
    def token_tag(token=nil)
    if token != false && protect_against_forgery?
    token ||= form_authenticity_token
    tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => ApplicationController::TOKEN_PLACEHOLDER)
    else
    ''
    end
    end

    end
    end
    end

    module ActionView
    module Helpers
    module CsrfHelper
    def csrf_meta_tags
    if protect_against_forgery?
    [
    tag('meta', :name => 'csrf-param', :content => request_forgery_protection_token),
    tag('meta', :name => 'csrf-token', :content => ApplicationController::TOKEN_PLACEHOLDER)
    ].join("\n").html_safe
    end
    end
    end
    end
    end
  2. @jamesbebbington jamesbebbington revised this gist Oct 28, 2011. 4 changed files with 38 additions and 48 deletions.
    17 changes: 17 additions & 0 deletions application_controller.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    class ApplicationController < ActionController::Base
    TOKEN_PLACEHOLDER = "__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__"

    after_filter :inject_csrf_token

    private

    def inject_csrf_token
    if protect_against_forgery? && token = session['_csrf_token']
    if body_with_token = response.body.gsub!(TOKEN_PLACEHOLDER, token)
    response.body = body_with_token
    logger.info "Injected authenticity token '#{token}'"
    end
    end
    end

    end
    20 changes: 20 additions & 0 deletions authentication_token_stories_test.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    # Webrat integration test

    require 'test_helper'

    class AuthenticationTokenStoriesTest < ActionController::IntegrationTest

    context "with forgery protection enabled" do
    setup { ActionController::Base.allow_forgery_protection = true }
    teardown { ActionController::Base.allow_forgery_protection = false }

    should "inject authentication token when visiting home page" do
    visit '/'
    token = session['_csrf_token']
    assert token.present?
    assert_match Regexp.new(Regexp.escape(token)), response.body
    end

    end

    end
    47 changes: 0 additions & 47 deletions caching_with_request_forgery_protection.rb
    Original file line number Diff line number Diff line change
    @@ -1,47 +0,0 @@
    # This middleware facilitates caching by replacing a piece of placeholder text with a session-specific Cross Site Request Forgery token
    # From http://www.jarrodspillers.com/2010/02/06/trying-to-use-rails-csrf-protection-on-cached-actions-rack-middleware-to-the-rescue/
    class CachingWithRequestForgeryProtection
    TOKEN_PLACEHOLDER = "__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__"

    def initialize(app)
    @app = app
    end

    def call(env)
    status, headers, response = @app.call(env)

    @token = env["rack.session"][:_csrf_token]

    if @token && headers['Content-Type'].try(:include?, "text/html") && response.respond_to?(:body)

    # Sometimes response is an ActionDispatch::Response, sometimes a Rack::Response
    # ActionDispatch::Response#body returns an instance of String
    # Rack::Response#body returns an instance of Array
    #
    # The rack spec states:
    # The Body must respond to each and must only yield String values.
    # The Body itself should not be an instance of String, as this will break in Ruby 1.9.
    # If the Body responds to close, it will be called after iteration.
    # from http://rack.rubyforge.org/doc/files/SPEC.html
    #
    # Therefore if we get a String we wrap it in an Array; FU ActionDispatch.
    response.body = [response.body] if response.body.is_a?(String)

    # Assumption: Returning body as an Array is fine
    [].tap do |body|
    response.body.each do |str|
    body << str.gsub(TOKEN_PLACEHOLDER, @token)
    end
    response.body = body
    end

    # Rack::Response has a Content-Length header set, ActionDispatch::Response doesn't
    if headers["Content-Length"]
    headers["Content-Length"] = response.body.join('').length.to_s
    end

    end

    [status, headers, response]
    end
    end
    2 changes: 1 addition & 1 deletion form_tag_helper.rb
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@ def token_tag
    tag(
    :input, :type => "hidden",
    :name => request_forgery_protection_token.to_s,
    :value => CachingWithRequestForgeryProtection::TOKEN_PLACEHOLDER
    :value => ApplicationController::TOKEN_PLACEHOLDER
    )
    else
    ''
  3. @jamesbebbington jamesbebbington revised this gist Sep 21, 2011. 1 changed file with 33 additions and 10 deletions.
    43 changes: 33 additions & 10 deletions caching_with_request_forgery_protection.rb
    Original file line number Diff line number Diff line change
    @@ -1,22 +1,45 @@
    # Originally from http://www.jarrodspillers.com/2010/02/06/trying-to-use-rails-csrf-protection-on-cached-actions-rack-middleware-to-the-rescue/
    # Updated for rails 3
    #
    # NOTE: Remember to add "before_filter :form_authenticity_token" to ApplicationController
    # and patch ActionView::ActionView::FormTagHelper#token_tag in form_tag_helper.rb

    # This middleware facilitates caching by replacing a piece of placeholder text with a session-specific Cross Site Request Forgery token
    # From http://www.jarrodspillers.com/2010/02/06/trying-to-use-rails-csrf-protection-on-cached-actions-rack-middleware-to-the-rescue/
    class CachingWithRequestForgeryProtection
    TOKEN_PLACEHOLDER = "__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__"

    def initialize(app)
    @app = app
    @app = app
    end

    def call(env)
    status, headers, response = @app.call(env)

    if response.is_a? ActionController::Response
    response.body = response.body.gsub(TOKEN_PLACEHOLDER, env["rack.session"][:_csrf_token])
    headers["Content-Length"] = response.body.length.to_s
    @token = env["rack.session"][:_csrf_token]

    if @token && headers['Content-Type'].try(:include?, "text/html") && response.respond_to?(:body)

    # Sometimes response is an ActionDispatch::Response, sometimes a Rack::Response
    # ActionDispatch::Response#body returns an instance of String
    # Rack::Response#body returns an instance of Array
    #
    # The rack spec states:
    # The Body must respond to each and must only yield String values.
    # The Body itself should not be an instance of String, as this will break in Ruby 1.9.
    # If the Body responds to close, it will be called after iteration.
    # from http://rack.rubyforge.org/doc/files/SPEC.html
    #
    # Therefore if we get a String we wrap it in an Array; FU ActionDispatch.
    response.body = [response.body] if response.body.is_a?(String)

    # Assumption: Returning body as an Array is fine
    [].tap do |body|
    response.body.each do |str|
    body << str.gsub(TOKEN_PLACEHOLDER, @token)
    end
    response.body = body
    end

    # Rack::Response has a Content-Length header set, ActionDispatch::Response doesn't
    if headers["Content-Length"]
    headers["Content-Length"] = response.body.join('').length.to_s
    end

    end

    [status, headers, response]
  4. @jamesbebbington jamesbebbington revised this gist Aug 4, 2011. 2 changed files with 21 additions and 11 deletions.
    15 changes: 10 additions & 5 deletions caching_with_request_forgery_protection.rb
    Original file line number Diff line number Diff line change
    @@ -1,19 +1,24 @@
    # Originally from http://www.jarrodspillers.com/2010/02/06/trying-to-use-rails-csrf-protection-on-cached-actions-rack-middleware-to-the-rescue/
    # Updated for rails 3
    #
    # NOTE: Remember to add "before_filter :form_authenticity_token" to ApplicationController
    # and patch ActionView::ActionView::FormTagHelper#token_tag in form_tag_helper.rb

    class CachingWithRequestForgeryProtection
    TOKEN_PLACEHOLDER = "__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__"

    def initialize(app)
    @app = app
    @app = app
    end

    def call(env)
    status, headers, response = @app.call(env)

    if response.is_a? ActionController::Response
    response.body = response.body.gsub("__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__", response.instance_variable_get(:@session)[:_csrf_token])
    response.body = response.body.gsub(TOKEN_PLACEHOLDER, env["rack.session"][:_csrf_token])
    headers["Content-Length"] = response.body.length.to_s
    end

    [status, headers, response]
    end
    end
    end
    17 changes: 11 additions & 6 deletions form_tag_helper.rb
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,22 @@
    # From http://www.jarrodspillers.com/2010/02/06/trying-to-use-rails-csrf-protection-on-cached-actions-rack-middleware-to-the-rescue/
    module ActionView
    module Helpers
    module FormTagHelper
    alias_method :token_tag_RAILS, :token_tag
    alias_method :token_tag_rails, :token_tag

    # Make all forms generate the same forgery_protection_token so that
    # Make all forms generate the same forgery_protection_token so that
    # they can be replaced by Rack before being sent back to the user.
    def token_tag
    unless protect_against_forgery?
    ''
    if protect_against_forgery?
    tag(
    :input, :type => "hidden",
    :name => request_forgery_protection_token.to_s,
    :value => CachingWithRequestForgeryProtection::TOKEN_PLACEHOLDER
    )
    else
    tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => "__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__")
    ''
    end
    end
    end
    end
    end
    end
  5. Robert Sosinski created this gist Apr 27, 2011.
    19 changes: 19 additions & 0 deletions caching_with_request_forgery_protection.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    # NOTE: Remember to add "before_filter :form_authenticity_token" to ApplicationController
    # and patch ActionView::ActionView::FormTagHelper#token_tag in form_tag_helper.rb

    class CachingWithRequestForgeryProtection
    def initialize(app)
    @app = app
    end

    def call(env)
    status, headers, response = @app.call(env)

    if response.is_a? ActionController::Response
    response.body = response.body.gsub("__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__", response.instance_variable_get(:@session)[:_csrf_token])
    headers["Content-Length"] = response.body.length.to_s
    end

    [status, headers, response]
    end
    end
    17 changes: 17 additions & 0 deletions form_tag_helper.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    module ActionView
    module Helpers
    module FormTagHelper
    alias_method :token_tag_RAILS, :token_tag

    # Make all forms generate the same forgery_protection_token so that
    # they can be replaced by Rack before being sent back to the user.
    def token_tag
    unless protect_against_forgery?
    ''
    else
    tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => "__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__")
    end
    end
    end
    end
    end