1
0
Fork 0
mirror of https://github.com/nov/fb_graph2 synced 2023-03-27 23:22:15 -04:00

signed request support

close #33
This commit is contained in:
nov 2015-02-06 16:13:41 +09:00
parent ac2f43b9b3
commit 30ebf9b406
5 changed files with 190 additions and 56 deletions

View file

@ -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'

View file

@ -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'

View file

@ -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

View 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

View file

@ -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