json-jwt 0.0.1 → 0.0.2

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.

Potentially problematic release.


This version of json-jwt might be problematic. Click here for more details.

data/Gemfile.lock CHANGED
@@ -1,15 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json-jwt (0.0.0)
4
+ json-jwt (0.0.1)
5
+ activesupport (>= 2.3)
6
+ i18n
5
7
  json (>= 1.4.3)
6
8
  url_safe_base64
7
9
 
8
10
  GEM
9
11
  remote: http://rubygems.org/
10
12
  specs:
13
+ activesupport (3.1.0)
14
+ multi_json (~> 1.0)
11
15
  diff-lcs (1.1.3)
16
+ i18n (0.6.0)
12
17
  json (1.6.0)
18
+ multi_json (1.0.3)
13
19
  rake (0.9.2)
14
20
  rcov (0.9.10)
15
21
  rspec (2.6.0)
data/README.rdoc CHANGED
@@ -13,6 +13,8 @@ JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON
13
13
 
14
14
  == Examples
15
15
 
16
+ === Encoding
17
+
16
18
  claim = {
17
19
  iss: 'nov',
18
20
  exp: 1.week.from_now,
@@ -28,6 +30,12 @@ JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON
28
30
  # With signature & encryption
29
31
  JSON::JWT.new(claim).sign(key, algorithm).encrypt(key, algorithm).to_s
30
32
 
33
+ === Decoding
34
+
35
+ jwt_string = "jwt_header.jwt_claims.jwt_signature"
36
+
37
+ JSON::JWT.decode(jwt_string, public_key)
38
+
31
39
  == Note on Patches/Pull Requests
32
40
 
33
41
  * Fork the project.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
data/json-jwt.gemspec CHANGED
@@ -12,6 +12,8 @@ Gem::Specification.new do |s|
12
12
  s.require_paths = ["lib"]
13
13
  s.add_runtime_dependency "json", ">= 1.4.3"
14
14
  s.add_runtime_dependency "url_safe_base64"
15
+ s.add_runtime_dependency "activesupport", ">= 2.3"
16
+ s.add_runtime_dependency "i18n"
15
17
  s.add_development_dependency "rake", ">= 0.8"
16
18
  s.add_development_dependency "rcov", ">= 0.9"
17
19
  s.add_development_dependency "rspec", ">= 2"
data/lib/json/jws.rb CHANGED
@@ -1,35 +1,29 @@
1
1
  module JSON
2
2
  class JWS < JWT
3
+ class InvalidFormat < JWT::InvalidFormat; end
4
+ class VerificationFailed < JWT::VerificationFailed; end
5
+
3
6
  def initialize(jwt)
4
- @header = jwt.header
5
7
  replace jwt
8
+ raise InvalidFormat.new('Signature Algorithm Required') unless algorithm
6
9
  end
7
10
 
8
- def sign(private_key_or_secret, algorithm)
9
- header[:alg] = algorithm
10
- digest = OpenSSL::Digest::Digest.new "SHA#{algorithm.to_s[2, 3]}"
11
- self.signature = case algorithm
12
- when :HS256, :HS384, :HS512
13
- secret = private_key_or_secret
14
- OpenSSL::HMAC.digest(
15
- digest,
16
- secret,
17
- signature_base_string
18
- )
19
- when :RS256, :RS384, :RS512
20
- private_key = private_key_or_secret
21
- private_key.sign(
22
- digest,
23
- signature_base_string
24
- )
25
- when :ES256, :ES384, :ES512
26
- # TODO
27
- end
11
+ def sign!(private_key_or_secret)
12
+ self.signature = sign signature_base_string, private_key_or_secret
28
13
  self
29
14
  end
30
15
 
16
+ def verify(signature_base_string, signature, public_key_or_secret)
17
+ sign(signature_base_string, public_key_or_secret) == signature or
18
+ raise VerificationFailed
19
+ end
20
+
31
21
  private
32
22
 
23
+ def algorithm
24
+ @header[:alg]
25
+ end
26
+
33
27
  def signature_base_string
34
28
  [
35
29
  header.to_json,
@@ -38,5 +32,22 @@ module JSON
38
32
  UrlSafeBase64.encode64 segment
39
33
  end.join('.')
40
34
  end
35
+
36
+ def sign(signature_base_string, private_key_or_secret)
37
+ digest = OpenSSL::Digest::Digest.new "SHA#{algorithm.to_s[2, 3]}"
38
+ case algorithm
39
+ when :HS256, :HS384, :HS512
40
+ secret = private_key_or_secret
41
+ OpenSSL::HMAC.digest digest, secret, signature_base_string
42
+ when :RS256, :RS384, :RS512
43
+ private_key = private_key_or_secret
44
+ private_key.sign digest, signature_base_string
45
+ when :ES256, :ES384, :ES512
46
+ # TODO
47
+ raise NotImplementedError.new
48
+ else
49
+ raise InvalidFormat.new('Unknown Signature Algorithm')
50
+ end
51
+ end
41
52
  end
42
53
  end
data/lib/json/jwt.rb CHANGED
@@ -6,21 +6,33 @@ module JSON
6
6
  class JWT < Hash
7
7
  attr_accessor :header, :signature
8
8
 
9
- def initialize(claim)
9
+ class Exception < StandardError; end
10
+ class InvalidFormat < Exception; end
11
+ class VerificationFailed < Exception; end
12
+
13
+ def initialize(claims)
10
14
  @header = {
11
15
  :typ => :JWT,
12
16
  :alg => :none
13
17
  }
14
18
  [:exp, :nbf, :iat].each do |key|
15
- if claim[key]
16
- claim[key] = claim[key].to_i
17
- end
19
+ claims[key] = claims[key].to_i if claims[key]
18
20
  end
19
- replace claim
21
+ replace claims
20
22
  end
21
23
 
22
- def sign(private_key_or_secret, algorithm = :RS256)
23
- JWS.new(self).sign(private_key_or_secret, algorithm)
24
+ def sign(private_key_or_secret, algorithm = :HS256)
25
+ header[:alg] = algorithm
26
+ JWS.new(self).sign!(private_key_or_secret)
27
+ end
28
+
29
+ def verify(signature_base_string, signature = '', prublic_key_or_secret = nil)
30
+ case header[:alg]
31
+ when :none
32
+ signature == '' or raise VerificationFailed
33
+ else
34
+ JWS.new(self).verify(signature_base_string, signature, prublic_key_or_secret)
35
+ end
24
36
  end
25
37
 
26
38
  def to_s
@@ -32,6 +44,32 @@ module JSON
32
44
  UrlSafeBase64.encode64 segment.to_s
33
45
  end.join('.')
34
46
  end
47
+
48
+ class << self
49
+ def decode(jwt_string, public_key_or_secret = nil)
50
+ raise InvalidFormat.new('Invalid JWT Format. JWT should include 2 dots.') unless jwt_string.count('.') == 2
51
+ header, claims, signature = jwt_string.split('.').collect do |segment|
52
+ UrlSafeBase64.decode64 segment.to_s
53
+ end
54
+ jwt = new JSON.parse(claims).with_indifferent_access
55
+ jwt.header = JSON.parse(header).with_indifferent_access
56
+ jwt.verify [header, claims].join('.'), signature, public_key_or_secret
57
+ jwt
58
+ rescue JSON::ParserError
59
+ raise InvalidFormat.new("Invalid JSON Format")
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def replace(hash_or_jwt)
66
+ super hash_or_jwt
67
+ if hash_or_jwt.is_a? JSON::JWT
68
+ self.header = hash_or_jwt.header
69
+ self.signature = hash_or_jwt.signature
70
+ end
71
+ self
72
+ end
35
73
  end
36
74
  end
37
75
 
@@ -1,9 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JSON::JWS do
4
- let(:jwt) { JSON::JWT.new claim }
4
+ let(:alg) { :none }
5
+ let(:jwt) do
6
+ _jwt_ = JSON::JWT.new claims
7
+ _jwt_.header[:alg] = alg
8
+ _jwt_
9
+ end
5
10
  let(:jws) { JSON::JWS.new jwt }
6
- let(:claim) do
11
+ let(:claims) do
7
12
  {
8
13
  :iss => 'joe',
9
14
  :exp => 1300819380,
@@ -22,7 +27,7 @@ describe JSON::JWS do
22
27
  its(:signature) { should be_nil }
23
28
  end
24
29
 
25
- describe '#sign' do
30
+ describe '#sign!' do
26
31
  shared_examples_for :jwt_with_expected_signature do
27
32
  it 'should generate expected signature' do
28
33
  UrlSafeBase64.encode64(signed.signature).should == expected_signature[alg]
@@ -42,10 +47,10 @@ describe JSON::JWS do
42
47
  }
43
48
  }
44
49
  let(:signed) do
45
- jws.sign key, alg
50
+ jws.sign! key
46
51
  end
47
52
  subject { signed }
48
-
53
+
49
54
  [:HS256, :HS384, :HS512].each do |algorithm|
50
55
  describe algorithm do
51
56
  let(:key) { shared_secret }
@@ -1,26 +1,25 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JSON::JWT do
4
- let(:jwt) { JSON::JWT.new claim }
5
- let(:claim) do
4
+ let(:jwt) { JSON::JWT.new claims }
5
+ let(:claims) do
6
6
  {
7
7
  :iss => 'joe',
8
8
  :exp => 1300819380,
9
9
  'http://example.com/is_root' => true
10
10
  }
11
11
  end
12
+ let(:no_signed) do
13
+ 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'
14
+ end
12
15
 
13
- context 'when no sign no encryption' do
14
- let :result do
15
- 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'
16
- end
17
-
16
+ context 'when not signed nor encrypted' do
18
17
  it do
19
- jwt.to_s.should == result
18
+ jwt.to_s.should == no_signed
20
19
  end
21
20
  end
22
21
 
23
- describe '.sign' do
22
+ describe '#sign' do
24
23
  [:HS256, :HS384, :HS512].each do |algorithm|
25
24
  context algorithm do
26
25
  it do
@@ -37,4 +36,32 @@ describe JSON::JWT do
37
36
  end
38
37
  end
39
38
  end
39
+
40
+ describe '#verify' do
41
+ context 'when not signed nor encrypted' do
42
+ context 'no signature given' do
43
+ it do
44
+ jwt.verify(no_signed.chop).should be_true
45
+ end
46
+ end
47
+
48
+ context 'otherwise' do
49
+ it do
50
+ expect do
51
+ jwt.verify(no_signed.chop, 'signature')
52
+ end.should raise_error JSON::JWT::VerificationFailed
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'when signed' do
58
+ before { jwt.header[:alg] = :HS256 }
59
+ it 'should delegate verification to JWS' do
60
+ jws = JSON::JWS.new jwt
61
+ jws.should_receive(:verify)
62
+ JSON::JWS.should_receive(:new).and_return(jws)
63
+ jwt.verify 'signature_base_string', 'signature', 'shared_secret'
64
+ end
65
+ end
66
+ end
40
67
  end
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-jwt
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
5
4
  prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 1
10
- version: 0.0.1
5
+ version: 0.0.2
11
6
  platform: ruby
12
7
  authors:
13
8
  - nov matake
@@ -15,7 +10,7 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-09-15 00:00:00 Z
13
+ date: 2011-09-21 00:00:00 Z
19
14
  dependencies:
20
15
  - !ruby/object:Gem::Dependency
21
16
  name: json
@@ -25,11 +20,6 @@ dependencies:
25
20
  requirements:
26
21
  - - ">="
27
22
  - !ruby/object:Gem::Version
28
- hash: 1
29
- segments:
30
- - 1
31
- - 4
32
- - 3
33
23
  version: 1.4.3
34
24
  type: :runtime
35
25
  version_requirements: *id001
@@ -41,56 +31,64 @@ dependencies:
41
31
  requirements:
42
32
  - - ">="
43
33
  - !ruby/object:Gem::Version
44
- hash: 3
45
- segments:
46
- - 0
47
34
  version: "0"
48
35
  type: :runtime
49
36
  version_requirements: *id002
50
37
  - !ruby/object:Gem::Dependency
51
- name: rake
38
+ name: activesupport
52
39
  prerelease: false
53
40
  requirement: &id003 !ruby/object:Gem::Requirement
54
41
  none: false
55
42
  requirements:
56
43
  - - ">="
57
44
  - !ruby/object:Gem::Version
58
- hash: 27
59
- segments:
60
- - 0
61
- - 8
45
+ version: "2.3"
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: i18n
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :runtime
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: rake
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
62
67
  version: "0.8"
63
68
  type: :development
64
- version_requirements: *id003
69
+ version_requirements: *id005
65
70
  - !ruby/object:Gem::Dependency
66
71
  name: rcov
67
72
  prerelease: false
68
- requirement: &id004 !ruby/object:Gem::Requirement
73
+ requirement: &id006 !ruby/object:Gem::Requirement
69
74
  none: false
70
75
  requirements:
71
76
  - - ">="
72
77
  - !ruby/object:Gem::Version
73
- hash: 25
74
- segments:
75
- - 0
76
- - 9
77
78
  version: "0.9"
78
79
  type: :development
79
- version_requirements: *id004
80
+ version_requirements: *id006
80
81
  - !ruby/object:Gem::Dependency
81
82
  name: rspec
82
83
  prerelease: false
83
- requirement: &id005 !ruby/object:Gem::Requirement
84
+ requirement: &id007 !ruby/object:Gem::Requirement
84
85
  none: false
85
86
  requirements:
86
87
  - - ">="
87
88
  - !ruby/object:Gem::Version
88
- hash: 7
89
- segments:
90
- - 2
91
89
  version: "2"
92
90
  type: :development
93
- version_requirements: *id005
91
+ version_requirements: *id007
94
92
  description: JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby
95
93
  email:
96
94
  - nov@matake.jp
@@ -133,23 +131,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
131
  requirements:
134
132
  - - ">="
135
133
  - !ruby/object:Gem::Version
136
- hash: 3
137
- segments:
138
- - 0
139
134
  version: "0"
140
135
  required_rubygems_version: !ruby/object:Gem::Requirement
141
136
  none: false
142
137
  requirements:
143
138
  - - ">="
144
139
  - !ruby/object:Gem::Version
145
- hash: 3
146
- segments:
147
- - 0
148
140
  version: "0"
149
141
  requirements: []
150
142
 
151
143
  rubyforge_project:
152
- rubygems_version: 1.8.5
144
+ rubygems_version: 1.8.10
153
145
  signing_key:
154
146
  specification_version: 3
155
147
  summary: JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby