signet 0.11.0 → 0.14.1
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 +4 -4
- data/CHANGELOG.md +51 -15
- data/Gemfile +5 -4
- data/README.md +4 -6
- data/Rakefile +107 -37
- data/lib/signet.rb +17 -14
- data/lib/signet/errors.rb +4 -4
- data/lib/signet/oauth_1.rb +129 -154
- data/lib/signet/oauth_1/client.rb +309 -343
- data/lib/signet/oauth_1/credential.rb +40 -37
- data/lib/signet/oauth_1/server.rb +197 -203
- data/lib/signet/oauth_1/signature_methods/hmac_sha1.rb +11 -10
- data/lib/signet/oauth_1/signature_methods/plaintext.rb +8 -7
- data/lib/signet/oauth_1/signature_methods/rsa_sha1.rb +11 -11
- data/lib/signet/oauth_2.rb +41 -43
- data/lib/signet/oauth_2/client.rb +328 -313
- data/lib/signet/version.rb +2 -73
- data/signet.gemspec +37 -39
- data/spec/signet/oauth_1/client_spec.rb +313 -315
- data/spec/signet/oauth_1/credential_spec.rb +64 -56
- data/spec/signet/oauth_1/server_spec.rb +362 -362
- data/spec/signet/oauth_1/signature_methods/hmac_sha1_spec.rb +26 -26
- data/spec/signet/oauth_1/signature_methods/plaintext_spec.rb +28 -28
- data/spec/signet/oauth_1/signature_methods/rsa_sha1_spec.rb +34 -35
- data/spec/signet/oauth_1_spec.rb +553 -524
- data/spec/signet/oauth_2/client_spec.rb +652 -576
- data/spec/signet/oauth_2_spec.rb +88 -89
- data/spec/signet_spec.rb +41 -41
- data/spec/spec_helper.rb +7 -7
- data/spec/spec_helper_spec.rb +8 -8
- metadata +64 -52
- data/tasks/clobber.rake +0 -2
- data/tasks/gem.rake +0 -34
- data/tasks/git.rake +0 -40
- data/tasks/metrics.rake +0 -41
- data/tasks/spec.rake +0 -34
- data/tasks/wiki.rake +0 -38
- data/tasks/yard.rake +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c94f4ee9a5ea982bba69826873be998a4cbf833af8c70920fd2384558efe33e5
|
4
|
+
data.tar.gz: 211e019a051159858a4e18cbe64efe9989a13df08b2d449e67ac4057f91f4332
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8e5ac7a7977d89976275a4988e62139622436dea9f539a934b99e94f32832e57c8c522a91647449f9b5ea199fa561ad62680803f7d1dbe5b40946087b95dae4
|
7
|
+
data.tar.gz: 2b6476b3b89d09d66c0274fa9bd1b5da6aebb68932e7e15325cf34ccca14b5d5f5a16f76a22330bbcb9f6b66882e016eeccb54977e7a87cc4ce6f32568361808
|
data/CHANGELOG.md
CHANGED
@@ -1,27 +1,63 @@
|
|
1
|
-
|
1
|
+
# Release History
|
2
|
+
|
3
|
+
## [0.14.1](https://www.github.com/googleapis/signet/compare/v0.14.0...v0.14.1) (2021-01-27)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* Fix OAuth1 signature with duplicate query param names ([9f5b81a](https://www.github.com/googleapis/signet/commit/9f5b81a60625a6e6f0e5bca24c67b90e73d7479b))
|
9
|
+
|
10
|
+
## 0.14.0 / 2020-03-31
|
11
|
+
|
12
|
+
* Support for fetching ID tokens from google oauth2 endpoint.
|
13
|
+
|
14
|
+
## 0.13.2 / 2020-03-25
|
15
|
+
|
16
|
+
Rerelease of 0.13.1.
|
17
|
+
|
18
|
+
## 0.13.1 / 2020-03-24
|
19
|
+
|
20
|
+
* Update github url
|
21
|
+
|
22
|
+
## 0.13.0 / 2020-02-24
|
23
|
+
|
24
|
+
* Support Faraday 1.x
|
25
|
+
|
26
|
+
## 0.12.0 / 2019-10-08
|
27
|
+
|
28
|
+
* This version now requires Ruby 2.4.
|
29
|
+
* Support array values of the "aud" field.
|
30
|
+
* Normalize the version constant to match related gems.
|
31
|
+
|
32
|
+
## 0.11.0 / 2018-10-08
|
33
|
+
|
2
34
|
* Add constant time comparison for oauth signatures.
|
3
35
|
|
4
|
-
## 0.10.0
|
36
|
+
## 0.10.0 / 2018-09-21
|
37
|
+
|
5
38
|
* Add UnexpectedStatusError class for http status errors that are not handled.
|
6
39
|
|
7
|
-
## 0.9.2
|
40
|
+
## 0.9.2 / 2018-09-12
|
41
|
+
|
8
42
|
* Update issued_at correctly when it is set simultaneously with expires_in.
|
9
43
|
|
10
|
-
## 0.9.1
|
44
|
+
## 0.9.1 / 2018-08-29
|
45
|
+
|
11
46
|
* Warn on EOL ruby versions.
|
12
47
|
* Fix DateTime normalization.
|
13
48
|
|
14
|
-
## 0.9.0
|
49
|
+
## 0.9.0 / 2018-08-20
|
50
|
+
|
15
51
|
* Add RemoteServerError class for 5xx level errors.
|
16
52
|
* Allow to_json to be called with arguments
|
17
53
|
* Expires_in now sets and reflects current expires_at value
|
18
54
|
* Expires_within(0) now returns false when expires_at is nil.
|
19
55
|
|
20
|
-
## 0.8.1
|
56
|
+
## 0.8.1 / 2017-10-13
|
21
57
|
|
22
58
|
* Restore support for Ruby 1.9.3
|
23
59
|
|
24
|
-
## 0.8.0
|
60
|
+
## 0.8.0 / 2017-10-12
|
25
61
|
|
26
62
|
* Ensure the "expires_at" attribute is recalculated on refresh (chutzimir)
|
27
63
|
* Fix warnings on Ruby 2.4 (koic)
|
@@ -29,20 +65,20 @@
|
|
29
65
|
* Provide signature verification algorithm for compatibility with ruby-jwt 2.0 (jurriaan)
|
30
66
|
* Signet::OAuth2::Client#decoded_id_token can take a keyfinder block (mvastola)
|
31
67
|
|
32
|
-
## 0.7.3
|
68
|
+
## 0.7.3 / 2016-06-20
|
33
69
|
|
34
70
|
* Fix timestamp parsing on 32-bit systems
|
35
71
|
* Fix expiration check when issue/expiry times are nil
|
36
72
|
|
37
|
-
## 0.7.2
|
73
|
+
## 0.7.2 / 2015-12-21
|
38
74
|
|
39
75
|
* Don't assume Faraday form encoding middleware is present
|
40
76
|
|
41
|
-
## 0.7.1
|
77
|
+
## 0.7.1 / 2015-12-17
|
42
78
|
|
43
79
|
* Fix an issue with date parsing
|
44
80
|
|
45
|
-
## 0.7
|
81
|
+
## 0.7 / 2015-12-06
|
46
82
|
|
47
83
|
* No longer overwrite SSL environment variables.
|
48
84
|
* Tighten up date & URL (de)serialization for OAuth2 client
|
@@ -51,7 +87,7 @@
|
|
51
87
|
* Add expires_within(sec) method to oauth2 client to facilitate proactive
|
52
88
|
refreshes
|
53
89
|
|
54
|
-
## 0.6.1
|
90
|
+
## 0.6.1 / 2015-06-08
|
55
91
|
|
56
92
|
* Fix language warnings for unused & shadowed variables ((@blowmage)[])
|
57
93
|
* Update SSL cert path for OSX ((@gambaroff)[])
|
@@ -59,14 +95,14 @@
|
|
59
95
|
* Fix incorrect parameter name in OAuth2 client docs ((@samuelreh)[])
|
60
96
|
* Fix symbolization of URL parameter keys ((@swifthand)[])
|
61
97
|
|
62
|
-
## 0.6.0
|
98
|
+
## 0.6.0 / 2014-12-05
|
63
99
|
|
64
100
|
* Drop support for ruby versions < 1.9.3
|
65
101
|
* Update gem dependencies and lock down versions tighter
|
66
102
|
* Allow form encoded responses when exchanging OAuth 2 authorization codes
|
67
103
|
* Normalize options keys for indifferent access
|
68
104
|
|
69
|
-
## 0.5.1
|
105
|
+
## 0.5.1 / 2014-06-08
|
70
106
|
|
71
107
|
* Allow Hash objects to be used to initialize authorization URI
|
72
108
|
* Added PLAINTEXT and RSA-SHA1 signature methods to OAuth 1 support
|
@@ -74,7 +110,7 @@
|
|
74
110
|
* The `approval_prompt` option no longer defaults to `:force`
|
75
111
|
* The `approval_prompt` and `prompt` are now mutually exclusive.
|
76
112
|
|
77
|
-
## 0.5.0
|
113
|
+
## 0.5.0 / 2013-05-31
|
78
114
|
|
79
115
|
* Switched to faraday 0.9.0
|
80
116
|
* Added `expires_at` option
|
data/Gemfile
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
gem
|
6
|
-
gem
|
7
|
-
gem
|
5
|
+
gem "bundler", ">= 1.15"
|
6
|
+
gem "gems", "~> 1.2"
|
7
|
+
gem "hurley"
|
8
|
+
gem "jruby-openssl", platforms: :jruby
|
data/README.md
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
# Signet
|
2
2
|
|
3
3
|
<dl>
|
4
|
-
<dt>Homepage</dt><dd><a href="
|
4
|
+
<dt>Homepage</dt><dd><a href="https://github.com/googleapis/signet/">https://github.com/googleapis/signet/</a></dd>
|
5
5
|
<dt>Author</dt><dd><a href="mailto:bobaman@google.com">Bob Aman</a></dd>
|
6
6
|
<dt>Copyright</dt><dd>Copyright © 2010 Google, Inc.</dd>
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
8
8
|
</dl>
|
9
9
|
|
10
10
|
[](https://badge.fury.io/rb/signet)
|
11
|
-
[](http://travis-ci.org/google/signet)
|
12
11
|
|
13
12
|
## Description
|
14
13
|
|
@@ -59,10 +58,9 @@ client.fetch_access_token!
|
|
59
58
|
Be sure `https://rubygems.org` is in your gem sources.
|
60
59
|
|
61
60
|
## Supported Ruby Versions
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
official support only for Ruby versions that are considered current and
|
61
|
+
|
62
|
+
This library requires Ruby 2.4 or later.
|
63
|
+
In general, this library supports Ruby versions that are considered current and
|
66
64
|
supported by Ruby Core (that is, Ruby versions that are either in normal
|
67
65
|
maintenance or in security maintenance).
|
68
66
|
See https://www.ruby-lang.org/en/downloads/branches/ for further details.
|
data/Rakefile
CHANGED
@@ -1,42 +1,112 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
require 'rubygems'
|
6
|
-
require 'rake'
|
1
|
+
require "rubygems"
|
2
|
+
require "json"
|
3
|
+
require "rake"
|
7
4
|
require "bundler/gem_tasks"
|
8
5
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
6
|
+
task :release_gem, :tag do |_t, args|
|
7
|
+
tag = args[:tag]
|
8
|
+
raise "You must provide a tag to release." if tag.nil?
|
9
|
+
|
10
|
+
# Verify the tag format "vVERSION"
|
11
|
+
m = tag.match /v(?<version>\S*)/
|
12
|
+
raise "Tag #{tag} does not match the expected format." if m.nil?
|
13
|
+
|
14
|
+
version = m[:version]
|
15
|
+
raise "You must provide a version." if version.nil?
|
16
|
+
|
17
|
+
api_token = ENV["RUBYGEMS_API_TOKEN"]
|
18
|
+
|
19
|
+
require "gems"
|
20
|
+
if api_token
|
21
|
+
::Gems.configure do |config|
|
22
|
+
config.key = api_token
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Bundler.with_clean_env do
|
27
|
+
sh "rm -rf pkg"
|
28
|
+
sh "bundle update"
|
29
|
+
sh "bundle exec rake build"
|
30
|
+
end
|
31
|
+
|
32
|
+
path_to_be_pushed = "pkg/signet-#{version}.gem"
|
33
|
+
gem_was_published = nil
|
34
|
+
if File.file? path_to_be_pushed
|
35
|
+
begin
|
36
|
+
response = ::Gems.push File.new(path_to_be_pushed)
|
37
|
+
puts response
|
38
|
+
raise unless response.include? "Successfully registered gem:"
|
39
|
+
gem_was_published = true
|
40
|
+
puts "Successfully built and pushed signet for version #{version}"
|
41
|
+
rescue StandardError => e
|
42
|
+
gem_was_published = false
|
43
|
+
puts "Error while releasing signet version #{version}: #{e.message}"
|
44
|
+
end
|
45
|
+
else
|
46
|
+
raise "Cannot build signet for version #{version}"
|
47
|
+
end
|
48
|
+
|
49
|
+
Rake::Task["kokoro:publish_docs"].invoke if gem_was_published
|
50
|
+
end
|
51
|
+
|
52
|
+
task :ci do
|
53
|
+
header "Using Ruby - #{RUBY_VERSION}"
|
54
|
+
sh "bundle exec rubocop"
|
55
|
+
sh "bundle exec rspec"
|
37
56
|
end
|
38
57
|
|
39
|
-
|
40
|
-
|
58
|
+
namespace :kokoro do
|
59
|
+
task :load_env_vars do
|
60
|
+
service_account = "#{ENV['KOKORO_GFILE_DIR']}/service-account.json"
|
61
|
+
ENV["GOOGLE_APPLICATION_CREDENTIALS"] = service_account
|
62
|
+
filename = "#{ENV['KOKORO_GFILE_DIR']}/env_vars.json"
|
63
|
+
env_vars = JSON.parse File.read(filename)
|
64
|
+
env_vars.each { |k, v| ENV[k] = v }
|
65
|
+
end
|
41
66
|
|
42
|
-
|
67
|
+
task :presubmit do
|
68
|
+
Rake::Task["ci"].invoke
|
69
|
+
end
|
70
|
+
|
71
|
+
task :continuous do
|
72
|
+
Rake::Task["ci"].invoke
|
73
|
+
end
|
74
|
+
|
75
|
+
task :nightly do
|
76
|
+
Rake::Task["ci"].invoke
|
77
|
+
end
|
78
|
+
|
79
|
+
task :release do
|
80
|
+
version = "0.1.0"
|
81
|
+
Bundler.with_clean_env do
|
82
|
+
version = `bundle exec gem list`
|
83
|
+
.split("\n").select { |line| line.include? "signet" }
|
84
|
+
.first.split("(").last.split(")").first || "0.1.0"
|
85
|
+
end
|
86
|
+
Rake::Task["kokoro:load_env_vars"].invoke
|
87
|
+
Rake::Task["release_gem"].invoke "v#{version}"
|
88
|
+
end
|
89
|
+
|
90
|
+
task :post do
|
91
|
+
require_relative "rakelib/link_checker.rb"
|
92
|
+
|
93
|
+
link_checker = LinkChecker.new
|
94
|
+
link_checker.run
|
95
|
+
exit link_checker.exit_status
|
96
|
+
end
|
97
|
+
|
98
|
+
task :publish_docs do
|
99
|
+
require_relative "rakelib/devsite_builder.rb"
|
100
|
+
|
101
|
+
DevsiteBuilder.new(__dir__).publish
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def header str, token = "#"
|
106
|
+
line_length = str.length + 8
|
107
|
+
puts ""
|
108
|
+
puts token * line_length
|
109
|
+
puts "#{token * 3} #{str} #{token * 3}"
|
110
|
+
puts token * line_length
|
111
|
+
puts ""
|
112
|
+
end
|
data/lib/signet.rb
CHANGED
@@ -12,13 +12,15 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
require
|
15
|
+
require "signet/version"
|
16
16
|
|
17
17
|
module Signet #:nodoc:
|
18
|
-
|
18
|
+
# rubocop:disable Metrics/AbcSize
|
19
|
+
# rubocop:disable Metrics/MethodLength
|
20
|
+
def self.parse_auth_param_list auth_param_string
|
19
21
|
# Production rules from:
|
20
22
|
# http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-12
|
21
|
-
token = /[
|
23
|
+
token = /[-!#{$OUTPUT_RECORD_SEPARATOR}%&'*+.^_`|~0-9a-zA-Z]+/
|
22
24
|
d_qdtext = /[\s\x21\x23-\x5B\x5D-\x7E\x80-\xFF]/n
|
23
25
|
d_quoted_pair = /\\[\s\x21-\x7E\x80-\xFF]/n
|
24
26
|
d_qs = /"(?:#{d_qdtext}|#{d_quoted_pair})*"/
|
@@ -36,10 +38,10 @@ module Signet #:nodoc:
|
|
36
38
|
#
|
37
39
|
# This would be way easier in Ruby 1.9, but we want backwards
|
38
40
|
# compatibility.
|
39
|
-
while (match = remainder.match
|
41
|
+
while (match = remainder.match auth_param)
|
40
42
|
if match.pre_match && match.pre_match !~ /^[\s,]*$/
|
41
43
|
raise ParseError,
|
42
|
-
|
44
|
+
"Unexpected auth param format: '#{auth_param_string}'."
|
43
45
|
end
|
44
46
|
auth_param_pairs << match.captures[0] # Appending pair
|
45
47
|
remainder = match.post_match
|
@@ -47,24 +49,25 @@ module Signet #:nodoc:
|
|
47
49
|
end
|
48
50
|
if last_match.post_match && last_match.post_match !~ /^[\s,]*$/
|
49
51
|
raise ParseError,
|
50
|
-
|
52
|
+
"Unexpected auth param format: '#{auth_param_string}'."
|
51
53
|
end
|
52
54
|
# Now parse the auth-param pair strings & turn them into key-value pairs.
|
53
|
-
|
54
|
-
name, value = pair.split
|
55
|
+
(auth_param_pairs.each_with_object [] do |pair, accu|
|
56
|
+
name, value = pair.split "=", 2
|
55
57
|
if value =~ /^".*"$/
|
56
58
|
value = value.gsub(/^"(.*)"$/, '\1').gsub(/\\(.)/, '\1')
|
57
59
|
elsif value =~ /^'.*'$/
|
58
60
|
value = value.gsub(/^'(.*)'$/, '\1').gsub(/\\(.)/, '\1')
|
59
|
-
elsif value =~
|
61
|
+
elsif value =~ %r{[\(\)<>@,;:\\\"/\[\]?={}]}
|
60
62
|
# Certain special characters are not allowed
|
61
|
-
raise ParseError,
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
raise ParseError,
|
64
|
+
"Unexpected characters in auth param " \
|
65
|
+
"list: '#{auth_param_string}'."
|
66
|
+
|
65
67
|
end
|
66
68
|
accu << [name, value]
|
67
|
-
accu
|
68
69
|
end)
|
69
70
|
end
|
71
|
+
# rubocop:enable Metrics/AbcSize
|
72
|
+
# rubocop:enable Metrics/MethodLength
|
70
73
|
end
|
data/lib/signet/errors.rb
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
require
|
15
|
+
require "addressable/uri"
|
16
16
|
|
17
17
|
module Signet
|
18
18
|
##
|
@@ -66,14 +66,14 @@ module Signet
|
|
66
66
|
# - <code>:uri</code> -
|
67
67
|
# A URI identifying a human-readable web page with additional
|
68
68
|
# information about the error, indended for the resource owner.
|
69
|
-
def initialize
|
70
|
-
super
|
69
|
+
def initialize message, options = {}
|
70
|
+
super message
|
71
71
|
@options = options
|
72
72
|
@request = options[:request]
|
73
73
|
@response = options[:response]
|
74
74
|
@code = options[:code]
|
75
75
|
@description = options[:description]
|
76
|
-
@uri = Addressable::URI.parse
|
76
|
+
@uri = Addressable::URI.parse options[:uri]
|
77
77
|
end
|
78
78
|
|
79
79
|
##
|
data/lib/signet/oauth_1.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "addressable/uri"
|
2
|
+
require "signet"
|
3
3
|
|
4
|
-
require
|
4
|
+
require "securerandom"
|
5
5
|
|
6
6
|
module Signet #:nodoc:
|
7
7
|
module OAuth1
|
8
|
-
OUT_OF_BAND =
|
8
|
+
OUT_OF_BAND = "oob".freeze
|
9
9
|
|
10
10
|
##
|
11
11
|
# Converts a value to a percent-encoded <code>String</code> according to
|
@@ -15,9 +15,9 @@ module Signet #:nodoc:
|
|
15
15
|
# @param [Symbol, #to_str] value The value to be encoded.
|
16
16
|
#
|
17
17
|
# @return [String] The percent-encoded value.
|
18
|
-
def self.encode
|
19
|
-
value = value.to_s if value.
|
20
|
-
|
18
|
+
def self.encode value
|
19
|
+
value = value.to_s if value.is_a? Symbol
|
20
|
+
Addressable::URI.encode_component(
|
21
21
|
value,
|
22
22
|
Addressable::URI::CharacterClasses::UNRESERVED
|
23
23
|
)
|
@@ -30,8 +30,8 @@ module Signet #:nodoc:
|
|
30
30
|
# The percent-encoded <code>String</code> to be unencoded.
|
31
31
|
#
|
32
32
|
# @return [String] The unencoded value.
|
33
|
-
def self.unencode
|
34
|
-
|
33
|
+
def self.unencode value
|
34
|
+
Addressable::URI.unencode_component value
|
35
35
|
end
|
36
36
|
|
37
37
|
##
|
@@ -39,8 +39,8 @@ module Signet #:nodoc:
|
|
39
39
|
# value.
|
40
40
|
#
|
41
41
|
# @return [String] The current timestamp.
|
42
|
-
def self.generate_timestamp
|
43
|
-
|
42
|
+
def self.generate_timestamp
|
43
|
+
Time.now.to_i.to_s
|
44
44
|
end
|
45
45
|
|
46
46
|
##
|
@@ -48,9 +48,10 @@ module Signet #:nodoc:
|
|
48
48
|
# value.
|
49
49
|
#
|
50
50
|
# @return [String] A random nonce.
|
51
|
-
def self.generate_nonce
|
52
|
-
|
51
|
+
def self.generate_nonce
|
52
|
+
SecureRandom.random_bytes(16).unpack("H*").join ""
|
53
53
|
end
|
54
|
+
# rubocop:disable Metrics/MethodLength
|
54
55
|
|
55
56
|
##
|
56
57
|
# Processes an options <code>Hash</code> to find a credential key value.
|
@@ -62,36 +63,36 @@ module Signet #:nodoc:
|
|
62
63
|
# or <code>:access</code>.
|
63
64
|
#
|
64
65
|
# @return [String] The credential key value.
|
65
|
-
def self.extract_credential_key_option
|
66
|
+
def self.extract_credential_key_option credential_type, options
|
66
67
|
# Normalize key to String to allow indifferent access.
|
67
|
-
options = options.
|
68
|
+
options = options.each_with_object({}) { |(k, v), accu| accu[k.to_s] = v; }
|
68
69
|
credential_key = "#{credential_type}_credential_key"
|
69
70
|
credential = "#{credential_type}_credential"
|
70
71
|
if options[credential_key]
|
71
72
|
credential_key = options[credential_key]
|
72
73
|
elsif options[credential]
|
73
|
-
require
|
74
|
-
|
74
|
+
require "signet/oauth_1/credential"
|
75
|
+
unless options[credential].respond_to? :key
|
75
76
|
raise TypeError,
|
76
|
-
|
77
|
-
|
77
|
+
"Expected Signet::OAuth1::Credential, " \
|
78
|
+
"got #{options[credential].class}."
|
78
79
|
end
|
79
80
|
credential_key = options[credential].key
|
80
81
|
elsif options["client"]
|
81
|
-
require
|
82
|
-
|
82
|
+
require "signet/oauth_1/client"
|
83
|
+
unless options["client"].is_a? ::Signet::OAuth1::Client
|
83
84
|
raise TypeError,
|
84
|
-
|
85
|
+
"Expected Signet::OAuth1::Client, got #{options['client'].class}."
|
85
86
|
end
|
86
|
-
credential_key = options["client"].send
|
87
|
+
credential_key = options["client"].send credential_key
|
87
88
|
else
|
88
89
|
credential_key = nil
|
89
90
|
end
|
90
|
-
if credential_key
|
91
|
+
if !credential_key.nil? && !credential_key.is_a?(String)
|
91
92
|
raise TypeError,
|
92
|
-
|
93
|
+
"Expected String, got #{credential_key.class}."
|
93
94
|
end
|
94
|
-
|
95
|
+
credential_key
|
95
96
|
end
|
96
97
|
|
97
98
|
##
|
@@ -104,37 +105,38 @@ module Signet #:nodoc:
|
|
104
105
|
# or <code>:access</code>.
|
105
106
|
#
|
106
107
|
# @return [String] The credential secret value.
|
107
|
-
def self.extract_credential_secret_option
|
108
|
+
def self.extract_credential_secret_option credential_type, options
|
108
109
|
# Normalize key to String to allow indifferent access.
|
109
|
-
options = options.
|
110
|
+
options = options.each_with_object({}) { |(k, v), accu| accu[k.to_s] = v; }
|
110
111
|
credential_secret = "#{credential_type}_credential_secret"
|
111
112
|
credential = "#{credential_type}_credential"
|
112
113
|
if options[credential_secret]
|
113
114
|
credential_secret = options[credential_secret]
|
114
115
|
elsif options[credential]
|
115
|
-
require
|
116
|
-
|
116
|
+
require "signet/oauth_1/credential"
|
117
|
+
unless options[credential].respond_to? :secret
|
117
118
|
raise TypeError,
|
118
|
-
|
119
|
-
|
119
|
+
"Expected Signet::OAuth1::Credential, " \
|
120
|
+
"got #{options[credential].class}."
|
120
121
|
end
|
121
122
|
credential_secret = options[credential].secret
|
122
123
|
elsif options["client"]
|
123
|
-
require
|
124
|
-
|
124
|
+
require "signet/oauth_1/client"
|
125
|
+
unless options["client"].is_a? ::Signet::OAuth1::Client
|
125
126
|
raise TypeError,
|
126
|
-
|
127
|
+
"Expected Signet::OAuth1::Client, got #{options['client'].class}."
|
127
128
|
end
|
128
|
-
credential_secret = options["client"].send
|
129
|
+
credential_secret = options["client"].send credential_secret
|
129
130
|
else
|
130
131
|
credential_secret = nil
|
131
132
|
end
|
132
|
-
if credential_secret
|
133
|
+
if !credential_secret.nil? && !credential_secret.is_a?(String)
|
133
134
|
raise TypeError,
|
134
|
-
|
135
|
+
"Expected String, got #{credential_secret.class}."
|
135
136
|
end
|
136
|
-
|
137
|
+
credential_secret
|
137
138
|
end
|
139
|
+
# rubocop:enable Metrics/MethodLength
|
138
140
|
|
139
141
|
##
|
140
142
|
# Normalizes a set of OAuth parameters according to the algorithm given
|
@@ -145,16 +147,14 @@ module Signet #:nodoc:
|
|
145
147
|
# @param [Enumerable] parameters The OAuth parameter list.
|
146
148
|
#
|
147
149
|
# @return [String] The normalized parameter list.
|
148
|
-
def self.normalize_parameters
|
149
|
-
|
150
|
-
raise TypeError, "Expected Enumerable, got #{parameters.class}."
|
151
|
-
end
|
150
|
+
def self.normalize_parameters parameters
|
151
|
+
raise TypeError, "Expected Enumerable, got #{parameters.class}." unless parameters.is_a? Enumerable
|
152
152
|
parameter_list = parameters.map do |k, v|
|
153
153
|
next if k == "oauth_signature"
|
154
154
|
# This is probably the wrong place to try to exclude the realm
|
155
|
-
"#{
|
155
|
+
"#{encode k}=#{encode v}"
|
156
156
|
end
|
157
|
-
|
157
|
+
parameter_list.compact.sort.join "&"
|
158
158
|
end
|
159
159
|
|
160
160
|
##
|
@@ -167,29 +167,27 @@ module Signet #:nodoc:
|
|
167
167
|
# @param [Enumerable] parameters The OAuth parameter list.
|
168
168
|
#
|
169
169
|
# @return [String] The signature base string.
|
170
|
-
def self.generate_base_string
|
171
|
-
|
172
|
-
raise TypeError, "Expected Enumerable, got #{parameters.class}."
|
173
|
-
end
|
170
|
+
def self.generate_base_string method, uri, parameters
|
171
|
+
raise TypeError, "Expected Enumerable, got #{parameters.class}." unless parameters.is_a? Enumerable
|
174
172
|
method = method.to_s.upcase
|
175
|
-
parsed_uri = Addressable::URI.parse
|
173
|
+
parsed_uri = Addressable::URI.parse uri
|
176
174
|
uri = Addressable::URI.new(
|
177
|
-
:
|
178
|
-
:
|
179
|
-
:
|
180
|
-
:
|
181
|
-
:
|
175
|
+
scheme: parsed_uri.normalized_scheme,
|
176
|
+
authority: parsed_uri.normalized_authority,
|
177
|
+
path: parsed_uri.path,
|
178
|
+
query: parsed_uri.query,
|
179
|
+
fragment: parsed_uri.fragment
|
182
180
|
)
|
183
|
-
uri_parameters = uri.query_values
|
181
|
+
uri_parameters = uri.query_values(Array) || []
|
184
182
|
uri = uri.omit(:query, :fragment).to_s
|
185
183
|
merged_parameters =
|
186
184
|
uri_parameters.concat(parameters.map { |k, v| [k, v] })
|
187
|
-
parameter_string =
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
].join(
|
185
|
+
parameter_string = normalize_parameters merged_parameters
|
186
|
+
[
|
187
|
+
encode(method),
|
188
|
+
encode(uri),
|
189
|
+
encode(parameter_string)
|
190
|
+
].join("&")
|
193
191
|
end
|
194
192
|
|
195
193
|
##
|
@@ -201,48 +199,45 @@ module Signet #:nodoc:
|
|
201
199
|
# The <code>Authorization</code> realm. See RFC 2617.
|
202
200
|
#
|
203
201
|
# @return [String] The <code>Authorization</code> header.
|
204
|
-
def self.generate_authorization_header
|
205
|
-
if !parameters.
|
202
|
+
def self.generate_authorization_header parameters, realm = nil
|
203
|
+
if !parameters.is_a?(Enumerable) || parameters.is_a?(String)
|
206
204
|
raise TypeError, "Expected Enumerable, got #{parameters.class}."
|
207
205
|
end
|
208
206
|
parameter_list = parameters.map do |k, v|
|
209
|
-
if k ==
|
207
|
+
if k == "realm"
|
210
208
|
raise ArgumentError,
|
211
|
-
|
209
|
+
'The "realm" parameter must be specified as a separate argument.'
|
212
210
|
end
|
213
|
-
"#{
|
211
|
+
"#{encode k}=\"#{encode v}\""
|
214
212
|
end
|
215
213
|
if realm
|
216
|
-
realm = realm.gsub
|
217
|
-
parameter_list.unshift
|
214
|
+
realm = realm.gsub '"', '\"'
|
215
|
+
parameter_list.unshift "realm=\"#{realm}\""
|
218
216
|
end
|
219
|
-
|
217
|
+
"OAuth " + parameter_list.join(", ")
|
220
218
|
end
|
221
219
|
|
222
220
|
##
|
223
221
|
# Parses an <code>Authorization</code> header into its component
|
224
222
|
# parameters. Parameter keys and values are decoded according to the
|
225
223
|
# rules given in RFC 5849.
|
226
|
-
def self.parse_authorization_header
|
227
|
-
|
228
|
-
raise TypeError, "Expected String, got #{field_value.class}."
|
229
|
-
end
|
224
|
+
def self.parse_authorization_header field_value
|
225
|
+
raise TypeError, "Expected String, got #{field_value.class}." unless field_value.is_a? String
|
230
226
|
auth_scheme = field_value[/^([-._0-9a-zA-Z]+)/, 1]
|
231
227
|
case auth_scheme
|
232
228
|
when /^OAuth$/i
|
233
229
|
# Other token types may be supported eventually
|
234
230
|
pairs = Signet.parse_auth_param_list(field_value[/^OAuth\s+(.*)$/i, 1])
|
235
|
-
return (pairs.
|
236
|
-
if k !=
|
237
|
-
k =
|
238
|
-
v =
|
231
|
+
return (pairs.each_with_object [] do |(k, v), accu|
|
232
|
+
if k != "realm"
|
233
|
+
k = unencode k
|
234
|
+
v = unencode v
|
239
235
|
end
|
240
236
|
accu << [k, v]
|
241
|
-
accu
|
242
237
|
end)
|
243
238
|
else
|
244
239
|
raise ParseError,
|
245
|
-
|
240
|
+
"Parsing non-OAuth Authorization headers is out of scope."
|
246
241
|
end
|
247
242
|
end
|
248
243
|
|
@@ -253,11 +248,9 @@ module Signet #:nodoc:
|
|
253
248
|
# @param [String] body The response body.
|
254
249
|
#
|
255
250
|
# @return [Signet::OAuth1::Credential] The OAuth credentials.
|
256
|
-
def self.parse_form_encoded_credentials
|
257
|
-
|
258
|
-
|
259
|
-
end
|
260
|
-
return Signet::OAuth1::Credential.new(
|
251
|
+
def self.parse_form_encoded_credentials body
|
252
|
+
raise TypeError, "Expected String, got #{body.class}." unless body.is_a? String
|
253
|
+
Signet::OAuth1::Credential.new(
|
261
254
|
Addressable::URI.form_unencode(body)
|
262
255
|
)
|
263
256
|
end
|
@@ -275,33 +268,33 @@ module Signet #:nodoc:
|
|
275
268
|
# The token credential secret. Omitted when unavailable.
|
276
269
|
#
|
277
270
|
# @return [String] The signature.
|
278
|
-
def self.sign_parameters
|
279
|
-
|
271
|
+
def self.sign_parameters method, uri, parameters,
|
272
|
+
client_credential_secret, token_credential_secret = nil
|
280
273
|
# Technically, the token_credential_secret parameter here may actually
|
281
274
|
# be a temporary credential secret when obtaining a token credential
|
282
275
|
# for the first time
|
283
|
-
base_string =
|
284
|
-
parameters = parameters.
|
285
|
-
signature_method = parameters[
|
276
|
+
base_string = generate_base_string method, uri, parameters
|
277
|
+
parameters = parameters.each_with_object({}) { |(k, v), h| h[k.to_s] = v; }
|
278
|
+
signature_method = parameters["oauth_signature_method"]
|
286
279
|
case signature_method
|
287
|
-
when
|
288
|
-
require
|
280
|
+
when "HMAC-SHA1"
|
281
|
+
require "signet/oauth_1/signature_methods/hmac_sha1"
|
289
282
|
return Signet::OAuth1::HMACSHA1.generate_signature(
|
290
283
|
base_string, client_credential_secret, token_credential_secret
|
291
284
|
)
|
292
|
-
when
|
293
|
-
require
|
285
|
+
when "RSA-SHA1"
|
286
|
+
require "signet/oauth_1/signature_methods/rsa_sha1"
|
294
287
|
return Signet::OAuth1::RSASHA1.generate_signature(
|
295
288
|
base_string, client_credential_secret, token_credential_secret
|
296
289
|
)
|
297
|
-
when
|
298
|
-
require
|
290
|
+
when "PLAINTEXT"
|
291
|
+
require "signet/oauth_1/signature_methods/plaintext"
|
299
292
|
return Signet::OAuth1::PLAINTEXT.generate_signature(
|
300
293
|
base_string, client_credential_secret, token_credential_secret
|
301
294
|
)
|
302
295
|
else
|
303
296
|
raise NotImplementedError,
|
304
|
-
|
297
|
+
"Unsupported signature method: #{signature_method}"
|
305
298
|
end
|
306
299
|
end
|
307
300
|
|
@@ -322,22 +315,20 @@ module Signet #:nodoc:
|
|
322
315
|
#
|
323
316
|
# @return [Array]
|
324
317
|
# The parameter list as an <code>Array</code> of key/value pairs.
|
325
|
-
def self.unsigned_temporary_credential_parameters
|
318
|
+
def self.unsigned_temporary_credential_parameters options = {}
|
326
319
|
options = {
|
327
|
-
:
|
328
|
-
:
|
329
|
-
:
|
320
|
+
callback: ::Signet::OAuth1::OUT_OF_BAND,
|
321
|
+
signature_method: "HMAC-SHA1",
|
322
|
+
additional_parameters: []
|
330
323
|
}.merge(options)
|
331
324
|
client_credential_key =
|
332
|
-
|
333
|
-
|
334
|
-
raise ArgumentError, "Missing :client_credential_key parameter."
|
335
|
-
end
|
325
|
+
extract_credential_key_option :client, options
|
326
|
+
raise ArgumentError, "Missing :client_credential_key parameter." if client_credential_key.nil?
|
336
327
|
parameters = [
|
337
328
|
["oauth_consumer_key", client_credential_key],
|
338
329
|
["oauth_signature_method", options[:signature_method]],
|
339
|
-
["oauth_timestamp",
|
340
|
-
["oauth_nonce",
|
330
|
+
["oauth_timestamp", generate_timestamp],
|
331
|
+
["oauth_nonce", generate_nonce],
|
341
332
|
["oauth_version", "1.0"],
|
342
333
|
["oauth_callback", options[:callback]]
|
343
334
|
]
|
@@ -345,7 +336,7 @@ module Signet #:nodoc:
|
|
345
336
|
options[:additional_parameters].each do |key, value|
|
346
337
|
parameters << [key, value]
|
347
338
|
end
|
348
|
-
|
339
|
+
parameters
|
349
340
|
end
|
350
341
|
|
351
342
|
##
|
@@ -356,28 +347,24 @@ module Signet #:nodoc:
|
|
356
347
|
# The base authorization URI.
|
357
348
|
#
|
358
349
|
# @return [String] The authorization URI to redirect the user to.
|
359
|
-
def self.generate_authorization_uri
|
350
|
+
def self.generate_authorization_uri authorization_uri, options = {}
|
360
351
|
options = {
|
361
|
-
:
|
362
|
-
:
|
352
|
+
callback: nil,
|
353
|
+
additional_parameters: {}
|
363
354
|
}.merge(options)
|
364
355
|
temporary_credential_key =
|
365
|
-
|
356
|
+
extract_credential_key_option :temporary, options
|
366
357
|
parsed_uri = Addressable::URI.parse(authorization_uri).dup
|
367
358
|
query_values = parsed_uri.query_values || {}
|
368
359
|
if options[:additional_parameters]
|
369
360
|
query_values = query_values.merge(
|
370
|
-
options[:additional_parameters].
|
361
|
+
options[:additional_parameters].each_with_object({}) { |(k, v), h| h[k] = v; }
|
371
362
|
)
|
372
363
|
end
|
373
|
-
if temporary_credential_key
|
374
|
-
|
375
|
-
end
|
376
|
-
if options[:callback]
|
377
|
-
query_values['oauth_callback'] = options[:callback]
|
378
|
-
end
|
364
|
+
query_values["oauth_token"] = temporary_credential_key if temporary_credential_key
|
365
|
+
query_values["oauth_callback"] = options[:callback] if options[:callback]
|
379
366
|
parsed_uri.query_values = query_values
|
380
|
-
|
367
|
+
parsed_uri.normalize.to_s
|
381
368
|
end
|
382
369
|
|
383
370
|
##
|
@@ -397,35 +384,29 @@ module Signet #:nodoc:
|
|
397
384
|
#
|
398
385
|
# @return [Array]
|
399
386
|
# The parameter list as an <code>Array</code> of key/value pairs.
|
400
|
-
def self.unsigned_token_credential_parameters
|
387
|
+
def self.unsigned_token_credential_parameters options = {}
|
401
388
|
options = {
|
402
|
-
:
|
403
|
-
:
|
389
|
+
signature_method: "HMAC-SHA1",
|
390
|
+
verifier: nil
|
404
391
|
}.merge(options)
|
405
392
|
client_credential_key =
|
406
|
-
|
393
|
+
extract_credential_key_option :client, options
|
407
394
|
temporary_credential_key =
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
if temporary_credential_key == nil
|
413
|
-
raise ArgumentError, "Missing :temporary_credential_key parameter."
|
414
|
-
end
|
415
|
-
if options[:verifier] == nil
|
416
|
-
raise ArgumentError, "Missing :verifier parameter."
|
417
|
-
end
|
395
|
+
extract_credential_key_option :temporary, options
|
396
|
+
raise ArgumentError, "Missing :client_credential_key parameter." if client_credential_key.nil?
|
397
|
+
raise ArgumentError, "Missing :temporary_credential_key parameter." if temporary_credential_key.nil?
|
398
|
+
raise ArgumentError, "Missing :verifier parameter." if options[:verifier].nil?
|
418
399
|
parameters = [
|
419
400
|
["oauth_consumer_key", client_credential_key],
|
420
401
|
["oauth_token", temporary_credential_key],
|
421
402
|
["oauth_signature_method", options[:signature_method]],
|
422
|
-
["oauth_timestamp",
|
423
|
-
["oauth_nonce",
|
403
|
+
["oauth_timestamp", generate_timestamp],
|
404
|
+
["oauth_nonce", generate_nonce],
|
424
405
|
["oauth_verifier", options[:verifier]],
|
425
406
|
["oauth_version", "1.0"]
|
426
407
|
]
|
427
408
|
# No additional parameters allowed here
|
428
|
-
|
409
|
+
parameters
|
429
410
|
end
|
430
411
|
|
431
412
|
##
|
@@ -445,35 +426,29 @@ module Signet #:nodoc:
|
|
445
426
|
#
|
446
427
|
# @return [Array]
|
447
428
|
# The parameter list as an <code>Array</code> of key/value pairs.
|
448
|
-
def self.unsigned_resource_parameters
|
429
|
+
def self.unsigned_resource_parameters options = {}
|
449
430
|
options = {
|
450
|
-
:
|
451
|
-
:
|
431
|
+
signature_method: "HMAC-SHA1",
|
432
|
+
two_legged: false
|
452
433
|
}.merge(options)
|
453
434
|
client_credential_key =
|
454
|
-
|
455
|
-
|
456
|
-
raise ArgumentError, "Missing :client_credential_key parameter."
|
457
|
-
end
|
435
|
+
extract_credential_key_option :client, options
|
436
|
+
raise ArgumentError, "Missing :client_credential_key parameter." if client_credential_key.nil?
|
458
437
|
unless options[:two_legged]
|
459
438
|
token_credential_key =
|
460
|
-
|
461
|
-
|
462
|
-
raise ArgumentError, "Missing :token_credential_key parameter."
|
463
|
-
end
|
439
|
+
extract_credential_key_option :token, options
|
440
|
+
raise ArgumentError, "Missing :token_credential_key parameter." if token_credential_key.nil?
|
464
441
|
end
|
465
442
|
parameters = [
|
466
443
|
["oauth_consumer_key", client_credential_key],
|
467
444
|
["oauth_signature_method", options[:signature_method]],
|
468
|
-
["oauth_timestamp",
|
469
|
-
["oauth_nonce",
|
445
|
+
["oauth_timestamp", generate_timestamp],
|
446
|
+
["oauth_nonce", generate_nonce],
|
470
447
|
["oauth_version", "1.0"]
|
471
448
|
]
|
472
|
-
unless options[:two_legged]
|
473
|
-
parameters << ["oauth_token", token_credential_key]
|
474
|
-
end
|
449
|
+
parameters << ["oauth_token", token_credential_key] unless options[:two_legged]
|
475
450
|
# No additional parameters allowed here
|
476
|
-
|
451
|
+
parameters
|
477
452
|
end
|
478
453
|
end
|
479
454
|
end
|