json_web_token 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -0
- data/README.md +5 -3
- data/json_web_token.gemspec +1 -1
- data/lib/json_web_token.rb +2 -2
- data/lib/json_web_token/algorithm/ecdsa.rb +28 -13
- data/lib/json_web_token/algorithm/hmac.rb +26 -10
- data/lib/json_web_token/algorithm/rsa.rb +21 -9
- data/lib/json_web_token/format/base64_url.rb +19 -20
- data/lib/json_web_token/jwa.rb +30 -13
- data/lib/json_web_token/jws.rb +50 -23
- data/lib/json_web_token/jwt.rb +31 -12
- data/lib/json_web_token/util.rb +1 -1
- data/lib/json_web_token/version.rb +1 -1
- data/spec/json_web_token/algorithm/ecdsa_spec.rb +17 -17
- data/spec/json_web_token/algorithm/hmac_spec.rb +44 -45
- data/spec/json_web_token/algorithm/rsa_spec.rb +21 -23
- data/spec/json_web_token/jwa_spec.rb +16 -17
- data/spec/json_web_token/jws_spec.rb +40 -32
- data/spec/json_web_token/jwt_spec.rb +55 -45
- data/spec/json_web_token/util_spec.rb +6 -6
- data/spec/json_web_token_spec.rb +1 -1
- data/spec/support/plausible_jwt.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 973c4dc365edec01a991491309d0332b3898dd57
|
4
|
+
data.tar.gz: 05d71d73011230c2b2f074eed6d2ea86bf0be1cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 640c8738d52377295275bc4c5498b02a7fd427ffdf2b8d14b5765acc90fd8868c401799f0ccbb0535d37143ee90138ff5f80621edee6c902344106a5f1727786
|
7
|
+
data.tar.gz: fa2e818be12da6b351eb202b4ca2de9ab0efdd48f789d1e61e2e3683ae7fa9f50026e716d69578eb2c850266f72b5cc6bac4c94d570148cd4194d06ceb67b49f
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# JSON Web Token [![travis][ci_img]][travis] [![
|
1
|
+
# JSON Web Token [![travis][ci_img]][travis] [![yard docs][yd_img]][yard_docs] [![code climate][cc_img]][code_climate]
|
2
2
|
|
3
3
|
## A JSON Web Token implementation for Ruby
|
4
4
|
|
@@ -36,7 +36,7 @@ Returns a JSON Web Token string
|
|
36
36
|
|
37
37
|
`claims` (required) string or hash
|
38
38
|
|
39
|
-
`options` (
|
39
|
+
`options` (required) hash
|
40
40
|
|
41
41
|
* **alg** (optional, default: `HS256`)
|
42
42
|
* **key** (required unless alg is 'none')
|
@@ -70,7 +70,7 @@ Returns either:
|
|
70
70
|
|
71
71
|
`jwt` (required) is a JSON web token string
|
72
72
|
|
73
|
-
`options` (
|
73
|
+
`options` (required) hash
|
74
74
|
|
75
75
|
* **alg** (optional, default: `HS256`)
|
76
76
|
* **key** (required unless alg is 'none')
|
@@ -141,5 +141,7 @@ Future implementation may include these features:
|
|
141
141
|
|
142
142
|
[travis]: https://travis-ci.org/garyf/json_web_token
|
143
143
|
[ci_img]: https://travis-ci.org/garyf/json_web_token.svg?branch=master
|
144
|
+
[yard_docs]: http://www.rubydoc.info/gems/json_web_token
|
145
|
+
[yd_img]: http://img.shields.io/badge/yard-docs-blue.svg
|
144
146
|
[code_climate]: https://codeclimate.com/github/garyf/json_web_token
|
145
147
|
[cc_img]: https://codeclimate.com/github/garyf/json_web_token/badges/gpa.svg
|
data/json_web_token.gemspec
CHANGED
@@ -16,6 +16,6 @@ Gem::Specification.new do |s|
|
|
16
16
|
# optional
|
17
17
|
s.add_runtime_dependency 'json', '~> 1.8', '>= 1.8.3'
|
18
18
|
s.add_development_dependency 'rspec', '~> 3.3'
|
19
|
-
s.description = 'Ruby implementation of the JSON Web Token
|
19
|
+
s.description = 'Ruby implementation of the JSON Web Token standard, RFC 7519'
|
20
20
|
s.required_ruby_version = '>= 2.0.0'
|
21
21
|
end
|
data/lib/json_web_token.rb
CHANGED
@@ -3,6 +3,8 @@ require 'json_web_token/format/asn1'
|
|
3
3
|
|
4
4
|
module JsonWebToken
|
5
5
|
module Algorithm
|
6
|
+
# Sign or verify a JSON Web Signature (JWS) structure using EDCSA
|
7
|
+
# @see http://tools.ietf.org/html/rfc7518#section-3.4
|
6
8
|
module Ecdsa
|
7
9
|
|
8
10
|
extend JsonWebToken::Algorithm::Common
|
@@ -16,30 +18,43 @@ module JsonWebToken
|
|
16
18
|
|
17
19
|
module_function
|
18
20
|
|
19
|
-
|
21
|
+
# @param sha_bits [String] desired security level in bits of the signature scheme
|
22
|
+
# @param private_key [OpenSSL::PKey::EC] key used to sign a digital signature, or mac
|
23
|
+
# @param signing_input [String] input payload for a mac computation
|
24
|
+
# @return [BinaryString] a digital signature, or mac
|
25
|
+
# @example
|
26
|
+
# Ecdsa.sign('256', private_key, 'signing_input').bytes
|
27
|
+
# # => [90, 34, 44, 252, 147, 130, 167, 173, 86, 191, 247, 93, 94, 12, 200, 30, 173, 115, 248, 89, 246, 222, 4, 213, 119, 74, 70, 20, 231, 194, 104, 103]
|
28
|
+
def sign(sha_bits, private_key, signing_input)
|
20
29
|
validate_key(private_key, sha_bits)
|
21
|
-
der = private_key.dsa_sign_asn1(ssl_digest_hash sha_bits,
|
30
|
+
der = private_key.dsa_sign_asn1(ssl_digest_hash sha_bits, signing_input)
|
22
31
|
der_to_signature(der, sha_bits)
|
23
32
|
end
|
24
33
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
# @param mac [BinaryString] a digital signature, or mac
|
35
|
+
# @param sha_bits [String] desired security level in bits of the signature scheme
|
36
|
+
# @param public_key [OpenSSL::PKey::EC] key used to verify a digital signature, or mac
|
37
|
+
# @param signing_input [String] input payload for a mac computation
|
38
|
+
# @return [Boolean] a predicate to verify the signing_input for a given +mac+
|
39
|
+
# @example
|
40
|
+
# Ecdsa.verify?(< binary_string >, '256', < public_key >, 'signing_input')
|
41
|
+
# # => true
|
42
|
+
def verify?(mac, sha_bits, public_key, signing_input)
|
43
|
+
validate_key(public_key, sha_bits)
|
44
|
+
validate_signature_size(mac, sha_bits)
|
45
|
+
der = signature_to_der(mac, sha_bits)
|
46
|
+
public_key.dsa_verify_asn1(ssl_digest_hash(sha_bits, signing_input), der)
|
30
47
|
end
|
31
48
|
|
32
|
-
# private
|
33
|
-
|
34
49
|
def validate_key_size(_key, _sha_bits); end
|
35
50
|
|
36
|
-
def ssl_digest_hash(sha_bits,
|
37
|
-
digest_new(sha_bits).digest(
|
51
|
+
def ssl_digest_hash(sha_bits, signing_input)
|
52
|
+
digest_new(sha_bits).digest(signing_input)
|
38
53
|
end
|
39
54
|
|
40
|
-
def validate_signature_size(
|
55
|
+
def validate_signature_size(mac, sha_bits)
|
41
56
|
n = MAC_BYTE_COUNT[sha_bits]
|
42
|
-
fail('Invalid signature') unless
|
57
|
+
fail('Invalid signature') unless mac && mac.bytesize == n
|
43
58
|
end
|
44
59
|
|
45
60
|
private_class_method :validate_key_size,
|
@@ -3,27 +3,43 @@ require 'json_web_token/util'
|
|
3
3
|
|
4
4
|
module JsonWebToken
|
5
5
|
module Algorithm
|
6
|
+
# Sign or verify a JSON Web Signature (JWS) structure using HMAC with SHA-2 algorithms
|
7
|
+
# @see http://tools.ietf.org/html/rfc7518#section-3.2
|
6
8
|
module Hmac
|
7
9
|
|
8
10
|
extend JsonWebToken::Algorithm::Common
|
9
11
|
|
10
12
|
module_function
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
# @param sha_bits [String] size of the hash output
|
15
|
+
# @param shared_key [String] secret key used to sign and verify a digital signature, or mac
|
16
|
+
# @param signing_input [String] input payload for a mac computation
|
17
|
+
# @return [BinaryString] a digital signature, or mac
|
18
|
+
# @example
|
19
|
+
# shared_key = "gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C"
|
20
|
+
# Hmac.sign('256', shared_key, 'signing_input').bytes
|
21
|
+
# # => [90, 34, 44, 252, 147, 130, 167, 173, 86, 191, 247, 93, 94, 12, 200, 30, 173, 115, 248, 89, 246, 222, 4, 213, 119, 74, 70, 20, 231, 194, 104, 103]
|
22
|
+
def sign(sha_bits, shared_key, signing_input)
|
23
|
+
validate_key(shared_key, sha_bits)
|
24
|
+
OpenSSL::HMAC.digest(digest_new(sha_bits), shared_key, signing_input)
|
15
25
|
end
|
16
26
|
|
17
|
-
|
18
|
-
|
19
|
-
|
27
|
+
# @param mac [BinaryString] a digital signature, or mac
|
28
|
+
# @param (see #sign)
|
29
|
+
# @return [Boolean] a predicate to verify the signing_input by comparing a given +mac+
|
30
|
+
# to the +mac+ for a newly signed message; comparison done in a constant-time manner
|
31
|
+
# to thwart timing attacks
|
32
|
+
# @example
|
33
|
+
# shared_key = "gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C"
|
34
|
+
# Hmac.verify?(< binary_string >, '256', shared_key, 'signing_input')
|
35
|
+
# # => true
|
36
|
+
def verify?(mac, sha_bits, shared_key, signing_input)
|
37
|
+
validate_key(shared_key, sha_bits)
|
38
|
+
Util.constant_time_compare?(mac, sign(sha_bits, shared_key, signing_input))
|
20
39
|
end
|
21
40
|
|
22
|
-
# private
|
23
|
-
|
24
|
-
# http://tools.ietf.org/html/rfc7518#section-3.2
|
25
41
|
def validate_key_size(key, sha_bits)
|
26
|
-
fail('Invalid key') unless key && key.bytesize * 8 >= sha_bits.to_i
|
42
|
+
fail('Invalid shared key') unless key && key.bytesize * 8 >= sha_bits.to_i
|
27
43
|
end
|
28
44
|
|
29
45
|
private_class_method :validate_key_size
|
@@ -2,6 +2,8 @@ require 'json_web_token/algorithm/common'
|
|
2
2
|
|
3
3
|
module JsonWebToken
|
4
4
|
module Algorithm
|
5
|
+
# Sign or verify a JSON Web Signature (JWS) structure using RSASSA-PKCS-v1_5
|
6
|
+
# @see http://tools.ietf.org/html/rfc7518#section-3.3
|
5
7
|
module Rsa
|
6
8
|
|
7
9
|
extend JsonWebToken::Algorithm::Common
|
@@ -10,19 +12,29 @@ module JsonWebToken
|
|
10
12
|
|
11
13
|
module_function
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
# @param sha_bits [String] desired security level in bits of the signature scheme
|
16
|
+
# @param private_key [OpenSSL::PKey::RSA] key used to sign a digital signature, or mac
|
17
|
+
# @param signing_input [String] input payload for a mac computation
|
18
|
+
# @return [BinaryString] a digital signature, or mac
|
19
|
+
# @example
|
20
|
+
# Rsa.sign('256', < private_key >, 'signing_input').bytes.length
|
21
|
+
# # => 256
|
22
|
+
def sign(sha_bits, private_key, signing_input)
|
23
|
+
validate_key(private_key, sha_bits)
|
24
|
+
private_key.sign(digest_new(sha_bits), signing_input)
|
16
25
|
end
|
17
26
|
|
18
|
-
|
19
|
-
|
20
|
-
|
27
|
+
# @param mac [BinaryString] a digital signature, or mac
|
28
|
+
# @param public_key [OpenSSL::PKey::RSA] key used to verify a digital signature, or mac
|
29
|
+
# @return [Boolean] a predicate to verify the signing_input for a given +mac+
|
30
|
+
# @example
|
31
|
+
# Rsa.verify?(< binary_string >, '256', < public_key >, 'signing_input')
|
32
|
+
# # => true
|
33
|
+
def verify?(mac, sha_bits, public_key, signing_input)
|
34
|
+
validate_key(public_key, sha_bits)
|
35
|
+
public_key.verify(digest_new(sha_bits), mac, signing_input)
|
21
36
|
end
|
22
37
|
|
23
|
-
# private
|
24
|
-
|
25
|
-
# http://tools.ietf.org/html/rfc7518#section-3.3
|
26
38
|
# https://github.com/ruby/openssl/issues/5
|
27
39
|
def validate_key_size(key, sha_bits)
|
28
40
|
fail('Invalid private key') unless key && key.n.num_bits >= KEY_BITS_MIN
|
@@ -2,44 +2,43 @@ require 'base64'
|
|
2
2
|
|
3
3
|
module JsonWebToken
|
4
4
|
module Format
|
5
|
+
# Provide base64url encoding and decoding functions without padding, based upon standard
|
6
|
+
# base64 encoding and decoding functions that do use padding
|
7
|
+
# @see http://tools.ietf.org/html/rfc7515#appendix-C
|
5
8
|
module Base64Url
|
6
|
-
|
7
9
|
module_function
|
8
10
|
|
11
|
+
# @param str [String]
|
12
|
+
# @return [String] a urlsafe_encode64 string with all trailing '=' padding removed
|
13
|
+
# @example
|
14
|
+
# Base64Url.encode('foo')
|
15
|
+
# # => 'Zm9v'
|
9
16
|
def encode(str)
|
10
|
-
|
17
|
+
base64_padding_removed(Base64.urlsafe_encode64(str))
|
11
18
|
end
|
12
19
|
|
20
|
+
# @param str [String] encoded as url_encode64
|
21
|
+
# @return [String] with trailing '=' padding added before decoding
|
22
|
+
# @example
|
23
|
+
# Base64Url.decode("YmFy")
|
24
|
+
# # => 'bar'
|
13
25
|
def decode(str)
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
# private
|
18
|
-
|
19
|
-
# http://tools.ietf.org/html/rfc7515#appendix-C
|
20
|
-
def url_safe_encode(str)
|
21
|
-
remove_base64_padding(Base64.urlsafe_encode64 str)
|
22
|
-
end
|
23
|
-
|
24
|
-
def url_safe_decode(str)
|
25
|
-
Base64.urlsafe_decode64(add_base64_padding str)
|
26
|
+
Base64.urlsafe_decode64(base64_padding_added(str))
|
26
27
|
end
|
27
28
|
|
28
|
-
def
|
29
|
+
def base64_padding_removed(encoded)
|
29
30
|
encoded.gsub(/[=]/, '')
|
30
31
|
end
|
31
32
|
|
32
|
-
def
|
33
|
+
def base64_padding_added(str)
|
33
34
|
mod = str.length % 4
|
34
35
|
return str if mod == 0
|
35
36
|
fail('Invalid base64 string') if mod == 1
|
36
37
|
"#{str}#{'=' * (4 - mod)}"
|
37
38
|
end
|
38
39
|
|
39
|
-
private_class_method :
|
40
|
-
:
|
41
|
-
:remove_base64_padding,
|
42
|
-
:add_base64_padding
|
40
|
+
private_class_method :base64_padding_removed,
|
41
|
+
:base64_padding_added
|
43
42
|
end
|
44
43
|
end
|
45
44
|
end
|
data/lib/json_web_token/jwa.rb
CHANGED
@@ -3,6 +3,8 @@ require 'json_web_token/algorithm/hmac'
|
|
3
3
|
require 'json_web_token/algorithm/rsa'
|
4
4
|
|
5
5
|
module JsonWebToken
|
6
|
+
# Choose a cryptographic algorithm to be used for a JSON Web Signature (JWS)
|
7
|
+
# @see http://tools.ietf.org/html/rfc7518
|
6
8
|
module Jwa
|
7
9
|
|
8
10
|
ALGORITHMS = /(HS|RS|ES)(256|384|512)?/i
|
@@ -10,18 +12,34 @@ module JsonWebToken
|
|
10
12
|
|
11
13
|
module_function
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
# @param algorithm [String] 'alg' header parameter value for JWS
|
16
|
+
# @param key [String | OpenSSL::PKey::RSA | OpenSSL::PKey::EC] secret key used to sign
|
17
|
+
# a digital signature, or mac
|
18
|
+
# @param signing_input [String] input payload for a mac computation
|
19
|
+
# @return [BinaryString] a digital signature, or mac
|
20
|
+
# @example
|
21
|
+
# key = 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'
|
22
|
+
# Jwa.sign('HS256', key, 'signing_input').bytes
|
23
|
+
# # => [90, 34, 44, 252, 147, 130, 167, 173, 86, 191, 247, 93, 94, 12, 200, 30, 173, 115, 248, 89, 246, 222, 4, 213, 119, 74, 70, 20, 231, 194, 104, 103]
|
24
|
+
def sign(algorithm, key, signing_input)
|
25
|
+
alg_module, sha_bits = validated_alg(algorithm)
|
26
|
+
alg_module.sign(sha_bits, key, signing_input)
|
16
27
|
end
|
17
28
|
|
18
|
-
|
19
|
-
|
20
|
-
|
29
|
+
# @param mac [BinaryString] a digital signature, or mac
|
30
|
+
# @param algorithm [String] 'alg' header parameter value for JWS
|
31
|
+
# @param key [String | OpenSSL::PKey::RSA | OpenSSL::PKey::EC] key used to verify
|
32
|
+
# a digital signature, or mac
|
33
|
+
# @param signing_input [String] input payload for a mac computation
|
34
|
+
# @example
|
35
|
+
# key = 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'
|
36
|
+
# Jwa.verify?(< binary_string >, 'HS256', key, 'signing_input')
|
37
|
+
# # => true
|
38
|
+
def verify?(mac, algorithm, key, signing_input)
|
39
|
+
alg_module, sha_bits = validated_alg(algorithm)
|
40
|
+
alg_module.verify?(mac, sha_bits, key, signing_input)
|
21
41
|
end
|
22
42
|
|
23
|
-
# private
|
24
|
-
|
25
43
|
def validated_alg(algorithm)
|
26
44
|
alg = destructured_alg(algorithm)
|
27
45
|
alg ? alg : fail('Unrecognized algorithm')
|
@@ -30,10 +48,9 @@ module JsonWebToken
|
|
30
48
|
def destructured_alg(algorithm)
|
31
49
|
match = algorithm.match(ALGORITHMS)
|
32
50
|
return unless match && match[0].length == ALG_LENGTH
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
}
|
51
|
+
alg_module = validated_constant(match[1].downcase)
|
52
|
+
sha_bits = match[2]
|
53
|
+
[alg_module, sha_bits]
|
37
54
|
end
|
38
55
|
|
39
56
|
def validated_constant(str)
|
@@ -46,7 +63,7 @@ module JsonWebToken
|
|
46
63
|
end
|
47
64
|
|
48
65
|
private_class_method :validated_alg,
|
49
|
-
:destructured_alg
|
66
|
+
:destructured_alg,
|
50
67
|
:validated_constant
|
51
68
|
end
|
52
69
|
end
|
data/lib/json_web_token/jws.rb
CHANGED
@@ -4,45 +4,72 @@ require 'json_web_token/jwa'
|
|
4
4
|
require 'json_web_token/util'
|
5
5
|
|
6
6
|
module JsonWebToken
|
7
|
+
# Represent content to be secured with digital signatures or Message Authentication Codes (MACs)
|
8
|
+
# @see http://tools.ietf.org/html/rfc7515
|
7
9
|
module Jws
|
8
10
|
|
9
11
|
MESSAGE_SIGNATURE_PARTS = 3
|
10
12
|
|
11
13
|
module_function
|
12
14
|
|
13
|
-
#
|
14
|
-
|
15
|
+
# @param header [Hash] the desired set of JWS header parameters
|
16
|
+
# @param payload [String] content to be used as the JWS payload
|
17
|
+
# @param key [String | OpenSSL::PKey::RSA | OpenSSL::PKey::EC] secret key used to sign
|
18
|
+
# a digital signature, or mac
|
19
|
+
# @return [String] a JSON Web Signature, representing a digitally signed payload
|
20
|
+
# @example
|
21
|
+
# header = {alg: 'HS256'}
|
22
|
+
# key = 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'
|
23
|
+
# Jws.sign(header, 'payload', key)
|
24
|
+
# # => 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
|
25
|
+
# @see http://tools.ietf.org/html/rfc7515#page-15
|
26
|
+
def sign(header, payload, key)
|
15
27
|
alg = alg_parameter(header)
|
16
|
-
|
17
|
-
"#{
|
28
|
+
signing_input = encode_input(header, payload)
|
29
|
+
"#{signing_input}.#{signature(alg, key, signing_input)}"
|
18
30
|
end
|
19
31
|
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
# http://tools.ietf.org/html/rfc7515#page-47
|
28
|
-
def
|
32
|
+
# @param header [Hash] the desired set of JWS header parameters
|
33
|
+
# @param payload [String] content to be used as the JWS payload
|
34
|
+
# @return [String] a JWS that provides no integrity protection (i.e. lacks a signature)
|
35
|
+
# @example
|
36
|
+
# header = {alg: 'none'}
|
37
|
+
# Jws.sign(header, 'payload')
|
38
|
+
# # => 'eyJhbGciOiJub25lIn0.cGF5bG9hZA.'
|
39
|
+
# @see http://tools.ietf.org/html/rfc7515#page-47
|
40
|
+
def unsecured_message(header, payload)
|
29
41
|
fail("Invalid 'alg' header parameter") unless alg_parameter(header) == 'none'
|
30
|
-
"#{
|
42
|
+
"#{encode_input(header, payload)}." # note trailing '.'
|
31
43
|
end
|
32
44
|
|
33
|
-
#
|
45
|
+
# @param jws [String] a JSON Web Signature
|
46
|
+
# @param algorithm [String] 'alg' header parameter value for JWS
|
47
|
+
# @param key [String | OpenSSL::PKey::RSA | OpenSSL::PKey::EC] key used to verify
|
48
|
+
# a digital signature, or mac
|
49
|
+
# @return [String | Boolean] a JWS if the mac verifies, or +false+ otherwise
|
50
|
+
# @example
|
51
|
+
# jws = 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
|
52
|
+
# key = 'gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C'
|
53
|
+
# Jws.verify(jws, 'HS256', key)
|
54
|
+
# # => 'eyJhbGciOiJIUzI1NiJ9.cGF5bG9hZA.uVTaOdyzp_f4mT_hfzU8LnCzdmlVC4t2itHDEYUZym4'
|
55
|
+
# @see http://tools.ietf.org/html/rfc7515#page-16
|
56
|
+
def verify(jws, algorithm, key = nil)
|
57
|
+
compare_alg(jws, algorithm)
|
58
|
+
return jws if algorithm == 'none'
|
59
|
+
signature_verify?(jws, algorithm, key) ? jws : false
|
60
|
+
end
|
34
61
|
|
35
62
|
def alg_parameter(header)
|
36
63
|
alg = Util.symbolize_keys(header)[:alg]
|
37
64
|
alg && !alg.empty? ? alg : fail("Missing required 'alg' header parameter")
|
38
65
|
end
|
39
66
|
|
40
|
-
def
|
41
|
-
"#{Format::Base64Url.encode
|
67
|
+
def encode_input(header, payload)
|
68
|
+
"#{Format::Base64Url.encode(header.to_json)}.#{Format::Base64Url.encode(payload)}"
|
42
69
|
end
|
43
70
|
|
44
71
|
def signature(algorithm, key, data)
|
45
|
-
Format::Base64Url.encode(Jwa.
|
72
|
+
Format::Base64Url.encode(Jwa.sign(algorithm, key, data))
|
46
73
|
end
|
47
74
|
|
48
75
|
# http://tools.ietf.org/html/rfc7515#section-4.1.1
|
@@ -54,22 +81,22 @@ module JsonWebToken
|
|
54
81
|
end
|
55
82
|
|
56
83
|
def decoded_header_json_to_hash(jws)
|
57
|
-
JSON.parse(Format::Base64Url.decode
|
84
|
+
JSON.parse(Format::Base64Url.decode(jws.split('.')[0]))
|
58
85
|
end
|
59
86
|
|
60
|
-
def
|
87
|
+
def signature_verify?(jws, algorithm, key)
|
61
88
|
ary = jws.split('.')
|
62
89
|
return unless key && ary.length == MESSAGE_SIGNATURE_PARTS
|
63
90
|
decoded_signature = Format::Base64Url.decode(ary[2])
|
64
91
|
payload = "#{ary[0]}.#{ary[1]}"
|
65
|
-
Jwa.
|
92
|
+
Jwa.verify?(decoded_signature, algorithm, key, payload)
|
66
93
|
end
|
67
94
|
|
68
95
|
private_class_method :alg_parameter,
|
69
|
-
:
|
96
|
+
:encode_input,
|
70
97
|
:signature,
|
71
98
|
:compare_alg,
|
72
99
|
:decoded_header_json_to_hash,
|
73
|
-
:
|
100
|
+
:signature_verify?
|
74
101
|
end
|
75
102
|
end
|