oauth2 0.9.4 → 1.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1f08c4d28879362b39b7c95041febcf876970cc6
4
- data.tar.gz: 22b630f65b3bae6df564836c8c67dfe81172c309
3
+ metadata.gz: 5a7e97c3a76d87a0499aa0cd5f9b908df43f5b91
4
+ data.tar.gz: 390e6188e44d5e7eb909a29141b63dc05276608d
5
5
  SHA512:
6
- metadata.gz: cf71ffafcd8e2fc3abc2efca44cbafabec97b35a61cdf76ddbc0297f1fb9bbf72bb8ba6432cd443324a052bb837c1fec89080684877f655a410d8f1f988b429b
7
- data.tar.gz: 0933fed7b3e4c8a4f58c5dab2f8bd71ff0252999023a4825d0e7249aeb6e0f2c77164669f3278ac2f358f47939c2f1779e02cf4170a5c119a7c753803ae38b40
6
+ metadata.gz: fe86948ffabdc2334b89db64fb4cb6c98a65f93198b543b380cab70c9d18daa47fcf92272678f5794caf23827e8e4e93f3d053d106d98a0438b4f1befb86301b
7
+ data.tar.gz: c5a507967b19c5019aaa4fd8f52448c78b4d13ada1041705d0f6526bc96b2b04311e063f7f5f98cd4a6520c61ab79eb841626c6e6dcf510bdb7a94c801e52ba1
data/README.md CHANGED
@@ -12,10 +12,7 @@
12
12
  [codeclimate]: https://codeclimate.com/github/intridea/oauth2
13
13
  [coveralls]: https://coveralls.io/r/intridea/oauth2
14
14
 
15
- A Ruby wrapper for the OAuth 2.0 specification. This is a work in progress,
16
- being built first to solve the pragmatic process of connecting to existing
17
- OAuth 2.0 endpoints (e.g. Facebook) with the goal of building it up to meet
18
- the entire specification over time.
15
+ A Ruby wrapper for the OAuth 2.0 specification.
19
16
 
20
17
  ## Installation
21
18
  gem install oauth2
data/Rakefile CHANGED
@@ -19,10 +19,10 @@ end
19
19
 
20
20
  begin
21
21
  require 'rubocop/rake_task'
22
- Rubocop::RakeTask.new
22
+ RuboCop::RakeTask.new
23
23
  rescue LoadError
24
24
  task :rubocop do
25
- $stderr.puts 'Rubocop is disabled'
25
+ $stderr.puts 'RuboCop is disabled'
26
26
  end
27
27
  end
28
28
 
@@ -33,7 +33,7 @@ end
33
33
 
34
34
  require 'yardstick/rake/verify'
35
35
  Yardstick::Rake::Verify.new do |verify|
36
- verify.threshold = 58.9
36
+ verify.threshold = 58.8
37
37
  end
38
38
 
39
39
  task :default => [:spec, :rubocop, :verify_measurements]
@@ -7,4 +7,5 @@ require 'oauth2/strategy/password'
7
7
  require 'oauth2/strategy/client_credentials'
8
8
  require 'oauth2/strategy/assertion'
9
9
  require 'oauth2/access_token'
10
+ require 'oauth2/mac_token'
10
11
  require 'oauth2/response'
@@ -0,0 +1,124 @@
1
+ require 'base64'
2
+ require 'digest'
3
+ require 'openssl'
4
+ require 'securerandom'
5
+
6
+ module OAuth2
7
+ class MACToken < AccessToken
8
+ # Generates a MACToken from an AccessToken and secret
9
+ #
10
+ # @param [AccessToken] token the OAuth2::Token instance
11
+ # @option [String] secret the secret key value
12
+ # @param [Hash] opts the options to create the Access Token with
13
+ # @see MACToken#initialize
14
+ def self.from_access_token(token, secret, options = {})
15
+ new(token.client, token.token, secret, token.params.merge(
16
+ :refresh_token => token.refresh_token,
17
+ :expires_in => token.expires_in,
18
+ :expires_at => token.expires_at
19
+ ).merge(options))
20
+ end
21
+
22
+ attr_reader :secret, :algorithm
23
+
24
+ # Initalize a MACToken
25
+ #
26
+ # @param [Client] client the OAuth2::Client instance
27
+ # @param [String] token the Access Token value
28
+ # @option [String] secret the secret key value
29
+ # @param [Hash] opts the options to create the Access Token with
30
+ # @option opts [String] :refresh_token (nil) the refresh_token value
31
+ # @option opts [FixNum, String] :expires_in (nil) the number of seconds in which the AccessToken will expire
32
+ # @option opts [FixNum, String] :expires_at (nil) the epoch time in seconds in which AccessToken will expire
33
+ # @option opts [FixNum, String] :algorithm (hmac-sha-256) the algorithm to use for the HMAC digest (one of 'hmac-sha-256', 'hmac-sha-1')
34
+ def initialize(client, token, secret, opts = {})
35
+ @secret = secret
36
+ self.algorithm = opts.delete(:algorithm) || 'hmac-sha-256'
37
+
38
+ super(client, token, opts)
39
+ end
40
+
41
+ # Make a request with the MAC Token
42
+ #
43
+ # @param [Symbol] verb the HTTP request method
44
+ # @param [String] path the HTTP URL path of the request
45
+ # @param [Hash] opts the options to make the request with
46
+ # @see Client#request
47
+ def request(verb, path, opts = {}, &block)
48
+ url = client.connection.build_url(path, opts[:params]).to_s
49
+
50
+ opts[:headers] ||= {}
51
+ opts[:headers].merge!('Authorization' => header(verb, url))
52
+
53
+ @client.request(verb, path, opts, &block)
54
+ end
55
+
56
+ # Get the headers hash (always an empty hash)
57
+ def headers
58
+ {}
59
+ end
60
+
61
+ # Generate the MAC header
62
+ #
63
+ # @param [Symbol] verb the HTTP request method
64
+ # @param [String] url the HTTP URL path of the request
65
+ def header(verb, url)
66
+ timestamp = Time.now.utc.to_i
67
+ nonce = Digest::MD5.hexdigest([timestamp, SecureRandom.hex].join(':'))
68
+
69
+ uri = URI.parse(url)
70
+
71
+ fail(ArgumentError, "could not parse \"#{url}\" into URI") unless uri.is_a?(URI::HTTP)
72
+
73
+ mac = signature(timestamp, nonce, verb, uri)
74
+
75
+ "MAC id=\"#{token}\", ts=\"#{timestamp}\", nonce=\"#{nonce}\", mac=\"#{mac}\""
76
+ end
77
+
78
+ # Generate the Base64-encoded HMAC digest signature
79
+ #
80
+ # @param [Fixnum] timestamp the timestamp of the request in seconds since epoch
81
+ # @param [String] nonce the MAC header nonce
82
+ # @param [Symbol] verb the HTTP request method
83
+ # @param [String] url the HTTP URL path of the request
84
+ def signature(timestamp, nonce, verb, uri)
85
+ signature = [
86
+ timestamp,
87
+ nonce,
88
+ verb.to_s.upcase,
89
+ uri.request_uri,
90
+ uri.host,
91
+ uri.port,
92
+ '', nil
93
+ ].join("\n")
94
+
95
+ strict_encode64(OpenSSL::HMAC.digest(@algorithm, secret, signature))
96
+ end
97
+
98
+ # Set the HMAC algorithm
99
+ #
100
+ # @param [String] alg the algorithm to use (one of 'hmac-sha-1', 'hmac-sha-256')
101
+ def algorithm=(alg)
102
+ @algorithm = case alg.to_s
103
+ when 'hmac-sha-1'
104
+ OpenSSL::Digest::SHA1.new
105
+ when 'hmac-sha-256'
106
+ OpenSSL::Digest::SHA256.new
107
+ else
108
+ fail(ArgumentError, 'Unsupported algorithm')
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ # No-op since we need the verb and path
115
+ # and the MAC always goes in a header
116
+ def token=(_)
117
+ end
118
+
119
+ # Base64.strict_encode64 is not available on Ruby 1.8.7
120
+ def strict_encode64(str)
121
+ Base64.encode64(str).gsub("\n", '')
122
+ end
123
+ end
124
+ end
@@ -1,8 +1,8 @@
1
1
  module OAuth2
2
2
  class Version
3
- MAJOR = 0
4
- MINOR = 9
5
- PATCH = 4
3
+ MAJOR = 1
4
+ MINOR = 0
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  class << self
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.add_dependency 'rack', '~> 1.2'
12
12
  spec.add_development_dependency 'bundler', '~> 1.0'
13
13
  spec.authors = ['Michael Bleigh', 'Erik Michaels-Ober']
14
- spec.description = %q(A Ruby wrapper for the OAuth 2.0 protocol built with a similar style to the original OAuth spec.)
14
+ spec.description = 'A Ruby wrapper for the OAuth 2.0 protocol built with a similar style to the original OAuth spec.'
15
15
  spec.email = ['michael@intridea.com', 'sferik@gmail.com']
16
16
  spec.files = %w(.document CONTRIBUTING.md LICENSE.md README.md Rakefile oauth2.gemspec)
17
17
  spec.files += Dir.glob('lib/**/*.rb')
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.name = 'oauth2'
22
22
  spec.require_paths = %w(lib)
23
23
  spec.required_rubygems_version = '>= 1.3.5'
24
- spec.summary = %q(A Ruby wrapper for the OAuth 2.0 protocol.)
24
+ spec.summary = 'A Ruby wrapper for the OAuth 2.0 protocol.'
25
25
  spec.test_files = Dir.glob('spec/**/*')
26
26
  spec.version = OAuth2::Version
27
27
  end
@@ -8,13 +8,12 @@ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
8
8
 
9
9
  SimpleCov.start do
10
10
  add_filter '/spec/'
11
- minimum_coverage(95.29)
11
+ minimum_coverage(95.33)
12
12
  end
13
13
 
14
14
  require 'oauth2'
15
15
  require 'addressable/uri'
16
16
  require 'rspec'
17
- require 'rspec/autorun'
18
17
 
19
18
  RSpec.configure do |config|
20
19
  config.expect_with :rspec do |c|
@@ -39,3 +38,5 @@ def capture_output(&block)
39
38
  end
40
39
  result
41
40
  end
41
+
42
+ VERBS = [:get, :post, :put, :delete]
@@ -1,10 +1,7 @@
1
1
  require 'helper'
2
2
 
3
- VERBS = [:get, :post, :put, :delete]
4
-
5
3
  describe AccessToken do
6
4
  let(:token) { 'monkey' }
7
- let(:token_body) { MultiJson.encode(:access_token => 'foo', :expires_in => 600, :refresh_token => 'bar') }
8
5
  let(:refresh_body) { MultiJson.encode(:access_token => 'refreshed_foo', :expires_in => 600, :refresh_token => 'refresh_bar') }
9
6
  let(:client) do
10
7
  Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
@@ -120,8 +120,8 @@ describe OAuth2::Client do
120
120
  end
121
121
 
122
122
  it 'outputs to $stdout when OAUTH_DEBUG=true' do
123
- ENV.stub(:[]).with('http_proxy').and_return(nil)
124
- ENV.stub(:[]).with('OAUTH_DEBUG').and_return('true')
123
+ allow(ENV).to receive(:[]).with('http_proxy').and_return(nil)
124
+ allow(ENV).to receive(:[]).with('OAUTH_DEBUG').and_return('true')
125
125
  output = capture_output do
126
126
  subject.request(:get, '/success')
127
127
  end
@@ -0,0 +1,119 @@
1
+ require 'helper'
2
+
3
+ describe MACToken do
4
+ let(:token) { 'monkey' }
5
+ let(:client) do
6
+ Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
7
+ builder.request :url_encoded
8
+ builder.adapter :test do |stub|
9
+ VERBS.each do |verb|
10
+ stub.send(verb, '/token/header') { |env| [200, {}, env[:request_headers]['Authorization']] }
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ subject { MACToken.new(client, token, 'abc123') }
17
+
18
+ describe '#initialize' do
19
+ it 'assigns client and token' do
20
+ expect(subject.client).to eq(client)
21
+ expect(subject.token).to eq(token)
22
+ end
23
+
24
+ it 'assigns secret' do
25
+ expect(subject.secret).to eq('abc123')
26
+ end
27
+
28
+ it 'defaults algorithm to hmac-sha-256' do
29
+ expect(subject.algorithm).to be_instance_of(OpenSSL::Digest::SHA256)
30
+ end
31
+
32
+ it 'handles hmac-sha-256' do
33
+ mac = MACToken.new(client, token, 'abc123', :algorithm => 'hmac-sha-256')
34
+ expect(mac.algorithm).to be_instance_of(OpenSSL::Digest::SHA256)
35
+ end
36
+
37
+ it 'handles hmac-sha-1' do
38
+ mac = MACToken.new(client, token, 'abc123', :algorithm => 'hmac-sha-1')
39
+ expect(mac.algorithm).to be_instance_of(OpenSSL::Digest::SHA1)
40
+ end
41
+
42
+ it 'raises on improper algorithm' do
43
+ expect { MACToken.new(client, token, 'abc123', :algorithm => 'invalid-sha') }.to raise_error(ArgumentError)
44
+ end
45
+ end
46
+
47
+ describe '#request' do
48
+ VERBS.each do |verb|
49
+ it "sends the token in the Authorization header for a #{verb.to_s.upcase} request" do
50
+ expect(subject.post('/token/header').body).to include("MAC id=\"#{token}\"")
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#header' do
56
+ it 'does not generate the same header twice' do
57
+ header = subject.header('get', 'https://www.example.com/hello')
58
+ duplicate_header = subject.header('get', 'https://www.example.com/hello')
59
+
60
+ expect(header).to_not eq(duplicate_header)
61
+ end
62
+
63
+ it 'generates the proper format' do
64
+ header = subject.header('get', 'https://www.example.com/hello?a=1')
65
+ expect(header).to match(/MAC id="#{token}", ts="[0-9]+", nonce="[^"]+", mac="[^"]+"/)
66
+ end
67
+
68
+ it 'passes ArgumentError with an invalid url' do
69
+ expect { subject.header('get', 'this-is-not-valid') }.to raise_error(ArgumentError)
70
+ end
71
+
72
+ it 'passes URI::InvalidURIError through' do
73
+ expect { subject.header('get', nil) }.to raise_error(URI::InvalidURIError)
74
+ end
75
+ end
76
+
77
+ describe '#signature' do
78
+ it 'generates properly' do
79
+ signature = subject.signature(0, 'random-string', 'get', URI('https://www.google.com'))
80
+ expect(signature).to eq('rMDjVA3VJj3v1OmxM29QQljKia6msl5rjN83x3bZmi8=')
81
+ end
82
+ end
83
+
84
+ describe '#headers' do
85
+ it 'is an empty hash' do
86
+ expect(subject.headers).to eq({})
87
+ end
88
+ end
89
+
90
+ describe '.from_access_token' do
91
+ let(:access_token) do
92
+ AccessToken.new(
93
+ client, token,
94
+ :expires_at => 1,
95
+ :expires_in => 1,
96
+ :refresh_token => 'abc',
97
+ :random => 1
98
+ )
99
+ end
100
+
101
+ subject { MACToken.from_access_token(access_token, 'hello') }
102
+
103
+ it 'initializes client, token, and secret properly' do
104
+ expect(subject.client).to eq(client)
105
+ expect(subject.token).to eq(token)
106
+ expect(subject.secret).to eq('hello')
107
+ end
108
+
109
+ it 'initializes configuration options' do
110
+ expect(subject.expires_at).to eq(1)
111
+ expect(subject.expires_in).to eq(1)
112
+ expect(subject.refresh_token).to eq('abc')
113
+ end
114
+
115
+ it 'initializes params' do
116
+ expect(subject.params).to eq(:random => 1)
117
+ end
118
+ end
119
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oauth2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
@@ -9,96 +9,96 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-24 00:00:00.000000000 Z
12
+ date: 2014-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0.8'
21
- - - <
21
+ - - "<"
22
22
  - !ruby/object:Gem::Version
23
23
  version: '0.10'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
- - - '>='
28
+ - - ">="
29
29
  - !ruby/object:Gem::Version
30
30
  version: '0.8'
31
- - - <
31
+ - - "<"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0.10'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: jwt
36
36
  requirement: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
41
  type: :runtime
42
42
  prerelease: false
43
43
  version_requirements: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.0'
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: multi_json
50
50
  requirement: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.3'
55
55
  type: :runtime
56
56
  prerelease: false
57
57
  version_requirements: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.3'
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: multi_xml
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.5'
69
69
  type: :runtime
70
70
  prerelease: false
71
71
  version_requirements: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0.5'
76
76
  - !ruby/object:Gem::Dependency
77
77
  name: rack
78
78
  requirement: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.2'
83
83
  type: :runtime
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: '1.2'
90
90
  - !ruby/object:Gem::Dependency
91
91
  name: bundler
92
92
  requirement: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.0'
97
97
  type: :development
98
98
  prerelease: false
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: '1.0'
104
104
  description: A Ruby wrapper for the OAuth 2.0 protocol built with a similar style
@@ -110,34 +110,36 @@ executables: []
110
110
  extensions: []
111
111
  extra_rdoc_files: []
112
112
  files:
113
- - .document
113
+ - ".document"
114
114
  - CONTRIBUTING.md
115
115
  - LICENSE.md
116
116
  - README.md
117
117
  - Rakefile
118
- - oauth2.gemspec
119
118
  - lib/oauth2.rb
120
119
  - lib/oauth2/access_token.rb
121
120
  - lib/oauth2/client.rb
122
121
  - lib/oauth2/error.rb
122
+ - lib/oauth2/mac_token.rb
123
123
  - lib/oauth2/response.rb
124
- - lib/oauth2/version.rb
125
- - lib/oauth2/strategy/implicit.rb
126
- - lib/oauth2/strategy/password.rb
127
124
  - lib/oauth2/strategy/assertion.rb
128
125
  - lib/oauth2/strategy/auth_code.rb
129
126
  - lib/oauth2/strategy/base.rb
130
127
  - lib/oauth2/strategy/client_credentials.rb
128
+ - lib/oauth2/strategy/implicit.rb
129
+ - lib/oauth2/strategy/password.rb
130
+ - lib/oauth2/version.rb
131
+ - oauth2.gemspec
131
132
  - spec/helper.rb
132
133
  - spec/oauth2/access_token_spec.rb
133
134
  - spec/oauth2/client_spec.rb
135
+ - spec/oauth2/mac_token_spec.rb
134
136
  - spec/oauth2/response_spec.rb
135
- - spec/oauth2/strategy/auth_code_spec.rb
136
- - spec/oauth2/strategy/password_spec.rb
137
- - spec/oauth2/strategy/implicit_spec.rb
138
- - spec/oauth2/strategy/client_credentials_spec.rb
139
137
  - spec/oauth2/strategy/assertion_spec.rb
138
+ - spec/oauth2/strategy/auth_code_spec.rb
140
139
  - spec/oauth2/strategy/base_spec.rb
140
+ - spec/oauth2/strategy/client_credentials_spec.rb
141
+ - spec/oauth2/strategy/implicit_spec.rb
142
+ - spec/oauth2/strategy/password_spec.rb
141
143
  homepage: http://github.com/intridea/oauth2
142
144
  licenses:
143
145
  - MIT
@@ -148,17 +150,17 @@ require_paths:
148
150
  - lib
149
151
  required_ruby_version: !ruby/object:Gem::Requirement
150
152
  requirements:
151
- - - '>='
153
+ - - ">="
152
154
  - !ruby/object:Gem::Version
153
155
  version: '0'
154
156
  required_rubygems_version: !ruby/object:Gem::Requirement
155
157
  requirements:
156
- - - '>='
158
+ - - ">="
157
159
  - !ruby/object:Gem::Version
158
160
  version: 1.3.5
159
161
  requirements: []
160
162
  rubyforge_project:
161
- rubygems_version: 2.0.14
163
+ rubygems_version: 2.2.2
162
164
  signing_key:
163
165
  specification_version: 4
164
166
  summary: A Ruby wrapper for the OAuth 2.0 protocol.
@@ -166,11 +168,12 @@ test_files:
166
168
  - spec/helper.rb
167
169
  - spec/oauth2/access_token_spec.rb
168
170
  - spec/oauth2/client_spec.rb
171
+ - spec/oauth2/mac_token_spec.rb
169
172
  - spec/oauth2/response_spec.rb
170
- - spec/oauth2/strategy/auth_code_spec.rb
171
- - spec/oauth2/strategy/password_spec.rb
172
- - spec/oauth2/strategy/implicit_spec.rb
173
- - spec/oauth2/strategy/client_credentials_spec.rb
174
173
  - spec/oauth2/strategy/assertion_spec.rb
174
+ - spec/oauth2/strategy/auth_code_spec.rb
175
175
  - spec/oauth2/strategy/base_spec.rb
176
+ - spec/oauth2/strategy/client_credentials_spec.rb
177
+ - spec/oauth2/strategy/implicit_spec.rb
178
+ - spec/oauth2/strategy/password_spec.rb
176
179
  has_rdoc: