oauth2 1.1.0 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +19 -0
  3. data/.jrubyrc +1 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +80 -0
  6. data/.rubocop_rspec.yml +26 -0
  7. data/.rubocop_todo.yml +15 -0
  8. data/.ruby-version +1 -0
  9. data/.travis.yml +87 -0
  10. data/CHANGELOG.md +152 -0
  11. data/CODE_OF_CONDUCT.md +74 -0
  12. data/Gemfile +40 -0
  13. data/LICENSE +22 -0
  14. data/README.md +131 -22
  15. data/Rakefile +45 -0
  16. data/gemfiles/jruby_1.7.gemfile +11 -0
  17. data/gemfiles/jruby_9.0.gemfile +7 -0
  18. data/gemfiles/jruby_9.1.gemfile +3 -0
  19. data/gemfiles/jruby_9.2.gemfile +3 -0
  20. data/gemfiles/jruby_head.gemfile +3 -0
  21. data/gemfiles/ruby_1.9.gemfile +11 -0
  22. data/gemfiles/ruby_2.0.gemfile +6 -0
  23. data/gemfiles/ruby_2.1.gemfile +6 -0
  24. data/gemfiles/ruby_2.2.gemfile +3 -0
  25. data/gemfiles/ruby_2.3.gemfile +3 -0
  26. data/gemfiles/ruby_2.4.gemfile +3 -0
  27. data/gemfiles/ruby_2.5.gemfile +3 -0
  28. data/gemfiles/ruby_2.6.gemfile +9 -0
  29. data/gemfiles/ruby_2.7.gemfile +9 -0
  30. data/gemfiles/ruby_head.gemfile +9 -0
  31. data/gemfiles/truffleruby.gemfile +3 -0
  32. data/lib/oauth2/access_token.rb +6 -6
  33. data/lib/oauth2/authenticator.rb +68 -0
  34. data/lib/oauth2/client.rb +49 -14
  35. data/lib/oauth2/error.rb +21 -5
  36. data/lib/oauth2/mac_token.rb +3 -3
  37. data/lib/oauth2/response.rb +1 -1
  38. data/lib/oauth2/strategy/assertion.rb +13 -11
  39. data/lib/oauth2/strategy/auth_code.rb +2 -1
  40. data/lib/oauth2/strategy/base.rb +0 -7
  41. data/lib/oauth2/strategy/client_credentials.rb +2 -14
  42. data/lib/oauth2/strategy/implicit.rb +1 -1
  43. data/lib/oauth2/strategy/password.rb +2 -2
  44. data/lib/oauth2/version.rb +2 -2
  45. data/lib/oauth2.rb +1 -0
  46. data/oauth2.gemspec +37 -9
  47. metadata +212 -20
  48. data/LICENSE.md +0 -20
data/README.md CHANGED
@@ -1,30 +1,72 @@
1
1
  # OAuth2
2
2
 
3
+ If you need the readme for a released version of the gem please find it below:
4
+
5
+ | Version | Release Date | Readme |
6
+ |----------|--------------|----------------------------------------------------------|
7
+ | 1.4.3 | Jan 29, 2020 | https://github.com/oauth-xx/oauth2/blob/v1.4.3/README.md |
8
+ | 1.4.2 | Oct 1, 2019 | https://github.com/oauth-xx/oauth2/blob/v1.4.2/README.md |
9
+ | 1.4.1 | Oct 13, 2018 | https://github.com/oauth-xx/oauth2/blob/v1.4.1/README.md |
10
+ | 1.4.0 | Jun 9, 2017 | https://github.com/oauth-xx/oauth2/blob/v1.4.0/README.md |
11
+ | 1.3.1 | Mar 3, 2017 | https://github.com/oauth-xx/oauth2/blob/v1.3.1/README.md |
12
+ | 1.3.0 | Dec 27, 2016 | https://github.com/oauth-xx/oauth2/blob/v1.3.0/README.md |
13
+ | 1.2.0 | Jun 30, 2016 | https://github.com/oauth-xx/oauth2/blob/v1.2.0/README.md |
14
+ | 1.1.0 | Jan 30, 2016 | https://github.com/oauth-xx/oauth2/blob/v1.1.0/README.md |
15
+ | 1.0.0 | May 23, 2014 | https://github.com/oauth-xx/oauth2/blob/v1.0.0/README.md |
16
+ | < 1.0.0 | Find here | https://github.com/oauth-xx/oauth2/tags |
17
+
3
18
  [![Gem Version](http://img.shields.io/gem/v/oauth2.svg)][gem]
4
- [![Build Status](http://img.shields.io/travis/intridea/oauth2.svg)][travis]
5
- [![Dependency Status](http://img.shields.io/gemnasium/intridea/oauth2.svg)][gemnasium]
6
- [![Code Climate](http://img.shields.io/codeclimate/github/intridea/oauth2.svg)][codeclimate]
7
- [![Coverage Status](http://img.shields.io/coveralls/intridea/oauth2.svg)][coveralls]
19
+ [![Total Downloads](https://img.shields.io/gem/dt/oauth2.svg)][gem]
20
+ [![Downloads Today](https://img.shields.io/gem/rt/oauth2.svg)][gem]
21
+ [![Build Status](https://travis-ci.org/oauth-xx/oauth2.svg?branch=1-4-stable)][travis]
22
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/688c612528ff90a46955/test_coverage)][codeclimate-coverage]
23
+ [![Maintainability](https://api.codeclimate.com/v1/badges/688c612528ff90a46955/maintainability)][codeclimate-maintainability]
24
+ [![Depfu](https://badges.depfu.com/badges/6d34dc1ba682bbdf9ae2a97848241743/count.svg)][depfu]
25
+ [![Open Source Helpers](https://www.codetriage.com/oauth-xx/oauth2/badges/users.svg)][code-triage]
26
+ [![Chat](https://img.shields.io/gitter/room/oauth-xx/oauth2.svg)](https://gitter.im/oauth-xx/oauth2)
27
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)][source-license]
28
+ [![Documentation](http://inch-ci.org/github/oauth-xx/oauth2.png)][inch-ci]
8
29
 
9
30
  [gem]: https://rubygems.org/gems/oauth2
10
- [travis]: http://travis-ci.org/intridea/oauth2
11
- [gemnasium]: https://gemnasium.com/intridea/oauth2
12
- [codeclimate]: https://codeclimate.com/github/intridea/oauth2
13
- [coveralls]: https://coveralls.io/r/intridea/oauth2
31
+ [travis]: http://travis-ci.org/oauth-xx/oauth2
32
+ [coveralls]: https://coveralls.io/r/oauth-xx/oauth2
33
+ [codeclimate-maintainability]: https://codeclimate.com/github/oauth-xx/oauth2/maintainability
34
+ [codeclimate-coverage]: https://codeclimate.com/github/oauth-xx/oauth2/test_coverage
35
+ [depfu]: https://depfu.com/github/oauth-xx/oauth2
36
+ [source-license]: https://opensource.org/licenses/MIT
37
+ [inch-ci]: http://inch-ci.org/github/oauth-xx/oauth2
38
+ [code-triage]: https://www.codetriage.com/oauth-xx/oauth2
39
+ [fossa1]: https://app.fossa.io/projects/git%2Bgithub.com%2Foauth-xx%2Foauth2?ref=badge_shield
40
+
41
+ A Ruby wrapper for the [OAuth 2.0 specification][oauth2-spec].
14
42
 
15
- A Ruby wrapper for the OAuth 2.0 specification.
43
+ [oauth2-spec]: https://oauth.net/2/
16
44
 
17
45
  ## Installation
18
- gem install oauth2
46
+
47
+ Add this line to your application's Gemfile:
48
+
49
+ ```ruby
50
+ gem 'oauth2'
51
+ ```
52
+
53
+ And then execute:
54
+
55
+ $ bundle
56
+
57
+ Or install it yourself as:
58
+
59
+ $ gem install oauth2
19
60
 
20
61
  ## Resources
62
+
21
63
  * [View Source on GitHub][code]
22
64
  * [Report Issues on GitHub][issues]
23
65
  * [Read More at the Wiki][wiki]
24
66
 
25
- [code]: https://github.com/intridea/oauth2
26
- [issues]: https://github.com/intridea/oauth2/issues
27
- [wiki]: https://wiki.github.com/intridea/oauth2
67
+ [code]: https://github.com/oauth-xx/oauth2
68
+ [issues]: https://github.com/oauth-xx/oauth2/issues
69
+ [wiki]: https://wiki.github.com/oauth-xx/oauth2
28
70
 
29
71
  ## Usage Examples
30
72
 
@@ -41,6 +83,7 @@ response.class.name
41
83
  # => OAuth2::Response
42
84
  ```
43
85
  ## OAuth2::Response
86
+
44
87
  The AccessToken methods #get, #post, #put and #delete and the generic #request
45
88
  will return an instance of the #OAuth2::Response class.
46
89
 
@@ -53,12 +96,14 @@ The original response body, headers, and status can be accessed via their
53
96
  respective methods.
54
97
 
55
98
  ## OAuth2::AccessToken
99
+
56
100
  If you have an existing Access Token for a user, you can initialize an instance
57
101
  using various class methods including the standard new, from_hash (if you have
58
102
  a hash of the values), or from_kvform (if you have an
59
103
  application/x-www-form-urlencoded encoded string of the values).
60
104
 
61
105
  ## OAuth2::Error
106
+
62
107
  On 400+ status code responses, an OAuth2::Error will be raised. If it is a
63
108
  standard OAuth2 error response, the body will be parsed and #code and #description will contain the values provided from the error and
64
109
  error_description parameters. The #response property of OAuth2::Error will
@@ -70,6 +115,7 @@ instance will be returned as usual and on 400+ status code responses, the
70
115
  Response instance will contain the OAuth2::Error instance.
71
116
 
72
117
  ## Authorization Grants
118
+
73
119
  Currently the Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials, and Assertion
74
120
  authentication grant types have helper strategy classes that simplify client
75
121
  use. They are available via the #auth_code, #implicit, #password, #client_credentials, and #assertion methods respectively.
@@ -100,18 +146,38 @@ You can always use the #request method on the OAuth2::Client instance to make
100
146
  requests for tokens for any Authentication grant type.
101
147
 
102
148
  ## Supported Ruby Versions
149
+
103
150
  This library aims to support and is [tested against][travis] the following Ruby
104
151
  implementations:
105
152
 
106
- * Ruby 1.8.7
153
+ ### Rubies with support ending at Oauth2 1.x
154
+
107
155
  * Ruby 1.9.3
156
+ - [JRuby 1.7][jruby-1.7] (targets MRI v1.9)
157
+
108
158
  * Ruby 2.0.0
109
- * Ruby 2.1.0
110
- * [JRuby][]
111
- * [Rubinius][]
159
+ - [JRuby 9.0][jruby-9.0] (targets MRI v2.0)
160
+ * Ruby 2.1
161
+
162
+ ---
163
+
164
+ ### Rubies with continued support past Oauth2 2.x
112
165
 
113
- [jruby]: http://jruby.org/
114
- [rubinius]: http://rubini.us/
166
+ * Ruby 2.2 - Support ends with version 2.x series
167
+ * Ruby 2.3 - Support ends with version 3.x series
168
+ - [JRuby 9.1][jruby-9.1] (targets MRI v2.3)
169
+ * Ruby 2.4 - Support ends with version 4.x series
170
+ * Ruby 2.5 - Support ends with version 5.x series
171
+ - [JRuby 9.2][jruby-9.2] (targets MRI v2.5)
172
+ - [truffleruby][truffleruby] (targets MRI 2.5)
173
+ * Ruby 2.6 - Support ends with version 6.x series
174
+ * Ruby 2.7 - Support ends with version 7.x series
175
+
176
+ [jruby-1.7]: https://www.jruby.org/2017/05/11/jruby-1-7-27.html
177
+ [jruby-9.0]: https://www.jruby.org/2016/01/26/jruby-9-0-5-0.html
178
+ [jruby-9.1]: https://www.jruby.org/2017/05/16/jruby-9-1-9-0.html
179
+ [jruby-9.2]: https://www.jruby.org/2018/05/24/jruby-9-2-0-0.html
180
+ [truffleruby]: https://github.com/oracle/truffleruby
115
181
 
116
182
  If something doesn't work on one of these interpreters, it's a bug.
117
183
 
@@ -126,8 +192,51 @@ implementation, you will be responsible for providing patches in a timely
126
192
  fashion. If critical issues for a particular implementation exist at the time
127
193
  of a major release, support for that Ruby version may be dropped.
128
194
 
195
+ ## Versioning
196
+
197
+ This library aims to adhere to [Semantic Versioning 2.0.0][semver].
198
+ Violations of this scheme should be reported as bugs. Specifically,
199
+ if a minor or patch version is released that breaks backward
200
+ compatibility, a new version should be immediately released that
201
+ restores compatibility. Breaking changes to the public API will
202
+ only be introduced with new major versions.
203
+
204
+ As a result of this policy, you can (and should) specify a
205
+ dependency on this gem using the [Pessimistic Version Constraint][pvc] with two digits of precision.
206
+
207
+ For example:
208
+
209
+ ```ruby
210
+ spec.add_dependency 'oauth2', '~> 1.4'
211
+ ```
212
+
213
+ [semver]: http://semver.org/
214
+ [pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
215
+
129
216
  ## License
130
- Copyright (c) 2011-2013 Michael Bleigh and Intridea, Inc. See [LICENSE][] for
131
- details.
132
217
 
133
- [license]: LICENSE.md
218
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)][source-license]
219
+
220
+ - Copyright (c) 2011-2013 Michael Bleigh and Intridea, Inc.
221
+ - Copyright (c) 2017-2018 [oauth-xx organization][oauth-xx]
222
+ - See [LICENSE][license] for details.
223
+
224
+ [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Foauth-xx%2Foauth2.svg?type=large)][fossa2]
225
+
226
+ [license]: LICENSE
227
+ [oauth-xx]: https://github.com/oauth-xx
228
+ [fossa2]: https://app.fossa.io/projects/git%2Bgithub.com%2Foauth-xx%2Foauth2?ref=badge_large
229
+
230
+ ## Development
231
+
232
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
233
+
234
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
235
+
236
+ ## Contributing
237
+
238
+ Bug reports and pull requests are welcome on GitHub at https://github.com/oauth-xx/oauth2. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
239
+
240
+ ## Code of Conduct
241
+
242
+ Everyone interacting in the OAuth2 project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/oauth-xx/oauth2/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ # !/usr/bin/env rake
4
+
5
+ require 'bundler/gem_tasks'
6
+
7
+ begin
8
+ require 'wwtd/tasks'
9
+ rescue LoadError
10
+ puts 'failed to load wwtd'
11
+ end
12
+
13
+ begin
14
+ require 'rspec/core/rake_task'
15
+ RSpec::Core::RakeTask.new(:spec)
16
+ rescue LoadError
17
+ task :spec do
18
+ warn 'rspec is disabled'
19
+ end
20
+ end
21
+ task :test => :spec
22
+
23
+ begin
24
+ require 'rubocop/rake_task'
25
+ RuboCop::RakeTask.new do |task|
26
+ task.options = ['-D'] # Display the name of the failing cops
27
+ end
28
+ rescue LoadError
29
+ task :rubocop do
30
+ warn 'RuboCop is disabled'
31
+ end
32
+ end
33
+
34
+ namespace :doc do
35
+ require 'rdoc/task'
36
+ require File.expand_path('../lib/oauth2/version', __FILE__)
37
+ RDoc::Task.new do |rdoc|
38
+ rdoc.rdoc_dir = 'rdoc'
39
+ rdoc.title = "oauth2 #{OAuth2::Version}"
40
+ rdoc.main = 'README.md'
41
+ rdoc.rdoc_files.include('README.md', 'LICENSE.md', 'lib/**/*.rb')
42
+ end
43
+ end
44
+
45
+ task :default => [:test, :rubocop]
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'faraday', '~> 0.15.4'
4
+
5
+ gem 'json', '< 2.0'
6
+ gem 'rack', '~> 1.2'
7
+ gem 'rake', [">= 10.0", "< 12"]
8
+ gem 'term-ansicolor', '< 1.4.0'
9
+ gem 'tins', '< 1.7'
10
+
11
+ gemspec :path => '../'
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'faraday', '~> 0.15.4'
4
+
5
+ gem 'rake', [">= 10.0", "< 12"]
6
+
7
+ gemspec :path => '../'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => '../'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => '../'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => '../'
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'faraday', '~> 0.15.4'
4
+
5
+ gem 'json', '< 2.0'
6
+ gem 'rack', '~> 1.2'
7
+ gem 'rake', [">= 10.0", "< 12"]
8
+ gem 'term-ansicolor', '< 1.4.0'
9
+ gem 'tins', '< 1.7'
10
+
11
+ gemspec :path => '../'
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'faraday', '~> 0.15.4'
4
+ gem 'rack', '~> 1.2'
5
+
6
+ gemspec :path => '../'
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'faraday', '~> 0.15.4'
4
+ gem 'rack', '~> 1.2'
5
+
6
+ gemspec :path => '../'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => '../'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => '../'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => '../'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development do
4
+ gem 'pry'
5
+ gem 'byebug'
6
+ gem 'pry-byebug'
7
+ end
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development do
4
+ gem 'pry'
5
+ gem 'byebug'
6
+ gem 'pry-byebug'
7
+ end
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development do
4
+ gem 'pry'
5
+ gem 'byebug'
6
+ gem 'pry-byebug'
7
+ end
8
+
9
+ gemspec :path => '../'
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => '../'
@@ -10,6 +10,7 @@ module OAuth2
10
10
  # @param [Hash] a hash of AccessToken property values
11
11
  # @return [AccessToken] the initalized AccessToken
12
12
  def from_hash(client, hash)
13
+ hash = hash.dup
13
14
  new(client, hash.delete('access_token') || hash.delete(:access_token), hash)
14
15
  end
15
16
 
@@ -39,6 +40,7 @@ module OAuth2
39
40
  def initialize(client, token, opts = {}) # rubocop:disable Metrics/AbcSize
40
41
  @client = client
41
42
  @token = token.to_s
43
+ opts = opts.dup
42
44
  [:refresh_token, :expires_in, :expires_at].each do |arg|
43
45
  instance_variable_set("@#{arg}", opts.delete(arg) || opts.delete(arg.to_s))
44
46
  end
@@ -78,9 +80,7 @@ module OAuth2
78
80
  # @return [AccessToken] a new AccessToken
79
81
  # @note options should be carried over to the new AccessToken
80
82
  def refresh!(params = {})
81
- fail('A refresh_token is not available') unless refresh_token
82
- params[:client_id] = @client.id
83
- params[:client_secret] = @client.secret
83
+ raise('A refresh_token is not available') unless refresh_token
84
84
  params[:grant_type] = 'refresh_token'
85
85
  params[:refresh_token] = refresh_token
86
86
  new_token = @client.get_token(params)
@@ -103,7 +103,7 @@ module OAuth2
103
103
  # @param [Hash] opts the options to make the request with
104
104
  # @see Client#request
105
105
  def request(verb, path, opts = {}, &block)
106
- self.token = opts
106
+ configure_authentication!(opts)
107
107
  @client.request(verb, path, opts, &block)
108
108
  end
109
109
 
@@ -149,7 +149,7 @@ module OAuth2
149
149
 
150
150
  private
151
151
 
152
- def token=(opts) # rubocop:disable MethodLength, Metrics/AbcSize
152
+ def configure_authentication!(opts) # rubocop:disable MethodLength, Metrics/AbcSize
153
153
  case options[:mode]
154
154
  when :header
155
155
  opts[:headers] ||= {}
@@ -166,7 +166,7 @@ module OAuth2
166
166
  end
167
167
  # @todo support for multi-part (file uploads)
168
168
  else
169
- fail("invalid :mode option of #{options[:mode]}")
169
+ raise("invalid :mode option of #{options[:mode]}")
170
170
  end
171
171
  end
172
172
  end
@@ -0,0 +1,68 @@
1
+ require 'base64'
2
+
3
+ module OAuth2
4
+ class Authenticator
5
+ attr_reader :mode, :id, :secret
6
+
7
+ def initialize(id, secret, mode)
8
+ @id = id
9
+ @secret = secret
10
+ @mode = mode
11
+ end
12
+
13
+ # Apply the request credentials used to authenticate to the Authorization Server
14
+ #
15
+ # Depending on configuration, this might be as request params or as an
16
+ # Authorization header.
17
+ #
18
+ # User-provided params and header take precedence.
19
+ #
20
+ # @param [Hash] params a Hash of params for the token endpoint
21
+ # @return [Hash] params amended with appropriate authentication details
22
+ def apply(params)
23
+ case mode.to_sym
24
+ when :basic_auth
25
+ apply_basic_auth(params)
26
+ when :request_body
27
+ apply_params_auth(params)
28
+ when :tls_client_auth
29
+ apply_client_id(params)
30
+ when :private_key_jwt
31
+ params
32
+ else
33
+ raise NotImplementedError
34
+ end
35
+ end
36
+
37
+ def self.encode_basic_auth(user, password)
38
+ 'Basic ' + Base64.encode64(user + ':' + password).delete("\n")
39
+ end
40
+
41
+ private
42
+
43
+ # Adds client_id and client_secret request parameters if they are not
44
+ # already set.
45
+ def apply_params_auth(params)
46
+ {'client_id' => id, 'client_secret' => secret}.merge(params)
47
+ end
48
+
49
+ # When using schemes that don't require the client_secret to be passed i.e TLS Client Auth,
50
+ # we don't want to send the secret
51
+ def apply_client_id(params)
52
+ { 'client_id' => id }.merge(params)
53
+ end
54
+
55
+ # Adds an `Authorization` header with Basic Auth credentials if and only if
56
+ # it is not already set in the params.
57
+ def apply_basic_auth(params)
58
+ headers = params.fetch(:headers, {})
59
+ headers = basic_auth_header.merge(headers)
60
+ params.merge(:headers => headers)
61
+ end
62
+
63
+ # @see https://tools.ietf.org/html/rfc2617#section-2
64
+ def basic_auth_header
65
+ {'Authorization' => self.class.encode_basic_auth(id, secret)}
66
+ end
67
+ end
68
+ end
data/lib/oauth2/client.rb CHANGED
@@ -3,7 +3,7 @@ require 'logger'
3
3
 
4
4
  module OAuth2
5
5
  # The OAuth2::Client class
6
- class Client
6
+ class Client # rubocop:disable Metrics/ClassLength
7
7
  attr_reader :id, :secret, :site
8
8
  attr_accessor :options
9
9
  attr_writer :connection
@@ -16,9 +16,11 @@ module OAuth2
16
16
  # @param [String] client_secret the client_secret value
17
17
  # @param [Hash] opts the options to create the client with
18
18
  # @option opts [String] :site the OAuth2 provider site host
19
+ # @option opts [String] :redirect_uri the absolute URI to the Redirection Endpoint for use in authorization grants and token exchange
19
20
  # @option opts [String] :authorize_url ('/oauth/authorize') absolute or relative URL path to the Authorization endpoint
20
21
  # @option opts [String] :token_url ('/oauth/token') absolute or relative URL path to the Token endpoint
21
22
  # @option opts [Symbol] :token_method (:post) HTTP method to use to request token (:get or :post)
23
+ # @option opts [Symbol] :auth_scheme (:basic_auth) HTTP method to use to authorize request (:basic_auth or :request_body)
22
24
  # @option opts [Hash] :connection_opts ({}) Hash of connection options to pass to initialize Faraday with
23
25
  # @option opts [FixNum] :max_redirects (5) maximum number of redirects to follow
24
26
  # @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error
@@ -33,6 +35,7 @@ module OAuth2
33
35
  @options = {:authorize_url => '/oauth/authorize',
34
36
  :token_url => '/oauth/token',
35
37
  :token_method => :post,
38
+ :auth_scheme => :request_body,
36
39
  :connection_opts => {},
37
40
  :connection_build => block,
38
41
  :max_redirects => 5,
@@ -52,9 +55,11 @@ module OAuth2
52
55
  def connection
53
56
  @connection ||= begin
54
57
  conn = Faraday.new(site, options[:connection_opts])
55
- conn.build do |b|
56
- options[:connection_build].call(b)
57
- end if options[:connection_build]
58
+ if options[:connection_build]
59
+ conn.build do |b|
60
+ options[:connection_build].call(b)
61
+ end
62
+ end
58
63
  conn
59
64
  end
60
65
  end
@@ -62,7 +67,8 @@ module OAuth2
62
67
  # The authorize endpoint URL of the OAuth2 provider
63
68
  #
64
69
  # @param [Hash] params additional query parameters
65
- def authorize_url(params = nil)
70
+ def authorize_url(params = {})
71
+ params = (params || {}).merge(redirection_params)
66
72
  connection.build_url(options[:authorize_url], params).to_s
67
73
  end
68
74
 
@@ -88,9 +94,10 @@ module OAuth2
88
94
  def request(verb, url, opts = {}) # rubocop:disable CyclomaticComplexity, MethodLength, Metrics/AbcSize
89
95
  connection.response :logger, ::Logger.new($stdout) if ENV['OAUTH_DEBUG'] == 'true'
90
96
 
91
- url = connection.build_url(url, opts[:params]).to_s
97
+ url = connection.build_url(url).to_s
92
98
 
93
99
  response = connection.run_request(verb, url, opts[:body], opts[:headers]) do |req|
100
+ req.params.update(opts[:params]) if opts[:params]
94
101
  yield(req) if block_given?
95
102
  end
96
103
  response = Response.new(response, :parse => opts[:parse])
@@ -110,12 +117,12 @@ module OAuth2
110
117
  response
111
118
  when 400..599
112
119
  error = Error.new(response)
113
- fail(error) if opts.fetch(:raise_errors, options[:raise_errors])
120
+ raise(error) if opts.fetch(:raise_errors, options[:raise_errors])
114
121
  response.error = error
115
122
  response
116
123
  else
117
124
  error = Error.new(response)
118
- fail(error, "Unhandled status code value of #{response.status}")
125
+ raise(error, "Unhandled status code value of #{response.status}")
119
126
  end
120
127
  end
121
128
 
@@ -124,20 +131,24 @@ module OAuth2
124
131
  # @param [Hash] params a Hash of params for the token endpoint
125
132
  # @param [Hash] access token options, to pass to the AccessToken object
126
133
  # @param [Class] class of access token for easier subclassing OAuth2::AccessToken
127
- # @return [AccessToken] the initalized AccessToken
128
- def get_token(params, access_token_opts = {}, access_token_class = AccessToken) # rubocop:disable Metrics/AbcSize
134
+ # @return [AccessToken] the initialized AccessToken
135
+ def get_token(params, access_token_opts = {}, access_token_class = AccessToken) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
136
+ params = Authenticator.new(id, secret, options[:auth_scheme]).apply(params)
129
137
  opts = {:raise_errors => options[:raise_errors], :parse => params.delete(:parse)}
138
+ headers = params.delete(:headers) || {}
130
139
  if options[:token_method] == :post
131
- headers = params.delete(:headers)
132
140
  opts[:body] = params
133
141
  opts[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
134
- opts[:headers].merge!(headers) if headers
135
142
  else
136
143
  opts[:params] = params
144
+ opts[:headers] = {}
137
145
  end
146
+ opts[:headers].merge!(headers)
138
147
  response = request(options[:token_method], token_url, opts)
139
- error = Error.new(response)
140
- fail(error) if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
148
+ if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
149
+ error = Error.new(response)
150
+ raise(error)
151
+ end
141
152
  access_token_class.from_hash(self, response.parsed.merge(access_token_opts))
142
153
  end
143
154
 
@@ -172,5 +183,29 @@ module OAuth2
172
183
  def assertion
173
184
  @assertion ||= OAuth2::Strategy::Assertion.new(self)
174
185
  end
186
+
187
+ # The redirect_uri parameters, if configured
188
+ #
189
+ # The redirect_uri query parameter is OPTIONAL (though encouraged) when
190
+ # requesting authorization. If it is provided at authorization time it MUST
191
+ # also be provided with the token exchange request.
192
+ #
193
+ # Providing the :redirect_uri to the OAuth2::Client instantiation will take
194
+ # care of managing this.
195
+ #
196
+ # @api semipublic
197
+ #
198
+ # @see https://tools.ietf.org/html/rfc6749#section-4.1
199
+ # @see https://tools.ietf.org/html/rfc6749#section-4.1.3
200
+ # @see https://tools.ietf.org/html/rfc6749#section-4.2.1
201
+ # @see https://tools.ietf.org/html/rfc6749#section-10.6
202
+ # @return [Hash] the params to add to a request or URL
203
+ def redirection_params
204
+ if options[:redirect_uri]
205
+ {'redirect_uri' => options[:redirect_uri]}
206
+ else
207
+ {}
208
+ end
209
+ end
175
210
  end
176
211
  end