rkerberos 0.2.2 → 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/spec/kadm5_spec.rb CHANGED
@@ -1,12 +1,15 @@
1
1
  # spec/kadm5_spec.rb
2
2
  # RSpec tests for Kerberos::Kadm5
3
3
 
4
- require 'rkerberos'
4
+ require 'spec_helper'
5
5
  require 'socket'
6
+ require 'fileutils'
7
+
8
+ RSpec.describe 'Kerberos::Kadm5', :kadm5 do
9
+ let(:server){ Kerberos::Kadm5::Config.new.admin_server }
10
+ subject(:klass){ Kerberos::Kadm5 }
6
11
 
7
- RSpec.describe Kerberos::Kadm5 do
8
12
  before(:all) do
9
- @server = Kerberos::Kadm5::Config.new.admin_server
10
13
  @host = Socket.gethostname
11
14
  @user = ENV['KRB5_ADMIN_PRINCIPAL']
12
15
  @pass = ENV['KRB5_ADMIN_PASSWORD']
@@ -23,44 +26,135 @@ RSpec.describe Kerberos::Kadm5 do
23
26
 
24
27
  describe 'constructor' do
25
28
  it 'responds to .new' do
26
- expect(described_class).to respond_to(:new)
29
+ expect(subject).to respond_to(:new)
27
30
  end
31
+
28
32
  it 'works with valid user and password' do
29
- expect { described_class.new(principal: user, password: pass) }.not_to raise_error
33
+ expect { subject.new(principal: user, password: pass) }.not_to raise_error
30
34
  end
35
+
31
36
  it 'works with valid service' do
32
37
  expect {
33
- described_class.new(principal: user, password: pass, service: 'kadmin/admin')
38
+ subject.new(principal: user, password: pass, service: 'kadmin/admin')
34
39
  }.not_to raise_error
35
40
  end
36
- it 'only accepts a hash argument' do
37
- expect { described_class.new(user) }.to raise_error(TypeError)
38
- expect { described_class.new(1) }.to raise_error(TypeError)
41
+
42
+ it 'accepts only keyword arguments' do
43
+ expect { subject.new({principal: user, password: pass}) }.to raise_error(ArgumentError)
44
+ expect { subject.new(user) }.to raise_error(ArgumentError)
45
+ expect { subject.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
39
46
  end
47
+
40
48
  it 'accepts a block and yields itself' do
41
- expect { described_class.new(principal: user, password: pass) {} }.not_to raise_error
42
- described_class.new(principal: user, password: pass) { |kadm5| expect(kadm5).to be_a(described_class) }
49
+ expect { subject.new(principal: user, password: pass) {} }.not_to raise_error
50
+ subject.new(principal: user, password: pass) { |kadm5| expect(kadm5).to be_a(subject) }
43
51
  end
52
+
44
53
  it 'requires principal to be specified' do
45
- expect { described_class.new({}) }.to raise_error(ArgumentError)
54
+ expect { subject.new }.to raise_error(ArgumentError)
46
55
  end
56
+
47
57
  it 'requires principal to be a string' do
48
- expect { described_class.new(principal: 1) }.to raise_error(TypeError)
58
+ expect { subject.new(principal: 1, password: pass) }.to raise_error(TypeError)
49
59
  end
60
+
50
61
  it 'requires password to be a string' do
51
- expect { described_class.new(principal: user, password: 1) }.to raise_error(TypeError)
62
+ expect { subject.new(principal: user, password: 1) }.to raise_error(TypeError)
52
63
  end
64
+
53
65
  it 'requires keytab to be a string or boolean' do
54
- expect { described_class.new(principal: user, keytab: 1) }.to raise_error(TypeError)
66
+ expect { subject.new(principal: user, keytab: 1) }.to raise_error(TypeError)
55
67
  end
68
+
56
69
  it 'requires service to be a string' do
57
- expect { described_class.new(principal: user, password: pass, service: 1) }.to raise_error(TypeError)
70
+ expect { subject.new(principal: user, password: pass, service: 1) }.to raise_error(TypeError)
71
+ end
72
+
73
+ it 'accepts a context keyword argument' do
74
+ ctx = Kerberos::Krb5::Context.new
75
+ expect { subject.new(principal: user, password: pass, context: ctx) }.not_to raise_error
76
+ end
77
+
78
+ it 'raises TypeError for non-Context context argument' do
79
+ expect { subject.new(principal: user, password: pass, context: "bad") }.to raise_error(TypeError)
80
+ end
81
+
82
+ it 'raises error for a closed context' do
83
+ ctx = Kerberos::Krb5::Context.new
84
+ ctx.close
85
+ expect { subject.new(principal: user, password: pass, context: ctx) }.to raise_error(Kerberos::Krb5::Exception)
86
+ end
87
+
88
+ context 'with a credentials cache', :cache do
89
+ let(:krb5) { Kerberos::Krb5.new }
90
+ let(:cache_path) { "/tmp/test_kadm5_ccache_#{Process.pid}" }
91
+ let(:cache_name) { "FILE:#{cache_path}" }
92
+ let(:cache) { Kerberos::Krb5::CredentialsCache.new(cache_name: cache_name) }
93
+
94
+ before(:each) do
95
+ krb5.get_init_creds_password(
96
+ principal: user,
97
+ password: pass,
98
+ service: 'kadmin/admin',
99
+ ccache: cache
100
+ )
101
+ end
102
+
103
+ after(:each) do
104
+ cache.close rescue nil
105
+ krb5.close rescue nil
106
+ FileUtils.rm_f([cache_path, "#{cache_path}.lock"])
107
+ end
108
+
109
+ it 'works with a populated credentials cache' do
110
+ expect { subject.new(principal: user, ccache: cache) }.not_to raise_error
111
+ end
112
+
113
+ it 'returns a Kadm5 object' do
114
+ kadm5 = subject.new(principal: user, ccache: cache)
115
+ expect(kadm5).to be_a(subject)
116
+ kadm5.close
117
+ end
118
+
119
+ it 'can perform operations after ccache authentication' do
120
+ kadm5 = subject.new(principal: user, ccache: cache)
121
+ privs = kadm5.get_privileges
122
+ expect(privs).to be_a(Integer)
123
+ expect(privs).not_to eq(0)
124
+ kadm5.close
125
+ end
126
+
127
+ it 'raises TypeError if ccache is not a CredentialsCache' do
128
+ expect {
129
+ subject.new(principal: user, ccache: "not_a_ccache")
130
+ }.to raise_error(TypeError)
131
+ end
132
+
133
+ it 'raises an error for a destroyed credentials cache' do
134
+ dead_ccache = Kerberos::Krb5::CredentialsCache.new
135
+ dead_ccache.destroy
136
+ expect {
137
+ subject.new(principal: user, ccache: dead_ccache)
138
+ }.to raise_error(Kerberos::Krb5::Exception)
139
+ end
140
+
141
+ it 'raises ArgumentError when both password and ccache are given' do
142
+ expect {
143
+ subject.new(principal: user, password: pass, ccache: cache)
144
+ }.to raise_error(ArgumentError)
145
+ end
146
+
147
+ it 'raises ArgumentError when both keytab and ccache are given' do
148
+ expect {
149
+ subject.new(principal: user, keytab: true, ccache: cache)
150
+ }.to raise_error(ArgumentError)
151
+ end
58
152
  end
59
153
  end
60
154
 
61
155
  describe '#get_privileges' do
62
156
  before(:each) do
63
- @kadm5 = described_class.new(principal: user, password: pass)
157
+ @kadm5 = subject.new(principal: user, password: pass)
64
158
  end
65
159
 
66
160
  after(:each) do
@@ -98,4 +192,185 @@ RSpec.describe Kerberos::Kadm5 do
98
192
  expect(result).to include('GET')
99
193
  end
100
194
  end
195
+
196
+ describe '#create_policy' do
197
+ before(:each) do
198
+ @kadm5 = subject.new(principal: user, password: pass)
199
+ @policy_name = "keyword_policy_#{Process.pid}"
200
+ end
201
+
202
+ after(:each) do
203
+ @kadm5.delete_policy(@policy_name) rescue nil
204
+ @kadm5.close
205
+ end
206
+
207
+ it 'accepts policy attributes as keywords' do
208
+ expect {
209
+ @kadm5.create_policy(name: @policy_name, min_length: 8)
210
+ }.not_to raise_error
211
+ expect(@kadm5.get_policy(@policy_name).min_length).to eq(8)
212
+ end
213
+
214
+ it 'accepts a Policy object positionally' do
215
+ policy = Kerberos::Kadm5::Policy.new(name: @policy_name, min_length: 9)
216
+ expect { @kadm5.create_policy(policy) }.not_to raise_error
217
+ expect(@kadm5.get_policy(@policy_name).min_length).to eq(9)
218
+ end
219
+
220
+ it 'rejects positional option hashes and unknown keywords' do
221
+ expect { @kadm5.create_policy({name: @policy_name}) }.to raise_error(TypeError)
222
+ expect {
223
+ @kadm5.create_policy(name: @policy_name, unknown: true)
224
+ }.to raise_error(ArgumentError, /unknown keyword/)
225
+ end
226
+ end
227
+
228
+ describe '#create_principal' do
229
+ before(:each) do
230
+ @kadm5 = subject.new(principal: user, password: pass)
231
+ @realm = Kerberos::Kadm5::Config.new.realm
232
+ @created = []
233
+ end
234
+
235
+ after(:each) do
236
+ @created.each do |name|
237
+ @kadm5.delete_principal(name) rescue nil
238
+ end
239
+ @kadm5.close
240
+ end
241
+
242
+ it 'creates a principal with name: and password:' do
243
+ pname = "create_test1@#{@realm}"
244
+ @kadm5.create_principal(name: pname, password: 'Test1234!')
245
+ @created << pname
246
+ p = @kadm5.find_principal(pname)
247
+ expect(p).to be_a(Kerberos::Krb5::Principal)
248
+ expect(p.principal).to eq(pname)
249
+ end
250
+
251
+ it 'returns self for chaining' do
252
+ pname = "create_test2@#{@realm}"
253
+ result = @kadm5.create_principal(name: pname, password: 'Test1234!')
254
+ @created << pname
255
+ expect(result).to equal(@kadm5)
256
+ end
257
+
258
+ it 'accepts a nil db_args option' do
259
+ pname = "create_test3@#{@realm}"
260
+ expect {
261
+ @kadm5.create_principal(name: pname, password: 'Test1234!', db_args: nil)
262
+ }.not_to raise_error
263
+ @created << pname
264
+ end
265
+
266
+ it 'raises ArgumentError when password: is missing' do
267
+ expect {
268
+ @kadm5.create_principal(name: "create_nopass@#{@realm}")
269
+ }.to raise_error(ArgumentError)
270
+ end
271
+
272
+ it 'raises ArgumentError when neither name: nor principal: is given' do
273
+ expect {
274
+ @kadm5.create_principal(password: 'Test1234!')
275
+ }.to raise_error(ArgumentError)
276
+ end
277
+
278
+ it 'raises ArgumentError with no arguments' do
279
+ expect {
280
+ @kadm5.create_principal
281
+ }.to raise_error(ArgumentError)
282
+ end
283
+
284
+ it 'rejects positional arguments and unknown keywords' do
285
+ expect {
286
+ @kadm5.create_principal("positional@#{@realm}", 'Test1234!')
287
+ }.to raise_error(ArgumentError)
288
+ expect {
289
+ @kadm5.create_principal(name: "unknown_kw@#{@realm}", password: 'Test1234!', unknown: true)
290
+ }.to raise_error(ArgumentError, /unknown keyword/)
291
+ end
292
+
293
+ it 'raises ArgumentError when both name: and principal: are given' do
294
+ p = Kerberos::Krb5::Principal.new(name: "create_both@#{@realm}")
295
+ expect {
296
+ @kadm5.create_principal(name: "create_both@#{@realm}", principal: p, password: 'Test1234!')
297
+ }.to raise_error(ArgumentError)
298
+ end
299
+
300
+ it 'raises an error for a duplicate principal' do
301
+ pname = "create_dup@#{@realm}"
302
+ @kadm5.create_principal(name: pname, password: 'Test1234!')
303
+ @created << pname
304
+ expect {
305
+ @kadm5.create_principal(name: pname, password: 'Test1234!')
306
+ }.to raise_error(Kerberos::Kadm5::Exception)
307
+ end
308
+
309
+ context 'with a Principal object' do
310
+ it 'creates a principal from a Principal object' do
311
+ pname = "create_obj1@#{@realm}"
312
+ p = Kerberos::Krb5::Principal.new(name: pname)
313
+ @kadm5.create_principal(principal: p, password: 'Test1234!')
314
+ @created << pname
315
+ found = @kadm5.find_principal(pname)
316
+ expect(found).to be_a(Kerberos::Krb5::Principal)
317
+ expect(found.principal).to eq(pname)
318
+ end
319
+
320
+ it 'raises TypeError if principal: is not a Principal object' do
321
+ expect {
322
+ @kadm5.create_principal(principal: "notaobj", password: 'Test1234!')
323
+ }.to raise_error(TypeError)
324
+ end
325
+
326
+ it 'raises ArgumentError if the principal has no name' do
327
+ p = Kerberos::Krb5::Principal.new
328
+ expect {
329
+ @kadm5.create_principal(principal: p, password: 'Test1234!')
330
+ }.to raise_error(ArgumentError)
331
+ end
332
+
333
+ it 'forwards the policy attribute' do
334
+ pname = "create_pol@#{@realm}"
335
+ p = Kerberos::Krb5::Principal.new(name: pname)
336
+ p.policy = 'strict_policy'
337
+ @kadm5.create_principal(principal: p, password: 'Changeme1!')
338
+ @created << pname
339
+ found = @kadm5.find_principal(pname)
340
+ expect(found.policy).to eq('strict_policy')
341
+ end
342
+
343
+ it 'forwards expire_time' do
344
+ pname = "create_exp@#{@realm}"
345
+ p = Kerberos::Krb5::Principal.new(name: pname)
346
+ future = Time.now + 86400 * 365
347
+ p.expire_time = future
348
+ @kadm5.create_principal(principal: p, password: 'Test1234!')
349
+ @created << pname
350
+ found = @kadm5.find_principal(pname)
351
+ # Allow a small delta for timestamp rounding
352
+ expect(found.expire_time.to_i).to be_within(1).of(future.to_i)
353
+ end
354
+
355
+ it 'forwards max_life' do
356
+ pname = "create_maxlife@#{@realm}"
357
+ p = Kerberos::Krb5::Principal.new(name: pname)
358
+ p.max_life = 7200
359
+ @kadm5.create_principal(principal: p, password: 'Test1234!')
360
+ @created << pname
361
+ found = @kadm5.find_principal(pname)
362
+ expect(found.max_life).to eq(7200)
363
+ end
364
+
365
+ it 'forwards max_renewable_life' do
366
+ pname = "create_maxrenew@#{@realm}"
367
+ p = Kerberos::Krb5::Principal.new(name: pname)
368
+ p.max_renewable_life = 14400
369
+ @kadm5.create_principal(principal: p, password: 'Test1234!')
370
+ @created << pname
371
+ found = @kadm5.find_principal(pname)
372
+ expect(found.max_renewable_life).to eq(14400)
373
+ end
374
+ end
375
+ end
101
376
  end