oauth2 1.4.4 → 2.0.9

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +242 -64
  3. data/CODE_OF_CONDUCT.md +105 -46
  4. data/CONTRIBUTING.md +27 -1
  5. data/LICENSE +1 -1
  6. data/README.md +445 -140
  7. data/SECURITY.md +26 -0
  8. data/lib/oauth2/access_token.rb +70 -28
  9. data/lib/oauth2/authenticator.rb +12 -5
  10. data/lib/oauth2/client.rb +208 -65
  11. data/lib/oauth2/error.rb +43 -24
  12. data/lib/oauth2/response.rb +81 -22
  13. data/lib/oauth2/strategy/assertion.rb +66 -39
  14. data/lib/oauth2/strategy/auth_code.rb +16 -3
  15. data/lib/oauth2/strategy/base.rb +2 -0
  16. data/lib/oauth2/strategy/client_credentials.rb +4 -2
  17. data/lib/oauth2/strategy/implicit.rb +10 -1
  18. data/lib/oauth2/strategy/password.rb +5 -3
  19. data/lib/oauth2/version.rb +3 -55
  20. data/lib/oauth2.rb +29 -1
  21. metadata +91 -105
  22. data/.document +0 -5
  23. data/.gitignore +0 -19
  24. data/.jrubyrc +0 -1
  25. data/.rspec +0 -2
  26. data/.rubocop.yml +0 -80
  27. data/.rubocop_rspec.yml +0 -26
  28. data/.rubocop_todo.yml +0 -15
  29. data/.ruby-version +0 -1
  30. data/.travis.yml +0 -87
  31. data/Gemfile +0 -40
  32. data/Rakefile +0 -45
  33. data/gemfiles/jruby_1.7.gemfile +0 -11
  34. data/gemfiles/jruby_9.0.gemfile +0 -7
  35. data/gemfiles/jruby_9.1.gemfile +0 -3
  36. data/gemfiles/jruby_9.2.gemfile +0 -3
  37. data/gemfiles/jruby_head.gemfile +0 -3
  38. data/gemfiles/ruby_1.9.gemfile +0 -11
  39. data/gemfiles/ruby_2.0.gemfile +0 -6
  40. data/gemfiles/ruby_2.1.gemfile +0 -6
  41. data/gemfiles/ruby_2.2.gemfile +0 -3
  42. data/gemfiles/ruby_2.3.gemfile +0 -3
  43. data/gemfiles/ruby_2.4.gemfile +0 -3
  44. data/gemfiles/ruby_2.5.gemfile +0 -3
  45. data/gemfiles/ruby_2.6.gemfile +0 -9
  46. data/gemfiles/ruby_2.7.gemfile +0 -9
  47. data/gemfiles/ruby_head.gemfile +0 -9
  48. data/gemfiles/truffleruby.gemfile +0 -3
  49. data/lib/oauth2/mac_token.rb +0 -122
  50. data/oauth2.gemspec +0 -52
data/lib/oauth2/error.rb CHANGED
@@ -1,40 +1,59 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth2
2
4
  class Error < StandardError
3
- attr_reader :response, :code, :description
5
+ attr_reader :response, :body, :code, :description
4
6
 
5
- # standard error values include:
6
- # :invalid_request, :invalid_client, :invalid_token, :invalid_grant, :unsupported_grant_type, :invalid_scope
7
+ # standard error codes include:
8
+ # 'invalid_request', 'invalid_client', 'invalid_token', 'invalid_grant', 'unsupported_grant_type', 'invalid_scope'
9
+ # response might be a Response object, or the response.parsed hash
7
10
  def initialize(response)
8
- response.error = self
9
11
  @response = response
10
-
11
- if response.parsed.is_a?(Hash)
12
- @code = response.parsed['error']
13
- @description = response.parsed['error_description']
14
- error_description = "#{@code}: #{@description}"
12
+ if response.respond_to?(:parsed)
13
+ if response.parsed.is_a?(Hash)
14
+ @code = response.parsed['error']
15
+ @description = response.parsed['error_description']
16
+ end
17
+ elsif response.is_a?(Hash)
18
+ @code = response['error']
19
+ @description = response['error_description']
15
20
  end
16
-
17
- super(error_message(response.body, :error_description => error_description))
21
+ @body = if response.respond_to?(:body)
22
+ response.body
23
+ else
24
+ @response
25
+ end
26
+ message_opts = parse_error_description(@code, @description)
27
+ super(error_message(@body, message_opts))
18
28
  end
19
29
 
20
- # Makes a error message
21
- # @param [String] response_body response body of request
22
- # @param [String] opts :error_description error description to show first line
30
+ private
31
+
23
32
  def error_message(response_body, opts = {})
24
- message = []
33
+ lines = []
25
34
 
26
- opts[:error_description] && message << opts[:error_description]
35
+ lines << opts[:error_description] if opts[:error_description]
36
+
37
+ error_string = if response_body.respond_to?(:encode) && opts[:error_description].respond_to?(:encoding)
38
+ script_encoding = opts[:error_description].encoding
39
+ response_body.encode(script_encoding, invalid: :replace, undef: :replace)
40
+ else
41
+ response_body
42
+ end
43
+
44
+ lines << error_string
45
+
46
+ lines.join("\n")
47
+ end
27
48
 
28
- error_message = if opts[:error_description] && opts[:error_description].respond_to?(:encoding)
29
- script_encoding = opts[:error_description].encoding
30
- response_body.encode(script_encoding, :invalid => :replace, :undef => :replace)
31
- else
32
- response_body
33
- end
49
+ def parse_error_description(code, description)
50
+ return {} unless code || description
34
51
 
35
- message << error_message
52
+ error_description = ''
53
+ error_description += "#{code}: " if code
54
+ error_description += description if description
36
55
 
37
- message.join("\n")
56
+ {error_description: error_description}
38
57
  end
39
58
  end
40
59
  end
@@ -1,25 +1,28 @@
1
- require 'multi_json'
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
2
4
  require 'multi_xml'
3
5
  require 'rack'
4
6
 
5
7
  module OAuth2
6
8
  # OAuth2::Response class
7
9
  class Response
10
+ DEFAULT_OPTIONS = {
11
+ parse: :automatic,
12
+ snaky: true,
13
+ }.freeze
8
14
  attr_reader :response
9
- attr_accessor :error, :options
15
+ attr_accessor :options
10
16
 
11
17
  # Procs that, when called, will parse a response body according
12
18
  # to the specified format.
13
19
  @@parsers = {
14
- :json => lambda { |body| MultiJson.load(body) rescue body }, # rubocop:disable RescueModifier
15
- :query => lambda { |body| Rack::Utils.parse_query(body) },
16
- :text => lambda { |body| body },
20
+ query: ->(body) { Rack::Utils.parse_query(body) },
21
+ text: ->(body) { body },
17
22
  }
18
23
 
19
24
  # Content type assignments for various potential HTTP content types.
20
25
  @@content_types = {
21
- 'application/json' => :json,
22
- 'text/javascript' => :json,
23
26
  'application/x-www-form-urlencoded' => :query,
24
27
  'text/plain' => :text,
25
28
  }
@@ -40,12 +43,17 @@ module OAuth2
40
43
  # Initializes a Response instance
41
44
  #
42
45
  # @param [Faraday::Response] response The Faraday response instance
43
- # @param [Hash] opts options in which to initialize the instance
44
- # @option opts [Symbol] :parse (:automatic) how to parse the response body. one of :query (for x-www-form-urlencoded),
46
+ # @param [Symbol] parse (:automatic) how to parse the response body. one of :query (for x-www-form-urlencoded),
45
47
  # :json, or :automatic (determined by Content-Type response header)
46
- def initialize(response, opts = {})
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)
47
52
  @response = response
48
- @options = {:parse => :automatic}.merge(opts)
53
+ @options = {
54
+ parse: parse,
55
+ snaky: snaky,
56
+ }.merge(options)
49
57
  end
50
58
 
51
59
  # The HTTP response headers
@@ -63,27 +71,78 @@ module OAuth2
63
71
  response.body || ''
64
72
  end
65
73
 
66
- # The parsed response body.
67
- # Will attempt to parse application/x-www-form-urlencoded and
68
- # application/json Content-Type response bodies
74
+ # The {#response} {#body} as parsed by {#parser}.
75
+ #
76
+ # @return [Object] As returned by {#parser} if it is #call-able.
77
+ # @return [nil] If the {#parser} is not #call-able.
69
78
  def parsed
70
- return nil unless @@parsers.key?(parser)
71
- @parsed ||= @@parsers[parser].call(body)
79
+ return @parsed if defined?(@parsed)
80
+
81
+ @parsed =
82
+ if parser.respond_to?(:call)
83
+ case parser.arity
84
+ when 0
85
+ parser.call
86
+ when 1
87
+ parser.call(body)
88
+ else
89
+ parser.call(body, response)
90
+ end
91
+ end
92
+
93
+ @parsed = SnakyHash::StringKeyed.new(@parsed) if options[:snaky] && @parsed.is_a?(Hash)
94
+
95
+ @parsed
72
96
  end
73
97
 
74
98
  # Attempts to determine the content type of the response.
75
99
  def content_type
76
- ((response.headers.values_at('content-type', 'Content-Type').compact.first || '').split(';').first || '').strip
100
+ return nil unless response.headers
101
+
102
+ ((response.headers.values_at('content-type', 'Content-Type').compact.first || '').split(';').first || '').strip.downcase
77
103
  end
78
104
 
79
- # Determines the parser that will be used to supply the content of #parsed
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}.
108
+ #
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.
112
+ #
113
+ # If no +:parse+ option is supplied, the lookup Symbol will be determined
114
+ # by looking up {#content_type} in {@@content_types}.
115
+ #
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.
118
+ #
119
+ # @return [Proc, #call] If a parser was found.
120
+ # @return [nil] If no parser was found.
80
121
  def parser
81
- return options[:parse].to_sym if @@parsers.key?(options[:parse])
82
- @@content_types[content_type]
122
+ return @parser if defined?(@parser)
123
+
124
+ @parser =
125
+ if options[:parse].respond_to?(:call)
126
+ options[:parse]
127
+ elsif options[:parse]
128
+ @@parsers[options[:parse].to_sym]
129
+ end
130
+
131
+ @parser ||= @@parsers[@@content_types[content_type]]
83
132
  end
84
133
  end
85
134
  end
86
135
 
87
- OAuth2::Response.register_parser(:xml, ['text/xml', 'application/rss+xml', 'application/rdf+xml', 'application/atom+xml']) do |body|
88
- MultiXml.parse(body) rescue body # rubocop:disable RescueModifier
136
+ OAuth2::Response.register_parser(:xml, ['text/xml', 'application/rss+xml', 'application/rdf+xml', 'application/atom+xml', 'application/xml']) do |body|
137
+ next body unless body.respond_to?(:to_str)
138
+
139
+ MultiXml.parse(body)
140
+ end
141
+
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|
143
+ next body unless body.respond_to?(:to_str)
144
+
145
+ body = body.dup.force_encoding(::Encoding::ASCII_8BIT) if body.respond_to?(:force_encoding)
146
+
147
+ ::JSON.parse(body)
89
148
  end
@@ -1,22 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'jwt'
2
4
 
3
5
  module OAuth2
4
6
  module Strategy
5
7
  # The Client Assertion Strategy
6
8
  #
7
- # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.3
9
+ # @see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-10#section-4.1.3
8
10
  #
9
11
  # Sample usage:
10
12
  # client = OAuth2::Client.new(client_id, client_secret,
11
- # :site => 'http://localhost:8080')
13
+ # :site => 'http://localhost:8080',
14
+ # :auth_scheme => :request_body)
15
+ #
16
+ # claim_set = {
17
+ # :iss => "http://localhost:3001",
18
+ # :aud => "http://localhost:8080/oauth2/token",
19
+ # :sub => "me@example.com",
20
+ # :exp => Time.now.utc.to_i + 3600,
21
+ # }
12
22
  #
13
- # params = {:hmac_secret => "some secret",
14
- # # or :private_key => "private key string",
15
- # :iss => "http://localhost:3001",
16
- # :prn => "me@here.com",
17
- # :exp => Time.now.utc.to_i + 3600}
23
+ # encoding = {
24
+ # :algorithm => 'HS256',
25
+ # :key => 'secret_key',
26
+ # }
18
27
  #
19
- # access = client.assertion.get_token(params)
28
+ # access = client.assertion.get_token(claim_set, encoding)
20
29
  # access.token # actual access_token string
21
30
  # access.get("/api/stuff") # making api calls with access token in header
22
31
  #
@@ -30,45 +39,63 @@ module OAuth2
30
39
 
31
40
  # Retrieve an access token given the specified client.
32
41
  #
33
- # @param [Hash] params assertion params
34
- # pass either :hmac_secret or :private_key, but not both.
42
+ # @param [Hash] claims the hash representation of the claims that should be encoded as a JWT (JSON Web Token)
43
+ #
44
+ # For reading on JWT and claim keys:
45
+ # @see https://github.com/jwt/ruby-jwt
46
+ # @see https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
47
+ # @see https://datatracker.ietf.org/doc/html/rfc7523#section-3
48
+ # @see https://www.iana.org/assignments/jwt/jwt.xhtml
49
+ #
50
+ # There are many possible claim keys, and applications may ask for their own custom keys.
51
+ # Some typically required ones:
52
+ # :iss (issuer)
53
+ # :aud (audience)
54
+ # :sub (subject) -- formerly :prn https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token-06#appendix-F
55
+ # :exp, (expiration time) -- in seconds, e.g. Time.now.utc.to_i + 3600
56
+ #
57
+ # Note that this method does *not* validate presence of those four claim keys indicated as required by RFC 7523.
58
+ # There are endpoints that may not conform with this RFC, and this gem should still work for those use cases.
59
+ #
60
+ # @param [Hash] encoding_opts a hash containing instructions on how the JWT should be encoded
61
+ # @option algorithm [String] the algorithm with which you would like the JWT to be encoded
62
+ # @option key [Object] the key with which you would like to encode the JWT
35
63
  #
36
- # params :hmac_secret, secret string.
37
- # params :private_key, private key string.
64
+ # These two options are passed directly to `JWT.encode`. For supported encoding arguments:
65
+ # @see https://github.com/jwt/ruby-jwt#algorithms-and-usage
66
+ # @see https://datatracker.ietf.org/doc/html/rfc7518#section-3.1
38
67
  #
39
- # params :iss, issuer
40
- # params :aud, audience, optional
41
- # params :prn, principal, current user
42
- # params :exp, expired at, in seconds, like Time.now.utc.to_i + 3600
68
+ # The object type of `:key` may depend on the value of `:algorithm`. Sample arguments:
69
+ # get_token(claim_set, {:algorithm => 'HS256', :key => 'secret_key'})
70
+ # get_token(claim_set, {:algorithm => 'RS256', :key => OpenSSL::PKCS12.new(File.read('my_key.p12'), 'not_secret')})
43
71
  #
44
- # @param [Hash] opts options
45
- def get_token(params = {}, opts = {})
46
- hash = build_request(params)
47
- @client.get_token(hash, opts.merge('refresh_token' => nil))
72
+ # @param [Hash] request_opts options that will be used to assemble the request
73
+ # @option request_opts [String] :scope the url parameter `scope` that may be required by some endpoints
74
+ # @see https://datatracker.ietf.org/doc/html/rfc7521#section-4.1
75
+ #
76
+ # @param [Hash] response_opts this will be merged with the token response to create the AccessToken object
77
+ # @see the access_token_opts argument to Client#get_token
78
+
79
+ def get_token(claims, encoding_opts, request_opts = {}, response_opts = {})
80
+ assertion = build_assertion(claims, encoding_opts)
81
+ params = build_request(assertion, request_opts)
82
+
83
+ @client.get_token(params, response_opts)
48
84
  end
49
85
 
50
- def build_request(params)
51
- assertion = build_assertion(params)
86
+ private
87
+
88
+ def build_request(assertion, request_opts = {})
52
89
  {
53
- :grant_type => 'assertion',
54
- :assertion_type => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
55
- :assertion => assertion,
56
- :scope => params[:scope],
57
- }
90
+ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
91
+ assertion: assertion,
92
+ }.merge(request_opts)
58
93
  end
59
94
 
60
- def build_assertion(params)
61
- claims = {
62
- :iss => params[:iss],
63
- :aud => params[:aud],
64
- :prn => params[:prn],
65
- :exp => params[:exp],
66
- }
67
- if params[:hmac_secret]
68
- JWT.encode(claims, params[:hmac_secret], 'HS256')
69
- elsif params[:private_key]
70
- JWT.encode(claims, params[:private_key], 'RS256')
71
- end
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?
97
+
98
+ JWT.encode(claims, encoding_opts[:key], encoding_opts[:algorithm])
72
99
  end
73
100
  end
74
101
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth2
2
4
  module Strategy
3
5
  # The Authorization Code Strategy
4
6
  #
5
- # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1
7
+ # @see http://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-15#section-4.1
6
8
  class AuthCode < Base
7
9
  # The required query parameters for the authorize URL
8
10
  #
@@ -15,6 +17,7 @@ module OAuth2
15
17
  #
16
18
  # @param [Hash] params additional query parameters for the URL
17
19
  def authorize_url(params = {})
20
+ assert_valid_params(params)
18
21
  @client.authorize_url(authorize_params.merge(params))
19
22
  end
20
23
 
@@ -22,12 +25,22 @@ module OAuth2
22
25
  #
23
26
  # @param [String] code The Authorization Code value
24
27
  # @param [Hash] params additional params
25
- # @param [Hash] opts options
28
+ # @param [Hash] opts access_token_opts, @see Client#get_token
26
29
  # @note that you must also provide a :redirect_uri with most OAuth 2.0 providers
27
30
  def get_token(code, params = {}, opts = {})
28
31
  params = {'grant_type' => 'authorization_code', 'code' => code}.merge(@client.redirection_params).merge(params)
32
+ params_dup = params.dup
33
+ params.each_key do |key|
34
+ params_dup[key.to_s] = params_dup.delete(key) if key.is_a?(Symbol)
35
+ end
36
+
37
+ @client.get_token(params_dup, opts)
38
+ end
39
+
40
+ private
29
41
 
30
- @client.get_token(params, opts)
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')
31
44
  end
32
45
  end
33
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth2
2
4
  module Strategy
3
5
  class Base
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth2
2
4
  module Strategy
3
5
  # The Client Credentials Strategy
4
6
  #
5
- # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.4
7
+ # @see http://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-15#section-4.4
6
8
  class ClientCredentials < Base
7
9
  # Not used for this strategy
8
10
  #
@@ -17,7 +19,7 @@ module OAuth2
17
19
  # @param [Hash] opts options
18
20
  def get_token(params = {}, opts = {})
19
21
  params = params.merge('grant_type' => 'client_credentials')
20
- @client.get_token(params, opts.merge('refresh_token' => nil))
22
+ @client.get_token(params, opts)
21
23
  end
22
24
  end
23
25
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth2
2
4
  module Strategy
3
5
  # The Implicit Strategy
4
6
  #
5
- # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-26#section-4.2
7
+ # @see http://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-26#section-4.2
6
8
  class Implicit < Base
7
9
  # The required query parameters for the authorize URL
8
10
  #
@@ -15,6 +17,7 @@ module OAuth2
15
17
  #
16
18
  # @param [Hash] params additional query parameters for the URL
17
19
  def authorize_url(params = {})
20
+ assert_valid_params(params)
18
21
  @client.authorize_url(authorize_params.merge(params))
19
22
  end
20
23
 
@@ -24,6 +27,12 @@ module OAuth2
24
27
  def get_token(*)
25
28
  raise(NotImplementedError, 'The token is accessed differently in this strategy')
26
29
  end
30
+
31
+ private
32
+
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')
35
+ end
27
36
  end
28
37
  end
29
38
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth2
2
4
  module Strategy
3
5
  # The Resource Owner Password Credentials Authorization Strategy
4
6
  #
5
- # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.3
7
+ # @see http://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-15#section-4.3
6
8
  class Password < Base
7
9
  # Not used for this strategy
8
10
  #
@@ -18,8 +20,8 @@ module OAuth2
18
20
  # @param [Hash] params additional params
19
21
  def get_token(username, password, params = {}, opts = {})
20
22
  params = {'grant_type' => 'password',
21
- 'username' => username,
22
- 'password' => password}.merge(params)
23
+ 'username' => username,
24
+ 'password' => password}.merge(params)
23
25
  @client.get_token(params, opts)
24
26
  end
25
27
  end
@@ -1,59 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth2
2
4
  module Version
3
- module_function
4
-
5
- # The major version
6
- #
7
- # @return [Integer]
8
- def major
9
- 1
10
- end
11
-
12
- # The minor version
13
- #
14
- # @return [Integer]
15
- def minor
16
- 4
17
- end
18
-
19
- # The patch version
20
- #
21
- # @return [Integer]
22
- def patch
23
- 4
24
- end
25
-
26
- # The pre-release version, if any
27
- #
28
- # @return [Integer, NilClass]
29
- def pre
30
- nil
31
- end
32
-
33
- # The version number as a hash
34
- #
35
- # @return [Hash]
36
- def to_h
37
- {
38
- :major => major,
39
- :minor => minor,
40
- :patch => patch,
41
- :pre => pre,
42
- }
43
- end
44
-
45
- # The version number as an array
46
- #
47
- # @return [Array]
48
- def to_a
49
- [major, minor, patch, pre].compact
50
- end
51
-
52
- # The version number as a string
53
- #
54
- # @return [String]
55
- def to_s
56
- to_a.join('.')
57
- end
5
+ VERSION = '2.0.9'.freeze
58
6
  end
59
7
  end
data/lib/oauth2.rb CHANGED
@@ -1,3 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # includes modules from stdlib
4
+ require 'cgi'
5
+ require 'time'
6
+
7
+ # third party gems
8
+ require 'snaky_hash'
9
+ require 'version_gem'
10
+
11
+ # includes gem files
12
+ require 'oauth2/version'
1
13
  require 'oauth2/error'
2
14
  require 'oauth2/authenticator'
3
15
  require 'oauth2/client'
@@ -8,5 +20,21 @@ require 'oauth2/strategy/password'
8
20
  require 'oauth2/strategy/client_credentials'
9
21
  require 'oauth2/strategy/assertion'
10
22
  require 'oauth2/access_token'
11
- require 'oauth2/mac_token'
12
23
  require 'oauth2/response'
24
+
25
+ # The namespace of this library
26
+ module OAuth2
27
+ DEFAULT_CONFIG = SnakyHash::SymbolKeyed.new(silence_extra_tokens_warning: false)
28
+ @config = DEFAULT_CONFIG.dup
29
+ class << self
30
+ attr_accessor :config
31
+ end
32
+ def configure
33
+ yield @config
34
+ end
35
+ module_function :configure
36
+ end
37
+
38
+ OAuth2::Version.class_eval do
39
+ extend VersionGem::Basic
40
+ end