Commit 7f5d12da authored by Illya Klymov's avatar Illya Klymov Committed by Mayra Cabrera

Add state param validation for Bitbucket OAuth flow

- pass state param and validate it via session

Changelog: security
parent 5b7647d9
......@@ -12,6 +12,12 @@ class Import::BitbucketController < Import::BaseController
rescue_from Bitbucket::Error::Unauthorized, with: :bitbucket_unauthorized
def callback
auth_state = session[:bitbucket_auth_state]
session[:bitbucket_auth_state] = nil
if auth_state.blank? || !ActiveSupport::SecurityUtils.secure_compare(auth_state, params[:state])
go_to_bitbucket_for_permissions
else
response = oauth_client.auth_code.get_token(params[:code], redirect_uri: users_import_bitbucket_callback_url)
session[:bitbucket_token] = response.token
......@@ -21,6 +27,7 @@ class Import::BitbucketController < Import::BaseController
redirect_to status_import_bitbucket_url
end
end
def status
super
......@@ -113,7 +120,9 @@ class Import::BitbucketController < Import::BaseController
end
def go_to_bitbucket_for_permissions
redirect_to oauth_client.auth_code.authorize_url(redirect_uri: users_import_bitbucket_callback_url)
state = SecureRandom.base64(64)
session[:bitbucket_auth_state] = state
redirect_to oauth_client.auth_code.authorize_url(redirect_uri: users_import_bitbucket_callback_url, state: state)
end
def bitbucket_unauthorized(exception)
......
......@@ -26,6 +26,29 @@ RSpec.describe Import::BitbucketController do
session[:oauth_request_token] = {}
end
context "when auth state param is invalid" do
let(:random_key) { "pure_random" }
let(:external_bitbucket_auth_url) { "http://fake.bitbucket.host/url" }
it "redirects to external auth url" do
allow(SecureRandom).to receive(:base64).and_return(random_key)
allow_next_instance_of(OAuth2::Client) do |client|
allow(client).to receive_message_chain(:auth_code, :authorize_url)
.with(redirect_uri: users_import_bitbucket_callback_url, state: random_key)
.and_return(external_bitbucket_auth_url)
end
get :callback, params: { code: code, state: "invalid-token" }
expect(controller).to redirect_to(external_bitbucket_auth_url)
end
end
context "when auth state param is valid" do
before do
session[:bitbucket_auth_state] = 'state'
end
it "updates access token" do
expires_at = Time.current + 1.day
expires_in = 1.day
......@@ -44,7 +67,7 @@ RSpec.describe Import::BitbucketController do
.and_return(access_token)
stub_omniauth_provider('bitbucket')
get :callback, params: { code: code }
get :callback, params: { code: code, state: 'state' }
expect(session[:bitbucket_token]).to eq(token)
expect(session[:bitbucket_refresh_token]).to eq(refresh_token)
......@@ -53,13 +76,35 @@ RSpec.describe Import::BitbucketController do
expect(controller).to redirect_to(status_import_bitbucket_url)
end
end
end
describe "GET status" do
before do
@repo = double(name: 'vim', slug: 'vim', owner: 'asd', full_name: 'asd/vim', clone_url: 'http://test.host/demo/url.git', 'valid?' => true)
@invalid_repo = double(name: 'mercurialrepo', slug: 'mercurialrepo', owner: 'asd', full_name: 'asd/mercurialrepo', clone_url: 'http://test.host/demo/mercurialrepo.git', 'valid?' => false)
allow(controller).to receive(:provider_url).and_return('http://demobitbucket.org')
end
context "when token does not exists" do
let(:random_key) { "pure_random" }
let(:external_bitbucket_auth_url) { "http://fake.bitbucket.host/url" }
it 'redirects to authorize url with state included' do
allow(SecureRandom).to receive(:base64).and_return(random_key)
allow_next_instance_of(OAuth2::Client) do |client|
allow(client).to receive_message_chain(:auth_code, :authorize_url)
.with(redirect_uri: users_import_bitbucket_callback_url, state: random_key)
.and_return(external_bitbucket_auth_url)
end
get :status, format: :json
expect(controller).to redirect_to(external_bitbucket_auth_url)
end
end
context "when token is valid" do
before do
assign_session_tokens
end
......@@ -102,6 +147,7 @@ RSpec.describe Import::BitbucketController do
end
end
end
end
describe "POST create" do
let(:bitbucket_username) { user.username }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment