OpenAuth2 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/License +9 -0
- data/Rakefile +126 -0
- data/Readme.markdown +224 -0
- data/Spec.markdown +0 -0
- data/examples/fb.rb +9 -0
- data/examples/google.rb +53 -0
- data/lib/open_auth2.rb +33 -0
- data/lib/open_auth2/client.rb +182 -0
- data/lib/open_auth2/config.rb +102 -0
- data/lib/open_auth2/connection.rb +38 -0
- data/lib/open_auth2/delegate_to_config.rb +25 -0
- data/lib/open_auth2/provider.rb +21 -0
- data/lib/open_auth2/provider/base.rb +31 -0
- data/lib/open_auth2/provider/default.rb +18 -0
- data/lib/open_auth2/provider/facebook.rb +23 -0
- data/lib/open_auth2/provider/google.rb +28 -0
- data/lib/open_auth2/token.rb +150 -0
- data/lib/open_auth2/version.rb +3 -0
- data/open_auth2.gemspec +74 -0
- data/spec/client_spec.rb +110 -0
- data/spec/config_spec.rb +119 -0
- data/spec/facebook/client_spec.rb +82 -0
- data/spec/facebook/token_spec.rb +92 -0
- data/spec/fixtures/creds.rb +18 -0
- data/spec/fixtures/vcr/fb/access_token.yml +36 -0
- data/spec/fixtures/vcr/fb/cocacola.yml +68 -0
- data/spec/fixtures/vcr/fb/me.yml +36 -0
- data/spec/fixtures/vcr/fb/post.yml +34 -0
- data/spec/fixtures/vcr/fb/refresh_token.yml +36 -0
- data/spec/fixtures/vcr/goog/access_token.yml +38 -0
- data/spec/fixtures/vcr/goog/list.yml +50 -0
- data/spec/fixtures/vcr/goog/post.yml +44 -0
- data/spec/fixtures/vcr/goog/refresh_token.yml +37 -0
- data/spec/google/client_spec.rb +59 -0
- data/spec/google/token_spec.rb +87 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/token_spec.rb +23 -0
- metadata +179 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module OpenAuth2
|
2
|
+
module Provider
|
3
|
+
module Google
|
4
|
+
Options = {
|
5
|
+
:authorize_url => 'https://accounts.google.com',
|
6
|
+
:code_url => 'https://accounts.google.com',
|
7
|
+
:authorize_path => '/o/oauth2/auth',
|
8
|
+
:redirect_uri => 'http://localhost:9393/google/callback',
|
9
|
+
:token_path => '/o/oauth2/token',
|
10
|
+
:endpoint => 'https://www.googleapis.com'
|
11
|
+
}
|
12
|
+
|
13
|
+
def self.parse(config, body)
|
14
|
+
json = JSON.parse(body)
|
15
|
+
|
16
|
+
config.access_token = json['access_token']
|
17
|
+
config.token_arrived_at = Time.now
|
18
|
+
config.token_expires_at = Time.now+3600
|
19
|
+
|
20
|
+
# google sends refresh_token when getting access_token, but not
|
21
|
+
# when refreshing
|
22
|
+
unless config.refresh_token
|
23
|
+
config.refresh_token = json['refresh_token']
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module OpenAuth2
|
2
|
+
|
3
|
+
# Used to get Access/Refresh tokens from OAuth server.
|
4
|
+
class Token
|
5
|
+
extend DelegateToConfig
|
6
|
+
include Connection
|
7
|
+
|
8
|
+
# Use it to set @config. Unlike Client, no error is raised since
|
9
|
+
# this is not part of public api. This will be called from
|
10
|
+
# Client#token internally only.
|
11
|
+
#
|
12
|
+
# Accepts:
|
13
|
+
# config: OpenAuth2::Config object
|
14
|
+
#
|
15
|
+
# Returns: self.
|
16
|
+
#
|
17
|
+
def initialize(config)
|
18
|
+
@config = config
|
19
|
+
@faraday_url = authorize_url
|
20
|
+
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# Packages the info from config & passed in arguments into an url
|
25
|
+
# that user has to visit to authorize this app.
|
26
|
+
#
|
27
|
+
# Examples:
|
28
|
+
# token.build_code_url
|
29
|
+
# #=> 'http://...'
|
30
|
+
#
|
31
|
+
# # or
|
32
|
+
# token.build_code_url(:scope => 'publish_stream')
|
33
|
+
#
|
34
|
+
# Accepts:
|
35
|
+
# params: (optional) Hash of additional config to be bundled into
|
36
|
+
# the url.
|
37
|
+
#
|
38
|
+
# Returns: String (url).
|
39
|
+
#
|
40
|
+
def build_code_url(params={})
|
41
|
+
url = URI::HTTPS.build(:host => host,
|
42
|
+
:path => authorize_path,
|
43
|
+
:query => encoded_body(params))
|
44
|
+
|
45
|
+
url.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
# Make request to OAuth server for access token & ask @config to
|
49
|
+
# parse it. @config delegates that to the appropriate provider.
|
50
|
+
#
|
51
|
+
# We ask @config since the format of response differs between
|
52
|
+
# OAuth servers widely.
|
53
|
+
#
|
54
|
+
# Accepts:
|
55
|
+
# params: (optional) Hash of additional config to be sent with
|
56
|
+
# request.
|
57
|
+
#
|
58
|
+
# Returns: ?.
|
59
|
+
#
|
60
|
+
def get(params={})
|
61
|
+
body = get_body_hash(params)
|
62
|
+
raw_request = post(body)
|
63
|
+
|
64
|
+
parse(raw_request)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Make request to OAuth server to refresh the access token &
|
68
|
+
# ask @config to parse it.
|
69
|
+
#
|
70
|
+
# Accepts:
|
71
|
+
# params: (optional) Hash of additional config to be sent with
|
72
|
+
# request.
|
73
|
+
#
|
74
|
+
# Returns: ?.
|
75
|
+
#
|
76
|
+
def refresh(params={})
|
77
|
+
body = refresh_body_hash(params)
|
78
|
+
raw_request = post(body)
|
79
|
+
|
80
|
+
parse(raw_request)
|
81
|
+
end
|
82
|
+
|
83
|
+
def token_expired?
|
84
|
+
token_expires_at > Time.now
|
85
|
+
rescue
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
# We use URI#parse to get rid of those pesky extra /.
|
92
|
+
def host
|
93
|
+
URI.parse(code_url).host
|
94
|
+
end
|
95
|
+
|
96
|
+
# Make travel safe.
|
97
|
+
def encoded_body(params)
|
98
|
+
URI.encode_www_form(url_body_hash(params))
|
99
|
+
end
|
100
|
+
|
101
|
+
# Combine default options & user arguments.
|
102
|
+
def url_body_hash(params)
|
103
|
+
|
104
|
+
# user can define scope as String or Array
|
105
|
+
joined_scope = scope.join(',') if scope.respond_to?(:join)
|
106
|
+
|
107
|
+
{
|
108
|
+
:response_type => response_type,
|
109
|
+
:client_id => client_id,
|
110
|
+
:redirect_uri => redirect_uri,
|
111
|
+
:scope => joined_scope
|
112
|
+
}.merge(params)
|
113
|
+
end
|
114
|
+
|
115
|
+
# TODO: learn about merge vs merge!
|
116
|
+
def get_body_hash(params)
|
117
|
+
{
|
118
|
+
:client_id => client_id,
|
119
|
+
:client_secret => client_secret,
|
120
|
+
:code => code,
|
121
|
+
:grant_type => access_token_grant_name,
|
122
|
+
:redirect_uri => redirect_uri
|
123
|
+
}.merge(params)
|
124
|
+
end
|
125
|
+
|
126
|
+
def refresh_body_hash(params)
|
127
|
+
{
|
128
|
+
:client_id => client_id,
|
129
|
+
:client_secret => client_secret,
|
130
|
+
:grant_type => refresh_token_grant_name,
|
131
|
+
refresh_token_name => refresh_token
|
132
|
+
}.merge(params)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Makes the actual request. connection is the Faraday object.
|
136
|
+
def post(body)
|
137
|
+
connection.post do |conn|
|
138
|
+
conn.headers["Content-Type"] = "application/x-www-form-urlencoded"
|
139
|
+
conn.headers["Accept"] = "application/json"
|
140
|
+
conn.url(token_path)
|
141
|
+
conn.body = body
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def parse(response)
|
146
|
+
@config.parse(response.body)
|
147
|
+
response
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/open_auth2.gemspec
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require './lib/open_auth2/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "OpenAuth2"
|
6
|
+
s.version = OpenAuth2::VERSION
|
7
|
+
s.authors = ["Senthil A"]
|
8
|
+
s.email = ["senthil196@gmail.com"]
|
9
|
+
s.homepage = "https://github.com/senthilnambi/OpenAuth2"
|
10
|
+
s.description = %q{OpenAuth2 is a thin OAuth2 wrapper written on top of Faraday in Ruby.}
|
11
|
+
s.summary = %q{OpenAuth2 is a thin OAuth2 wrapper written on top of Faraday in Ruby. The goal is a simple, well documented, easy to use interface for all your OAuth2 needs.}
|
12
|
+
|
13
|
+
s.rubyforge_project = "OpenAuth2"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map do |f|
|
18
|
+
File.basename(f)
|
19
|
+
end
|
20
|
+
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_dependency 'faraday', '~> 0.7'
|
24
|
+
s.add_dependency 'activesupport', '~> 3.2'
|
25
|
+
|
26
|
+
s.add_development_dependency 'rake', '~> 0.9'
|
27
|
+
s.add_development_dependency 'rspec', '~> 2.8'
|
28
|
+
s.add_development_dependency 'vcr', '~> 1.11'
|
29
|
+
s.add_development_dependency 'fakeweb', '~> 1.3'
|
30
|
+
s.add_development_dependency 'timecop', '~> 0.3'
|
31
|
+
|
32
|
+
# = MANIFEST =
|
33
|
+
s.files = %w[
|
34
|
+
Gemfile
|
35
|
+
License
|
36
|
+
Rakefile
|
37
|
+
Readme.markdown
|
38
|
+
Spec.markdown
|
39
|
+
examples/fb.rb
|
40
|
+
examples/google.rb
|
41
|
+
lib/open_auth2.rb
|
42
|
+
lib/open_auth2/client.rb
|
43
|
+
lib/open_auth2/config.rb
|
44
|
+
lib/open_auth2/connection.rb
|
45
|
+
lib/open_auth2/delegate_to_config.rb
|
46
|
+
lib/open_auth2/provider.rb
|
47
|
+
lib/open_auth2/provider/base.rb
|
48
|
+
lib/open_auth2/provider/default.rb
|
49
|
+
lib/open_auth2/provider/facebook.rb
|
50
|
+
lib/open_auth2/provider/google.rb
|
51
|
+
lib/open_auth2/token.rb
|
52
|
+
lib/open_auth2/version.rb
|
53
|
+
open_auth2.gemspec
|
54
|
+
spec/client_spec.rb
|
55
|
+
spec/config_spec.rb
|
56
|
+
spec/facebook/client_spec.rb
|
57
|
+
spec/facebook/token_spec.rb
|
58
|
+
spec/fixtures/creds.rb
|
59
|
+
spec/fixtures/vcr/fb/access_token.yml
|
60
|
+
spec/fixtures/vcr/fb/cocacola.yml
|
61
|
+
spec/fixtures/vcr/fb/me.yml
|
62
|
+
spec/fixtures/vcr/fb/post.yml
|
63
|
+
spec/fixtures/vcr/fb/refresh_token.yml
|
64
|
+
spec/fixtures/vcr/goog/access_token.yml
|
65
|
+
spec/fixtures/vcr/goog/list.yml
|
66
|
+
spec/fixtures/vcr/goog/post.yml
|
67
|
+
spec/fixtures/vcr/goog/refresh_token.yml
|
68
|
+
spec/google/client_spec.rb
|
69
|
+
spec/google/token_spec.rb
|
70
|
+
spec/spec_helper.rb
|
71
|
+
spec/token_spec.rb
|
72
|
+
]
|
73
|
+
# = MANIFEST =
|
74
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'open_auth2'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe OpenAuth2::Client do
|
5
|
+
let(:config) do
|
6
|
+
OpenAuth2::Config.new do |c|
|
7
|
+
c.provider = :facebook
|
8
|
+
c.access_token = :access_token
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context '#initialize' do
|
13
|
+
it 'accepts config as argument' do
|
14
|
+
subject = described_class.new(config)
|
15
|
+
subject.config.should == config
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'accepts config via block' do
|
19
|
+
subject = described_class.new do |c|
|
20
|
+
c.config = config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'raises NoConfigObject' do
|
25
|
+
expect do
|
26
|
+
subject = described_class.new
|
27
|
+
end.to raise_error(OpenAuth2::NoConfigObject)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'raises UnknownConfigObject' do
|
31
|
+
expect do
|
32
|
+
subject = described_class.new('string')
|
33
|
+
end.to raise_error(OpenAuth2::UnknownConfigObject)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sets @faraday_url' do
|
37
|
+
subject.faraday_url.should == 'https://graph.facebook.com'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context '#configure' do
|
42
|
+
it 'accepts a block to set/overwrite config' do
|
43
|
+
subject.configure do |c|
|
44
|
+
c.access_token = :access_token
|
45
|
+
c.refresh_token = :refresh_token
|
46
|
+
end
|
47
|
+
|
48
|
+
subject.access_token.should == :access_token
|
49
|
+
subject.refresh_token.should == :refresh_token
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'raises NoConfigObject' do
|
53
|
+
expect do
|
54
|
+
subject = described_class.new(config)
|
55
|
+
subject.configure {|c| c.config = nil }
|
56
|
+
end.to raise_error(OpenAuth2::NoConfigObject)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises UnknownConfigObject' do
|
60
|
+
expect do
|
61
|
+
subject = described_class.new(config)
|
62
|
+
subject.configure {|c| c.config = 'string' }
|
63
|
+
end.to raise_error(OpenAuth2::UnknownConfigObject)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context '#token' do
|
68
|
+
it 'returns OpenAuth2::Token object' do
|
69
|
+
subject.token.should be_an(OpenAuth2::Token)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context '#build_code_url' do
|
74
|
+
it 'delegates to OpenAuth2::Token' do
|
75
|
+
OpenAuth2::Token.any_instance.should_receive(:build_code_url)
|
76
|
+
subject.build_code_url
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
subject { described_class.new(config) }
|
81
|
+
|
82
|
+
context OpenAuth2::DelegateToConfig do
|
83
|
+
it 'delegates Options getter methods' do
|
84
|
+
subject.authorize_url.should == 'https://graph.facebook.com'
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'delegates Options setter methods' do
|
88
|
+
url = 'http://facebook.com'
|
89
|
+
subject.authorize_url = url
|
90
|
+
|
91
|
+
subject.authorize_url.should == url
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'overwritten Options stays that way' do
|
95
|
+
config.access_token.should == :access_token
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context OpenAuth2::Connection do
|
100
|
+
it 'returns Faraday::Connection object' do
|
101
|
+
subject.connection.should be_a(Faraday::Connection)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'yields Faraday::Connection object' do
|
105
|
+
subject.connection do |f|
|
106
|
+
f.response :logger
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'open_auth2'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe OpenAuth2::Config do
|
5
|
+
subject { described_class.new }
|
6
|
+
|
7
|
+
it 'overwrites default values' do
|
8
|
+
overwrite_response_type
|
9
|
+
subject.response_type.should == :overwritten
|
10
|
+
end
|
11
|
+
|
12
|
+
context '#initialize' do
|
13
|
+
subject do
|
14
|
+
described_class.new do |c|
|
15
|
+
c.client_id = :set_in_new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'sets default as provider' do
|
20
|
+
subject.provider.should == :default
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'accepts a block to set config' do
|
24
|
+
subject.client_id.should == :set_in_new
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context '#configure' do
|
29
|
+
it 'accepts a block to set/overwrite config' do
|
30
|
+
subject.configure do |c|
|
31
|
+
c.client_id = :set_in_configure
|
32
|
+
end
|
33
|
+
|
34
|
+
subject.client_id.should == :set_in_configure
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context '#provider=' do
|
39
|
+
before do
|
40
|
+
subject.provider = :facebook
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'sets provider' do
|
44
|
+
subject.provider.should == :facebook
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'sets provider_string' do
|
48
|
+
subject.provider_string.should == 'facebook'
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:facebook_const) do
|
52
|
+
OpenAuth2::Provider::Facebook
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'sets provider_const' do
|
56
|
+
subject.provider_const.should == facebook_const
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'copies over options from provider' do
|
60
|
+
subject.authorize_url.should == 'https://graph.facebook.com'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'keeps non-overlapping default options' do
|
64
|
+
subject.response_type.should == 'code'
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'overwrites overlapping default options' do
|
68
|
+
subject.refresh_token_name.should == 'fb_exchange_token'
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'raises UnknownProvider if arg is not in list of providers' do
|
72
|
+
expect do
|
73
|
+
subject.provider = :unknown
|
74
|
+
end.to raise_error(OpenAuth2::UnknownProvider)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'provides list of known providers with UnknownProvider' do
|
78
|
+
# mimicking beh. of users including their own provider
|
79
|
+
module OpenAuth2::Provider module UserDefined end end
|
80
|
+
|
81
|
+
providers = [:Default, :Facebook, :Google, :UserDefined]
|
82
|
+
error_message = "Known Providers: #{providers}"
|
83
|
+
|
84
|
+
expect do
|
85
|
+
subject.provider = :unknown
|
86
|
+
end.to raise_error(OpenAuth2::UnknownProvider, error_message)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
let(:overwrite_response_type) do
|
91
|
+
subject.configure do |c|
|
92
|
+
c.response_type = :overwritten
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context '#reset_provider' do
|
97
|
+
it 'resets locally set values' do
|
98
|
+
overwrite_response_type
|
99
|
+
subject.reset_provider
|
100
|
+
|
101
|
+
subject.response_type.should == 'code'
|
102
|
+
end
|
103
|
+
|
104
|
+
let(:set_to_fb_and_reset) do
|
105
|
+
subject.provider = :facebook
|
106
|
+
subject.reset_provider
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'resets provider to default' do
|
110
|
+
set_to_fb_and_reset
|
111
|
+
subject.provider.should == :default
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'resets all config to default values' do
|
115
|
+
set_to_fb_and_reset
|
116
|
+
subject.authorize_url.should == nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|