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 +7 -1
- data/README.rdoc +8 -0
- data/VERSION +1 -1
- data/json-jwt.gemspec +2 -0
- data/lib/json/jws.rb +32 -21
- data/lib/json/jwt.rb +45 -7
- data/spec/json/jws_spec.rb +10 -5
- data/spec/json/jwt_spec.rb +36 -9
- metadata +31 -39
data/Gemfile.lock
CHANGED
@@ -1,15 +1,21 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
json-jwt (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
|
+
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
|
9
|
-
|
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
|
-
|
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
|
16
|
-
claim[key] = claim[key].to_i
|
17
|
-
end
|
19
|
+
claims[key] = claims[key].to_i if claims[key]
|
18
20
|
end
|
19
|
-
replace
|
21
|
+
replace claims
|
20
22
|
end
|
21
23
|
|
22
|
-
def sign(private_key_or_secret, algorithm = :
|
23
|
-
|
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
|
|
data/spec/json/jws_spec.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe JSON::JWS do
|
4
|
-
let(:
|
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(:
|
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
|
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 }
|
data/spec/json/jwt_spec.rb
CHANGED
@@ -1,26 +1,25 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe JSON::JWT do
|
4
|
-
let(:jwt) { JSON::JWT.new
|
5
|
-
let(:
|
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
|
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 ==
|
18
|
+
jwt.to_s.should == no_signed
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
describe '
|
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
|
-
|
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-
|
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:
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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: *
|
69
|
+
version_requirements: *id005
|
65
70
|
- !ruby/object:Gem::Dependency
|
66
71
|
name: rcov
|
67
72
|
prerelease: false
|
68
|
-
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: *
|
80
|
+
version_requirements: *id006
|
80
81
|
- !ruby/object:Gem::Dependency
|
81
82
|
name: rspec
|
82
83
|
prerelease: false
|
83
|
-
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: *
|
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.
|
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
|