oauth2 2.0.9 → 2.0.11

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.
@@ -0,0 +1,31 @@
1
+ module OAuth2
2
+ module FilteredAttributes
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def filtered_attributes(*attributes)
9
+ @filtered_attribute_names = attributes.map(&:to_sym)
10
+ end
11
+
12
+ def filtered_attribute_names
13
+ @filtered_attribute_names || []
14
+ end
15
+ end
16
+
17
+ def inspect
18
+ filtered_attribute_names = self.class.filtered_attribute_names
19
+ return super if filtered_attribute_names.empty?
20
+
21
+ inspected_vars = instance_variables.map do |var|
22
+ if filtered_attribute_names.any? { |filtered_var| var.to_s.include?(filtered_var.to_s) }
23
+ "#{var}=[FILTERED]"
24
+ else
25
+ "#{var}=#{instance_variable_get(var).inspect}"
26
+ end
27
+ end
28
+ "#<#{self.class}:#{object_id} #{inspected_vars.join(", ")}>"
29
+ end
30
+ end
31
+ end
@@ -1,37 +1,55 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
- require 'multi_xml'
5
- require 'rack'
3
+ require "json"
4
+ require "multi_xml"
5
+ require "rack"
6
6
 
7
7
  module OAuth2
8
- # OAuth2::Response class
8
+ # The Response class handles HTTP responses in the OAuth2 gem, providing methods
9
+ # to access and parse response data in various formats.
10
+ #
11
+ # @since 1.0.0
9
12
  class Response
13
+ # Default configuration options for Response instances
14
+ #
15
+ # @return [Hash] The default options hash
10
16
  DEFAULT_OPTIONS = {
11
17
  parse: :automatic,
12
18
  snaky: true,
19
+ snaky_hash_klass: SnakyHash::StringKeyed,
13
20
  }.freeze
21
+
22
+ # @return [Faraday::Response] The raw Faraday response object
14
23
  attr_reader :response
24
+
25
+ # @return [Hash] The options hash for this instance
15
26
  attr_accessor :options
16
27
 
17
- # Procs that, when called, will parse a response body according
18
- # to the specified format.
28
+ # @private
29
+ # Storage for response body parser procedures
30
+ #
31
+ # @return [Hash<Symbol, Proc>] Hash of parser procs keyed by format symbol
19
32
  @@parsers = {
20
33
  query: ->(body) { Rack::Utils.parse_query(body) },
21
34
  text: ->(body) { body },
22
35
  }
23
36
 
24
- # Content type assignments for various potential HTTP content types.
37
+ # @private
38
+ # Maps content types to parser symbols
39
+ #
40
+ # @return [Hash<String, Symbol>] Hash of content types mapped to parser symbols
25
41
  @@content_types = {
26
- 'application/x-www-form-urlencoded' => :query,
27
- 'text/plain' => :text,
42
+ "application/x-www-form-urlencoded" => :query,
43
+ "text/plain" => :text,
28
44
  }
29
45
 
30
46
  # Adds a new content type parser.
31
47
  #
32
- # @param [Symbol] key A descriptive symbol key such as :json or :query.
33
- # @param [Array] mime_types One or more mime types to which this parser applies.
34
- # @yield [String] A block returning parsed content.
48
+ # @param [Symbol] key A descriptive symbol key such as :json or :query
49
+ # @param [Array<String>, String] mime_types One or more mime types to which this parser applies
50
+ # @yield [String] Block that will be called to parse the response body
51
+ # @yieldparam [String] body The response body to parse
52
+ # @return [void]
35
53
  def self.register_parser(key, mime_types, &block)
36
54
  key = key.to_sym
37
55
  @@parsers[key] = block
@@ -43,38 +61,48 @@ module OAuth2
43
61
  # Initializes a Response instance
44
62
  #
45
63
  # @param [Faraday::Response] response The Faraday response instance
46
- # @param [Symbol] parse (:automatic) how to parse the response body. one of :query (for x-www-form-urlencoded),
47
- # :json, or :automatic (determined by Content-Type response header)
48
- # @param [true, false] snaky (true) Convert @parsed to a snake-case,
49
- # indifferent-access SnakyHash::StringKeyed, which is a subclass of Hashie::Mash (from hashie gem)?
50
- # @param [Hash] options all other options for initializing the instance
51
- def initialize(response, parse: :automatic, snaky: true, **options)
64
+ # @param [Symbol] parse (:automatic) How to parse the response body
65
+ # @param [Boolean] snaky (true) Whether to convert parsed response to snake_case using SnakyHash
66
+ # @param [Class, nil] snaky_hash_klass (nil) Custom class for snake_case hash conversion
67
+ # @param [Hash] options Additional options for the response
68
+ # @option options [Symbol] :parse (:automatic) Parse strategy (:query, :json, or :automatic)
69
+ # @option options [Boolean] :snaky (true) Enable/disable snake_case conversion
70
+ # @option options [Class] :snaky_hash_klass (SnakyHash::StringKeyed) Class to use for hash conversion
71
+ # @return [OAuth2::Response] The new Response instance
72
+ def initialize(response, parse: :automatic, snaky: true, snaky_hash_klass: nil, **options)
52
73
  @response = response
53
74
  @options = {
54
75
  parse: parse,
55
76
  snaky: snaky,
77
+ snaky_hash_klass: snaky_hash_klass,
56
78
  }.merge(options)
57
79
  end
58
80
 
59
81
  # The HTTP response headers
82
+ #
83
+ # @return [Hash] The response headers
60
84
  def headers
61
85
  response.headers
62
86
  end
63
87
 
64
88
  # The HTTP response status code
89
+ #
90
+ # @return [Integer] The response status code
65
91
  def status
66
92
  response.status
67
93
  end
68
94
 
69
95
  # The HTTP response body
96
+ #
97
+ # @return [String] The response body or empty string if nil
70
98
  def body
71
- response.body || ''
99
+ response.body || ""
72
100
  end
73
101
 
74
- # The {#response} {#body} as parsed by {#parser}.
102
+ # The parsed response body
75
103
  #
76
- # @return [Object] As returned by {#parser} if it is #call-able.
77
- # @return [nil] If the {#parser} is not #call-able.
104
+ # @return [Object, SnakyHash::StringKeyed] The parsed response body
105
+ # @return [nil] If no parser is available
78
106
  def parsed
79
107
  return @parsed if defined?(@parsed)
80
108
 
@@ -90,34 +118,37 @@ module OAuth2
90
118
  end
91
119
  end
92
120
 
93
- @parsed = SnakyHash::StringKeyed.new(@parsed) if options[:snaky] && @parsed.is_a?(Hash)
121
+ if options[:snaky] && @parsed.is_a?(Hash)
122
+ hash_klass = options[:snaky_hash_klass] || DEFAULT_OPTIONS[:snaky_hash_klass]
123
+ @parsed = hash_klass[@parsed]
124
+ end
94
125
 
95
126
  @parsed
96
127
  end
97
128
 
98
- # Attempts to determine the content type of the response.
129
+ # Determines the content type of the response
130
+ #
131
+ # @return [String, nil] The content type or nil if headers are not present
99
132
  def content_type
100
- return nil unless response.headers
133
+ return unless response.headers
101
134
 
102
- ((response.headers.values_at('content-type', 'Content-Type').compact.first || '').split(';').first || '').strip.downcase
135
+ ((response.headers.values_at("content-type", "Content-Type").compact.first || "").split(";").first || "").strip.downcase
103
136
  end
104
137
 
105
- # Determines the parser (a Proc or other Object which responds to #call)
106
- # that will be passed the {#body} (and optional {#response}) to supply
107
- # {#parsed}.
138
+ # Determines the parser to be used for the response body
108
139
  #
109
- # The parser can be supplied as the +:parse+ option in the form of a Proc
110
- # (or other Object responding to #call) or a Symbol. In the latter case,
111
- # the actual parser will be looked up in {@@parsers} by the supplied Symbol.
140
+ # @note The parser can be supplied as the +:parse+ option in the form of a Proc
141
+ # (or other Object responding to #call) or a Symbol. In the latter case,
142
+ # the actual parser will be looked up in {@@parsers} by the supplied Symbol.
112
143
  #
113
- # If no +:parse+ option is supplied, the lookup Symbol will be determined
114
- # by looking up {#content_type} in {@@content_types}.
144
+ # @note If no +:parse+ option is supplied, the lookup Symbol will be determined
145
+ # by looking up {#content_type} in {@@content_types}.
115
146
  #
116
- # If {#parser} is a Proc, it will be called with no arguments, just
117
- # {#body}, or {#body} and {#response}, depending on the Proc's arity.
147
+ # @note If {#parser} is a Proc, it will be called with no arguments, just
148
+ # {#body}, or {#body} and {#response}, depending on the Proc's arity.
118
149
  #
119
- # @return [Proc, #call] If a parser was found.
120
- # @return [nil] If no parser was found.
150
+ # @return [Proc, #call] The parser proc or callable object
151
+ # @return [nil] If no suitable parser is found
121
152
  def parser
122
153
  return @parser if defined?(@parser)
123
154
 
@@ -133,16 +164,21 @@ module OAuth2
133
164
  end
134
165
  end
135
166
 
136
- OAuth2::Response.register_parser(:xml, ['text/xml', 'application/rss+xml', 'application/rdf+xml', 'application/atom+xml', 'application/xml']) do |body|
167
+ # Register XML parser
168
+ # @api private
169
+ OAuth2::Response.register_parser(:xml, ["text/xml", "application/rss+xml", "application/rdf+xml", "application/atom+xml", "application/xml"]) do |body|
137
170
  next body unless body.respond_to?(:to_str)
138
171
 
139
172
  MultiXml.parse(body)
140
173
  end
141
174
 
142
- OAuth2::Response.register_parser(:json, ['application/json', 'text/javascript', 'application/hal+json', 'application/vnd.collection+json', 'application/vnd.api+json', 'application/problem+json']) do |body|
175
+ # Register JSON parser
176
+ # @api private
177
+ OAuth2::Response.register_parser(:json, ["application/json", "text/javascript", "application/hal+json", "application/vnd.collection+json", "application/vnd.api+json", "application/problem+json"]) do |body|
143
178
  next body unless body.respond_to?(:to_str)
144
179
 
145
- body = body.dup.force_encoding(::Encoding::ASCII_8BIT) if body.respond_to?(:force_encoding)
180
+ body = body.dup.force_encoding(Encoding::ASCII_8BIT) if body.respond_to?(:force_encoding)
181
+ next body if body.respond_to?(:empty?) && body.empty?
146
182
 
147
- ::JSON.parse(body)
183
+ JSON.parse(body)
148
184
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'jwt'
3
+ require "jwt"
4
4
 
5
5
  module OAuth2
6
6
  module Strategy
@@ -34,7 +34,7 @@ module OAuth2
34
34
  #
35
35
  # @raise [NotImplementedError]
36
36
  def authorize_url
37
- raise(NotImplementedError, 'The authorization endpoint is not used in this strategy')
37
+ raise(NotImplementedError, "The authorization endpoint is not used in this strategy")
38
38
  end
39
39
 
40
40
  # Retrieve an access token given the specified client.
@@ -87,13 +87,13 @@ module OAuth2
87
87
 
88
88
  def build_request(assertion, request_opts = {})
89
89
  {
90
- grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
90
+ grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
91
91
  assertion: assertion,
92
92
  }.merge(request_opts)
93
93
  end
94
94
 
95
95
  def build_assertion(claims, encoding_opts)
96
- raise ArgumentError.new(message: 'Please provide an encoding_opts hash with :algorithm and :key') if !encoding_opts.is_a?(Hash) || (%i[algorithm key] - encoding_opts.keys).any?
96
+ raise ArgumentError.new(message: "Please provide an encoding_opts hash with :algorithm and :key") if !encoding_opts.is_a?(Hash) || (%i[algorithm key] - encoding_opts.keys).any?
97
97
 
98
98
  JWT.encode(claims, encoding_opts[:key], encoding_opts[:algorithm])
99
99
  end
@@ -10,7 +10,7 @@ module OAuth2
10
10
  #
11
11
  # @param [Hash] params additional query parameters
12
12
  def authorize_params(params = {})
13
- params.merge('response_type' => 'code', 'client_id' => @client.id)
13
+ params.merge("response_type" => "code", "client_id" => @client.id)
14
14
  end
15
15
 
16
16
  # The authorization URL endpoint of the provider
@@ -28,7 +28,7 @@ module OAuth2
28
28
  # @param [Hash] opts access_token_opts, @see Client#get_token
29
29
  # @note that you must also provide a :redirect_uri with most OAuth 2.0 providers
30
30
  def get_token(code, params = {}, opts = {})
31
- params = {'grant_type' => 'authorization_code', 'code' => code}.merge(@client.redirection_params).merge(params)
31
+ params = {"grant_type" => "authorization_code", "code" => code}.merge(@client.redirection_params).merge(params)
32
32
  params_dup = params.dup
33
33
  params.each_key do |key|
34
34
  params_dup[key.to_s] = params_dup.delete(key) if key.is_a?(Symbol)
@@ -40,7 +40,7 @@ module OAuth2
40
40
  private
41
41
 
42
42
  def assert_valid_params(params)
43
- raise(ArgumentError, 'client_secret is not allowed in authorize URL query params') if params.key?(:client_secret) || params.key?('client_secret')
43
+ raise(ArgumentError, "client_secret is not allowed in authorize URL query params") if params.key?(:client_secret) || params.key?("client_secret")
44
44
  end
45
45
  end
46
46
  end
@@ -10,7 +10,7 @@ module OAuth2
10
10
  #
11
11
  # @raise [NotImplementedError]
12
12
  def authorize_url
13
- raise(NotImplementedError, 'The authorization endpoint is not used in this strategy')
13
+ raise(NotImplementedError, "The authorization endpoint is not used in this strategy")
14
14
  end
15
15
 
16
16
  # Retrieve an access token given the specified client.
@@ -18,7 +18,7 @@ module OAuth2
18
18
  # @param [Hash] params additional params
19
19
  # @param [Hash] opts options
20
20
  def get_token(params = {}, opts = {})
21
- params = params.merge('grant_type' => 'client_credentials')
21
+ params = params.merge("grant_type" => "client_credentials")
22
22
  @client.get_token(params, opts)
23
23
  end
24
24
  end
@@ -10,7 +10,7 @@ module OAuth2
10
10
  #
11
11
  # @param [Hash] params additional query parameters
12
12
  def authorize_params(params = {})
13
- params.merge('response_type' => 'token', 'client_id' => @client.id)
13
+ params.merge("response_type" => "token", "client_id" => @client.id)
14
14
  end
15
15
 
16
16
  # The authorization URL endpoint of the provider
@@ -25,13 +25,13 @@ module OAuth2
25
25
  #
26
26
  # @raise [NotImplementedError]
27
27
  def get_token(*)
28
- raise(NotImplementedError, 'The token is accessed differently in this strategy')
28
+ raise(NotImplementedError, "The token is accessed differently in this strategy")
29
29
  end
30
30
 
31
31
  private
32
32
 
33
33
  def assert_valid_params(params)
34
- raise(ArgumentError, 'client_secret is not allowed in authorize URL query params') if params.key?(:client_secret) || params.key?('client_secret')
34
+ raise(ArgumentError, "client_secret is not allowed in authorize URL query params") if params.key?(:client_secret) || params.key?("client_secret")
35
35
  end
36
36
  end
37
37
  end
@@ -10,7 +10,7 @@ module OAuth2
10
10
  #
11
11
  # @raise [NotImplementedError]
12
12
  def authorize_url
13
- raise(NotImplementedError, 'The authorization endpoint is not used in this strategy')
13
+ raise(NotImplementedError, "The authorization endpoint is not used in this strategy")
14
14
  end
15
15
 
16
16
  # Retrieve an access token given the specified End User username and password.
@@ -19,9 +19,11 @@ module OAuth2
19
19
  # @param [String] password the End User password
20
20
  # @param [Hash] params additional params
21
21
  def get_token(username, password, params = {}, opts = {})
22
- params = {'grant_type' => 'password',
23
- 'username' => username,
24
- 'password' => password}.merge(params)
22
+ params = {
23
+ "grant_type" => "password",
24
+ "username" => username,
25
+ "password" => password,
26
+ }.merge(params)
25
27
  @client.get_token(params, opts)
26
28
  end
27
29
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OAuth2
4
4
  module Version
5
- VERSION = '2.0.9'.freeze
5
+ VERSION = "2.0.11"
6
6
  end
7
7
  end
data/lib/oauth2.rb CHANGED
@@ -1,33 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # includes modules from stdlib
4
- require 'cgi'
5
- require 'time'
4
+ require "cgi"
5
+ require "time"
6
6
 
7
7
  # third party gems
8
- require 'snaky_hash'
9
- require 'version_gem'
8
+ require "snaky_hash"
9
+ require "version_gem"
10
10
 
11
11
  # includes gem files
12
- require 'oauth2/version'
13
- require 'oauth2/error'
14
- require 'oauth2/authenticator'
15
- require 'oauth2/client'
16
- require 'oauth2/strategy/base'
17
- require 'oauth2/strategy/auth_code'
18
- require 'oauth2/strategy/implicit'
19
- require 'oauth2/strategy/password'
20
- require 'oauth2/strategy/client_credentials'
21
- require 'oauth2/strategy/assertion'
22
- require 'oauth2/access_token'
23
- require 'oauth2/response'
12
+ require_relative "oauth2/version"
13
+ require_relative "oauth2/filtered_attributes"
14
+ require_relative "oauth2/error"
15
+ require_relative "oauth2/authenticator"
16
+ require_relative "oauth2/client"
17
+ require_relative "oauth2/strategy/base"
18
+ require_relative "oauth2/strategy/auth_code"
19
+ require_relative "oauth2/strategy/implicit"
20
+ require_relative "oauth2/strategy/password"
21
+ require_relative "oauth2/strategy/client_credentials"
22
+ require_relative "oauth2/strategy/assertion"
23
+ require_relative "oauth2/access_token"
24
+ require_relative "oauth2/response"
24
25
 
25
26
  # The namespace of this library
26
27
  module OAuth2
27
- DEFAULT_CONFIG = SnakyHash::SymbolKeyed.new(silence_extra_tokens_warning: false)
28
+ OAUTH_DEBUG = ENV.fetch("OAUTH_DEBUG", "false").casecmp("true").zero?
29
+ DEFAULT_CONFIG = SnakyHash::SymbolKeyed.new(
30
+ silence_extra_tokens_warning: true,
31
+ silence_no_tokens_warning: true,
32
+ )
28
33
  @config = DEFAULT_CONFIG.dup
29
34
  class << self
30
- attr_accessor :config
35
+ attr_reader :config
31
36
  end
32
37
  def configure
33
38
  yield @config
data.tar.gz.sig ADDED
Binary file