Skip to content

Commit

Permalink
Skip CSRF protection if a valid session token is present
Browse files Browse the repository at this point in the history
  • Loading branch information
Aditya Mattos committed Jun 2, 2020
1 parent b75299e commit caf27a4
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/controllers/concerns/shopify_app/authenticated.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module Authenticated
included do
include ShopifyApp::Localization
include ShopifyApp::LoginProtection
include ShopifyApp::CsrfProtection
include ShopifyApp::EmbeddedApp
before_action :login_again_if_different_user_or_shop
around_action :activate_shopify_session
Expand Down
1 change: 1 addition & 0 deletions lib/shopify_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def self.use_webpacker?
require 'shopify_app/utils'

# controller concerns
require 'shopify_app/controller_concerns/csrf_protection'
require 'shopify_app/controller_concerns/localization'
require 'shopify_app/controller_concerns/itp'
require 'shopify_app/controller_concerns/login_protection'
Expand Down
22 changes: 22 additions & 0 deletions lib/shopify_app/controller_concerns/csrf_protection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true
module ShopifyApp
module CsrfProtection
extend ActiveSupport::Concern

MissingIncludeError = Class.new(StandardError)

included do
unless ancestors.include?(ShopifyApp::LoginProtection)
raise(MissingIncludeError, 'You must include ShopifyApp::LoginProtection before including this module.')
end

protect_from_forgery with: :exception, unless: :valid_session_token?
end

private

def valid_session_token?
jwt_shopify_domain.present?
end
end
end
1 change: 1 addition & 0 deletions test/controllers/concerns/authenticated_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def index
test "includes all the needed concerns" do
AuthenticatedTestController.include?(ShopifyApp::Localization)
AuthenticatedTestController.include?(ShopifyApp::LoginProtection)
AuthenticatedTestController.include?(ShopifyApp::CsrfProtection)
AuthenticatedTestController.include?(ShopifyApp::EmbeddedApp)
end
end
62 changes: 62 additions & 0 deletions test/shopify_app/controller_concerns/csrf_protection_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

class CsrfProtectionController < ActionController::Base
include ShopifyApp::LoginProtection
include ShopifyApp::CsrfProtection

def authenticity_token
render(json: { authenticity_token: form_authenticity_token })
end

def csrf_test
head(:ok)
end
end

class CsrfProtectionTest < ActionDispatch::IntegrationTest
setup do
@authenticity_protection = ActionController::Base.allow_forgery_protection
ActionController::Base.allow_forgery_protection = true
Rails.application.routes.draw do
get '/authenticity_token', to: 'csrf_protection#authenticity_token'
post '/csrf_protection_test', to: 'csrf_protection#csrf_test'
end
end

teardown do
ActionController::Base.allow_forgery_protection = @authenticity_protection
Rails.application.reload_routes!
end

test 'it raises an error if module is included without including ShopifyApp::LoginProtection first' do
error = assert_raises ShopifyApp::CsrfProtection::MissingIncludeError do
class Test
include ShopifyApp::CsrfProtection
end
end

assert_equal 'You must include ShopifyApp::LoginProtection before including this module.', error.message
end

test 'it raises an invalid authenticity token error if a valid session token or csrf token is not provided' do
assert_raises ActionController::InvalidAuthenticityToken do
post '/csrf_protection_test'
end
end

test 'it does not raise if a valid CSRF token was provided' do
get '/authenticity_token'

csrf_token = JSON.parse(response.body)['authenticity_token']

post '/csrf_protection_test', headers: { 'X-CSRF-Token': csrf_token }

assert_response :ok
end

test 'it does not raise if a valid session token was provided' do
post '/csrf_protection_test', env: { 'jwt.shopify_domain': "exampleshop.myshopify.com" }

assert_response :ok
end
end

0 comments on commit caf27a4

Please sign in to comment.