Move Utils to SignedRequest class.
Josef Šimánek
9 years ago
0 | require 'base64' | |
1 | require 'openssl' | |
2 | ||
3 | module OmniAuth | |
4 | module Facebook | |
5 | class SignedRequest | |
6 | class UnknownSignatureAlgorithmError < NotImplementedError; end | |
7 | ||
8 | SUPPORTED_ALGORITHM = 'HMAC-SHA256' | |
9 | ||
10 | def self.parse_signed_request(value, secret) | |
11 | signature, encoded_payload = value.split('.') | |
12 | return if signature.nil? | |
13 | ||
14 | decoded_hex_signature = base64_decode_url(signature) | |
15 | decoded_payload = MultiJson.decode(base64_decode_url(encoded_payload)) | |
16 | ||
17 | unless decoded_payload['algorithm'] == SUPPORTED_ALGORITHM | |
18 | raise UnknownSignatureAlgorithmError, "unknown algorithm: #{decoded_payload['algorithm']}" | |
19 | end | |
20 | ||
21 | if valid_signature?(secret, decoded_hex_signature, encoded_payload) | |
22 | decoded_payload | |
23 | end | |
24 | end | |
25 | ||
26 | def self.valid_signature?(secret, signature, payload, algorithm = OpenSSL::Digest::SHA256.new) | |
27 | OpenSSL::HMAC.digest(algorithm, secret, payload) == signature | |
28 | end | |
29 | ||
30 | def self.base64_decode_url(value) | |
31 | value += '=' * (4 - value.size.modulo(4)) | |
32 | Base64.decode64(value.tr('-_', '+/')) | |
33 | end | |
34 | end | |
35 | end | |
36 | end |
0 | 0 | require 'omniauth/strategies/oauth2' |
1 | require 'base64' | |
1 | require 'omniauth/facebook/signed_request' | |
2 | 2 | require 'openssl' |
3 | 3 | require 'rack/utils' |
4 | 4 | require 'uri' |
5 | 5 | |
6 | 6 | module OmniAuth |
7 | module Utils | |
8 | class UnknownSignatureAlgorithmError < NotImplementedError; end | |
9 | ||
10 | SUPPORTED_ALGORITHM = 'HMAC-SHA256' | |
11 | ||
12 | def Utils.parse_signed_request(value, secret) | |
13 | signature, encoded_payload = value.split('.') | |
14 | return if signature.nil? | |
15 | ||
16 | decoded_hex_signature = base64_decode_url(signature) | |
17 | decoded_payload = MultiJson.decode(base64_decode_url(encoded_payload)) | |
18 | ||
19 | unless decoded_payload['algorithm'] == SUPPORTED_ALGORITHM | |
20 | raise UnknownSignatureAlgorithmError, "unknown algorithm: #{decoded_payload['algorithm']}" | |
21 | end | |
22 | ||
23 | if valid_signature?(secret, decoded_hex_signature, encoded_payload) | |
24 | decoded_payload | |
25 | end | |
26 | end | |
27 | ||
28 | def Utils.valid_signature?(secret, signature, payload, algorithm = OpenSSL::Digest::SHA256.new) | |
29 | OpenSSL::HMAC.digest(algorithm, secret, payload) == signature | |
30 | end | |
31 | ||
32 | def Utils.base64_decode_url(value) | |
33 | value += '=' * (4 - value.size.modulo(4)) | |
34 | Base64.decode64(value.tr('-_', '+/')) | |
35 | end | |
36 | end | |
37 | ||
38 | 7 | module Strategies |
39 | 8 | class Facebook < OmniAuth::Strategies::OAuth2 |
40 | 9 | class NoAuthorizationCodeError < StandardError; end |
41 | ||
10 | ||
42 | 11 | DEFAULT_SCOPE = 'email' |
43 | 12 | |
44 | 13 | option :client_options, { |
102 | 71 | end |
103 | 72 | rescue NoAuthorizationCodeError => e |
104 | 73 | fail!(:no_authorization_code, e) |
105 | rescue Utils::UnknownSignatureAlgorithmError => e | |
74 | rescue OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError => e | |
106 | 75 | fail!(:unknown_signature_algorithm, e) |
107 | 76 | end |
108 | 77 | |
148 | 117 | private |
149 | 118 | |
150 | 119 | def signed_request_from_cookie |
151 | @signed_request_from_cookie ||= raw_signed_request_from_cookie && Utils.parse_signed_request(raw_signed_request_from_cookie, client.secret) | |
120 | @signed_request_from_cookie ||= raw_signed_request_from_cookie && OmniAuth::Facebook::SignedRequest.parse_signed_request(raw_signed_request_from_cookie, client.secret) | |
152 | 121 | end |
153 | 122 | |
154 | 123 | def raw_signed_request_from_cookie |
436 | 436 | |
437 | 437 | test 'throws an error if the algorithm is unknown' do |
438 | 438 | setup('UNKNOWN-ALGO') |
439 | assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Utils::UnknownSignatureAlgorithmError) { strategy.send(:signed_request_from_cookie) }.message | |
439 | assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError) { strategy.send(:signed_request_from_cookie) }.message | |
440 | 440 | end |
441 | 441 | end |
442 | 442 | |
496 | 496 | end |
497 | 497 | |
498 | 498 | test 'calls fail! when an algorithm is unknown' do |
499 | strategy.expects(:fail!).times(1).with(:unknown_signature_algorithm, kind_of(OmniAuth::Utils::UnknownSignatureAlgorithmError)) | |
499 | strategy.expects(:fail!).times(1).with(:unknown_signature_algorithm, kind_of(OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError)) | |
500 | 500 | strategy.callback_phase |
501 | 501 | end |
502 | 502 | end |