jwt 0.1.4 → 0.1.5
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.
- data/Manifest +2 -1
- data/Rakefile +5 -5
- data/jwt.gemspec +20 -17
- data/lib/jwt.rb +30 -22
- data/spec/helper.rb +6 -0
- data/spec/{jwt.rb → jwt_spec.rb} +40 -5
- metadata +28 -12
data/Manifest
CHANGED
data/Rakefile
CHANGED
@@ -2,16 +2,16 @@ require 'rubygems'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'echoe'
|
4
4
|
|
5
|
-
Echoe.new('jwt', '0.1.
|
5
|
+
Echoe.new('jwt', '0.1.5') do |p|
|
6
6
|
p.description = "JSON Web Token implementation in Ruby"
|
7
7
|
p.url = "http://github.com/progrium/ruby-jwt"
|
8
8
|
p.author = "Jeff Lindsay"
|
9
|
-
p.email = "
|
9
|
+
p.email = "progrium@gmail.com"
|
10
10
|
p.ignore_pattern = ["tmp/*"]
|
11
|
-
p.runtime_dependencies = ["
|
12
|
-
p.development_dependencies = []
|
11
|
+
p.runtime_dependencies = ["multi_json >=1.0"]
|
12
|
+
p.development_dependencies = ["echoe >=4.6.3"]
|
13
13
|
end
|
14
14
|
|
15
15
|
task :test do
|
16
|
-
sh "rspec spec/
|
16
|
+
sh "rspec spec/jwt_spec.rb"
|
17
17
|
end
|
data/jwt.gemspec
CHANGED
@@ -1,32 +1,35 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
-
s.name =
|
5
|
-
s.version = "0.1.
|
4
|
+
s.name = "jwt"
|
5
|
+
s.version = "0.1.5"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
-
s.authors = [
|
9
|
-
s.date =
|
10
|
-
s.description =
|
11
|
-
s.email =
|
12
|
-
s.extra_rdoc_files = [
|
13
|
-
s.files = [
|
14
|
-
s.homepage =
|
15
|
-
s.rdoc_options = [
|
16
|
-
s.require_paths = [
|
17
|
-
s.rubyforge_project =
|
18
|
-
s.rubygems_version =
|
19
|
-
s.summary =
|
8
|
+
s.authors = ["Jeff Lindsay"]
|
9
|
+
s.date = "2012-07-20"
|
10
|
+
s.description = "JSON Web Token implementation in Ruby"
|
11
|
+
s.email = "progrium@gmail.com"
|
12
|
+
s.extra_rdoc_files = ["lib/jwt.rb"]
|
13
|
+
s.files = ["Rakefile", "lib/jwt.rb", "spec/helper.rb", "spec/jwt_spec.rb", "Manifest", "jwt.gemspec"]
|
14
|
+
s.homepage = "http://github.com/progrium/ruby-jwt"
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Jwt", "--main", "README.md"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = "jwt"
|
18
|
+
s.rubygems_version = "1.8.24"
|
19
|
+
s.summary = "JSON Web Token implementation in Ruby"
|
20
20
|
|
21
21
|
if s.respond_to? :specification_version then
|
22
22
|
s.specification_version = 3
|
23
23
|
|
24
24
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
25
|
-
s.add_runtime_dependency(%q<
|
25
|
+
s.add_runtime_dependency(%q<multi_json>, [">= 1.0"])
|
26
|
+
s.add_development_dependency(%q<echoe>, [">= 4.6.3"])
|
26
27
|
else
|
27
|
-
s.add_dependency(%q<
|
28
|
+
s.add_dependency(%q<multi_json>, [">= 1.0"])
|
29
|
+
s.add_dependency(%q<echoe>, [">= 4.6.3"])
|
28
30
|
end
|
29
31
|
else
|
30
|
-
s.add_dependency(%q<
|
32
|
+
s.add_dependency(%q<multi_json>, [">= 1.0"])
|
33
|
+
s.add_dependency(%q<echoe>, [">= 4.6.3"])
|
31
34
|
end
|
32
35
|
end
|
data/lib/jwt.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
#
|
1
|
+
#
|
2
2
|
# JSON Web Token implementation
|
3
|
-
#
|
3
|
+
#
|
4
4
|
# Should be up to date with the latest spec:
|
5
5
|
# http://self-issued.info/docs/draft-jones-json-web-token-06.html
|
6
6
|
|
7
7
|
require "base64"
|
8
8
|
require "openssl"
|
9
|
-
require "
|
9
|
+
require "multi_json"
|
10
10
|
|
11
11
|
module JWT
|
12
12
|
class DecodeError < Exception; end
|
13
|
-
|
13
|
+
|
14
14
|
def self.sign(algorithm, msg, key)
|
15
15
|
if ["HS256", "HS384", "HS512"].include?(algorithm)
|
16
16
|
sign_hmac(algorithm, msg, key)
|
@@ -32,22 +32,22 @@ module JWT
|
|
32
32
|
def self.sign_hmac(algorithm, msg, key)
|
33
33
|
OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def self.base64url_decode(str)
|
37
37
|
str += '=' * (4 - str.length.modulo(4))
|
38
38
|
Base64.decode64(str.gsub("-", "+").gsub("_", "/"))
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def self.base64url_encode(str)
|
42
42
|
Base64.encode64(str).gsub("+", "-").gsub("/", "_").gsub("\n", "").gsub('=', '')
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.encode(payload, key, algorithm='HS256')
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.encode(payload, key, algorithm='HS256', header_fields={})
|
46
46
|
algorithm ||= "none"
|
47
47
|
segments = []
|
48
|
-
header = {"typ" => "JWT", "alg" => algorithm}
|
49
|
-
segments << base64url_encode(header
|
50
|
-
segments << base64url_encode(payload
|
48
|
+
header = {"typ" => "JWT", "alg" => algorithm}.merge(header_fields)
|
49
|
+
segments << base64url_encode(MultiJson.encode(header))
|
50
|
+
segments << base64url_encode(MultiJson.encode(payload))
|
51
51
|
signing_input = segments.join('.')
|
52
52
|
if algorithm != "none"
|
53
53
|
signature = sign(algorithm, signing_input, key)
|
@@ -57,15 +57,15 @@ module JWT
|
|
57
57
|
end
|
58
58
|
segments.join('.')
|
59
59
|
end
|
60
|
-
|
61
|
-
def self.decode(jwt, key=nil, verify=true)
|
60
|
+
|
61
|
+
def self.decode(jwt, key=nil, verify=true, &keyfinder)
|
62
62
|
segments = jwt.split('.')
|
63
63
|
raise JWT::DecodeError.new("Not enough or too many segments") unless [2,3].include? segments.length
|
64
64
|
header_segment, payload_segment, crypto_segment = segments
|
65
65
|
signing_input = [header_segment, payload_segment].join('.')
|
66
66
|
begin
|
67
|
-
header =
|
68
|
-
payload =
|
67
|
+
header = MultiJson.decode(base64url_decode(header_segment))
|
68
|
+
payload = MultiJson.decode(base64url_decode(payload_segment))
|
69
69
|
signature = base64url_decode(crypto_segment) if verify
|
70
70
|
rescue JSON::ParserError
|
71
71
|
raise JWT::DecodeError.new("Invalid segment encoding")
|
@@ -73,12 +73,20 @@ module JWT
|
|
73
73
|
if verify == true
|
74
74
|
algo = header['alg']
|
75
75
|
|
76
|
-
if
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
if keyfinder
|
77
|
+
key = keyfinder.call(header)
|
78
|
+
end
|
79
|
+
|
80
|
+
begin
|
81
|
+
if ["HS256", "HS384", "HS512"].include?(algo)
|
82
|
+
raise JWT::DecodeError.new("Signature verification failed") unless signature == sign_hmac(algo, signing_input, key)
|
83
|
+
elsif ["RS256", "RS384", "RS512"].include?(algo)
|
84
|
+
raise JWT::DecodeError.new("Signature verification failed") unless verify_rsa(algo, key, signing_input, signature)
|
85
|
+
else
|
86
|
+
raise JWT::DecodeError.new("Algorithm not supported")
|
87
|
+
end
|
88
|
+
rescue OpenSSL::PKey::PKeyError
|
89
|
+
raise JWT::DecodeError.new("Signature verification failed")
|
82
90
|
end
|
83
91
|
end
|
84
92
|
payload
|
data/spec/helper.rb
ADDED
data/spec/{jwt.rb → jwt_spec.rb}
RENAMED
@@ -13,12 +13,22 @@ describe JWT do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it "encodes and decodes JWTs for RSA signatures" do
|
16
|
-
private_key = OpenSSL::PKey::RSA.generate(512)
|
16
|
+
private_key = OpenSSL::PKey::RSA.generate(512)
|
17
17
|
jwt = JWT.encode(@payload, private_key, "RS256")
|
18
18
|
decoded_payload = JWT.decode(jwt, private_key.public_key)
|
19
19
|
decoded_payload.should == @payload
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
|
+
it "encodes and decodes JWTs with custom header fields" do
|
23
|
+
private_key = OpenSSL::PKey::RSA.generate(512)
|
24
|
+
jwt = JWT.encode(@payload, private_key, "RS256", {"kid" => 'default'})
|
25
|
+
decoded_payload = JWT.decode(jwt) do |header|
|
26
|
+
header["kid"].should == 'default'
|
27
|
+
private_key.public_key
|
28
|
+
end
|
29
|
+
decoded_payload.should == @payload
|
30
|
+
end
|
31
|
+
|
22
32
|
it "decodes valid JWTs" do
|
23
33
|
example_payload = {"hello" => "world"}
|
24
34
|
example_secret = 'secret'
|
@@ -40,7 +50,7 @@ describe JWT do
|
|
40
50
|
jwt = JWT.encode(@payload, right_private_key, "RS256")
|
41
51
|
lambda { JWT.decode(jwt, bad_private_key.public_key) }.should raise_error(JWT::DecodeError)
|
42
52
|
end
|
43
|
-
|
53
|
+
|
44
54
|
it "allows decoding without key" do
|
45
55
|
right_secret = 'foo'
|
46
56
|
bad_secret = 'bar'
|
@@ -48,15 +58,40 @@ describe JWT do
|
|
48
58
|
decoded_payload = JWT.decode(jwt, bad_secret, false)
|
49
59
|
decoded_payload.should == @payload
|
50
60
|
end
|
51
|
-
|
61
|
+
|
52
62
|
it "raises exception on unsupported crypto algorithm" do
|
53
63
|
lambda { JWT.encode(@payload, "secret", 'HS1024') }.should raise_error(NotImplementedError)
|
54
64
|
end
|
55
|
-
|
65
|
+
|
56
66
|
it "encodes and decodes plaintext JWTs" do
|
57
67
|
jwt = JWT.encode(@payload, nil, nil)
|
58
68
|
jwt.split('.').length.should == 2
|
59
69
|
decoded_payload = JWT.decode(jwt, nil, nil)
|
60
70
|
decoded_payload.should == @payload
|
61
71
|
end
|
72
|
+
|
73
|
+
it "raise exception on invalid signature" do
|
74
|
+
pubkey = OpenSSL::PKey::RSA.new(<<-PUBKEY)
|
75
|
+
-----BEGIN PUBLIC KEY-----
|
76
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCaY7425h964bjaoLeUm
|
77
|
+
SlZ8sK7VtVk9zHbGmZh2ygGYwfuUf2bmMye2Ofv99yDE/rd4loVIAcu7RVvDRgHq
|
78
|
+
3/CZTnIrSvHsiJQsHBNa3d+F1ihPfzURzf1M5k7CFReBj2SBXhDXd57oRfBQj12w
|
79
|
+
CVhhwP6kGTAWuoppbIIIBfNF2lE/Nvm7lVVYQqL9xOrP/AQ4xRbpQlB8Ll9sO9Or
|
80
|
+
SvbWhCDa/LMOWxHdmrcJi6XoSg1vnOyCoKbyAoauTt/XqdkHbkDdQ6HFbJieu9il
|
81
|
+
LDZZNliPhfENuKeC2MCGVXTEu8Cqhy1w6e4axavLlXoYf4laJIZ/e7au8SqDbY0B
|
82
|
+
xwIDAQAB
|
83
|
+
-----END PUBLIC KEY-----
|
84
|
+
PUBKEY
|
85
|
+
jwt = (
|
86
|
+
'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY' +
|
87
|
+
'XVkIjoiMTA2MDM1Nzg5MTY4OC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSI' +
|
88
|
+
'sImNpZCI6IjEwNjAzNTc4OTE2ODguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb' +
|
89
|
+
'20iLCJpZCI6IjExNjQ1MjgyNDMwOTg1Njc4MjE2MyIsInRva2VuX2hhc2giOiJ' +
|
90
|
+
'0Z2hEOUo4bjhWME4ydmN3NmVNaWpnIiwiaWF0IjoxMzIwNjcwOTc4LCJleHAiO' +
|
91
|
+
'jEzMjA2NzQ4Nzh9.D8x_wirkxDElqKdJBcsIws3Ogesk38okz6MN7zqC7nEAA7' +
|
92
|
+
'wcy1PxsROY1fmBvXSer0IQesAqOW-rPOCNReSn-eY8d53ph1x2HAF-AzEi3GOl' +
|
93
|
+
'6hFycH8wj7Su6JqqyEbIVLxE7q7DkAZGaMPkxbTHs1EhSd5_oaKQ6O4xO3ZnnT4'
|
94
|
+
)
|
95
|
+
lambda { JWT.decode(jwt, pubkey, true) }.should raise_error(JWT::DecodeError)
|
96
|
+
end
|
62
97
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jwt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 5
|
10
|
+
version: 0.1.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jeff Lindsay
|
@@ -15,26 +15,41 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2012-07-20 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
21
|
+
name: multi_json
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
none: false
|
25
25
|
requirements:
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
28
|
+
hash: 15
|
29
29
|
segments:
|
30
30
|
- 1
|
31
|
-
-
|
32
|
-
|
33
|
-
version: 1.2.4
|
31
|
+
- 0
|
32
|
+
version: "1.0"
|
34
33
|
type: :runtime
|
35
34
|
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: echoe
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 33
|
44
|
+
segments:
|
45
|
+
- 4
|
46
|
+
- 6
|
47
|
+
- 3
|
48
|
+
version: 4.6.3
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
36
51
|
description: JSON Web Token implementation in Ruby
|
37
|
-
email:
|
52
|
+
email: progrium@gmail.com
|
38
53
|
executables: []
|
39
54
|
|
40
55
|
extensions: []
|
@@ -44,7 +59,8 @@ extra_rdoc_files:
|
|
44
59
|
files:
|
45
60
|
- Rakefile
|
46
61
|
- lib/jwt.rb
|
47
|
-
- spec/
|
62
|
+
- spec/helper.rb
|
63
|
+
- spec/jwt_spec.rb
|
48
64
|
- Manifest
|
49
65
|
- jwt.gemspec
|
50
66
|
homepage: http://github.com/progrium/ruby-jwt
|
@@ -82,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
98
|
requirements: []
|
83
99
|
|
84
100
|
rubyforge_project: jwt
|
85
|
-
rubygems_version: 1.8.
|
101
|
+
rubygems_version: 1.8.24
|
86
102
|
signing_key:
|
87
103
|
specification_version: 3
|
88
104
|
summary: JSON Web Token implementation in Ruby
|