sandal 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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