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 CHANGED
@@ -1,4 +1,5 @@
1
1
  Rakefile
2
2
  lib/jwt.rb
3
- spec/jwt.rb
3
+ spec/helper.rb
4
+ spec/jwt_spec.rb
4
5
  Manifest
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.4') do |p|
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 = "jeff.lindsay@twilio.com"
9
+ p.email = "progrium@gmail.com"
10
10
  p.ignore_pattern = ["tmp/*"]
11
- p.runtime_dependencies = ["json >=1.2.4"]
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/jwt.rb"
16
+ sh "rspec spec/jwt_spec.rb"
17
17
  end
@@ -1,32 +1,35 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.name = %q{jwt}
5
- s.version = "0.1.4"
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 = [%q{Jeff Lindsay}]
9
- s.date = %q{2011-11-11}
10
- s.description = %q{JSON Web Token implementation in Ruby}
11
- s.email = %q{jeff.lindsay@twilio.com}
12
- s.extra_rdoc_files = [%q{lib/jwt.rb}]
13
- s.files = [%q{Rakefile}, %q{lib/jwt.rb}, %q{spec/jwt.rb}, %q{Manifest}, %q{jwt.gemspec}]
14
- s.homepage = %q{http://github.com/progrium/ruby-jwt}
15
- s.rdoc_options = [%q{--line-numbers}, %q{--inline-source}, %q{--title}, %q{Jwt}, %q{--main}, %q{README.md}]
16
- s.require_paths = [%q{lib}]
17
- s.rubyforge_project = %q{jwt}
18
- s.rubygems_version = %q{1.8.5}
19
- s.summary = %q{JSON Web Token implementation in Ruby}
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<json>, [">= 1.2.4"])
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<json>, [">= 1.2.4"])
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<json>, [">= 1.2.4"])
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 "json"
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.to_json)
50
- segments << base64url_encode(payload.to_json)
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 = JSON.parse(base64url_decode(header_segment))
68
- payload = JSON.parse(base64url_decode(payload_segment))
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 ["HS256", "HS384", "HS512"].include?(algo)
77
- raise JWT::DecodeError.new("Signature verification failed") unless signature == sign_hmac(algo, signing_input, key)
78
- elsif ["RS256", "RS384", "RS512"].include?(algo)
79
- raise JWT::DecodeError.new("Signature verification failed") unless verify_rsa(algo, key, signing_input, signature)
80
- else
81
- raise JWT::DecodeError.new("Algorithm not supported")
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
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require "#{File.dirname(__FILE__)}/../lib/jwt.rb"
3
+
4
+ RSpec.configure do |c|
5
+ end
6
+
@@ -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: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 4
10
- version: 0.1.4
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: 2011-11-11 00:00:00 Z
18
+ date: 2012-07-20 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: json
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: 23
28
+ hash: 15
29
29
  segments:
30
30
  - 1
31
- - 2
32
- - 4
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: jeff.lindsay@twilio.com
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/jwt.rb
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.5
101
+ rubygems_version: 1.8.24
86
102
  signing_key:
87
103
  specification_version: 3
88
104
  summary: JSON Web Token implementation in Ruby