diff --git a/lib/omniauth/facebook/signed_request.rb b/lib/omniauth/facebook/signed_request.rb new file mode 100644 index 0000000..48e0634 --- /dev/null +++ b/lib/omniauth/facebook/signed_request.rb @@ -0,0 +1,37 @@ +require 'base64' +require 'openssl' + +module OmniAuth + module Facebook + class SignedRequest + class UnknownSignatureAlgorithmError < NotImplementedError; end + + SUPPORTED_ALGORITHM = 'HMAC-SHA256' + + def self.parse_signed_request(value, secret) + signature, encoded_payload = value.split('.') + return if signature.nil? + + decoded_hex_signature = base64_decode_url(signature) + decoded_payload = MultiJson.decode(base64_decode_url(encoded_payload)) + + unless decoded_payload['algorithm'] == SUPPORTED_ALGORITHM + raise UnknownSignatureAlgorithmError, "unknown algorithm: #{decoded_payload['algorithm']}" + end + + if valid_signature?(secret, decoded_hex_signature, encoded_payload) + decoded_payload + end + end + + def self.valid_signature?(secret, signature, payload, algorithm = OpenSSL::Digest::SHA256.new) + OpenSSL::HMAC.digest(algorithm, secret, payload) == signature + end + + def self.base64_decode_url(value) + value += '=' * (4 - value.size.modulo(4)) + Base64.decode64(value.tr('-_', '+/')) + end + end + end +end diff --git a/lib/omniauth/strategies/facebook.rb b/lib/omniauth/strategies/facebook.rb index c52516c..c7c6e38 100644 --- a/lib/omniauth/strategies/facebook.rb +++ b/lib/omniauth/strategies/facebook.rb @@ -1,45 +1,14 @@ require 'omniauth/strategies/oauth2' -require 'base64' +require 'omniauth/facebook/signed_request' require 'openssl' require 'rack/utils' require 'uri' module OmniAuth - module Utils - class UnknownSignatureAlgorithmError < NotImplementedError; end - - SUPPORTED_ALGORITHM = 'HMAC-SHA256' - - def Utils.parse_signed_request(value, secret) - signature, encoded_payload = value.split('.') - return if signature.nil? - - decoded_hex_signature = base64_decode_url(signature) - decoded_payload = MultiJson.decode(base64_decode_url(encoded_payload)) - - unless decoded_payload['algorithm'] == SUPPORTED_ALGORITHM - raise UnknownSignatureAlgorithmError, "unknown algorithm: #{decoded_payload['algorithm']}" - end - - if valid_signature?(secret, decoded_hex_signature, encoded_payload) - decoded_payload - end - end - - def Utils.valid_signature?(secret, signature, payload, algorithm = OpenSSL::Digest::SHA256.new) - OpenSSL::HMAC.digest(algorithm, secret, payload) == signature - end - - def Utils.base64_decode_url(value) - value += '=' * (4 - value.size.modulo(4)) - Base64.decode64(value.tr('-_', '+/')) - end - end - module Strategies class Facebook < OmniAuth::Strategies::OAuth2 class NoAuthorizationCodeError < StandardError; end - + DEFAULT_SCOPE = 'email' option :client_options, { @@ -103,7 +72,7 @@ module OmniAuth end rescue NoAuthorizationCodeError => e fail!(:no_authorization_code, e) - rescue Utils::UnknownSignatureAlgorithmError => e + rescue OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError => e fail!(:unknown_signature_algorithm, e) end @@ -149,7 +118,7 @@ module OmniAuth private def signed_request_from_cookie - @signed_request_from_cookie ||= raw_signed_request_from_cookie && Utils.parse_signed_request(raw_signed_request_from_cookie, client.secret) + @signed_request_from_cookie ||= raw_signed_request_from_cookie && OmniAuth::Facebook::SignedRequest.parse_signed_request(raw_signed_request_from_cookie, client.secret) end def raw_signed_request_from_cookie diff --git a/test/test.rb b/test/test.rb index f282e87..3a97803 100644 --- a/test/test.rb +++ b/test/test.rb @@ -437,7 +437,7 @@ module SignedRequestTests test 'throws an error if the algorithm is unknown' do setup('UNKNOWN-ALGO') - assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Utils::UnknownSignatureAlgorithmError) { strategy.send(:signed_request_from_cookie) }.message + assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError) { strategy.send(:signed_request_from_cookie) }.message end end @@ -497,7 +497,7 @@ module SignedRequestTests end test 'calls fail! when an algorithm is unknown' do - strategy.expects(:fail!).times(1).with(:unknown_signature_algorithm, kind_of(OmniAuth::Utils::UnknownSignatureAlgorithmError)) + strategy.expects(:fail!).times(1).with(:unknown_signature_algorithm, kind_of(OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError)) strategy.callback_phase end end