mirror of
https://github.com/nov/fb_graph2
synced 2023-03-27 23:22:15 -04:00
parent
ac2f43b9b3
commit
30ebf9b406
5 changed files with 190 additions and 56 deletions
|
@ -15,6 +15,7 @@ Gem::Specification.new do |gem|
|
|||
|
||||
gem.add_runtime_dependency 'httpclient', '>= 2.4'
|
||||
gem.add_runtime_dependency 'rack-oauth2', '>= 1.0'
|
||||
gem.add_runtime_dependency 'url_safe_base64'
|
||||
gem.add_runtime_dependency 'multi_json'
|
||||
gem.add_runtime_dependency 'activesupport', '>= 3.2'
|
||||
gem.add_development_dependency 'rake'
|
||||
|
|
|
@ -40,6 +40,7 @@ module FbGraph2
|
|||
end
|
||||
end
|
||||
|
||||
require 'fb_graph2/exception'
|
||||
require 'fb_graph2/attribute_assigner'
|
||||
require 'fb_graph2/node'
|
||||
require 'fb_graph2/collection'
|
||||
|
|
|
@ -37,5 +37,23 @@ module FbGraph2
|
|||
input_token: input_token.to_s
|
||||
)
|
||||
end
|
||||
|
||||
def from_cookie(cookie)
|
||||
token = case cookie
|
||||
when String
|
||||
cookie
|
||||
else
|
||||
cookie["fbsr_#{identifier}"]
|
||||
end
|
||||
from_signed_request token
|
||||
end
|
||||
|
||||
def from_signed_request(token)
|
||||
SignedRequest.new(token).verify! self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Dir[File.join(__dir__, 'auth/*.rb')].each do |file|
|
||||
require file
|
||||
end
|
40
lib/fb_graph2/auth/signed_request.rb
Normal file
40
lib/fb_graph2/auth/signed_request.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
require 'url_safe_base64'
|
||||
|
||||
module FbGraph2
|
||||
class Auth
|
||||
class SignedRequest
|
||||
class VerificationFailed < Exception::BadRequest; end
|
||||
|
||||
attr_accessor :payload, :access_token, :user
|
||||
|
||||
def initialize(token)
|
||||
signature_str, @payload_str = token.split('.', 2)
|
||||
@signature = UrlSafeBase64.decode64 signature_str
|
||||
payload_json = UrlSafeBase64.decode64 @payload_str
|
||||
self.payload = MultiJson.load(payload_json).with_indifferent_access
|
||||
rescue => e
|
||||
raise VerificationFailed.new 'Decode failed'
|
||||
end
|
||||
|
||||
def verify!(client)
|
||||
digest = OpenSSL::Digest::SHA256.new
|
||||
signature = OpenSSL::HMAC.digest OpenSSL::Digest::SHA256.new, client.secret, @payload_str
|
||||
raise VerificationFailed.new('Verification failed') unless @signature == signature
|
||||
instantiate client
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def instantiate(client)
|
||||
if payload[:code].present?
|
||||
client.authorization_code = payload[:code]
|
||||
self.access_token = client.access_token!
|
||||
else
|
||||
self.access_token = payload[:oauth_token]
|
||||
end
|
||||
self.user = User.new(payload[:user_id], payload[:user] || {}).authenticate(access_token)
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +1,78 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe FbGraph2::Auth do
|
||||
describe '.app' do
|
||||
subject { instance }
|
||||
let(:instance) { FbGraph2::Auth.new 'client_id', 'client_secret' }
|
||||
subject { instance }
|
||||
let(:instance) { FbGraph2::Auth.new 'client_id', 'client_secret' }
|
||||
|
||||
it { should be_a Rack::OAuth2::Client }
|
||||
it { should be_a Rack::OAuth2::Client }
|
||||
|
||||
describe 'fb_exchange_token grant' do
|
||||
describe '#debug_token!' do
|
||||
before do
|
||||
mock_graph :post, 'oauth/access_token', 'token_response', params: {
|
||||
grant_type: 'client_credentials',
|
||||
client_id: 'client_id',
|
||||
client_secret: 'client_secret'
|
||||
}, disable_api_versioning: true
|
||||
end
|
||||
|
||||
context 'when user_token given' do
|
||||
subject do
|
||||
mock_graph :get, 'debug_token', 'token_metadata/user_token', params: {
|
||||
input_token: 'user_token'
|
||||
} do
|
||||
instance.debug_token! 'user_token'
|
||||
end
|
||||
end
|
||||
it { should be_instance_of FbGraph2::TokenMetadata }
|
||||
its(:app) { should be_instance_of FbGraph2::App }
|
||||
its(:user) { should be_instance_of FbGraph2::User }
|
||||
its(:page) { should be_nil }
|
||||
end
|
||||
|
||||
context 'when app_token given' do
|
||||
subject do
|
||||
mock_graph :get, 'debug_token', 'token_metadata/app_token', params: {
|
||||
input_token: 'app_token'
|
||||
} do
|
||||
instance.debug_token! 'app_token'
|
||||
end
|
||||
end
|
||||
it { should be_instance_of FbGraph2::TokenMetadata }
|
||||
its(:app) { should be_instance_of FbGraph2::App }
|
||||
its(:user) { should be_nil }
|
||||
its(:page) { should be_nil }
|
||||
end
|
||||
|
||||
context 'when page_token given' do
|
||||
subject do
|
||||
mock_graph :get, 'debug_token', 'token_metadata/page_token', params: {
|
||||
input_token: 'page_token'
|
||||
} do
|
||||
instance.debug_token! 'page_token'
|
||||
end
|
||||
end
|
||||
it { should be_instance_of FbGraph2::TokenMetadata }
|
||||
its(:app) { should be_instance_of FbGraph2::App }
|
||||
its(:user) { should be_instance_of FbGraph2::User }
|
||||
its(:page) { should be_instance_of FbGraph2::Page }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#access_token!' do
|
||||
context 'when error occured' do
|
||||
it do
|
||||
expect do
|
||||
mock_graph :post, 'oauth/access_token', 'error/400/191', status: [400, 'Bad Request'], disable_api_versioning: true do
|
||||
instance.authorization_code = 'auth_code'
|
||||
instance.access_token!
|
||||
end
|
||||
end.to raise_error(FbGraph2::Exception) do |e|
|
||||
e.message.should == 'Missing redirect_uri parameter.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when fb_exchange_token grant given' do
|
||||
it do
|
||||
instance.fb_exchange_token = 'short_lived_access_token'
|
||||
access_token = mock_graph :post, 'oauth/access_token', 'token_response', params: {
|
||||
|
@ -21,69 +86,78 @@ describe FbGraph2::Auth do
|
|||
access_token.should be_instance_of Rack::OAuth2::AccessToken::Legacy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#debug_token!' do
|
||||
before do
|
||||
mock_graph :post, 'oauth/access_token', 'token_response', params: {
|
||||
grant_type: 'client_credentials',
|
||||
describe '#from_cookie' do
|
||||
let(:token) do
|
||||
'9heZHFs6tDH/Nif4CqmBaMQ8nKEOc5g2WgVJa10LF00.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImNvZGUiOiI4ZDYwZDY4NDA4MmQ1NjczMjY3MWUxNzAuMS01Nzk2MTIyNzZ8N2pkVlp6MlNLNUY2b0gtQ21FQWtZZVpuVjEwIiwiaXNzdWVkX2F0IjoxMzEyOTUzOTcxLCJ1c2VyX2lkIjo1Nzk2MTIyNzZ9'
|
||||
end
|
||||
|
||||
it 'should return FbGraph2::Auth::SignedRequest' do
|
||||
signed_request = mock_graph :post, 'oauth/access_token', 'token_response', params: {
|
||||
grant_type: 'authorization_code',
|
||||
code: '8d60d684082d56732671e170.1-579612276|7jdVZz2SK5F6oH-CmEAkYeZnV10',
|
||||
client_id: 'client_id',
|
||||
client_secret: 'client_secret'
|
||||
}, disable_api_versioning: true do
|
||||
instance.from_cookie token
|
||||
end
|
||||
signed_request.should be_instance_of FbGraph2::Auth::SignedRequest
|
||||
signed_request.access_token.should be_instance_of Rack::OAuth2::AccessToken::Legacy
|
||||
signed_request.access_token.access_token.should == 'access_token'
|
||||
signed_request.user.should be_instance_of FbGraph2::User
|
||||
end
|
||||
|
||||
context 'when cookie object given' do
|
||||
let(:cookie) do
|
||||
{'fbsr_client_id' => token}
|
||||
end
|
||||
|
||||
it 'should handle it too' do
|
||||
signed_request = mock_graph :post, 'oauth/access_token', 'token_response', params: {
|
||||
grant_type: 'authorization_code',
|
||||
code: '8d60d684082d56732671e170.1-579612276|7jdVZz2SK5F6oH-CmEAkYeZnV10',
|
||||
client_id: 'client_id',
|
||||
client_secret: 'client_secret'
|
||||
}, disable_api_versioning: true
|
||||
end
|
||||
|
||||
context 'when user_token given' do
|
||||
subject do
|
||||
mock_graph :get, 'debug_token', 'token_metadata/user_token', params: {
|
||||
input_token: 'user_token'
|
||||
} do
|
||||
instance.debug_token! 'user_token'
|
||||
end
|
||||
}, disable_api_versioning: true do
|
||||
instance.from_cookie cookie
|
||||
end
|
||||
it { should be_instance_of FbGraph2::TokenMetadata }
|
||||
its(:app) { should be_instance_of FbGraph2::App }
|
||||
its(:user) { should be_instance_of FbGraph2::User }
|
||||
its(:page) { should be_nil }
|
||||
signed_request.should be_instance_of FbGraph2::Auth::SignedRequest
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when app_token given' do
|
||||
subject do
|
||||
mock_graph :get, 'debug_token', 'token_metadata/app_token', params: {
|
||||
input_token: 'app_token'
|
||||
} do
|
||||
instance.debug_token! 'app_token'
|
||||
end
|
||||
end
|
||||
it { should be_instance_of FbGraph2::TokenMetadata }
|
||||
its(:app) { should be_instance_of FbGraph2::App }
|
||||
its(:user) { should be_nil }
|
||||
its(:page) { should be_nil }
|
||||
end
|
||||
describe '#from_signed_request' do
|
||||
let(:token) do
|
||||
'LqsgnfcsRdfjOgyW6ZuSLpGBVsxUBegEqai4EcrWS0A=.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjAsImlzc3VlZF9hdCI6MTI5ODc4MzczOSwib2F1dGhfdG9rZW4iOiIxMzQxNDU2NDMyOTQzMjJ8MmI4YTZmOTc1NTJjNmRjZWQyMDU4MTBiLTU3OTYxMjI3NnxGS1o0akdKZ0JwN2k3bFlrOVhhUk1QZ3lhNnMiLCJ1c2VyIjp7ImNvdW50cnkiOiJqcCIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjU3OTYxMjI3NiJ9'
|
||||
end
|
||||
|
||||
context 'when page_token given' do
|
||||
subject do
|
||||
mock_graph :get, 'debug_token', 'token_metadata/page_token', params: {
|
||||
input_token: 'page_token'
|
||||
} do
|
||||
instance.debug_token! 'page_token'
|
||||
end
|
||||
end
|
||||
it { should be_instance_of FbGraph2::TokenMetadata }
|
||||
its(:app) { should be_instance_of FbGraph2::App }
|
||||
its(:user) { should be_instance_of FbGraph2::User }
|
||||
its(:page) { should be_instance_of FbGraph2::Page }
|
||||
it 'should return FbGraph2::Auth::SignedRequest' do
|
||||
signed_request = instance.from_signed_request token
|
||||
signed_request.should be_instance_of FbGraph2::Auth::SignedRequest
|
||||
signed_request.access_token.should == '134145643294322|2b8a6f97552c6dced205810b-579612276|FKZ4jGJgBp7i7lYk9XaRMPgya6s'
|
||||
signed_request.user.should be_instance_of FbGraph2::User
|
||||
end
|
||||
|
||||
context 'when invalid format' do
|
||||
let(:token) { 'invalid.invalid' }
|
||||
|
||||
it do
|
||||
expect do
|
||||
instance.from_cookie token
|
||||
end.to raise_error FbGraph2::Auth::SignedRequest::VerificationFailed
|
||||
end
|
||||
end
|
||||
|
||||
context 'when error occured' do
|
||||
context 'when signature invalid' do
|
||||
let(:token) do
|
||||
'4Xnb6TwumZfUQcrflVQHYLOmaWq1oMHbZmI7_pxZXeU.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjE0MjMwNDQwMDAsImlzc3VlZF9hdCI6MTQyMzAzNjk3MSwib2F1dGhfdG9rZW4iOiJDQUFDWkN1RXk5ZHBVQkFKUDFJY3BMaThGaU04RnBpcjB2clBmZjhaQXQxblpCSGdyMG9pTUdNVXNBaU9ZZ0F4NkpibkZrMXNJSW95ZjRYMktKSHlVc2ROcmhCd1UwanBoUGFPQzU0bGw4emVMWkFScFZ0b0RYY3FIZE9lNGZjdGVmMHZ5eXdsU0NrTkhIWGdmSDhaQVNUZ1JvQlpCbmRqVHpmQXVtMjFGMFpDdUtZWExDY1pBZ1VEeXJ3d0piekVuYVJybWFxZ2s3VFhOZ3cwZlJaQmVNVVpCM1Q0VG1DMktXU3laQ1laRCIsInRva2VuX2Zvcl9idXNpbmVzcyI6IkFieUR4YVF0cTVPSEVfN04iLCJ1c2VyIjp7ImNvdW50cnkiOiJqcCIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjU3OTYxMjI3NiJ9'
|
||||
end
|
||||
|
||||
it do
|
||||
expect do
|
||||
mock_graph :post, 'oauth/access_token', 'error/400/191', status: [400, 'Bad Request'], disable_api_versioning: true do
|
||||
instance.authorization_code = 'auth_code'
|
||||
instance.access_token!
|
||||
end
|
||||
end.to raise_error(FbGraph2::Exception) do |e|
|
||||
e.message.should == 'Missing redirect_uri parameter.'
|
||||
end
|
||||
instance.from_cookie token
|
||||
end.to raise_error FbGraph2::Auth::SignedRequest::VerificationFailed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue