rkerberos 0.2.3 → 0.3.1
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.
- checksums.yaml +4 -4
- data/CHANGES.md +30 -0
- data/EXAMPLES.md +1015 -0
- data/MANIFEST.md +17 -12
- data/README.md +17 -6
- data/ext/rkerberos/ccache.c +99 -26
- data/ext/rkerberos/config.c +62 -10
- data/ext/rkerberos/context.c +132 -14
- data/ext/rkerberos/kadm5.c +332 -116
- data/ext/rkerberos/keytab.c +230 -79
- data/ext/rkerberos/policy.c +25 -23
- data/ext/rkerberos/principal.c +139 -11
- data/ext/rkerberos/rkerberos.c +269 -52
- data/ext/rkerberos/rkerberos.h +14 -0
- data/rkerberos.gemspec +10 -7
- data/spec/config_spec.rb +41 -0
- data/spec/context_spec.rb +96 -0
- data/spec/credentials_cache_spec.rb +82 -26
- data/spec/kadm5_spec.rb +319 -5
- data/spec/krb5_keytab_spec.rb +275 -20
- data/spec/krb5_spec.rb +186 -21
- data/spec/policy_spec.rb +4 -0
- data/spec/principal_spec.rb +116 -10
- metadata +9 -8
data/spec/krb5_keytab_spec.rb
CHANGED
|
@@ -36,22 +36,64 @@ RSpec.describe Kerberos::Krb5::Keytab, :kadm5 do
|
|
|
36
36
|
|
|
37
37
|
subject(:keytab) { described_class.new }
|
|
38
38
|
|
|
39
|
+
def write_keytab_with_invalid_second_record(destination)
|
|
40
|
+
data = File.binread(@keytab_file)
|
|
41
|
+
first_record_size = data.byteslice(2, 4).unpack1('N')
|
|
42
|
+
second_record_offset = 6 + first_record_size
|
|
43
|
+
|
|
44
|
+
# INT32_MIN is reserved as an invalid record size by the FILE keytab
|
|
45
|
+
# implementation, so iteration must fail after yielding the first entry.
|
|
46
|
+
data[second_record_offset, 4] = [0x80000000].pack('N')
|
|
47
|
+
File.binwrite(destination, data)
|
|
48
|
+
end
|
|
49
|
+
|
|
39
50
|
describe 'constructor' do
|
|
40
|
-
it 'accepts an optional name' do
|
|
41
|
-
expect { described_class.new("FILE:/usr/local/var/keytab") }.not_to raise_error
|
|
42
|
-
expect { described_class.new("FILE:/bogus/keytab") }.not_to raise_error
|
|
51
|
+
it 'accepts an optional name keyword' do
|
|
52
|
+
expect { described_class.new(name: "FILE:/usr/local/var/keytab") }.not_to raise_error
|
|
53
|
+
expect { described_class.new(name: "FILE:/bogus/keytab") }.not_to raise_error
|
|
43
54
|
end
|
|
44
55
|
|
|
45
56
|
it 'raises error for invalid residual type' do
|
|
46
57
|
expect {
|
|
47
|
-
described_class.new("BOGUS:/tmp/keytab")
|
|
58
|
+
described_class.new(name: "BOGUS:/tmp/keytab")
|
|
48
59
|
}.to raise_error(Kerberos::Krb5::Keytab::Exception)
|
|
49
60
|
end
|
|
61
|
+
|
|
62
|
+
it 'accepts a context keyword argument' do
|
|
63
|
+
ctx = Kerberos::Krb5::Context.new
|
|
64
|
+
keytab = described_class.new(name: @keytab_name, context: ctx)
|
|
65
|
+
expect { ctx.close }.to raise_error(Kerberos::Krb5::Exception, /dependent wrapper/)
|
|
66
|
+
keytab.close
|
|
67
|
+
expect { ctx.close }.not_to raise_error
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'works with context and no name' do
|
|
71
|
+
ctx = Kerberos::Krb5::Context.new
|
|
72
|
+
expect { described_class.new(context: ctx) }.not_to raise_error
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'rejects positional arguments' do
|
|
76
|
+
expect { described_class.new(@keytab_name) }.to raise_error(ArgumentError)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'rejects unknown keywords' do
|
|
80
|
+
expect { described_class.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'raises TypeError for non-Context context argument' do
|
|
84
|
+
expect { described_class.new(context: "bad") }.to raise_error(TypeError)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'raises error for a closed context' do
|
|
88
|
+
ctx = Kerberos::Krb5::Context.new
|
|
89
|
+
ctx.close
|
|
90
|
+
expect { described_class.new(context: ctx) }.to raise_error(Kerberos::Krb5::Exception)
|
|
91
|
+
end
|
|
50
92
|
end
|
|
51
93
|
|
|
52
94
|
describe '#keytab_name and #keytab_type' do
|
|
53
95
|
it 'returns the underlying name and type strings' do
|
|
54
|
-
kt = described_class.new(@keytab_name)
|
|
96
|
+
kt = described_class.new(name: @keytab_name)
|
|
55
97
|
expect(kt).to respond_to(:keytab_name)
|
|
56
98
|
expect(kt).to respond_to(:keytab_type)
|
|
57
99
|
|
|
@@ -67,34 +109,43 @@ RSpec.describe Kerberos::Krb5::Keytab, :kadm5 do
|
|
|
67
109
|
|
|
68
110
|
describe '#close' do
|
|
69
111
|
it 'returns true' do
|
|
70
|
-
kt = described_class.new(@keytab_name)
|
|
112
|
+
kt = described_class.new(name: @keytab_name)
|
|
71
113
|
expect(kt.close).to eq(true)
|
|
72
114
|
end
|
|
73
115
|
|
|
74
116
|
it 'can be called multiple times without error' do
|
|
75
|
-
kt = described_class.new(@keytab_name)
|
|
117
|
+
kt = described_class.new(name: @keytab_name)
|
|
76
118
|
kt.close
|
|
77
119
|
expect { kt.close }.not_to raise_error
|
|
78
120
|
end
|
|
79
121
|
|
|
80
122
|
it 'raises an error when calling keytab_name after close' do
|
|
81
|
-
kt = described_class.new(@keytab_name)
|
|
123
|
+
kt = described_class.new(name: @keytab_name)
|
|
82
124
|
kt.close
|
|
83
125
|
expect { kt.keytab_name }.to raise_error(Kerberos::Krb5::Exception)
|
|
84
126
|
end
|
|
85
127
|
|
|
86
128
|
it 'raises an error when calling keytab_type after close' do
|
|
87
|
-
kt = described_class.new(@keytab_name)
|
|
129
|
+
kt = described_class.new(name: @keytab_name)
|
|
88
130
|
kt.close
|
|
89
131
|
expect { kt.keytab_type }.to raise_error(Kerberos::Krb5::Exception)
|
|
90
132
|
end
|
|
91
133
|
|
|
92
134
|
it 'does not segfault when garbage collected after close' do
|
|
93
|
-
kt = described_class.new(@keytab_name)
|
|
135
|
+
kt = described_class.new(name: @keytab_name)
|
|
94
136
|
kt.close
|
|
95
137
|
kt = nil
|
|
96
138
|
GC.start
|
|
97
139
|
end
|
|
140
|
+
|
|
141
|
+
it 'raises from every operation that requires the closed handle' do
|
|
142
|
+
kt = described_class.new(name: @keytab_name)
|
|
143
|
+
kt.close
|
|
144
|
+
|
|
145
|
+
expect { kt.default_name }.to raise_error(Kerberos::Krb5::Exception)
|
|
146
|
+
expect { kt.each { |_| } }.to raise_error(Kerberos::Krb5::Exception)
|
|
147
|
+
expect { kt.get_entry("testuser1@#{@realm}") }.to raise_error(Kerberos::Krb5::Exception)
|
|
148
|
+
end
|
|
98
149
|
end
|
|
99
150
|
|
|
100
151
|
describe '.foreach' do
|
|
@@ -129,6 +180,19 @@ RSpec.describe Kerberos::Krb5::Keytab, :kadm5 do
|
|
|
129
180
|
}.to raise_error(Kerberos::Krb5::Exception)
|
|
130
181
|
end
|
|
131
182
|
|
|
183
|
+
it 'raises when an error interrupts iteration' do
|
|
184
|
+
corrupt_keytab = File.join(Dir.tmpdir, "invalid-foreach-#{Process.pid}.keytab")
|
|
185
|
+
write_keytab_with_invalid_second_record(corrupt_keytab)
|
|
186
|
+
entries = []
|
|
187
|
+
|
|
188
|
+
expect {
|
|
189
|
+
described_class.foreach("FILE:#{corrupt_keytab}") { |entry| entries << entry }
|
|
190
|
+
}.to raise_error(Kerberos::Krb5::Exception, /krb5_kt_next_entry/)
|
|
191
|
+
expect(entries).not_to be_empty
|
|
192
|
+
ensure
|
|
193
|
+
FileUtils.rm_f(corrupt_keytab)
|
|
194
|
+
end
|
|
195
|
+
|
|
132
196
|
it 'raises an error for an invalid keytab type' do
|
|
133
197
|
expect {
|
|
134
198
|
described_class.foreach("BOGUS:/tmp/keytab") { |_| }
|
|
@@ -152,7 +216,7 @@ RSpec.describe Kerberos::Krb5::Keytab, :kadm5 do
|
|
|
152
216
|
|
|
153
217
|
describe '#each' do
|
|
154
218
|
it 'yields keytab entries for a valid keytab' do
|
|
155
|
-
kt = described_class.new(@keytab_name)
|
|
219
|
+
kt = described_class.new(name: @keytab_name)
|
|
156
220
|
entries = []
|
|
157
221
|
kt.each { |entry| entries << entry }
|
|
158
222
|
expect(entries.length).to eq(2)
|
|
@@ -166,25 +230,40 @@ RSpec.describe Kerberos::Krb5::Keytab, :kadm5 do
|
|
|
166
230
|
end
|
|
167
231
|
|
|
168
232
|
it 'does not leak resources when the block raises' do
|
|
169
|
-
kt = described_class.new(@keytab_name)
|
|
233
|
+
kt = described_class.new(name: @keytab_name)
|
|
170
234
|
expect {
|
|
171
235
|
kt.each { |_| raise "boom" }
|
|
172
236
|
}.to raise_error(RuntimeError, "boom")
|
|
173
237
|
end
|
|
174
238
|
|
|
175
239
|
it 'does not leak resources when the block breaks' do
|
|
176
|
-
kt = described_class.new(@keytab_name)
|
|
240
|
+
kt = described_class.new(name: @keytab_name)
|
|
177
241
|
result = catch(:done) do
|
|
178
242
|
kt.each { |_| throw :done, :escaped }
|
|
179
243
|
:completed
|
|
180
244
|
end
|
|
181
245
|
expect(result).to eq(:escaped)
|
|
182
246
|
end
|
|
247
|
+
|
|
248
|
+
it 'raises instead of returning a partial result after an iteration error' do
|
|
249
|
+
corrupt_keytab = File.join(Dir.tmpdir, "invalid-each-#{Process.pid}.keytab")
|
|
250
|
+
write_keytab_with_invalid_second_record(corrupt_keytab)
|
|
251
|
+
entries = []
|
|
252
|
+
kt = described_class.new(name: "FILE:#{corrupt_keytab}")
|
|
253
|
+
|
|
254
|
+
expect {
|
|
255
|
+
kt.each { |entry| entries << entry }
|
|
256
|
+
}.to raise_error(Kerberos::Krb5::Exception, /krb5_kt_next_entry/)
|
|
257
|
+
expect(entries).not_to be_empty
|
|
258
|
+
ensure
|
|
259
|
+
kt&.close
|
|
260
|
+
FileUtils.rm_f(corrupt_keytab)
|
|
261
|
+
end
|
|
183
262
|
end
|
|
184
263
|
|
|
185
264
|
describe '#get_entry' do
|
|
186
265
|
it 'finds an entry by principal name' do
|
|
187
|
-
kt = described_class.new(@keytab_name)
|
|
266
|
+
kt = described_class.new(name: @keytab_name)
|
|
188
267
|
entry = kt.get_entry("testuser1@#{@realm}")
|
|
189
268
|
expect(entry).to be_a(Kerberos::Krb5::Keytab::Entry)
|
|
190
269
|
expect(entry.principal).to eq("testuser1@#{@realm}")
|
|
@@ -194,14 +273,14 @@ RSpec.describe Kerberos::Krb5::Keytab, :kadm5 do
|
|
|
194
273
|
end
|
|
195
274
|
|
|
196
275
|
it 'finds an entry filtering by vno' do
|
|
197
|
-
kt = described_class.new(@keytab_name)
|
|
276
|
+
kt = described_class.new(name: @keytab_name)
|
|
198
277
|
entry = kt.get_entry("testuser1@#{@realm}", 1)
|
|
199
278
|
expect(entry.principal).to eq("testuser1@#{@realm}")
|
|
200
279
|
expect(entry.vno).to eq(1)
|
|
201
280
|
end
|
|
202
281
|
|
|
203
282
|
it 'finds an entry filtering by vno and enctype' do
|
|
204
|
-
kt = described_class.new(@keytab_name)
|
|
283
|
+
kt = described_class.new(name: @keytab_name)
|
|
205
284
|
# aes128-cts-hmac-sha1-96 is enctype 17
|
|
206
285
|
entry = kt.get_entry("testuser1@#{@realm}", 1, 17)
|
|
207
286
|
expect(entry.principal).to eq("testuser1@#{@realm}")
|
|
@@ -210,21 +289,21 @@ RSpec.describe Kerberos::Krb5::Keytab, :kadm5 do
|
|
|
210
289
|
end
|
|
211
290
|
|
|
212
291
|
it 'raises an error for a non-existent principal' do
|
|
213
|
-
kt = described_class.new(@keytab_name)
|
|
292
|
+
kt = described_class.new(name: @keytab_name)
|
|
214
293
|
expect {
|
|
215
294
|
kt.get_entry("bogus@#{@realm}")
|
|
216
295
|
}.to raise_error(Kerberos::Krb5::Exception)
|
|
217
296
|
end
|
|
218
297
|
|
|
219
298
|
it 'is aliased as find' do
|
|
220
|
-
kt = described_class.new(@keytab_name)
|
|
299
|
+
kt = described_class.new(name: @keytab_name)
|
|
221
300
|
expect(kt.method(:find)).to eq(kt.method(:get_entry))
|
|
222
301
|
end
|
|
223
302
|
end
|
|
224
303
|
|
|
225
304
|
describe '#dup' do
|
|
226
305
|
it 'creates an independent handle referring to same keytab' do
|
|
227
|
-
kt1 = described_class.new(@keytab_name)
|
|
306
|
+
kt1 = described_class.new(name: @keytab_name)
|
|
228
307
|
kt2 = kt1.dup
|
|
229
308
|
expect(kt2).to be_a(described_class)
|
|
230
309
|
expect(kt2.keytab_name).to eq(kt1.keytab_name)
|
|
@@ -235,8 +314,184 @@ RSpec.describe Kerberos::Krb5::Keytab, :kadm5 do
|
|
|
235
314
|
end
|
|
236
315
|
|
|
237
316
|
it 'clone is an alias for dup' do
|
|
238
|
-
kt = described_class.new(@keytab_name)
|
|
317
|
+
kt = described_class.new(name: @keytab_name)
|
|
239
318
|
expect(kt.method(:clone)).to eq(kt.method(:dup))
|
|
240
319
|
end
|
|
241
320
|
end
|
|
321
|
+
|
|
322
|
+
describe '#have_content?' do
|
|
323
|
+
it 'returns true for a keytab with entries' do
|
|
324
|
+
kt = described_class.new(name: @keytab_name)
|
|
325
|
+
expect(kt.have_content?).to be true
|
|
326
|
+
kt.close
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
it 'returns false for an empty keytab' do
|
|
330
|
+
empty_file = File.join(Dir.tmpdir, 'empty_test.keytab')
|
|
331
|
+
FileUtils.touch(empty_file)
|
|
332
|
+
kt = described_class.new(name: "FILE:#{empty_file}")
|
|
333
|
+
expect(kt.have_content?).to be false
|
|
334
|
+
kt.close
|
|
335
|
+
FileUtils.rm_f(empty_file)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
it 'raises when the context is closed' do
|
|
339
|
+
kt = described_class.new(name: @keytab_name)
|
|
340
|
+
kt.close
|
|
341
|
+
expect { kt.have_content? }.to raise_error(Kerberos::Krb5::Exception)
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
describe '#add_entry' do
|
|
346
|
+
let(:add_kt_file) { File.join(Dir.tmpdir, 'add_test.keytab') }
|
|
347
|
+
let(:add_kt_name) { "FILE:#{add_kt_file}" }
|
|
348
|
+
|
|
349
|
+
after(:each) { FileUtils.rm_f(add_kt_file) }
|
|
350
|
+
|
|
351
|
+
it 'adds an entry that is retrievable via get_entry' do
|
|
352
|
+
kt = described_class.new(name: add_kt_name)
|
|
353
|
+
kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret', vno: 1)
|
|
354
|
+
|
|
355
|
+
entry = kt.get_entry("testuser1@#{@realm}")
|
|
356
|
+
expect(entry).to be_a(Kerberos::Krb5::Keytab::Entry)
|
|
357
|
+
expect(entry.principal).to eq("testuser1@#{@realm}")
|
|
358
|
+
expect(entry.vno).to eq(1)
|
|
359
|
+
# default enctype is aes256-cts-hmac-sha1-96 = 18
|
|
360
|
+
expect(entry.key).to eq(18)
|
|
361
|
+
kt.close
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it 'accepts an explicit enctype' do
|
|
365
|
+
kt = described_class.new(name: add_kt_name)
|
|
366
|
+
# aes128-cts-hmac-sha1-96 = 17
|
|
367
|
+
kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret', vno: 2, enctype: 17)
|
|
368
|
+
|
|
369
|
+
entry = kt.get_entry("testuser1@#{@realm}", 2, 17)
|
|
370
|
+
expect(entry.vno).to eq(2)
|
|
371
|
+
expect(entry.key).to eq(17)
|
|
372
|
+
kt.close
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
it 'can add multiple entries for the same principal' do
|
|
376
|
+
kt = described_class.new(name: add_kt_name)
|
|
377
|
+
kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret', vno: 1, enctype: 18)
|
|
378
|
+
kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret', vno: 1, enctype: 17)
|
|
379
|
+
|
|
380
|
+
entries = []
|
|
381
|
+
kt.each { |e| entries << e }
|
|
382
|
+
expect(entries.length).to eq(2)
|
|
383
|
+
kt.close
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
it 'returns self for chaining' do
|
|
387
|
+
kt = described_class.new(name: add_kt_name)
|
|
388
|
+
result = kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret')
|
|
389
|
+
expect(result).to equal(kt)
|
|
390
|
+
kt.close
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
it 'raises ArgumentError when principal is missing' do
|
|
394
|
+
kt = described_class.new(name: add_kt_name)
|
|
395
|
+
expect { kt.add_entry(password: 'secret') }.to raise_error(ArgumentError)
|
|
396
|
+
kt.close
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
it 'raises ArgumentError when password is missing' do
|
|
400
|
+
kt = described_class.new(name: add_kt_name)
|
|
401
|
+
expect { kt.add_entry(principal: "testuser1@#{@realm}") }.to raise_error(ArgumentError)
|
|
402
|
+
kt.close
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
it 'raises ArgumentError with no arguments' do
|
|
406
|
+
kt = described_class.new(name: add_kt_name)
|
|
407
|
+
expect { kt.add_entry }.to raise_error(ArgumentError)
|
|
408
|
+
kt.close
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
it 'rejects unknown keywords' do
|
|
412
|
+
kt = described_class.new(name: add_kt_name)
|
|
413
|
+
expect {
|
|
414
|
+
kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret', unknown: true)
|
|
415
|
+
}.to raise_error(ArgumentError, /unknown keyword/)
|
|
416
|
+
kt.close
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
it 'raises when the keytab is closed' do
|
|
420
|
+
kt = described_class.new(name: add_kt_name)
|
|
421
|
+
kt.close
|
|
422
|
+
expect {
|
|
423
|
+
kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret')
|
|
424
|
+
}.to raise_error(Kerberos::Krb5::Exception)
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
describe '#remove_entry' do
|
|
429
|
+
let(:rm_kt_file) { File.join(Dir.tmpdir, 'remove_test.keytab') }
|
|
430
|
+
let(:rm_kt_name) { "FILE:#{rm_kt_file}" }
|
|
431
|
+
|
|
432
|
+
before(:each) do
|
|
433
|
+
@rm_kt = described_class.new(name: rm_kt_name)
|
|
434
|
+
@rm_kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret', vno: 1, enctype: 18)
|
|
435
|
+
@rm_kt.add_entry(principal: "testuser1@#{@realm}", password: 'secret', vno: 2, enctype: 17)
|
|
436
|
+
@rm_kt.add_entry(principal: "testuser2@#{@realm}", password: 'secret', vno: 1, enctype: 18)
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
after(:each) do
|
|
440
|
+
@rm_kt.close rescue nil
|
|
441
|
+
FileUtils.rm_f(rm_kt_file)
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
it 'removes all entries for a principal when vno and enctype are defaulted' do
|
|
445
|
+
@rm_kt.remove_entry(principal: "testuser1@#{@realm}")
|
|
446
|
+
entries = []
|
|
447
|
+
@rm_kt.each { |e| entries << e }
|
|
448
|
+
principals = entries.map(&:principal)
|
|
449
|
+
expect(principals).not_to include("testuser1@#{@realm}")
|
|
450
|
+
expect(principals).to include("testuser2@#{@realm}")
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
it 'removes only the entry matching a specific vno' do
|
|
454
|
+
@rm_kt.remove_entry(principal: "testuser1@#{@realm}", vno: 1)
|
|
455
|
+
entry = @rm_kt.get_entry("testuser1@#{@realm}")
|
|
456
|
+
expect(entry.vno).to eq(2)
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
it 'removes only the entry matching a specific enctype' do
|
|
460
|
+
@rm_kt.remove_entry(principal: "testuser1@#{@realm}", enctype: 17)
|
|
461
|
+
entry = @rm_kt.get_entry("testuser1@#{@realm}")
|
|
462
|
+
expect(entry.key).to eq(18)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
it 'returns self for chaining' do
|
|
466
|
+
result = @rm_kt.remove_entry(principal: "testuser2@#{@realm}")
|
|
467
|
+
expect(result).to equal(@rm_kt)
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
it 'raises ArgumentError when principal is missing' do
|
|
471
|
+
expect { @rm_kt.remove_entry(vno: 1) }.to raise_error(ArgumentError)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
it 'raises ArgumentError with no arguments' do
|
|
475
|
+
expect { @rm_kt.remove_entry }.to raise_error(ArgumentError)
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
it 'rejects unknown keywords' do
|
|
479
|
+
expect {
|
|
480
|
+
@rm_kt.remove_entry(principal: "testuser1@#{@realm}", unknown: true)
|
|
481
|
+
}.to raise_error(ArgumentError, /unknown keyword/)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
it 'raises when the keytab is closed' do
|
|
485
|
+
@rm_kt.close
|
|
486
|
+
expect {
|
|
487
|
+
@rm_kt.remove_entry(principal: "testuser1@#{@realm}")
|
|
488
|
+
}.to raise_error(Kerberos::Krb5::Exception)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
it 'raises for a non-existent entry' do
|
|
492
|
+
expect {
|
|
493
|
+
@rm_kt.remove_entry(principal: "nobody@#{@realm}")
|
|
494
|
+
}.to raise_error(Kerberos::Krb5::Keytab::Exception)
|
|
495
|
+
end
|
|
496
|
+
end
|
|
242
497
|
end
|