OpenAuth2 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
@@ -0,0 +1,3 @@
1
+ module OpenAuth2
2
+ VERSION = '0.0.1'
3
+ end
@@ -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
@@ -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
@@ -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