rkerberos 0.2.3 → 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.
@@ -36,43 +36,74 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
36
36
  end
37
37
 
38
38
  it 'creates a cache with a principal' do
39
- expect { described_class.new(princ) }.not_to raise_error
39
+ expect { described_class.new(principal: princ) }.not_to raise_error
40
40
  expect(File.exist?(cfile)).to be true
41
41
  expect(cache_found?).to be true
42
42
  end
43
43
 
44
44
  it 'accepts an explicit cache name' do
45
- expect { described_class.new(princ, cfile) }.not_to raise_error
46
- expect { described_class.new(nil, cfile) }.not_to raise_error
45
+ expect { described_class.new(principal: princ, cache_name: cfile) }.not_to raise_error
46
+ expect { described_class.new(cache_name: cfile) }.not_to raise_error
47
47
  end
48
48
 
49
- it 'raises error for non-string argument' do
50
- expect { described_class.new(true) }.to raise_error(TypeError)
49
+ it 'raises error for non-string principal' do
50
+ expect { described_class.new(principal: true) }.to raise_error(TypeError)
51
51
  end
52
52
 
53
- it 'accepts only up to two arguments' do
54
- expect { described_class.new(princ, cfile, cfile) }.to raise_error(ArgumentError)
53
+ it 'accepts Principal objects (duck-typed as #principal)' do
54
+ obj = Kerberos::Krb5::Principal.new(name: princ)
55
+ expect { described_class.new(principal: obj) }.not_to raise_error
56
+ expect(described_class.new(principal: obj).primary_principal).to eq(princ)
57
+ end
58
+
59
+ it 'raises error for positional arguments' do
60
+ expect { described_class.new(princ) }.to raise_error(ArgumentError)
61
+ end
62
+
63
+ it 'rejects unknown keywords' do
64
+ expect { described_class.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
65
+ end
66
+
67
+ it 'accepts a context option' do
68
+ ctx = Kerberos::Krb5::Context.new
69
+ expect { described_class.new(principal: princ, context: ctx) }.not_to raise_error
70
+ end
71
+
72
+ it 'uses the context when provided' do
73
+ ctx = Kerberos::Krb5::Context.new
74
+ c = described_class.new(principal: princ, context: ctx)
75
+ expect(c.primary_principal).to eq(princ)
76
+ end
77
+
78
+ it 'raises TypeError for non-Context context argument' do
79
+ expect { described_class.new(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 { described_class.new(context: ctx) }.to raise_error(Kerberos::Krb5::Exception)
55
86
  end
56
87
  end
57
88
 
58
89
  describe '#close' do
59
90
  it 'responds to close' do
60
- expect(described_class.new(princ)).to respond_to(:close)
91
+ expect(described_class.new(principal: princ)).to respond_to(:close)
61
92
  end
62
93
 
63
94
  it 'does not delete credentials cache' do
64
- c = described_class.new(princ)
95
+ c = described_class.new(principal: princ)
65
96
  expect { c.close }.not_to raise_error
66
97
  expect(cache_found?).to be true
67
98
  end
68
99
 
69
100
  it 'can be called multiple times without error' do
70
- c = described_class.new(princ)
101
+ c = described_class.new(principal: princ)
71
102
  expect { 3.times { c.close } }.not_to raise_error
72
103
  end
73
104
 
74
105
  it 'raises error when calling method on closed object' do
75
- c = described_class.new(princ)
106
+ c = described_class.new(principal: princ)
76
107
  c.close
77
108
  expect { c.default_name }.to raise_error(Kerberos::Krb5::Exception)
78
109
  end
@@ -80,20 +111,20 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
80
111
 
81
112
  describe '#default_name' do
82
113
  it 'responds to default_name' do
83
- c = described_class.new(princ)
114
+ c = described_class.new(principal: princ)
84
115
  expect(c).to respond_to(:default_name)
85
116
  expect { c.default_name }.not_to raise_error
86
117
  end
87
118
 
88
119
  it 'returns a string' do
89
- c = described_class.new(princ)
120
+ c = described_class.new(principal: princ)
90
121
  expect(c.default_name).to be_a(String)
91
122
  end
92
123
  end
93
124
 
94
125
  describe '#cache_name and #cache_type' do
95
126
  it 'returns the ccache name and type' do
96
- c = described_class.new(princ)
127
+ c = described_class.new(principal: princ)
97
128
  expect(c).to respond_to(:cache_name)
98
129
  expect(c).to respond_to(:cache_type)
99
130
 
@@ -108,7 +139,7 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
108
139
 
109
140
  describe '#principal' do
110
141
  it 'is an alias for primary_principal' do
111
- c = described_class.new(princ)
142
+ c = described_class.new(principal: princ)
112
143
  expect(c).to respond_to(:principal)
113
144
  expect(c.principal).to eq(c.primary_principal)
114
145
  end
@@ -116,13 +147,13 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
116
147
 
117
148
  describe '#primary_principal' do
118
149
  it 'responds to primary_principal' do
119
- c = described_class.new(princ)
150
+ c = described_class.new(principal: princ)
120
151
  expect(c).to respond_to(:primary_principal)
121
152
  expect { c.primary_principal }.not_to raise_error
122
153
  end
123
154
 
124
155
  it 'returns expected results' do
125
- c = described_class.new(princ)
156
+ c = described_class.new(principal: princ)
126
157
  expect(c.primary_principal).to be_a(String)
127
158
  expect(c.primary_principal.size).to be > 0
128
159
  expect(c.primary_principal).to include('@')
@@ -131,18 +162,18 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
131
162
 
132
163
  describe '#destroy' do
133
164
  it 'responds to destroy' do
134
- c = described_class.new(princ)
165
+ c = described_class.new(principal: princ)
135
166
  expect(c).to respond_to(:destroy)
136
167
  end
137
168
 
138
169
  it 'deletes credentials cache' do
139
- c = described_class.new(princ)
170
+ c = described_class.new(principal: princ)
140
171
  expect { c.destroy }.not_to raise_error
141
172
  expect(cache_found?).to be false
142
173
  end
143
174
 
144
175
  it 'delete is an alias for destroy' do
145
- c = described_class.new(princ)
176
+ c = described_class.new(principal: princ)
146
177
  expect(c).to respond_to(:delete)
147
178
  expect(c.method(:delete)).to eq(c.method(:destroy))
148
179
  end
@@ -153,20 +184,20 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
153
184
  end
154
185
 
155
186
  it 'raises error when calling method on destroyed object' do
156
- c = described_class.new(princ)
187
+ c = described_class.new(principal: princ)
157
188
  c.destroy
158
189
  expect { c.default_name }.to raise_error(Kerberos::Krb5::Exception)
159
190
  end
160
191
 
161
192
  it 'does not accept arguments' do
162
- c = described_class.new(princ)
193
+ c = described_class.new(principal: princ)
163
194
  expect { c.destroy(true) }.to raise_error(ArgumentError)
164
195
  end
165
196
  end
166
197
 
167
198
  describe '#dup' do
168
199
  it 'returns a new cache object with the same properties' do
169
- c = described_class.new(princ)
200
+ c = described_class.new(principal: princ)
170
201
  c2 = c.dup
171
202
  expect(c2).to be_a(described_class)
172
203
  expect(c2.default_name).to eq(c.default_name)
@@ -174,23 +205,45 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
174
205
  end
175
206
 
176
207
  it 'closing original does not affect duplicate' do
177
- c = described_class.new(princ)
208
+ c = described_class.new(principal: princ)
178
209
  c2 = c.dup
179
210
  c.close
180
211
  expect { c2.default_name }.not_to raise_error
181
212
  end
182
213
 
183
214
  it 'closing duplicate does not affect original' do
184
- c = described_class.new(princ)
215
+ c = described_class.new(principal: princ)
185
216
  c2 = c.dup
186
217
  c2.close
187
218
  expect { c.default_name }.not_to raise_error
188
219
  end
189
220
 
190
221
  it 'raises when duping closed cache' do
191
- c = described_class.new(princ)
222
+ c = described_class.new(principal: princ)
192
223
  c.close
193
224
  expect { c.dup }.to raise_error(Kerberos::Krb5::Exception)
194
225
  end
195
226
  end
227
+
228
+ describe '#full_name' do
229
+ it 'returns a string including the type prefix' do
230
+ cc = described_class.new(principal: princ)
231
+ name = cc.full_name
232
+ expect(name).to be_a(String)
233
+ expect(name).to match(/\A\w+:/)
234
+ cc.close
235
+ end
236
+
237
+ it 'includes FILE: for a file-based cache' do
238
+ cc = described_class.new(principal: princ, cache_name: cfile)
239
+ expect(cc.full_name).to start_with('FILE:')
240
+ cc.close
241
+ end
242
+
243
+ it 'raises when the context is closed' do
244
+ cc = described_class.new(principal: princ)
245
+ cc.close
246
+ expect { cc.full_name }.to raise_error(Kerberos::Krb5::Exception)
247
+ end
248
+ end
196
249
  end
data/spec/kadm5_spec.rb CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'spec_helper'
5
5
  require 'socket'
6
+ require 'fileutils'
6
7
 
7
8
  RSpec.describe 'Kerberos::Kadm5', :kadm5 do
8
9
  let(:server){ Kerberos::Kadm5::Config.new.admin_server }
@@ -27,37 +28,128 @@ RSpec.describe 'Kerberos::Kadm5', :kadm5 do
27
28
  it 'responds to .new' do
28
29
  expect(subject).to respond_to(:new)
29
30
  end
31
+
30
32
  it 'works with valid user and password' do
31
33
  expect { subject.new(principal: user, password: pass) }.not_to raise_error
32
34
  end
35
+
33
36
  it 'works with valid service' do
34
37
  expect {
35
38
  subject.new(principal: user, password: pass, service: 'kadmin/admin')
36
39
  }.not_to raise_error
37
40
  end
38
- it 'only accepts a hash argument' do
39
- expect { subject.new(user) }.to raise_error(TypeError)
40
- expect { subject.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/)
41
46
  end
47
+
42
48
  it 'accepts a block and yields itself' do
43
49
  expect { subject.new(principal: user, password: pass) {} }.not_to raise_error
44
50
  subject.new(principal: user, password: pass) { |kadm5| expect(kadm5).to be_a(subject) }
45
51
  end
52
+
46
53
  it 'requires principal to be specified' do
47
- expect { subject.new({}) }.to raise_error(ArgumentError)
54
+ expect { subject.new }.to raise_error(ArgumentError)
48
55
  end
56
+
49
57
  it 'requires principal to be a string' do
50
- expect { subject.new(principal: 1) }.to raise_error(TypeError)
58
+ expect { subject.new(principal: 1, password: pass) }.to raise_error(TypeError)
51
59
  end
60
+
52
61
  it 'requires password to be a string' do
53
62
  expect { subject.new(principal: user, password: 1) }.to raise_error(TypeError)
54
63
  end
64
+
55
65
  it 'requires keytab to be a string or boolean' do
56
66
  expect { subject.new(principal: user, keytab: 1) }.to raise_error(TypeError)
57
67
  end
68
+
58
69
  it 'requires service to be a string' do
59
70
  expect { subject.new(principal: user, password: pass, service: 1) }.to raise_error(TypeError)
60
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
152
+ end
61
153
  end
62
154
 
63
155
  describe '#get_privileges' do
@@ -100,4 +192,185 @@ RSpec.describe 'Kerberos::Kadm5', :kadm5 do
100
192
  expect(result).to include('GET')
101
193
  end
102
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
103
376
  end