json-jwt 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.

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