oauth2 1.2.0 → 1.3.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: 64323d2b66a74a3aba80fa955d23d280e64ede95
4
- data.tar.gz: b5d9c12d616a0ccd67d15eed3b887cd6b1e174ec
3
+ metadata.gz: 0de0695b29bf1d20066a08a8536d70a9bea3e827
4
+ data.tar.gz: 184943366118bf412220fbde4ac0d1becdfa2055
5
5
  SHA512:
6
- metadata.gz: d0c36b6f6f2a2b8db5d8aae0f7897ffa6de5321ee06064f757f523ca144a119befde42d13943f4507848999adc0f68b011534ddd64258210dbabbcfa6c83e34b
7
- data.tar.gz: 8aef0531493683b4b9fc390a545e297e1107611d76363486acc473925264337438992b3f7b288a546e17685a7d198e306fc8b2d4f3dc153c1acd1f20f7e6cca7
6
+ metadata.gz: 8fe7c101b47debe6489b4bad62211d774079f599749fcc7e36fddd076f305db8ae3baab500877656a5a698b1484da1467d3a9b60fff07b9520d9cc314e542f8b
7
+ data.tar.gz: da02d83327a1c147bd6cf28cc416bcb4c82168c723f17871fcc1a3b16cb42e35726672055a2829234d6e8b565e1d576fc339b747467f38f728e9559cb087b3cc
@@ -1,4 +1,5 @@
1
1
  require 'oauth2/error'
2
+ require 'oauth2/authenticator'
2
3
  require 'oauth2/client'
3
4
  require 'oauth2/strategy/base'
4
5
  require 'oauth2/strategy/auth_code'
@@ -81,8 +81,6 @@ module OAuth2
81
81
  # @note options should be carried over to the new AccessToken
82
82
  def refresh!(params = {})
83
83
  raise('A refresh_token is not available') unless refresh_token
84
- params[:client_id] = @client.id
85
- params[:client_secret] = @client.secret
86
84
  params[:grant_type] = 'refresh_token'
87
85
  params[:refresh_token] = refresh_token
88
86
  new_token = @client.get_token(params)
@@ -105,7 +103,7 @@ module OAuth2
105
103
  # @param [Hash] opts the options to make the request with
106
104
  # @see Client#request
107
105
  def request(verb, path, opts = {}, &block)
108
- self.token = opts
106
+ configure_authentication!(opts)
109
107
  @client.request(verb, path, opts, &block)
110
108
  end
111
109
 
@@ -151,7 +149,7 @@ module OAuth2
151
149
 
152
150
  private
153
151
 
154
- def token=(opts) # rubocop:disable MethodLength, Metrics/AbcSize
152
+ def configure_authentication!(opts) # rubocop:disable MethodLength, Metrics/AbcSize
155
153
  case options[:mode]
156
154
  when :header
157
155
  opts[:headers] ||= {}
@@ -0,0 +1,58 @@
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
+ else
29
+ raise NotImplementedError
30
+ end
31
+ end
32
+
33
+ def self.encode_basic_auth(user, password)
34
+ 'Basic ' + Base64.encode64(user + ':' + password).delete("\n")
35
+ end
36
+
37
+ private
38
+
39
+ # Adds client_id and client_secret request parameters if they are not
40
+ # already set.
41
+ def apply_params_auth(params)
42
+ {'client_id' => id, 'client_secret' => secret}.merge(params)
43
+ end
44
+
45
+ # Adds an `Authorization` header with Basic Auth credentials if and only if
46
+ # it is not already set in the params.
47
+ def apply_basic_auth(params)
48
+ headers = params.fetch(:headers, {})
49
+ headers = basic_auth_header.merge(headers)
50
+ params.merge(:headers => headers)
51
+ end
52
+
53
+ # @see https://tools.ietf.org/html/rfc2617#section-2
54
+ def basic_auth_header
55
+ {'Authorization' => self.class.encode_basic_auth(id, secret)}
56
+ end
57
+ end
58
+ end
@@ -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
 
@@ -125,19 +131,23 @@ module OAuth2
125
131
  # @param [Hash] access token options, to pass to the AccessToken object
126
132
  # @param [Class] class of access token for easier subclassing OAuth2::AccessToken
127
133
  # @return [AccessToken] the initalized AccessToken
128
- def get_token(params, access_token_opts = {}, access_token_class = AccessToken) # rubocop:disable Metrics/AbcSize
134
+ def get_token(params, access_token_opts = {}, access_token_class = AccessToken) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
135
+ params = Authenticator.new(id, secret, options[:auth_scheme]).apply(params)
129
136
  opts = {:raise_errors => options[:raise_errors], :parse => params.delete(:parse)}
137
+ headers = params.delete(:headers) || {}
130
138
  if options[:token_method] == :post
131
- headers = params.delete(:headers)
132
139
  opts[:body] = params
133
140
  opts[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
134
- opts[:headers].merge!(headers) if headers
135
141
  else
136
142
  opts[:params] = params
143
+ opts[:headers] = {}
137
144
  end
145
+ opts[:headers].merge!(headers)
138
146
  response = request(options[:token_method], token_url, opts)
139
- error = Error.new(response)
140
- raise(error) if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
147
+ if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
148
+ error = Error.new(response)
149
+ raise(error)
150
+ end
141
151
  access_token_class.from_hash(self, response.parsed.merge(access_token_opts))
142
152
  end
143
153
 
@@ -172,5 +182,29 @@ module OAuth2
172
182
  def assertion
173
183
  @assertion ||= OAuth2::Strategy::Assertion.new(self)
174
184
  end
185
+
186
+ # The redirect_uri parameters, if configured
187
+ #
188
+ # The redirect_uri query parameter is OPTIONAL (though encouraged) when
189
+ # requesting authorization. If it is provided at authorization time it MUST
190
+ # also be provided with the token exchange request.
191
+ #
192
+ # Providing the :redirect_uri to the OAuth2::Client instantiation will take
193
+ # care of managing this.
194
+ #
195
+ # @api semipublic
196
+ #
197
+ # @see https://tools.ietf.org/html/rfc6749#section-4.1
198
+ # @see https://tools.ietf.org/html/rfc6749#section-4.1.3
199
+ # @see https://tools.ietf.org/html/rfc6749#section-4.2.1
200
+ # @see https://tools.ietf.org/html/rfc6749#section-10.6
201
+ # @return [Hash] the params to add to a request or URL
202
+ def redirection_params
203
+ if options[:redirect_uri]
204
+ {'redirect_uri' => options[:redirect_uri]}
205
+ else
206
+ {}
207
+ end
208
+ end
175
209
  end
176
210
  end
@@ -27,7 +27,7 @@ module OAuth2
27
27
 
28
28
  error_message = if opts[:error_description] && opts[:error_description].respond_to?(:encoding)
29
29
  script_encoding = opts[:error_description].encoding
30
- response_body.encode(script_encoding)
30
+ response_body.encode(script_encoding, :invalid => :replace, :undef => :replace)
31
31
  else
32
32
  response_body
33
33
  end
@@ -27,7 +27,7 @@ module OAuth2
27
27
  # Adds a new content type parser.
28
28
  #
29
29
  # @param [Symbol] key A descriptive symbol key such as :json or :query.
30
- # @param [Array] One or more mime types to which this parser applies.
30
+ # @param [Array] mime_types One or more mime types to which this parser applies.
31
31
  # @yield [String] A block returning parsed content.
32
32
  def self.register_parser(key, mime_types, &block)
33
33
  key = key.to_sym
@@ -54,7 +54,7 @@ module OAuth2
54
54
  :assertion_type => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
55
55
  :assertion => assertion,
56
56
  :scope => params[:scope],
57
- }.merge(client_params)
57
+ }
58
58
  end
59
59
 
60
60
  def build_assertion(params)
@@ -25,7 +25,8 @@ module OAuth2
25
25
  # @param [Hash] opts options
26
26
  # @note that you must also provide a :redirect_uri with most OAuth 2.0 providers
27
27
  def get_token(code, params = {}, opts = {})
28
- params = {'grant_type' => 'authorization_code', 'code' => code}.merge(client_params).merge(params)
28
+ params = {'grant_type' => 'authorization_code', 'code' => code}.merge(@client.redirection_params).merge(params)
29
+
29
30
  @client.get_token(params, opts)
30
31
  end
31
32
  end
@@ -4,13 +4,6 @@ module OAuth2
4
4
  def initialize(client)
5
5
  @client = client
6
6
  end
7
-
8
- # The OAuth client_id and client_secret
9
- #
10
- # @return [Hash]
11
- def client_params
12
- {'client_id' => @client.id, 'client_secret' => @client.secret}
13
- end
14
7
  end
15
8
  end
16
9
  end
@@ -1,5 +1,3 @@
1
- require 'base64'
2
-
3
1
  module OAuth2
4
2
  module Strategy
5
3
  # The Client Credentials Strategy
@@ -18,19 +16,9 @@ module OAuth2
18
16
  # @param [Hash] params additional params
19
17
  # @param [Hash] opts options
20
18
  def get_token(params = {}, opts = {})
21
- request_body = opts.delete('auth_scheme') == 'request_body'
22
- params['grant_type'] = 'client_credentials'
23
- params.merge!(request_body ? client_params : {:headers => {'Authorization' => authorization(client_params['client_id'], client_params['client_secret'])}})
19
+ params = params.merge('grant_type' => 'client_credentials')
24
20
  @client.get_token(params, opts.merge('refresh_token' => nil))
25
21
  end
26
-
27
- # Returns the Authorization header value for Basic Authentication
28
- #
29
- # @param [String] The client ID
30
- # @param [String] the client secret
31
- def authorization(client_id, client_secret)
32
- 'Basic ' + Base64.encode64(client_id + ':' + client_secret).delete("\n")
33
- end
34
22
  end
35
23
  end
36
24
  end
@@ -19,7 +19,7 @@ module OAuth2
19
19
  def get_token(username, password, params = {}, opts = {})
20
20
  params = {'grant_type' => 'password',
21
21
  'username' => username,
22
- 'password' => password}.merge(client_params).merge(params)
22
+ 'password' => password}.merge(params)
23
23
  @client.get_token(params, opts)
24
24
  end
25
25
  end
@@ -13,7 +13,7 @@ module OAuth2
13
13
  #
14
14
  # @return [Integer]
15
15
  def minor
16
- 2
16
+ 3
17
17
  end
18
18
 
19
19
  # The patch version
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'oauth2/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.add_dependency 'faraday', ['>= 0.8', '< 0.10']
7
+ spec.add_dependency 'faraday', ['>= 0.8', '< 0.11']
8
8
  spec.add_dependency 'jwt', '~> 1.0'
9
9
  spec.add_dependency 'multi_json', '~> 1.3'
10
10
  spec.add_dependency 'multi_xml', '~> 0.5'
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: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-07-01 00:00:00.000000000 Z
12
+ date: 2016-12-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -20,7 +20,7 @@ dependencies:
20
20
  version: '0.8'
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '0.10'
23
+ version: '0.11'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -30,7 +30,7 @@ dependencies:
30
30
  version: '0.8'
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.10'
33
+ version: '0.11'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: jwt
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,7 @@ files:
122
122
  - README.md
123
123
  - lib/oauth2.rb
124
124
  - lib/oauth2/access_token.rb
125
+ - lib/oauth2/authenticator.rb
125
126
  - lib/oauth2/client.rb
126
127
  - lib/oauth2/error.rb
127
128
  - lib/oauth2/mac_token.rb
@@ -154,9 +155,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
155
  version: 1.3.5
155
156
  requirements: []
156
157
  rubyforge_project:
157
- rubygems_version: 2.2.5
158
+ rubygems_version: 2.5.2
158
159
  signing_key:
159
160
  specification_version: 4
160
161
  summary: A Ruby wrapper for the OAuth 2.0 protocol.
161
162
  test_files: []
162
- has_rdoc: