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 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