From 7fd8c5956dafc18e833c2f89dadaf9531f460e9c Mon Sep 17 00:00:00 2001 From: Steve Pettitt Date: Wed, 28 Sep 2016 17:26:08 +0100 Subject: [PATCH] Check CSRF, allow a Stripe account to be connected to more than one enterprise (but not vice versa) --- .../admin/enterprises_controller.rb | 33 +++++++++++-------- app/models/stripe_account.rb | 2 +- spec/features/admin/stripe_connect_spec.rb | 13 ++++++++ 3 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 spec/features/admin/stripe_connect_spec.rb diff --git a/app/controllers/admin/enterprises_controller.rb b/app/controllers/admin/enterprises_controller.rb index c3d515649e..c33a68c1e7 100644 --- a/app/controllers/admin/enterprises_controller.rb +++ b/app/controllers/admin/enterprises_controller.rb @@ -115,26 +115,31 @@ module Admin end def stripe_connect - redirect_to authorize_stripe(params[:enterprise_id]) # csrf: form_authenticity_token) + redirect_to authorize_stripe(params[:enterprise_id], csrf: form_authenticity_token) end def stripe_connect_callback - # Check CSRF? if params["code"] - # Get the deets from Stripe - response_params = get_stripe_token(params["code"]).params - # Get the Enterprise state = JSON.parse(params["state"].gsub("=>",":")) - @enterprise = Enterprise.find_by_permalink(state["enterprise_id"]) - - stripe_account = StripeAccount.new(stripe_user_id: response_params["stripe_user_id"], stripe_publishable_key: response_params["stripe_publishable_key"], enterprise: @enterprise) - if stripe_account.save - respond_to do |format| - format.html { redirect_to main_app.edit_admin_enterprise_path(@enterprise), notice: "Stripe account connected successfully."} - format.json { render json: stripe_account } - end + # Check csrf + if state["csrf"] != form_authenticity_token + redirect_to '/unauthorized' else - render text: "Failed to save Stripe token", status: 500 + # Get the Enterprise + @enterprise = Enterprise.find_by_permalink(state["enterprise_id"]) + + # Get the deets from Stripe + response_params = get_stripe_token(params["code"]).params + + stripe_account = StripeAccount.new(stripe_user_id: response_params["stripe_user_id"], stripe_publishable_key: response_params["stripe_publishable_key"], enterprise: @enterprise) + if stripe_account.save + respond_to do |format| + format.html { redirect_to main_app.edit_admin_enterprise_path(@enterprise), notice: "Stripe account connected successfully."} + format.json { render json: stripe_account } + end + else + render text: "Failed to save Stripe token", status: 500 + end end else render text: params["error_description"], status: 500 diff --git a/app/models/stripe_account.rb b/app/models/stripe_account.rb index d84f875df0..dd263a6b37 100644 --- a/app/models/stripe_account.rb +++ b/app/models/stripe_account.rb @@ -1,5 +1,5 @@ class StripeAccount < ActiveRecord::Base belongs_to :enterprise validates_presence_of :stripe_user_id, :stripe_publishable_key - validates_uniqueness_of :stripe_user_id, :enterprise_id + validates_uniqueness_of :enterprise_id end diff --git a/spec/features/admin/stripe_connect_spec.rb b/spec/features/admin/stripe_connect_spec.rb new file mode 100644 index 0000000000..3a7dae2a88 --- /dev/null +++ b/spec/features/admin/stripe_connect_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +feature "Connecting a Stripe Account" do + include AuthenticationWorkflow + include WebHelper + before(:each) { login_to_admin_section } + let!(:enterprise) { create :enterprise } + + scenario "Passing an invalid CSRF token" do + visit "/stripe/callback?state=%7B%22csrf%22%3D%3E%22ByQF3~~~nonsense~~~4hwwmhAek4u4AEo0%3D%22%2C+%22enterprise_id%22%3D%3E%22#{enterprise.permalink}%22%7D&scope=read_only&code=ac_9HJF2pynjz5vlRWGXtpnGvL3yT9y01DY" + page.should have_content "Unauthorized" + end +end