panjiva-oauth2 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZTRiNmRhZTJhZjVlNTY5ZDU1MDQzZjEyNDg1NzRhM2QyYWJlOTIxMw==
5
+ data.tar.gz: !binary |-
6
+ NTI0MjQ4MzBkYTlmM2ExZTZjZDg5ODgzMDZiYjZhMjUyZWM4M2RmMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MTJkYTgzNjM2MTQ3YzVkYTk0YTNhNDFmZDQwZjNlNmE2NjBmM2I4Y2RhMWI1
10
+ Njk0NjA1N2ViZjI0NzA3Njc2NDkwMTY0OThmM2ZkMjFjNTQzZjY5NmZlNTEw
11
+ Y2NkNTdmYTEyOWFjMzJkMGRjNGRjMGI2NWM2YWRjZTAyYTBmMjI=
12
+ data.tar.gz: !binary |-
13
+ OTFiNzYwMDY4ZWQxZWEwMzBmYmM4YThiOTM0ZTA5OTk3ZGY2OTBmYmYyOGEy
14
+ MTYyYTkyZWE3YjA5ZGY2OWJmOGMyYTY1ZTJmMmQ4OTlmMmU0ZGZjYzMzZTc2
15
+ NDkyYTVhMWVkMjAxMmI4M2M5NTZlMGJjZDU4MWJhYjRhZjVhYWM=
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gemtest ADDED
File without changes
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ .rvmrc
2
+ /live
3
+
4
+ ## MAC OS
5
+ .DS_Store
6
+
7
+ ## TEXTMATE
8
+ *.tmproj
9
+ tmtags
10
+
11
+ ## EMACS
12
+ *~
13
+ \#*
14
+ .\#*
15
+
16
+ ## VIM
17
+ *.swp
18
+
19
+ ## PROJECT::GENERAL
20
+ coverage
21
+ doc
22
+ rdoc
23
+ log
24
+
25
+ ## BUNDLER
26
+ *.gem
27
+ .bundle
28
+ pkg
29
+ Gemfile.lock
30
+
31
+ ## RCOV
32
+ coverage.data
33
+
34
+ ## PROJECT::SPECIFIC
35
+ .svn
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format=nested
3
+ --backtrace
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.1
4
+ - 1.9.2
5
+ - jruby
6
+ - rbx
7
+ - ree
data/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # CHANGELOG
2
+
3
+ * [0.4.1 - April 20, 2011](https://github.com/intridea/oauth2/compare/v0.4.0...v0.4.1)
4
+ * [0.4.0 - April 20, 2011](https://github.com/intridea/oauth2/compare/v0.3.0...v0.4.0)
5
+ * [0.3.0 - April 8, 2011](https://github.com/intridea/oauth2/compare/v0.2.0...v0.3.0)
6
+ * [0.2.0 - April 1, 2011](https://github.com/intridea/oauth2/compare/v0.1.1...v0.2.0)
7
+ * [0.1.1 - January 12, 2011](https://github.com/intridea/oauth2/compare/v0.1.0...v0.1.1)
8
+ * [0.1.0 - October 13, 2010](https://github.com/intridea/oauth2/compare/v0.0.13...v0.1.0)
9
+ * [0.0.13 - August 17, 2010](https://github.com/intridea/oauth2/compare/v0.0.12...v0.0.13)
10
+ * [0.0.12 - August 17, 2010](https://github.com/intridea/oauth2/compare/v0.0.11...v0.0.12)
11
+ * [0.0.11 - August 17, 2010](https://github.com/intridea/oauth2/compare/v0.0.10...v0.0.11)
12
+ * [0.0.10 - June 19, 2010](https://github.com/intridea/oauth2/compare/v0.0.9...v0.0.10)
13
+ * [0.0.9 - June 18, 2010](https://github.com/intridea/oauth2/compare/v0.0.8...v0.0.9)
14
+ * [0.0.8 - April 27, 2010](https://github.com/intridea/oauth2/compare/v0.0.7...v0.0.8)
15
+ * [0.0.7 - April 27, 2010](https://github.com/intridea/oauth2/compare/v0.0.6...v0.0.7)
16
+ * [0.0.6 - April 25, 2010](https://github.com/intridea/oauth2/compare/v0.0.5...v0.0.6)
17
+ * [0.0.5 - April 23, 2010](https://github.com/intridea/oauth2/compare/v0.0.4...v0.0.5)
18
+ * [0.0.4 - April 22, 2010](https://github.com/intridea/oauth2/compare/v0.0.3...v0.0.4)
19
+ * [0.0.3 - April 22, 2010](https://github.com/intridea/oauth2/compare/v0.0.2...v0.0.3)
20
+ * [0.0.2 - April 22, 2010](https://github.com/intridea/oauth2/compare/v0.0.1...v0.0.2)
21
+ * [0.0.1 - April 22, 2010](https://github.com/intridea/oauth2/compare/311d9f42e52b832119170d90e818f0f0b0078851...v0.0.1)
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Intridea, Inc. and Michael Bleigh
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ OAuth2 Fork (version 0.4.1 - OUT OF DATE)
2
+ =========================================
3
+
4
+ changelog: relaxed 0.8 > version dependency for faraday
5
+ -------------------------------------------------------
6
+
7
+
8
+ OAuth2
9
+ ======
10
+ A Ruby wrapper for the OAuth 2.0 specification. This is a work in progress, being built first to solve the pragmatic process of connecting to existing OAuth 2.0 endpoints (a.k.a. Facebook) with the goal of building it up to meet the entire specification over time.
11
+
12
+ Installation
13
+ ------------
14
+ gem install oauth2
15
+
16
+ Continuous Integration
17
+ ----------------------
18
+ [![Build Status](http://travis-ci.org/intridea/oauth2.png)](http://travis-ci.org/intridea/oauth2)
19
+
20
+ Resources
21
+ ---------
22
+ * View Source on GitHub (https://github.com/intridea/oauth2)
23
+ * Report Issues on GitHub (https://github.com/intridea/oauth2/issues)
24
+ * Read More at the Wiki (https://wiki.github.com/intridea/oauth2)
25
+
26
+ Web Server Example (Sinatra)
27
+ ----------------------------
28
+ Below is a fully functional example of a Sinatra application that would authenticate to Facebook utilizing the OAuth 2.0 web server flow.
29
+
30
+ require 'rubygems'
31
+ require 'sinatra'
32
+ require 'oauth2'
33
+ require 'json'
34
+
35
+ def client
36
+ OAuth2::Client.new('app_id', 'app_secret', :site => 'https://graph.facebook.com')
37
+ end
38
+
39
+ get '/auth/facebook' do
40
+ redirect client.web_server.authorize_url(
41
+ :redirect_uri => redirect_uri,
42
+ :scope => 'email,offline_access'
43
+ )
44
+ end
45
+
46
+ get '/auth/facebook/callback' do
47
+ access_token = client.web_server.get_access_token(params[:code], :redirect_uri => redirect_uri)
48
+ user = JSON.parse(access_token.get('/me'))
49
+ user.inspect
50
+ end
51
+
52
+ def redirect_uri
53
+ uri = URI.parse(request.url)
54
+ uri.path = '/auth/facebook/callback'
55
+ uri.query = nil
56
+ uri.to_s
57
+ end
58
+
59
+ That's all there is to it! You can use the access token like you would with the
60
+ OAuth gem, calling HTTP verbs on it etc. You can view more examples on the [OAuth2
61
+ Wiki](http://wiki.github.com/intridea/oauth2/examples).
62
+
63
+ JSON Parsing
64
+ ------------
65
+ Because JSON has become the standard format of the OAuth 2.0 specification,
66
+ the <tt>oauth2</tt> gem contains a mode that will perform automatic parsing
67
+ of JSON response bodies, returning a hash instead of a string. To enable this
68
+ mode, simply add the <tt>:parse_json</tt> option to your client initialization:
69
+
70
+ client = OAuth2::Client.new(
71
+ 'app_id',
72
+ 'app_secret',
73
+ :site => 'https://example.com',
74
+ :parse_json => true,
75
+ )
76
+
77
+ # Obtain an access token using the client
78
+ token.get('/some/url.json') #=> {"some" => "hash"}
79
+
80
+ Testing
81
+ -------
82
+ To use the OAuth2 client for testing error conditions do:
83
+
84
+ my_client.raise_errors = false
85
+
86
+ It will then return the error status and response instead of raising an exception.
87
+
88
+ Note on Patches/Pull Requests
89
+ -----------------------------
90
+ 1. Fork the project.
91
+ 2. Create a topic branch.
92
+ 3. Implement your feature or bug fix.
93
+ 4. Add documentation for your feature or bug fix.
94
+ 5. Add specs for your feature or bug fix.
95
+ 6. Run <tt>bundle exec rake spec</tt>. If your changes are not 100% covered, go back to step 5.
96
+ 7. Commit and push your changes.
97
+ 8. Submit a pull request. Please do not include changes to the [gemspec](https://github.com/intridea/oauth2/blob/master/oauth2.gemspec), [version](https://github.com/intridea/oauth2/blob/master/lib/oauth2/version.rb), or [changelog](https://github.com/intridea/oauth2/blob/master/CHANGELOG.md) file. (If you want to create your own version for some reason, please do so in a separate commit.)
98
+
99
+ Copyright
100
+ ---------
101
+ Copyright (c) 2011 Intridea, Inc. and Michael Bleigh.
102
+ See [LICENSE](https://github.com/intridea/oauth2/blob/master/LICENSE.md) for details.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+ task :test => :spec
9
+
10
+ require 'rake/rdoctask'
11
+ Rake::RDocTask.new do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = "oauth2 #{OAuth2::VERSION}"
14
+ rdoc.rdoc_files.include('README*')
15
+ rdoc.rdoc_files.include('lib/**/*.rb')
16
+ end
data/lib/oauth2.rb ADDED
@@ -0,0 +1,13 @@
1
+ module OAuth2
2
+ class ErrorWithResponse < StandardError; attr_accessor :response end
3
+ class AccessDenied < ErrorWithResponse; end
4
+ class Conflict < ErrorWithResponse; end
5
+ class HTTPError < ErrorWithResponse; end
6
+ end
7
+
8
+ require 'oauth2/client'
9
+ require 'oauth2/strategy/base'
10
+ require 'oauth2/strategy/web_server'
11
+ require 'oauth2/strategy/password'
12
+ require 'oauth2/access_token'
13
+ require 'oauth2/response_object'
@@ -0,0 +1,53 @@
1
+ module OAuth2
2
+ class AccessToken
3
+ attr_reader :client, :token, :refresh_token, :expires_in, :expires_at, :params
4
+ attr_accessor :token_param
5
+
6
+ def initialize(client, token, refresh_token=nil, expires_in=nil, params={})
7
+ @client = client
8
+ @token = token.to_s
9
+ @refresh_token = refresh_token.to_s
10
+ @expires_in = (expires_in.nil? || expires_in == '') ? nil : expires_in.to_i
11
+ @expires_at = Time.now + @expires_in if @expires_in
12
+ @params = params
13
+ @token_param = 'oauth_token'
14
+ end
15
+
16
+ def [](key)
17
+ @params[key]
18
+ end
19
+
20
+ # True if the token in question has an expiration time.
21
+ def expires?
22
+ !!@expires_in
23
+ end
24
+
25
+ def expired?
26
+ expires? && expires_at < Time.now
27
+ end
28
+
29
+ def request(verb, path, params={}, headers={})
30
+ if params.instance_of?(Hash)
31
+ params = params.merge token_param => @token
32
+ end
33
+ headers = headers.merge 'Authorization' => "OAuth #{@token}"
34
+ @client.request(verb, path, params, headers)
35
+ end
36
+
37
+ def get(path, params={}, headers={})
38
+ request(:get, path, params, headers)
39
+ end
40
+
41
+ def post(path, params={}, headers={})
42
+ request(:post, path, params, headers)
43
+ end
44
+
45
+ def put(path, params={}, headers={})
46
+ request(:put, path, params, headers)
47
+ end
48
+
49
+ def delete(path, params={}, headers={})
50
+ request(:delete, path, params, headers)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,105 @@
1
+ require 'faraday'
2
+
3
+ module OAuth2
4
+ class Client
5
+ attr_accessor :id, :secret, :site, :connection, :options, :raise_errors, :token_method
6
+ attr_writer :json
7
+
8
+ # Instantiate a new OAuth 2.0 client using the
9
+ # client ID and client secret registered to your
10
+ # application.
11
+ #
12
+ # Options:
13
+ #
14
+ # <tt>:site</tt> :: Specify a base URL for your OAuth 2.0 client.
15
+ # <tt>:authorize_path</tt> :: Specify the path to the authorization endpoint.
16
+ # <tt>:authorize_url</tt> :: Specify a full URL of the authorization endpoint.
17
+ # <tt>:access_token_path</tt> :: Specify the path to the access token endpoint.
18
+ # <tt>:access_token_method</tt> :: Specify the method to use for token endpoints, can be :get or :post
19
+ # (note: for Facebook this should be :get and for Google this should be :post)
20
+ # <tt>:access_token_url</tt> :: Specify the full URL of the access token endpoint.
21
+ # <tt>:parse_json</tt> :: If true, <tt>application/json</tt> responses will be automatically parsed.
22
+ # <tt>:ssl</tt> :: Specify SSL options for the connection.
23
+ # <tt>:adapter</tt> :: The name of the Faraday::Adapter::* class to use, e.g. :net_http. To pass arguments
24
+ # to the adapter pass an array here, e.g. [:action_dispatch, my_test_session]
25
+ # <tt>:raise_errors</tt> :: Default true. When false it will then return the error status and response instead of raising an exception.
26
+ def initialize(client_id, client_secret, opts={})
27
+ self.options = opts.dup
28
+ self.token_method = self.options.delete(:access_token_method) || :post
29
+ adapter = self.options.delete(:adapter)
30
+ ssl_opts = self.options.delete(:ssl) || {}
31
+ connection_opts = ssl_opts ? {:ssl => ssl_opts} : {}
32
+ self.id = client_id
33
+ self.secret = client_secret
34
+ self.site = self.options.delete(:site) if self.options[:site]
35
+ self.connection = Faraday::Connection.new(site, connection_opts)
36
+ self.json = self.options.delete(:parse_json)
37
+ self.raise_errors = !(self.options.delete(:raise_errors) == false)
38
+
39
+ if adapter && adapter != :test
40
+ connection.build do |b|
41
+ b.adapter(*[adapter].flatten)
42
+ end
43
+ end
44
+ end
45
+
46
+ def authorize_url(params=nil)
47
+ path = options[:authorize_url] || options[:authorize_path] || "/oauth/authorize"
48
+ connection.build_url(path, params).to_s
49
+ end
50
+
51
+ def access_token_url(params=nil)
52
+ path = options[:access_token_url] || options[:access_token_path] || "/oauth/access_token"
53
+ connection.build_url(path, params).to_s
54
+ end
55
+
56
+ # Makes a request relative to the specified site root.
57
+ def request(verb, url, params={}, headers={})
58
+ if (verb == :get) || (verb == :delete)
59
+ resp = connection.run_request(verb, url, nil, headers) do |req|
60
+ req.params.update(params)
61
+ end
62
+ else
63
+ resp = connection.run_request(verb, url, params, headers)
64
+ end
65
+
66
+ if raise_errors
67
+ case resp.status
68
+ when 200...299
69
+ return response_for(resp)
70
+ when 302
71
+ return request(verb, resp.headers['location'], params, headers)
72
+ when 401
73
+ e = OAuth2::AccessDenied.new("Received HTTP 401 during request.")
74
+ e.response = resp
75
+ raise e
76
+ when 409
77
+ e = OAuth2::Conflict.new("Received HTTP 409 during request.")
78
+ e.response = resp
79
+ raise e
80
+ else
81
+ e = OAuth2::HTTPError.new("Received HTTP #{resp.status} during request.")
82
+ e.response = resp
83
+ raise e
84
+ end
85
+ else
86
+ response_for resp
87
+ end
88
+ end
89
+
90
+ def json?; !!@json end
91
+
92
+ def web_server; OAuth2::Strategy::WebServer.new(self) end
93
+ def password; OAuth2::Strategy::Password.new(self) end
94
+
95
+ private
96
+
97
+ def response_for(resp)
98
+ if json?
99
+ return ResponseObject.from(resp)
100
+ else
101
+ return ResponseString.new(resp)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,58 @@
1
+ module OAuth2
2
+ module ResponseObject
3
+ def self.from(response)
4
+ object = MultiJson.decode(response.body)
5
+
6
+ case object
7
+ when Array
8
+ ResponseArray.new(response, object)
9
+ when Hash
10
+ ResponseHash.new(response, object)
11
+ else
12
+ ResponseString.new(response)
13
+ end
14
+ rescue
15
+ ResponseString.new(response)
16
+ end
17
+
18
+ def self.included(base)
19
+ base.class_eval do
20
+ attr_accessor :response
21
+ end
22
+ end
23
+
24
+ def headers; response.headers end
25
+ def status; response.status end
26
+ end
27
+
28
+ class ResponseHash < Hash
29
+ include ResponseObject
30
+
31
+ def initialize(response, hash)
32
+ self.response = response
33
+ hash.keys.each{|k| self[k] = hash[k]}
34
+ end
35
+ end
36
+
37
+ class ResponseArray < Array
38
+ include ResponseObject
39
+
40
+ def initialize(response, array)
41
+ self.response = response
42
+ super(array)
43
+ end
44
+ end
45
+
46
+ # This special String class is returned from HTTP requests
47
+ # and contains the original full response along with convenience
48
+ # methods for accessing the HTTP status code and headers. It
49
+ # is returned from all access token requests.
50
+ class ResponseString < String
51
+ include ResponseObject
52
+
53
+ def initialize(response)
54
+ super(response.body.to_s)
55
+ self.response = response
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,38 @@
1
+ module OAuth2
2
+ module Strategy
3
+ class Base #:nodoc:
4
+ def initialize(client)#:nodoc:
5
+ @client = client
6
+ end
7
+
8
+ def authorize_url(options={}) #:nodoc:
9
+ @client.authorize_url(authorize_params(options))
10
+ end
11
+
12
+ def authorize_params(options={}) #:nodoc:
13
+ options = options.inject({}){|h, (k, v)| h[k.to_s] = v; h}
14
+ {'client_id' => @client.id}.merge(options)
15
+ end
16
+
17
+ def access_token_url(options={})
18
+ @client.access_token_url(access_token_params(options))
19
+ end
20
+
21
+ def access_token_params(options={})
22
+ return default_params(options)
23
+ end
24
+
25
+ def refresh_token_params(options={})
26
+ return default_params(options)
27
+ end
28
+
29
+ private
30
+ def default_params(options={})
31
+ {
32
+ 'client_id' => @client.id,
33
+ 'client_secret' => @client.secret
34
+ }.merge(options)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ require 'multi_json'
2
+
3
+ module OAuth2
4
+ module Strategy
5
+ class Password < Base
6
+ def authorize_url
7
+ raise NotImplementedError, "The authorization endpoint is not used in this strategy"
8
+ end
9
+ # Retrieve an access token given the specified validation code.
10
+ # Note that you must also provide a <tt>:redirect_uri</tt> option
11
+ # in order to successfully verify your request for most OAuth 2.0
12
+ # endpoints.
13
+ def get_access_token(username, password, options={})
14
+ response = @client.request(:post, @client.access_token_url, access_token_params(username, password, options))
15
+
16
+ params = MultiJson.decode(response) rescue nil
17
+ # the ActiveSupport JSON parser won't cause an exception when
18
+ # given a formencoded string, so make sure that it was
19
+ # actually parsed in an Hash. This covers even the case where
20
+ # it caused an exception since it'll still be nil.
21
+ params = Rack::Utils.parse_query(response) unless params.is_a? Hash
22
+
23
+ access = params.delete('access_token')
24
+ refresh = params.delete('refresh_token')
25
+ expires_in = params.delete('expires_in')
26
+ OAuth2::AccessToken.new(@client, access, refresh, expires_in, params)
27
+ end
28
+
29
+ def access_token_params(username, password, options={}) #:nodoc:
30
+ super(options).merge({
31
+ 'grant_type' => 'password',
32
+ 'username' => username,
33
+ 'password' => password
34
+ })
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,58 @@
1
+ require 'multi_json'
2
+
3
+ module OAuth2
4
+ module Strategy
5
+ class WebServer < Base
6
+ def authorize_params(options={}) #:nodoc:
7
+ super(options).merge('response_type' => 'code')
8
+ end
9
+
10
+ # Retrieve an access token given the specified validation code.
11
+ # Note that you must also provide a <tt>:redirect_uri</tt> option
12
+ # in order to successfully verify your request for most OAuth 2.0
13
+ # endpoints.
14
+ def get_access_token(code, options={})
15
+ response = @client.request(@client.token_method, @client.access_token_url, access_token_params(code, options))
16
+ parse_response(response)
17
+ end
18
+
19
+ def refresh_access_token(refresh_token, options={})
20
+ response = @client.request(@client.token_method, @client.access_token_url, refresh_token_params(refresh_token, options))
21
+ parse_response(response, refresh_token)
22
+ end
23
+
24
+ def access_token_params(code, options={}) #:nodoc:
25
+ super(options).merge({
26
+ 'grant_type' => 'authorization_code',
27
+ 'code' => code,
28
+ })
29
+ end
30
+
31
+ def refresh_token_params(refresh_token, options={}) #:nodoc:
32
+ super(options).merge({
33
+ 'grant_type' => 'refresh_token',
34
+ 'refresh_token' => refresh_token,
35
+ })
36
+ end
37
+
38
+ def parse_response(response, refresh_token = nil)
39
+ if response.is_a? Hash
40
+ params = response
41
+ else
42
+ params = MultiJson.decode(response) rescue nil
43
+ # the ActiveSupport JSON parser won't cause an exception when
44
+ # given a formencoded string, so make sure that it was
45
+ # actually parsed in an Hash. This covers even the case where
46
+ # it caused an exception since it'll still be nil.
47
+ params = Rack::Utils.parse_query(response) unless params.is_a? Hash
48
+ end
49
+
50
+ access = params.delete('access_token')
51
+ refresh = params.delete('refresh_token') || refresh_token
52
+ # params['expires'] is only for Facebook
53
+ expires_in = params.delete('expires_in') || params.delete('expires')
54
+ OAuth2::AccessToken.new(@client, access, refresh, expires_in, params)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module OAuth2
2
+ VERSION = "0.4.1"
3
+ end
data/oauth2.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/oauth2/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "panjiva-oauth2"
6
+ s.version = OAuth2::VERSION
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Michael Bleigh"]
9
+ s.description = %q{A Ruby wrapper for the OAuth 2.0 protocol built with a similar style to the original OAuth gem.}
10
+ s.summary = %q{A Ruby wrapper for the OAuth 2.0 protocol.}
11
+ s.email = "michael@intridea.com"
12
+ s.homepage = "http://github.com/intridea/oauth2"
13
+ s.require_paths = ["lib"]
14
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.add_runtime_dependency("faraday", ">= 0.6.1")
18
+ s.add_runtime_dependency("multi_json", ">= 0.0.5")
19
+ s.add_development_dependency("json_pure", "~> 1.5")
20
+ s.add_development_dependency("rake", "~> 0.8")
21
+ s.add_development_dependency("simplecov", "~> 0.4")
22
+ s.add_development_dependency("rspec", "~> 2.5")
23
+ s.add_development_dependency("ZenTest", "~> 4.5")
24
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ describe OAuth2::AccessToken do
4
+ let(:client) do
5
+ cli = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com')
6
+ cli.connection.build do |b|
7
+ b.adapter :test do |stub|
8
+ stub.get('/client?oauth_token=monkey') {|env| [200, {}, 'get']}
9
+ stub.post('/client') {|env| [200, {}, 'oauth_token=' << env[:body]['oauth_token']]}
10
+ stub.get('/empty_get?oauth_token=monkey') {|env| [204, {}, nil]}
11
+ stub.put('/client') {|env| [200, {}, 'oauth_token=' << env[:body]['oauth_token']]}
12
+ stub.delete('/client?oauth_token=monkey') {|env| [200, {}, 'delete']}
13
+ end
14
+ end
15
+ cli
16
+ end
17
+
18
+ let(:token) {'monkey'}
19
+
20
+ subject {OAuth2::AccessToken.new(client, token)}
21
+
22
+ describe '#initialize' do
23
+ it 'should assign client and token' do
24
+ subject.client.should == client
25
+ subject.token.should == token
26
+ end
27
+
28
+ it 'should assign extra params' do
29
+ target = OAuth2::AccessToken.new(client, token, nil, nil, {'foo' => 'bar'})
30
+ target.params.should include('foo')
31
+ target.params['foo'].should == 'bar'
32
+ end
33
+
34
+ %w(get delete).each do |http_method|
35
+ it "makes #{http_method.upcase} requests with access token" do
36
+ subject.send(http_method.to_sym, 'client').should == http_method
37
+ end
38
+ end
39
+
40
+ %w(post put).each do |http_method|
41
+ it "makes #{http_method.upcase} requests with access token" do
42
+ subject.send(http_method.to_sym, 'client').should == 'oauth_token=monkey'
43
+ end
44
+ end
45
+
46
+ it "works with a null response body" do
47
+ subject.get('empty_get').should == ''
48
+ end
49
+ end
50
+
51
+ describe '#expires?' do
52
+ it 'should be false if there is no expires_at' do
53
+ OAuth2::AccessToken.new(client, token).should_not be_expires
54
+ end
55
+
56
+ it 'should be true if there is an expires_at' do
57
+ OAuth2::AccessToken.new(client, token, 'abaca', 600).should be_expires
58
+ end
59
+ end
60
+
61
+ describe '#expires_at' do
62
+ before do
63
+ @now = Time.now
64
+ Time.stub!(:now).and_return(@now)
65
+ end
66
+
67
+ subject{OAuth2::AccessToken.new(client, token, 'abaca', 600)}
68
+
69
+ it 'should be a time representation of #expires_in' do
70
+ subject.expires_at.should == (@now + 600)
71
+ end
72
+ end
73
+
74
+ describe '#expired?' do
75
+ it 'should be false if there is no expires_at' do
76
+ OAuth2::AccessToken.new(client, token).should_not be_expired
77
+ end
78
+
79
+ it 'should be false if expires_at is in the future' do
80
+ OAuth2::AccessToken.new(client, token, 'abaca', 10800).should_not be_expired
81
+ end
82
+
83
+ it 'should be true if expires_at is in the past' do
84
+ access = OAuth2::AccessToken.new(client, token, 'abaca', 600)
85
+ @now = Time.now + 10800
86
+ Time.stub!(:now).and_return(@now)
87
+ access.should be_expired
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+
3
+ describe OAuth2::Client do
4
+ subject do
5
+ cli = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com')
6
+ cli.connection.build do |b|
7
+ b.adapter :test do |stub|
8
+ stub.get('/success') {|env| [200, {'Content-Type' => 'text/awesome'}, 'yay']}
9
+ stub.get('/unauthorized') {|env| [401, {'Content-Type' => 'text/plain'}, 'not authorized']}
10
+ stub.get('/conflict') {|env| [409, {'Content-Type' => 'text/plain'}, 'not authorized']}
11
+ stub.get('/redirect') {|env| [302, {'Content-Type' => 'text/plain', 'location' => '/success' }, '']}
12
+ stub.get('/error') {|env| [500, {}, '']}
13
+ stub.get('/json') {|env| [200, {'Content-Type' => 'application/json; charset=utf8'}, '{"abc":"def"}']}
14
+ end
15
+ end
16
+ cli
17
+ end
18
+
19
+ describe '#initialize' do
20
+ it 'should assign id and secret' do
21
+ subject.id.should == 'abc'
22
+ subject.secret.should == 'def'
23
+ end
24
+
25
+ it 'should assign site from the options hash' do
26
+ subject.site.should == 'https://api.example.com'
27
+ end
28
+
29
+ it 'should assign Faraday::Connection#host' do
30
+ subject.connection.host.should == 'api.example.com'
31
+ end
32
+
33
+ it 'should leave Faraday::Connection#ssl unset' do
34
+ subject.connection.ssl.should == {}
35
+ end
36
+
37
+ it "should be able to pass parameters to the adapter, e.g. Faraday::Adapter::ActionDispatch" do
38
+ connection = stub('connection')
39
+ Faraday::Connection.stub(:new => connection)
40
+ session = stub('session', :to_ary => nil)
41
+ builder = stub('builder')
42
+ connection.stub(:build).and_yield(builder)
43
+
44
+ builder.should_receive(:adapter).with(:action_dispatch, session)
45
+
46
+ OAuth2::Client.new('abc', 'def', :adapter => [:action_dispatch, session])
47
+ end
48
+
49
+ it "defaults raise_errors to true" do
50
+ subject.raise_errors.should be_true
51
+ end
52
+
53
+ it "allows true/false for raise_errors option" do
54
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => false)
55
+ client.raise_errors.should be_false
56
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => true)
57
+ client.raise_errors.should be_true
58
+ end
59
+
60
+ it "allows get/post for access_token_method option" do
61
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :get)
62
+ client.token_method.should == :get
63
+ client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :post)
64
+ client.token_method.should == :post
65
+ end
66
+ end
67
+
68
+ %w(authorize access_token).each do |path_type|
69
+ describe "##{path_type}_url" do
70
+ it "should default to a path of /oauth/#{path_type}" do
71
+ subject.send("#{path_type}_url").should == "https://api.example.com/oauth/#{path_type}"
72
+ end
73
+
74
+ it "should be settable via the :#{path_type}_path option" do
75
+ subject.options[:"#{path_type}_path"] = '/oauth/custom'
76
+ subject.send("#{path_type}_url").should == 'https://api.example.com/oauth/custom'
77
+ end
78
+
79
+ it "should be settable via the :#{path_type}_url option" do
80
+ subject.options[:"#{path_type}_url"] = 'https://abc.com/authorize'
81
+ subject.send("#{path_type}_url").should == 'https://abc.com/authorize'
82
+ end
83
+ end
84
+ end
85
+
86
+ describe "#request" do
87
+ it "returns ResponseString on successful response" do
88
+ response = subject.request(:get, '/success', {}, {})
89
+ response.should == 'yay'
90
+ response.status.should == 200
91
+ response.headers.should == {'Content-Type' => 'text/awesome'}
92
+ end
93
+
94
+ it "follows redirects properly" do
95
+ response = subject.request(:get, '/redirect', {}, {})
96
+ response.should == 'yay'
97
+ response.status.should == 200
98
+ response.headers.should == {'Content-Type' => 'text/awesome'}
99
+ end
100
+
101
+ it "returns ResponseString on error if raise_errors is false" do
102
+ subject.raise_errors = false
103
+ response = subject.request(:get, '/unauthorized', {}, {})
104
+
105
+ response.should == 'not authorized'
106
+ response.status.should == 401
107
+ response.headers.should == {'Content-Type' => 'text/plain'}
108
+ end
109
+
110
+ it "raises OAuth2::AccessDenied on 401 response" do
111
+ lambda {subject.request(:get, '/unauthorized', {}, {})}.should raise_error(OAuth2::AccessDenied)
112
+ end
113
+
114
+ it "raises OAuth2::Conflict on 409 response" do
115
+ lambda {subject.request(:get, '/conflict', {}, {})}.should raise_error(OAuth2::Conflict)
116
+ end
117
+
118
+ it "raises OAuth2::HTTPError on error response" do
119
+ lambda {subject.request(:get, '/error', {}, {})}.should raise_error(OAuth2::HTTPError)
120
+ end
121
+ end
122
+
123
+ it '#web_server should instantiate a WebServer strategy with this client' do
124
+ subject.web_server.should be_kind_of(OAuth2::Strategy::WebServer)
125
+ end
126
+
127
+ context 'with JSON parsing' do
128
+ before do
129
+ subject.json = true
130
+ end
131
+
132
+ describe '#request' do
133
+ it 'should return a response hash' do
134
+ response = subject.request(:get, '/json')
135
+ puts response.inspect
136
+ response.should be_kind_of(OAuth2::ResponseHash)
137
+ response['abc'].should == 'def'
138
+ end
139
+
140
+ it 'should only try to decode application/json' do
141
+ subject.request(:get, '/success').should == 'yay'
142
+ end
143
+ end
144
+
145
+ it 'should set json? based on the :parse_json option' do
146
+ OAuth2::Client.new('abc', 'def', :site => 'http://example.com', :parse_json => true).should be_json
147
+ OAuth2::Client.new('abc', 'def', :site => 'http://example.com', :parse_json => false).should_not be_json
148
+ end
149
+
150
+ after do
151
+ subject.json = false
152
+ end
153
+ end
154
+
155
+ context 'with SSL options' do
156
+ subject do
157
+ cli = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :ssl => {:ca_file => 'foo.pem'})
158
+ cli.connection.build do |b|
159
+ b.adapter :test
160
+ end
161
+ cli
162
+ end
163
+
164
+ it 'should pass the SSL options along to Faraday::Connection#ssl' do
165
+ subject.connection.ssl.should == {:ca_file => 'foo.pem'}
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe OAuth2::Strategy::Base do
4
+ it 'should initialize with a Client' do
5
+ lambda{OAuth2::Strategy::Base.new(OAuth2::Client.new('abc', 'def'))}.should_not raise_error
6
+ end
7
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe OAuth2::Strategy::Password do
4
+ let(:client) do
5
+ cli = OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com')
6
+ cli.connection.build do |b|
7
+ b.adapter :test do |stub|
8
+ stub.post('/oauth/access_token') do |env|
9
+ case @mode
10
+ when "formencoded"
11
+ [200, {}, 'expires_in=600&access_token=salmon&refresh_token=trout']
12
+ when "json"
13
+ [200, {}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
14
+ end
15
+ end
16
+ end
17
+ end
18
+ cli
19
+ end
20
+ subject {client.password}
21
+
22
+ describe "#authorize_url" do
23
+ it "should raise NotImplementedError" do
24
+ lambda {subject.authorize_url}.should raise_error(NotImplementedError)
25
+ end
26
+ end
27
+
28
+ %w(json formencoded).each do |mode|
29
+ describe "#get_access_token (#{mode})" do
30
+ before do
31
+ @mode = mode
32
+ @access = subject.get_access_token('username', 'password')
33
+ end
34
+
35
+ it 'returns AccessToken with same Client' do
36
+ @access.client.should == client
37
+ end
38
+
39
+ it 'returns AccessToken with #token' do
40
+ @access.token.should == 'salmon'
41
+ end
42
+
43
+ it 'returns AccessToken with #refresh_token' do
44
+ @access.refresh_token.should == 'trout'
45
+ end
46
+
47
+ it 'returns AccessToken with #expires_in' do
48
+ @access.expires_in.should == 600
49
+ end
50
+
51
+ it 'returns AccessToken with #expires_at' do
52
+ @access.expires_at.should be_kind_of(Time)
53
+ end
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ describe OAuth2::Strategy::WebServer do
4
+ let(:client) do
5
+ cli = OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com')
6
+ cli.connection.build do |b|
7
+ b.adapter :test do |stub|
8
+ stub.get('/oauth/access_token?client_id=abc&client_secret=def&code=sushi&grant_type=authorization_code') do |env|
9
+ case @mode
10
+ when "formencoded"
11
+ [200, {}, 'expires_in=600&access_token=salmon&refresh_token=trout&extra_param=steve']
12
+ when "json"
13
+ [200, {}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout","extra_param":"steve"}']
14
+ when "from_facebook"
15
+ [200, {}, 'expires=600&access_token=salmon&refresh_token=trout&extra_param=steve']
16
+ end
17
+ end
18
+ stub.post('/oauth/access_token', { 'client_id' => 'abc', 'client_secret' => 'def', 'code' => 'sushi', 'grant_type' => 'authorization_code' }) do |env|
19
+ case @mode
20
+ when "formencoded"
21
+ [200, {}, 'expires_in=600&access_token=salmon&refresh_token=trout&extra_param=steve']
22
+ when "json"
23
+ [200, {}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout","extra_param":"steve"}']
24
+ when "from_facebook"
25
+ [200, {}, 'expires=600&access_token=salmon&refresh_token=trout&extra_param=steve']
26
+ end
27
+ end
28
+ stub.get('/oauth/access_token?client_id=abc&client_secret=def&grant_type=refresh_token&refresh_token=trout') do |env|
29
+ case @mode
30
+ when "formencoded"
31
+ [200, {}, 'expires_in=600&access_token=tuna']
32
+ when "json"
33
+ [200, {}, '{"expires_in":600,"access_token":"tuna"}']
34
+ end
35
+ end
36
+ stub.post('/oauth/access_token', { 'client_id' => 'abc', 'client_secret' => 'def', 'refresh_token' => 'trout', 'grant_type' => 'refresh_token' }) do |env|
37
+ case @mode
38
+ when "formencoded"
39
+ [200, {}, 'expires_in=600&access_token=tuna']
40
+ when "json"
41
+ [200, {}, '{"expires_in":600,"access_token":"tuna"}']
42
+ end
43
+ end
44
+ end
45
+ end
46
+ cli
47
+ end
48
+ subject{client.web_server}
49
+
50
+ describe '#authorize_url' do
51
+ it 'should include the client_id' do
52
+ subject.authorize_url.should be_include('client_id=abc')
53
+ end
54
+
55
+ it 'should include the type' do
56
+ subject.authorize_url.should be_include('response_type=code')
57
+ end
58
+
59
+ it 'should include passed in options' do
60
+ cb = 'http://myserver.local/oauth/callback'
61
+ subject.authorize_url(:redirect_uri => cb).should be_include("redirect_uri=#{Rack::Utils.escape(cb)}")
62
+ end
63
+ end
64
+
65
+ %w(json formencoded from_facebook).each do |mode|
66
+ [false, true].each do |parse_json|
67
+ [:get, :post].each do |verb|
68
+ describe "#get_access_token (#{mode}, token_method=#{verb} parse_json=#{parse_json})" do
69
+ before do
70
+ @mode = mode
71
+ client.json=parse_json
72
+ client.token_method=verb
73
+ @access = subject.get_access_token('sushi')
74
+ end
75
+
76
+ it 'returns AccessToken with same Client' do
77
+ @access.client.should == client
78
+ end
79
+
80
+ it 'returns AccessToken with #token' do
81
+ @access.token.should == 'salmon'
82
+ end
83
+
84
+ it 'returns AccessToken with #refresh_token' do
85
+ @access.refresh_token.should == 'trout'
86
+ end
87
+
88
+ it 'returns AccessToken with #expires_in' do
89
+ @access.expires_in.should == 600
90
+ end
91
+
92
+ it 'returns AccessToken with #expires_at' do
93
+ @access.expires_at.should be_kind_of(Time)
94
+ end
95
+
96
+ it 'returns AccessToken with params accessible via []' do
97
+ @access['extra_param'].should == 'steve'
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ %w(json formencoded).each do |mode|
105
+ [false, true].each do |parse_json|
106
+ [:get].each do |verb|
107
+ describe "#refresh_access_token (#{mode}, token_method=#{verb} parse_json=#{parse_json})" do
108
+ before do
109
+ @mode = mode
110
+ client.json=parse_json
111
+ client.token_method=verb
112
+ @access = subject.refresh_access_token('trout')
113
+ end
114
+
115
+ it 'returns AccessToken with same Client' do
116
+ @access.client.should == client
117
+ end
118
+
119
+ it 'returns AccessToken with #token' do
120
+ @access.token.should == 'tuna'
121
+ end
122
+
123
+ it 'returns AccessToken with #refresh_token' do
124
+ @access.refresh_token.should == 'trout'
125
+ end
126
+
127
+ it 'returns AccessToken with #expires_in' do
128
+ @access.expires_in.should == 600
129
+ end
130
+
131
+ it 'returns AccessToken with #expires_at' do
132
+ @access.expires_at.should be_kind_of(Time)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,11 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup
4
+
5
+ require 'simplecov'
6
+ SimpleCov.start
7
+ require 'oauth2'
8
+ require 'rspec'
9
+ require 'rspec/autorun'
10
+
11
+ Faraday.default_adapter = :test
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: panjiva-oauth2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Bleigh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.6.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: multi_json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: json_pure
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '2.5'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '2.5'
97
+ - !ruby/object:Gem::Dependency
98
+ name: ZenTest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '4.5'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '4.5'
111
+ description: A Ruby wrapper for the OAuth 2.0 protocol built with a similar style
112
+ to the original OAuth gem.
113
+ email: michael@intridea.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .document
119
+ - .gemtest
120
+ - .gitignore
121
+ - .rspec
122
+ - .travis.yml
123
+ - CHANGELOG.md
124
+ - Gemfile
125
+ - LICENSE.md
126
+ - README.md
127
+ - Rakefile
128
+ - lib/oauth2.rb
129
+ - lib/oauth2/access_token.rb
130
+ - lib/oauth2/client.rb
131
+ - lib/oauth2/response_object.rb
132
+ - lib/oauth2/strategy/base.rb
133
+ - lib/oauth2/strategy/password.rb
134
+ - lib/oauth2/strategy/web_server.rb
135
+ - lib/oauth2/version.rb
136
+ - oauth2.gemspec
137
+ - spec/oauth2/access_token_spec.rb
138
+ - spec/oauth2/client_spec.rb
139
+ - spec/oauth2/strategy/base_spec.rb
140
+ - spec/oauth2/strategy/password_spec.rb
141
+ - spec/oauth2/strategy/web_server_spec.rb
142
+ - spec/spec_helper.rb
143
+ homepage: http://github.com/intridea/oauth2
144
+ licenses: []
145
+ metadata: {}
146
+ post_install_message:
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ! '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ! '>='
158
+ - !ruby/object:Gem::Version
159
+ version: 1.3.6
160
+ requirements: []
161
+ rubyforge_project:
162
+ rubygems_version: 2.1.11
163
+ signing_key:
164
+ specification_version: 4
165
+ summary: A Ruby wrapper for the OAuth 2.0 protocol.
166
+ test_files: []