oauth2 0.9.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: