Skip to content

Commit 9029a4a

Browse files
author
AlexanderPavlenko
committed
CSRF protection
1 parent 89d984e commit 9029a4a

File tree

2 files changed

+20
-5
lines changed

2 files changed

+20
-5
lines changed

lib/omniauth/strategies/oauth2.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ def request_phase
4747
end
4848

4949
def authorize_params
50-
options.authorize_params.merge(options.authorize_options.inject({}){|h,k| h[k.to_sym] = options[k] if options[k]; h})
50+
if options.authorize_params[:state].to_s.empty?
51+
options.authorize_params[:state] = 3.times.map{ rand.to_s[2..-1] }.reduce(&:concat)
52+
end
53+
params = options.authorize_params.merge(options.authorize_options.inject({}){|h,k| h[k.to_sym] = options[k] if options[k]; h})
54+
session['omniauth.state'] = params[:state]
55+
params
5156
end
5257

5358
def token_params
@@ -58,6 +63,9 @@ def callback_phase
5863
if request.params['error'] || request.params['error_reason']
5964
raise CallbackError.new(request.params['error'], request.params['error_description'] || request.params['error_reason'], request.params['error_uri'])
6065
end
66+
if request.params['state'] != session.delete('omniauth.state')
67+
raise CallbackError.new(nil, :csrf_detected)
68+
end
6169

6270
self.access_token = build_access_token
6371
self.access_token = access_token.refresh! if access_token.expired?

spec/omniauth/strategies/oauth2_spec.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@ def app; lambda{|env| [200, {}, ["Hello."]]} end
2222
subject { fresh_strategy }
2323

2424
it 'should include any authorize params passed in the :authorize_params option' do
25-
instance = subject.new('abc', 'def', :authorize_params => {:foo => 'bar', :baz => 'zip'})
26-
instance.authorize_params.should == {'foo' => 'bar', 'baz' => 'zip'}
25+
instance = subject.new('abc', 'def', :authorize_params => {:foo => 'bar', :baz => 'zip', :state => '123'})
26+
instance.authorize_params.should == {'foo' => 'bar', 'baz' => 'zip', 'state' => '123'}
2727
end
2828

2929
it 'should include top-level options that are marked as :authorize_options' do
30-
instance = subject.new('abc', 'def', :authorize_options => [:scope, :foo], :scope => 'bar', :foo => 'baz')
31-
instance.authorize_params.should == {'scope' => 'bar', 'foo' => 'baz'}
30+
instance = subject.new('abc', 'def', :authorize_options => [:scope, :foo], :scope => 'bar', :foo => 'baz', :authorize_params => {:state => '123'})
31+
instance.authorize_params.should == {'scope' => 'bar', 'foo' => 'baz', 'state' => '123'}
32+
end
33+
34+
it 'should include random state in the authorize params' do
35+
instance = subject.new('abc', 'def')
36+
instance.authorize_params.keys.should == ['state']
37+
instance.session['omniauth.state'].should_not be_empty
38+
instance.session['omniauth.state'].should == instance.authorize_params['state']
3239
end
3340
end
3441

0 commit comments

Comments
 (0)