sandal 0.2.0 → 0.3.0

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/sandal.gemspec CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_development_dependency 'bundler', '>= 1.3'
24
24
  s.add_development_dependency 'rake', '>= 10.0'
25
25
  s.add_development_dependency 'rspec', '>= 2.13'
26
+ s.add_development_dependency 'simplecov', '>= 0.7'
26
27
  s.add_development_dependency 'coveralls', '>= 0.6'
27
28
  s.add_development_dependency 'yard', '>= 0.8'
28
29
  s.add_development_dependency 'redcarpet', '>= 2.2' unless RUBY_PLATFORM == 'java' # for yard
data/spec/helper.rb CHANGED
@@ -1,9 +1,21 @@
1
1
  require 'coveralls'
2
- Coveralls.wear!
2
+ require 'simplecov'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter]
7
+ SimpleCov.start do
8
+ add_filter 'spec/'
9
+ add_group 'Encryption', 'sandal/enc'
10
+ add_group 'Signatures', 'sandal/sig'
11
+ end
12
+
3
13
 
4
14
  require 'rspec'
15
+
5
16
  RSpec.configure do |c|
6
17
  c.treat_symbols_as_metadata_keys_with_true_values = true
18
+ c.filter_run_excluding :timing_dependent # these are unreliable so don't run unless specified explicitly
7
19
  c.filter_run_excluding :jruby_incompatible if RUBY_PLATFORM == 'java'
8
20
  end
9
21
 
@@ -0,0 +1,213 @@
1
+ require 'helper'
2
+
3
+ describe Sandal::Claims do
4
+
5
+ context '#validate_claims' do
6
+
7
+ it 'calls #validate_aud when valid audiences are provided' do
8
+ claims = { 'aud' => 'example.org' }.extend(Sandal::Claims)
9
+ valid_aud = %w(example.org)
10
+ claims.should_receive(:validate_aud).with(valid_aud)
11
+ claims.validate_claims(valid_aud: valid_aud)
12
+ end
13
+
14
+ it 'calls #validate_exp by default' do
15
+ claims = {}.extend(Sandal::Claims)
16
+ claims.should_receive(:validate_exp)
17
+ claims.validate_claims
18
+ end
19
+
20
+ it 'does not call #validate_exp when the :ignore_exp option is set' do
21
+ claims = {}.extend(Sandal::Claims)
22
+ claims.should_not_receive(:validate_exp)
23
+ claims.validate_claims(ignore_exp: true)
24
+ end
25
+
26
+ it 'calls #validate_iss when valid issuers are provided' do
27
+ claims = { 'iss' => 'example.org' }.extend(Sandal::Claims)
28
+ valid_iss = %w(example.org)
29
+ claims.should_receive(:validate_iss).with(valid_iss)
30
+ claims.validate_claims(valid_iss: valid_iss)
31
+ end
32
+
33
+ it 'calls #validate_nbf by default' do
34
+ claims = {}.extend(Sandal::Claims)
35
+ claims.should_receive(:validate_nbf)
36
+ claims.validate_claims
37
+ end
38
+
39
+ it 'does not call #validate_nbf when the :ignore_nbf option is set' do
40
+ claims = {}.extend(Sandal::Claims)
41
+ claims.should_not_receive(:validate_nbf)
42
+ claims.validate_claims(ignore_nbf: true)
43
+ end
44
+
45
+ end
46
+
47
+ context '#validate_aud' do
48
+
49
+ it 'succeeds when the audience claim is missing and no valid audiences are given' do
50
+ claims = {}.extend(Sandal::Claims)
51
+ claims.validate_aud([])
52
+ end
53
+
54
+ it 'succeeds when the audience string is empty and no valid audiences are given' do
55
+ claims = { 'aud' => '' }.extend(Sandal::Claims)
56
+ claims.validate_aud([])
57
+ end
58
+
59
+ it 'succeeds when the audience string is the same as the valid audience' do
60
+ claims = { 'aud' => 'example.org' }.extend(Sandal::Claims)
61
+ claims.validate_aud(%w(example.org))
62
+ end
63
+
64
+ it 'succeeds when the audience string is the same as a valid audience' do
65
+ claims = { 'aud' => 'example.org' }.extend(Sandal::Claims)
66
+ claims.validate_aud(%w(example.org example.com))
67
+ end
68
+
69
+ it 'succeeds when the audience array is empty and no valid audiences are given' do
70
+ claims = { 'aud' => [] }.extend(Sandal::Claims)
71
+ claims.validate_aud([])
72
+ end
73
+
74
+ it 'succeeds when the audience array is the same as the valid audience' do
75
+ claims = { 'aud' => %w(example.org) }.extend(Sandal::Claims)
76
+ claims.validate_aud(%w(example.org))
77
+ end
78
+
79
+ it 'succeeds when the audience array contains a valid audience' do
80
+ claims = { 'aud' => %w(example.org example.com) }.extend(Sandal::Claims)
81
+ claims.validate_aud(%w(example.org))
82
+ end
83
+
84
+ it 'succeeds when the audience array contains multiple valid audiences' do
85
+ claims = { 'aud' => %w(example.org example.com example.net) }.extend(Sandal::Claims)
86
+ claims.validate_aud(%w(example.com example.org))
87
+ end
88
+
89
+ it 'raises a ClaimError when the audience claim is missing and a valid audience is given' do
90
+ claims = {}.extend(Sandal::Claims)
91
+ expect { claims.validate_aud(%w(example.org)) }.to raise_error Sandal::ClaimError
92
+ end
93
+
94
+ it 'raises a ClaimError when the audience string is empty and a valid audience is given' do
95
+ claims = { 'aud' => '' }.extend(Sandal::Claims)
96
+ expect { claims.validate_aud(%w(example.org)) }.to raise_error Sandal::ClaimError
97
+ end
98
+
99
+ it 'raises a ClaimError when the audience string does not contain a valid audience' do
100
+ claims = { 'aud' => 'example.com' }.extend(Sandal::Claims)
101
+ expect { claims.validate_aud(%w(example.org example.net)) }.to raise_error Sandal::ClaimError
102
+ end
103
+
104
+ it 'raises a ClaimError when the audience array is empty and a valid audience is given' do
105
+ claims = { 'aud' => [] }.extend(Sandal::Claims)
106
+ expect { claims.validate_aud(%w(example.org)) }.to raise_error Sandal::ClaimError
107
+ end
108
+
109
+ it 'raises a ClaimError when the audience array does not contain a valid audience' do
110
+ claims = { 'aud' => %w(example.com example.net) }.extend(Sandal::Claims)
111
+ expect { claims.validate_aud(%w(example.org)) }.to raise_error Sandal::ClaimError
112
+ end
113
+
114
+ end
115
+
116
+ context '#validate_exp' do
117
+
118
+ it 'succeeds when the expires claim is missing' do
119
+ claims = {}.extend(Sandal::Claims)
120
+ claims.validate_exp
121
+ end
122
+
123
+ it 'succeeds when the expiry time is in the future' do
124
+ claims = { 'exp' => (Time.now + 300).to_i }.extend(Sandal::Claims)
125
+ claims.validate_exp
126
+ end
127
+
128
+ it 'succeeds when the expiry time is in the past but within the max clock skew' do
129
+ claims = { 'exp' => (Time.now - 60).to_i }.extend(Sandal::Claims)
130
+ claims.validate_exp(120)
131
+ end
132
+
133
+ it 'raises a ClaimError when the expiry time is in the past with no clock skew' do
134
+ claims = { 'exp' => (Time.now - 300).to_i }.extend(Sandal::Claims)
135
+ expect { claims.validate_exp }.to raise_error Sandal::ClaimError
136
+ end
137
+
138
+ it 'raises a ClaimError when the expiry time is in the past and outside the max clock skew' do
139
+ claims = { 'exp' => (Time.now - 300).to_i }.extend(Sandal::Claims)
140
+ expect { claims.validate_exp(120) }.to raise_error Sandal::ClaimError
141
+ end
142
+
143
+ end
144
+
145
+ context '#validate_iss' do
146
+
147
+ it 'succeeds when the issuer claim is missing and no valid issuers are given' do
148
+ claims = {}.extend(Sandal::Claims)
149
+ claims.validate_iss([])
150
+ end
151
+
152
+ it 'succeeds when the issuer string is empty and no valid issuers are given' do
153
+ claims = { 'iss' => '' }.extend(Sandal::Claims)
154
+ claims.validate_iss([])
155
+ end
156
+
157
+ it 'succeeds when the issuer string is the same as the valid issuer' do
158
+ claims = { 'iss' => 'example.org' }.extend(Sandal::Claims)
159
+ claims.validate_iss(%w(example.org))
160
+ end
161
+
162
+ it 'succeeds when the issuer string is the same as a valid issuer' do
163
+ claims = { 'iss' => 'example.org' }.extend(Sandal::Claims)
164
+ claims.validate_iss(%w(example.org example.com))
165
+ end
166
+
167
+ it 'raises a ClaimError when the issuer claim is missing and a valid issuer is given' do
168
+ claims = {}.extend(Sandal::Claims)
169
+ expect { claims.validate_iss(%w(example.org)) }.to raise_error Sandal::ClaimError
170
+ end
171
+
172
+ it 'raises a ClaimError when the issuer string is empty and a valid issuer is given' do
173
+ claims = { 'iss' => '' }.extend(Sandal::Claims)
174
+ expect { claims.validate_iss(%w(example.org)) }.to raise_error Sandal::ClaimError
175
+ end
176
+
177
+ it 'raises a ClaimError when the issuer string is not a valid issuer' do
178
+ claims = { 'iss' => 'example.com' }.extend(Sandal::Claims)
179
+ expect { claims.validate_iss(%w(example.org example.net)) }.to raise_error Sandal::ClaimError
180
+ end
181
+
182
+ end
183
+
184
+ context '#validate_nbf' do
185
+
186
+ it 'succeeds when the not-before claim is missing' do
187
+ claims = {}.extend(Sandal::Claims)
188
+ claims.validate_nbf
189
+ end
190
+
191
+ it 'succeeds when the not-before time is in the past' do
192
+ claims = { 'nbf' => (Time.now - 300).to_i }.extend(Sandal::Claims)
193
+ claims.validate_nbf
194
+ end
195
+
196
+ it 'succeeds when the not-before time is in the future but within the max clock skew' do
197
+ claims = { 'nbf' => (Time.now + 60).to_i }.extend(Sandal::Claims)
198
+ claims.validate_nbf(120)
199
+ end
200
+
201
+ it 'raises a ClaimError when the not-before time is in the future with no clock skew' do
202
+ claims = { 'nbf' => (Time.now + 300).to_i }.extend(Sandal::Claims)
203
+ expect { claims.validate_nbf }.to raise_error Sandal::ClaimError
204
+ end
205
+
206
+ it 'raises a ClaimError when the not-before time is in the future and outside the max clock skew' do
207
+ claims = { 'nbf' => (Time.now + 300).to_i }.extend(Sandal::Claims)
208
+ expect { claims.validate_nbf(120) }.to raise_error Sandal::ClaimError
209
+ end
210
+
211
+ end
212
+
213
+ end
@@ -1,10 +1,11 @@
1
1
  require 'helper'
2
2
  require 'openssl'
3
- require 'securerandom'
3
+ require_relative 'shared_examples'
4
4
 
5
5
  # TODO: These tests are really for the Sandal module rather than just the algorithm -- move them!
6
6
 
7
7
  describe Sandal::Enc::A128CBC_HS256 do
8
+ include_examples 'algorithm compatibility', Sandal::Enc::A128CBC_HS256
8
9
 
9
10
  # these tests don't run with jruby as it errors when you try and set rsa.d parameter directly
10
11
  context 'using the example RSA key from JWE section A.2', :jruby_incompatible do
@@ -20,7 +21,7 @@ describe Sandal::Enc::A128CBC_HS256 do
20
21
  token = 'eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDK0hTMjU2In0.ZmnlqWgjXyqwjr7cXHys8F79anIUI6J2UWdAyRQEcGBU-KPHsePM910_RoTDGu1IW40Dn0dvcdVEjpJcPPNIbzWcMxDi131Ejeg-b8ViW5YX5oRdYdiR4gMSDDB3mbkInMNUFT-PK5CuZRnHB2rUK5fhPuF6XFqLLZCG5Q_rJm6Evex-XLcNQAJNa1-6CIU12Wj3mPExxw9vbnsQDU7B4BfmhdyiflLA7Ae5ZGoVRl3A__yLPXxRjHFhpOeDp_adx8NyejF5cz9yDKULugNsDMdlHeJQOMGVLYaSZt3KP6aWNSqFA1PHDg-10ceuTEtq_vPE4-Gtev4N4K4Eudlj4Q.AxY8DCtDaGlsbGljb3RoZQ.Rxsjg6PIExcmGSF7LnSEkDqWIKfAw1wZz2XpabV5PwQsolKwEauWYZNE9Q1hZJEZ.8LXqMd0JLGsxMaB5uoNaMpg7uUW_p40RlaZHCwMIyzk'
21
22
  payload = Sandal.decrypt_token(token) do |header|
22
23
  alg = Sandal::Enc::Alg::RSA1_5.new(@rsa)
23
- encrypter = Sandal::Enc::A128CBC_HS256.new(alg)
24
+ Sandal::Enc::A128CBC_HS256.new(alg)
24
25
  end
25
26
  payload.should == 'No matter where you go, there you are.'
26
27
  end
@@ -29,7 +30,7 @@ describe Sandal::Enc::A128CBC_HS256 do
29
30
  token = 'eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDK0hTMjU2In0.ZmnlqWgjXyqwjr7cXHys8F79anIUI6J2UWdAyRQEcGBU-KPHsePM910_RoTDGu1IW40Dn0dvcdVEjpJcPPNIbzWcMxDi131Ejeg-b8ViW5YX5oRdYdiR4gMSDDB3mbkInMNUFT-PK5CuZRnHB2rUK5fhPuF6XFqLLZCG5Q_rJm6Evex-XLcNQAJNa1-6CIU12Wj3mPExxw9vbnsQDU7B4BfmhdyiflLA7Ae5ZGoVRl3A__yLPXxRjHFhpOeDp_adx8NyejF5cz9yDKULugNsDMdlHeJQOMGVLYaSZt3KP6aWNSqFA1PHDg-10ceuTEtq_vPE4-Gtev4N4K4Eudlj4Q.AxY8DCtDaGlsbGljb3RoZQ.Rxsjg6PIExcmGSF7LnSEkDqWIKfAw1wZz2XpabV5PwQsolKwEauWYZNE9Q1hZJEZ.7V5ZDko0v_mf2PAc4JMiUg'
30
31
  expect { Sandal.decrypt_token(token) do |header|
31
32
  alg = Sandal::Enc::Alg::RSA1_5.new(@rsa)
32
- encrypter = Sandal::Enc::A128CBC_HS256.new(alg)
33
+ Sandal::Enc::A128CBC_HS256.new(alg)
33
34
  end }.to raise_error Sandal::TokenError, 'Invalid integrity value.'
34
35
  end
35
36
 
@@ -40,45 +41,8 @@ describe Sandal::Enc::A128CBC_HS256 do
40
41
  expect { Sandal.decrypt_token(token) do |header|
41
42
  rsa = OpenSSL::PKey::RSA.new(2048)
42
43
  alg = Sandal::Enc::Alg::RSA1_5.new(rsa)
43
- encrypter = Sandal::Enc::A128CBC_HS256.new(alg)
44
- end }.to raise_error Sandal::TokenError, 'Failed to decrypt the content master key.'
45
- end
46
-
47
- it 'can encrypt and decrypt tokens with the "dir" algorithm' do
48
- payload = 'Some text to encrypt'
49
- content_master_key = SecureRandom.random_bytes(16)
50
-
51
- encrypter = Sandal::Enc::A128CBC_HS256.new(Sandal::Enc::Alg::Direct.new(content_master_key))
52
- token = Sandal.encrypt_token(payload, encrypter)
53
-
54
- output = Sandal.decrypt_token(token) { encrypter }
55
- output.should == payload
56
- end
57
-
58
- it 'can encrypt and decrypt tokens with the RSA1_5 algorithm' do
59
- payload = 'Some other text to encrypt'
60
- rsa = OpenSSL::PKey::RSA.new(2048)
61
-
62
- encrypter = Sandal::Enc::A128CBC_HS256.new(Sandal::Enc::Alg::RSA1_5.new(rsa.public_key))
63
- token = Sandal.encrypt_token(payload, encrypter)
64
-
65
- output = Sandal.decrypt_token(token) do
66
- Sandal::Enc::A128CBC_HS256.new(Sandal::Enc::Alg::RSA1_5.new(rsa))
67
- end
68
- output.should == payload
69
- end
70
-
71
- it 'can encrypt and decrypt tokens with the RSA-OAEP algorithm' do
72
- payload = 'Some more text to encrypt'
73
- rsa = OpenSSL::PKey::RSA.new(2048)
74
-
75
- encrypter = Sandal::Enc::A128CBC_HS256.new(Sandal::Enc::Alg::RSA_OAEP.new(rsa.public_key))
76
- token = Sandal.encrypt_token(payload, encrypter)
77
-
78
- output = Sandal.decrypt_token(token) do
79
- Sandal::Enc::A128CBC_HS256.new(Sandal::Enc::Alg::RSA_OAEP.new(rsa))
80
- end
81
- output.should == payload
44
+ Sandal::Enc::A128CBC_HS256.new(alg)
45
+ end }.to raise_error Sandal::TokenError, 'Cannot decrypt content master key.'
82
46
  end
83
47
 
84
48
  end
@@ -1,26 +1,13 @@
1
1
  require 'helper'
2
2
  require 'openssl'
3
- require 'securerandom'
3
+ require_relative 'shared_examples'
4
4
 
5
5
  # TODO: These tests are really for the Sandal module rather than just the algorithm -- move them!
6
6
 
7
7
  if defined? Sandal::Enc::A128GCM
8
8
 
9
9
  describe Sandal::Enc::A128GCM do
10
-
11
- it 'can encrypt and decrypt tokens with the RSA-OAEP algorithm' do
12
- payload = 'Some more text to encrypt'
13
- rsa = OpenSSL::PKey::RSA.new(2048)
14
-
15
- encrypter = Sandal::Enc::A128GCM.new(Sandal::Enc::Alg::RSA_OAEP.new(rsa.public_key))
16
- token = Sandal.encrypt_token(payload, encrypter)
17
-
18
- output = Sandal.decrypt_token(token) do
19
- Sandal::Enc::A128GCM.new(Sandal::Enc::Alg::RSA_OAEP.new(rsa))
20
- end
21
- output.should == payload
22
- end
23
-
10
+ include_examples 'algorithm compatibility', Sandal::Enc::A128GCM
24
11
  end
25
12
 
26
13
  end
@@ -0,0 +1,10 @@
1
+ require 'helper'
2
+ require 'openssl'
3
+ require_relative 'shared_examples'
4
+
5
+ # TODO: These tests are really for the Sandal module rather than just the algorithm -- move them!
6
+
7
+ describe Sandal::Enc::A256CBC_HS512 do
8
+ include_examples 'algorithm compatibility', Sandal::Enc::A256CBC_HS512
9
+ end
10
+
@@ -0,0 +1,52 @@
1
+ require 'helper'
2
+ require 'openssl'
3
+ require_relative 'shared_examples'
4
+
5
+ # TODO: These tests are really for the Sandal module rather than just the algorithm -- move them!
6
+
7
+ if defined? Sandal::Enc::A256GCM
8
+
9
+ describe Sandal::Enc::A256GCM do
10
+ include_examples 'algorithm compatibility', Sandal::Enc::A256GCM
11
+
12
+ # these tests don't run with jruby as it errors when you try and set rsa.d parameter directly
13
+ context 'using the example RSA key from JWE section A.1', :jruby_incompatible do
14
+
15
+ before :all do
16
+ @rsa = OpenSSL::PKey::RSA.new(2048)
17
+ @rsa.n = make_bn([161, 168, 84, 34, 133, 176, 208, 173, 46, 176, 163, 110, 57, 30, 135, 227, 9, 31, 226, 128, 84, 92, 116, 241, 70, 248, 27, 227, 193, 62, 5, 91, 241, 145, 224, 205, 141, 176, 184, 133, 239, 43, 81, 103, 9, 161, 153, 157, 179, 104, 123, 51, 189, 34, 152, 69, 97, 69, 78, 93, 140, 131, 87, 182, 169, 101, 92, 142, 3, 22, 167, 8, 212, 56, 35, 79, 210, 222, 192, 208, 252, 49, 109, 138, 173, 253, 210, 166, 201, 63, 102, 74, 5, 158, 41, 90, 144, 108, 160, 79, 10, 89, 222, 231, 172, 31, 227, 197, 0, 19, 72, 81, 138, 78, 136, 221, 121, 118, 196, 17, 146, 10, 244, 188, 72, 113, 55, 221, 162, 217, 171, 27, 57, 233, 210, 101, 236, 154, 199, 56, 138, 239, 101, 48, 198, 186, 202, 160, 76, 111, 234, 71, 57, 183, 5, 211, 171, 136, 126, 64, 40, 75, 58, 89, 244, 254, 107, 84, 103, 7, 236, 69, 163, 18, 180, 251, 58, 153, 46, 151, 174, 12, 103, 197, 181, 161, 162, 55, 250, 235, 123, 110, 17, 11, 158, 24, 47, 133, 8, 199, 235, 107, 126, 130, 246, 73, 195, 20, 108, 202, 176, 214, 187, 45, 146, 182, 118, 54, 32, 200, 61, 201, 71, 243, 1, 255, 131, 84, 37, 111, 211, 168, 228, 45, 192, 118, 27, 197, 235, 232, 36, 10, 230, 248, 190, 82, 182, 140, 35, 204, 108, 190, 253, 186, 186, 27])
18
+ @rsa.e = make_bn([1, 0, 1])
19
+ @rsa.d = make_bn([144, 183, 109, 34, 62, 134, 108, 57, 44, 252, 10, 66, 73, 54, 16, 181, 233, 92, 54, 219, 101, 42, 35, 178, 63, 51, 43, 92, 119, 136, 251, 41, 53, 23, 191, 164, 164, 60, 88, 227, 229, 152, 228, 213, 149, 228, 169, 237, 104, 71, 151, 75, 88, 252, 216, 77, 251, 231, 28, 97, 88, 193, 215, 202, 248, 216, 121, 195, 211, 245, 250, 112, 71, 243, 61, 129, 95, 39, 244, 122, 225, 217, 169, 211, 165, 48, 253, 220, 59, 122, 219, 42, 86, 223, 32, 236, 39, 48, 103, 78, 122, 216, 187, 88, 176, 89, 24, 1, 42, 177, 24, 99, 142, 170, 1, 146, 43, 3, 108, 64, 194, 121, 182, 95, 187, 134, 71, 88, 96, 134, 74, 131, 167, 69, 106, 143, 121, 27, 72, 44, 245, 95, 39, 194, 179, 175, 203, 122, 16, 112, 183, 17, 200, 202, 31, 17, 138, 156, 184, 210, 157, 184, 154, 131, 128, 110, 12, 85, 195, 122, 241, 79, 251, 229, 183, 117, 21, 123, 133, 142, 220, 153, 9, 59, 57, 105, 81, 255, 138, 77, 82, 54, 62, 216, 38, 249, 208, 17, 197, 49, 45, 19, 232, 157, 251, 131, 137, 175, 72, 126, 43, 229, 69, 179, 117, 82, 157, 213, 83, 35, 57, 210, 197, 252, 171, 143, 194, 11, 47, 163, 6, 253, 75, 252, 96, 11, 187, 84, 130, 210, 7, 121, 78, 91, 79, 57, 251, 138, 132, 220, 60, 224, 173, 56, 224, 201])
20
+ end
21
+
22
+ it 'can decrypt the example token' do
23
+ token = 'eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.M2XxpbORKezKSzzQL_95-GjiudRBTqn_omS8z9xgoRb7L0Jw5UsEbxmtyHn2T71mrZLkjg4Mp8gbhYoltPkEOHvAopz25-vZ8C2e1cOaAo5WPcbSIuFcB4DjBOM3t0UAO6JHkWLuAEYoe58lcxIQneyKdaYSLbV9cKqoUoFQpvKWYRHZbfszIyfsa18rmgTjzrtLDTPnc09DSJE24aQ8w3i8RXEDthW9T1J6LsTH_vwHdwUgkI-tC2PNeGrnM-dNSfzF3Y7-lwcGy0FsdXkPXytvDV7y4pZeeUiQ-0VdibIN2AjjfW60nfrPuOjepMFG6BBBbR37pHcyzext9epOAQ.48V1_ALb6US04U3b._e21tGGhac_peEFkLXr2dMPUZiUkrw.7V5ZDko0v_mf2PAc4JMiUg'
24
+ payload = Sandal.decrypt_token(token) do |header|
25
+ alg = Sandal::Enc::Alg::RSA_OAEP.new(@rsa)
26
+ Sandal::Enc::A256GCM.new(alg)
27
+ end
28
+ payload.should == 'Live long and prosper.'
29
+ end
30
+
31
+ it 'raises a token error when the integrity value is changed' do
32
+ token = 'eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.M2XxpbORKezKSzzQL_95-GjiudRBTqn_omS8z9xgoRb7L0Jw5UsEbxmtyHn2T71mrZLkjg4Mp8gbhYoltPkEOHvAopz25-vZ8C2e1cOaAo5WPcbSIuFcB4DjBOM3t0UAO6JHkWLuAEYoe58lcxIQneyKdaYSLbV9cKqoUoFQpvKWYRHZbfszIyfsa18rmgTjzrtLDTPnc09DSJE24aQ8w3i8RXEDthW9T1J6LsTH_vwHdwUgkI-tC2PNeGrnM-dNSfzF3Y7-lwcGy0FsdXkPXytvDV7y4pZeeUiQ-0VdibIN2AjjfW60nfrPuOjepMFG6BBBbR37pHcyzext9epOAQ.48V1_ALb6US04U3b._e21tGGhac_peEFkLXr2dMPUZiUkrw.8LXqMd0JLGsxMaB5uoNaMpg7uUW_p40RlaZHCwMIyzk'
33
+ expect { Sandal.decrypt_token(token) do |header|
34
+ alg = Sandal::Enc::Alg::RSA_OAEP.new(@rsa)
35
+ Sandal::Enc::A256GCM.new(alg)
36
+ end }.to raise_error Sandal::TokenError, 'Invalid token.'
37
+ end
38
+
39
+ end
40
+
41
+ it 'raises a token error when the RSA keys JWE section A.1 are changed' do
42
+ token = 'eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.M2XxpbORKezKSzzQL_95-GjiudRBTqn_omS8z9xgoRb7L0Jw5UsEbxmtyHn2T71mrZLkjg4Mp8gbhYoltPkEOHvAopz25-vZ8C2e1cOaAo5WPcbSIuFcB4DjBOM3t0UAO6JHkWLuAEYoe58lcxIQneyKdaYSLbV9cKqoUoFQpvKWYRHZbfszIyfsa18rmgTjzrtLDTPnc09DSJE24aQ8w3i8RXEDthW9T1J6LsTH_vwHdwUgkI-tC2PNeGrnM-dNSfzF3Y7-lwcGy0FsdXkPXytvDV7y4pZeeUiQ-0VdibIN2AjjfW60nfrPuOjepMFG6BBBbR37pHcyzext9epOAQ.48V1_ALb6US04U3b._e21tGGhac_peEFkLXr2dMPUZiUkrw.8LXqMd0JLGsxMaB5uoNaMpg7uUW_p40RlaZHCwMIyzk'
43
+ expect { Sandal.decrypt_token(token) do |header|
44
+ rsa = OpenSSL::PKey::RSA.new(2048)
45
+ alg = Sandal::Enc::Alg::RSA_OAEP.new(rsa)
46
+ Sandal::Enc::A256GCM.new(alg)
47
+ end }.to raise_error Sandal::TokenError, 'Cannot decrypt content master key.'
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,55 @@
1
+ require 'helper'
2
+ require 'openssl'
3
+
4
+ describe Sandal::Enc::Alg::Direct do
5
+
6
+ context '#name' do
7
+
8
+ it 'is "dir"' do
9
+ alg = Sandal::Enc::Alg::Direct.new('some cmk')
10
+ alg.name.should == 'dir'
11
+ end
12
+
13
+ end
14
+
15
+ context '#cmk' do
16
+
17
+ it 'returns the real CMK' do
18
+ cmk = 'the real cmk'
19
+ alg = Sandal::Enc::Alg::Direct.new(cmk)
20
+ alg.cmk.should == cmk
21
+ end
22
+
23
+ end
24
+
25
+ context '#encrypt_cmk' do
26
+
27
+ it 'returns an empty string' do
28
+ alg = Sandal::Enc::Alg::Direct.new('the real cmk')
29
+ alg.encrypt_cmk('any value').should == ''
30
+ end
31
+
32
+ end
33
+
34
+ context '#decrypt_cmk' do
35
+
36
+ it 'returns the real CMK when the value to decrypt is nil' do
37
+ cmk = 'the real cmk'
38
+ alg = Sandal::Enc::Alg::Direct.new(cmk)
39
+ alg.decrypt_cmk(nil).should == cmk
40
+ end
41
+
42
+ it 'returns the real CMK when the value to decrypt is empty' do
43
+ cmk = 'the real cmk'
44
+ alg = Sandal::Enc::Alg::Direct.new(cmk)
45
+ alg.decrypt_cmk('').should == cmk
46
+ end
47
+
48
+ it 'raises a TokenError if the value to decrypt is not nil or empty' do
49
+ alg = Sandal::Enc::Alg::Direct.new('the real cmk')
50
+ expect { alg.decrypt_cmk('a value') }.to raise_error Sandal::TokenError
51
+ end
52
+
53
+ end
54
+
55
+ end