use state to avoid handshake spoofing

This commit is contained in:
Konstantin Haase 2012-09-18 16:36:06 +02:00
parent 05acb00c2e
commit e9523dc21d
2 changed files with 30 additions and 13 deletions

View File

@ -22,5 +22,9 @@ class Travis::Api::App
# TODO # TODO
User.where(:login => 'svenfuchs').first User.where(:login => 'svenfuchs').first
end end
def redis
Thread.current[:redis] ||= ::Redis.connect(url: Travis.config.redis.url)
end
end end
end end

View File

@ -1,6 +1,7 @@
require 'travis/api/app' require 'travis/api/app'
require 'addressable/uri' require 'addressable/uri'
require 'faraday' require 'faraday'
require 'securerandom'
class Travis::Api::App class Travis::Api::App
class Endpoint class Endpoint
@ -60,7 +61,7 @@ class Travis::Api::App
# #
# * **token**: GitHub token for checking authorization (required) # * **token**: GitHub token for checking authorization (required)
post '/github' do post '/github' do
{ 'access_token' => github_to_travis(params[:token]) } { 'access_token' => github_to_travis(params[:token], app_id: 1) }
end end
get '/post_message' do get '/post_message' do
@ -72,15 +73,16 @@ class Travis::Api::App
redirect_uri: url redirect_uri: url
} }
if params[:code] if params[:code] and state_ok?(params[:state])
endpoint.path = config.access_token_path endpoint.path = config.access_token_path
values[:state] = params[:state]
values[:code] = params[:code] values[:code] = params[:code]
values[:state] = params[:state] if params[:state]
values[:client_secret] = config.client_secret values[:client_secret] = config.client_secret
github_token = get_token(endpoint.to_s, values)
token = github_to_travis get_token(endpoint.to_s, values) token = github_to_travis(github_token, app_id: 0)
{ 'access_token' => token } { 'access_token' => token }
else else
values[:state] = create_state
endpoint.path = config.authorize_path endpoint.path = config.authorize_path
endpoint.query_values = values endpoint.query_values = values
redirect to(endpoint.to_s) redirect to(endpoint.to_s)
@ -93,7 +95,18 @@ class Travis::Api::App
private private
def github_to_travis(token) def create_state
state = SecureRandom.urlsafe_base64(16)
redis.sadd('github:states', state)
redis.expire('github:states', 1800)
state
end
def state_ok?(state)
redis.srem('github:states', state) if state
end
def github_to_travis(token, options = {})
data = GH.with(token: token.to_s) { GH['user'] } data = GH.with(token: token.to_s) { GH['user'] }
scopes = parse_scopes data.headers['x-oauth-scopes'] scopes = parse_scopes data.headers['x-oauth-scopes']
user = User.find_by_login(data['login']) user = User.find_by_login(data['login'])
@ -101,11 +114,11 @@ class Travis::Api::App
halt 403, 'not a Travis user' if user.nil? halt 403, 'not a Travis user' if user.nil?
halt 403, 'insufficient access' unless acceptable? scopes halt 403, 'insufficient access' unless acceptable? scopes
generate_token(user) generate_token options.merge(user: user)
end end
def get_token(endoint, value) def get_token(endoint, values)
response = Faraday.get(endoint, value) response = Faraday.post(endoint, values)
parameters = Addressable::URI.form_unencode(response.body) parameters = Addressable::URI.form_unencode(response.body)
parameters.assoc("access_token").last parameters.assoc("access_token").last
end end
@ -114,8 +127,8 @@ class Travis::Api::App
data.gsub(/\s/,'').split(',') if data data.gsub(/\s/,'').split(',') if data
end end
def generate_token(user) def generate_token(options)
AccessToken.create(user: user).token AccessToken.create(options).token
end end
def acceptable?(scopes) def acceptable?(scopes)