jwt 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|