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_spec.rb
CHANGED
|
@@ -23,7 +23,7 @@ RSpec.describe Kerberos::Krb5 do
|
|
|
23
23
|
let(:service) { 'kadmin/admin' }
|
|
24
24
|
|
|
25
25
|
it 'has the correct version constant' do
|
|
26
|
-
expect(Kerberos::Krb5::VERSION).to eq('0.
|
|
26
|
+
expect(Kerberos::Krb5::VERSION).to eq('0.3.1')
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
it 'accepts a block and yields itself' do
|
|
@@ -31,6 +31,31 @@ RSpec.describe Kerberos::Krb5 do
|
|
|
31
31
|
described_class.new { |k| expect(k).to be_a(described_class) }
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
describe 'constructor' do
|
|
35
|
+
it 'accepts a context keyword argument' do
|
|
36
|
+
context = Kerberos::Krb5::Context.new
|
|
37
|
+
k = described_class.new(context: context)
|
|
38
|
+
expect(k).to be_a(described_class)
|
|
39
|
+
expect(k.get_default_realm).to eq(@realm)
|
|
40
|
+
k.close
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'raises TypeError if context is not a Kerberos::Krb5::Context' do
|
|
44
|
+
expect { described_class.new(context: 'bad') }.to raise_error(TypeError, /context must be/)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'raises an error if the context is closed' do
|
|
48
|
+
context = Kerberos::Krb5::Context.new
|
|
49
|
+
context.close
|
|
50
|
+
expect { described_class.new(context: context) }.to raise_error(Kerberos::Krb5::Exception, /context is closed/)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'rejects positional option hashes and unknown keywords' do
|
|
54
|
+
expect { described_class.new({context: nil}) }.to raise_error(ArgumentError)
|
|
55
|
+
expect { described_class.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
34
59
|
describe '#get_default_realm' do
|
|
35
60
|
it 'responds to get_default_realm' do
|
|
36
61
|
expect(krb5).to respond_to(:get_default_realm)
|
|
@@ -48,6 +73,17 @@ RSpec.describe Kerberos::Krb5 do
|
|
|
48
73
|
it 'default_realm is an alias for get_default_realm' do
|
|
49
74
|
expect(krb5.method(:default_realm)).to eq(krb5.method(:get_default_realm))
|
|
50
75
|
end
|
|
76
|
+
it 'raises after the object is closed' do
|
|
77
|
+
krb5.close
|
|
78
|
+
expect { krb5.get_default_realm }.to raise_error(Kerberos::Krb5::Exception)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '#set_default_realm' do
|
|
83
|
+
it 'raises after the object is closed' do
|
|
84
|
+
krb5.close
|
|
85
|
+
expect { krb5.set_default_realm(@realm) }.to raise_error(Kerberos::Krb5::Exception)
|
|
86
|
+
end
|
|
51
87
|
end
|
|
52
88
|
|
|
53
89
|
describe '#verify_init_creds', :kadm5 do
|
|
@@ -68,53 +104,108 @@ RSpec.describe Kerberos::Krb5 do
|
|
|
68
104
|
expect(krb5).to respond_to(:verify_init_creds)
|
|
69
105
|
end
|
|
70
106
|
|
|
107
|
+
it 'requires get_init_creds_password arguments as keywords' do
|
|
108
|
+
expect { krb5.get_init_creds_password(user, 'changeme') }.to raise_error(ArgumentError)
|
|
109
|
+
expect {
|
|
110
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme', unknown: true)
|
|
111
|
+
}.to raise_error(ArgumentError, /unknown keyword/)
|
|
112
|
+
end
|
|
113
|
+
|
|
71
114
|
it 'raises when no credentials have been acquired' do
|
|
72
115
|
expect { krb5.verify_init_creds }.to raise_error(Kerberos::Krb5::Exception)
|
|
73
116
|
end
|
|
74
117
|
|
|
75
118
|
it 'validates argument types' do
|
|
76
|
-
expect { krb5.verify_init_creds(true) }.to raise_error(TypeError)
|
|
77
|
-
expect { krb5.verify_init_creds(
|
|
78
|
-
expect { krb5.verify_init_creds(
|
|
119
|
+
expect { krb5.verify_init_creds(server: true) }.to raise_error(TypeError)
|
|
120
|
+
expect { krb5.verify_init_creds(keytab: true) }.to raise_error(TypeError)
|
|
121
|
+
expect { krb5.verify_init_creds(ccache: true) }.to raise_error(TypeError)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it 'accepts only documented keyword arguments' do
|
|
125
|
+
expect { krb5.verify_init_creds(nil) }.to raise_error(ArgumentError)
|
|
126
|
+
expect { krb5.verify_init_creds(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
79
127
|
end
|
|
80
128
|
|
|
81
129
|
it 'verifies credentials obtained via password' do
|
|
82
|
-
krb5.get_init_creds_password(user, 'changeme')
|
|
130
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme')
|
|
83
131
|
expect(krb5.verify_init_creds).to be true
|
|
84
132
|
end
|
|
85
133
|
|
|
86
134
|
it 'accepts a server principal string' do
|
|
87
|
-
krb5.get_init_creds_password(user, 'changeme')
|
|
88
|
-
expect(krb5.verify_init_creds("kadmin/admin@#{@realm}")).to be true
|
|
135
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme')
|
|
136
|
+
expect(krb5.verify_init_creds(server: "kadmin/admin@#{@realm}")).to be true
|
|
89
137
|
end
|
|
90
138
|
|
|
91
139
|
it 'accepts a Keytab object' do
|
|
92
|
-
krb5.get_init_creds_password(user, 'changeme')
|
|
140
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme')
|
|
93
141
|
kt = Kerberos::Krb5::Keytab.new
|
|
94
|
-
expect(krb5.verify_init_creds(
|
|
142
|
+
expect(krb5.verify_init_creds(keytab: kt)).to be true
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it 'rejects a closed Keytab object' do
|
|
146
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme')
|
|
147
|
+
kt = Kerberos::Krb5::Keytab.new
|
|
148
|
+
kt.close
|
|
149
|
+
expect { krb5.verify_init_creds(keytab: kt) }
|
|
150
|
+
.to raise_error(Kerberos::Krb5::Exception, /keytab is closed/)
|
|
95
151
|
end
|
|
96
152
|
|
|
97
153
|
it 'stores additional credentials in provided CredentialsCache' do
|
|
98
154
|
ccache = Kerberos::Krb5::CredentialsCache.new
|
|
99
|
-
krb5.get_init_creds_password(user, 'changeme')
|
|
100
|
-
expect(krb5.verify_init_creds(
|
|
155
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme')
|
|
156
|
+
expect(krb5.verify_init_creds(ccache: ccache)).to be true
|
|
101
157
|
expect(ccache.primary_principal).to be_a(String)
|
|
102
158
|
expect(ccache.primary_principal).to include('@')
|
|
103
159
|
end
|
|
104
160
|
|
|
161
|
+
it 'rejects a closed CredentialsCache' do
|
|
162
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme')
|
|
163
|
+
ccache = Kerberos::Krb5::CredentialsCache.new
|
|
164
|
+
ccache.close
|
|
165
|
+
expect { krb5.verify_init_creds(ccache: ccache) }
|
|
166
|
+
.to raise_error(Kerberos::Krb5::Exception, /credentials cache is closed/)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'does not acquire credentials into a closed CredentialsCache' do
|
|
170
|
+
ccache = Kerberos::Krb5::CredentialsCache.new
|
|
171
|
+
ccache.close
|
|
172
|
+
expect {
|
|
173
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme', ccache: ccache)
|
|
174
|
+
}.to raise_error(Kerberos::Krb5::Exception, /credentials cache is closed/)
|
|
175
|
+
end
|
|
176
|
+
|
|
105
177
|
it 'provides authenticate! which acquires and verifies (Zanarotti mitigation)' do
|
|
106
178
|
expect(krb5).to respond_to(:authenticate!)
|
|
107
|
-
expect(krb5.authenticate!(user, 'changeme')).to be true
|
|
179
|
+
expect(krb5.authenticate!(principal: user, password: 'changeme')).to be true
|
|
108
180
|
expect(krb5.verify_init_creds).to be true
|
|
109
181
|
end
|
|
110
182
|
|
|
111
183
|
it 'accepts an optional service argument' do
|
|
112
|
-
expect {
|
|
113
|
-
|
|
184
|
+
expect {
|
|
185
|
+
krb5.authenticate!(principal: user, password: 'changeme', service: 'verify/rkerberos-test')
|
|
186
|
+
}.not_to raise_error
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it 'fails closed when no verification keytab is available' do
|
|
190
|
+
original_keytab = ENV['KRB5_KTNAME']
|
|
191
|
+
ENV['KRB5_KTNAME'] = "FILE:/tmp/missing_verify_keytab_#{Process.pid}"
|
|
192
|
+
|
|
193
|
+
expect {
|
|
194
|
+
described_class.new.authenticate!(principal: user, password: 'changeme')
|
|
195
|
+
}.to raise_error(Kerberos::Krb5::Exception, /krb5_verify_init_creds/)
|
|
196
|
+
ensure
|
|
197
|
+
ENV['KRB5_KTNAME'] = original_keytab
|
|
114
198
|
end
|
|
115
199
|
|
|
116
200
|
it 'validates argument types for authenticate!' do
|
|
117
|
-
expect { krb5.authenticate!(true, true) }.to raise_error(TypeError)
|
|
201
|
+
expect { krb5.authenticate!(principal: true, password: true) }.to raise_error(TypeError)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it 'requires authenticate! arguments as keywords' do
|
|
205
|
+
expect { krb5.authenticate!(user, 'changeme') }.to raise_error(ArgumentError)
|
|
206
|
+
expect {
|
|
207
|
+
krb5.authenticate!(principal: user, password: 'changeme', unknown: true)
|
|
208
|
+
}.to raise_error(ArgumentError, /unknown keyword/)
|
|
118
209
|
end
|
|
119
210
|
end
|
|
120
211
|
|
|
@@ -154,16 +245,16 @@ RSpec.describe Kerberos::Krb5 do
|
|
|
154
245
|
end
|
|
155
246
|
|
|
156
247
|
it 'changes the password successfully' do
|
|
157
|
-
krb5.get_init_creds_password(user, 'changeme')
|
|
248
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme')
|
|
158
249
|
expect(krb5.change_password('changeme', 'Newpass99!')).to be true
|
|
159
250
|
# Verify we can authenticate with the new password
|
|
160
251
|
krb5_check = described_class.new
|
|
161
|
-
expect(krb5_check.get_init_creds_password(user, 'Newpass99!')).to be true
|
|
252
|
+
expect(krb5_check.get_init_creds_password(principal: user, password: 'Newpass99!')).to be true
|
|
162
253
|
krb5_check.close
|
|
163
254
|
end
|
|
164
255
|
|
|
165
256
|
it 'raises with a meaningful message when the old password is wrong' do
|
|
166
|
-
krb5.get_init_creds_password(user, 'changeme')
|
|
257
|
+
krb5.get_init_creds_password(principal: user, password: 'changeme')
|
|
167
258
|
expect {
|
|
168
259
|
krb5.change_password('wrongpass', 'Newpass99!')
|
|
169
260
|
}.to raise_error(Kerberos::Krb5::Exception, /krb5_(get_init_creds_password|change_password)/)
|
|
@@ -180,7 +271,7 @@ RSpec.describe Kerberos::Krb5 do
|
|
|
180
271
|
let(:compliant_pw) { 'Changeme1!' }
|
|
181
272
|
|
|
182
273
|
it 'raises an exception with the KDC rejection reason' do
|
|
183
|
-
krb5.get_init_creds_password(policy_user, compliant_pw)
|
|
274
|
+
krb5.get_init_creds_password(principal: policy_user, password: compliant_pw)
|
|
184
275
|
expect {
|
|
185
276
|
krb5.change_password(compliant_pw, 'a')
|
|
186
277
|
}.to raise_error(Kerberos::Krb5::Exception, /krb5_change_password/)
|
|
@@ -208,18 +299,92 @@ RSpec.describe Kerberos::Krb5 do
|
|
|
208
299
|
expect(krb5).to respond_to(:get_init_creds_keytab)
|
|
209
300
|
end
|
|
210
301
|
|
|
302
|
+
it 'accepts only documented keyword arguments' do
|
|
303
|
+
expect { krb5.get_init_creds_keytab(user) }.to raise_error(ArgumentError)
|
|
304
|
+
expect { krb5.get_init_creds_keytab(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
305
|
+
end
|
|
306
|
+
|
|
211
307
|
it 'acquires credentials for a principal from a supplied keytab file' do
|
|
212
308
|
kt_name = "FILE:#{@kt_file}"
|
|
213
|
-
expect { krb5.get_init_creds_keytab(user, kt_name) }.not_to raise_error
|
|
309
|
+
expect { krb5.get_init_creds_keytab(principal: user, keytab: kt_name) }.not_to raise_error
|
|
214
310
|
expect(krb5.verify_init_creds).to be true
|
|
215
311
|
end
|
|
216
312
|
|
|
217
313
|
it 'accepts a CredentialsCache to receive credentials' do
|
|
218
314
|
ccache = Kerberos::Krb5::CredentialsCache.new
|
|
219
315
|
kt_name = "FILE:#{@kt_file}"
|
|
220
|
-
expect { krb5.get_init_creds_keytab(user, kt_name,
|
|
316
|
+
expect { krb5.get_init_creds_keytab(principal: user, keytab: kt_name, ccache: ccache) }.not_to raise_error
|
|
221
317
|
expect(ccache.primary_principal).to be_a(String)
|
|
222
318
|
expect(ccache.primary_principal).to include('@')
|
|
223
319
|
end
|
|
320
|
+
|
|
321
|
+
it 'rejects a closed CredentialsCache' do
|
|
322
|
+
ccache = Kerberos::Krb5::CredentialsCache.new
|
|
323
|
+
ccache.close
|
|
324
|
+
kt_name = "FILE:#{@kt_file}"
|
|
325
|
+
expect {
|
|
326
|
+
krb5.get_init_creds_keytab(principal: user, keytab: kt_name, ccache: ccache)
|
|
327
|
+
}.to raise_error(Kerberos::Krb5::Exception, /credentials cache is closed/)
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
describe '.thread_safe?' do
|
|
332
|
+
it 'returns a boolean' do
|
|
333
|
+
result = described_class.thread_safe?
|
|
334
|
+
expect([true, false]).to include(result)
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
it 'is callable without an instance' do
|
|
338
|
+
expect(described_class).to respond_to(:thread_safe?)
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
describe '#get_host_realm' do
|
|
343
|
+
it 'responds to get_host_realm' do
|
|
344
|
+
expect(krb5).to respond_to(:get_host_realm)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
it 'returns an array of realm strings' do
|
|
348
|
+
result = krb5.get_host_realm('localhost')
|
|
349
|
+
expect(result).to be_a(Array)
|
|
350
|
+
result.each { |r| expect(r).to be_a(String) }
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
it 'returns a non-empty array for a known hostname' do
|
|
354
|
+
result = krb5.get_host_realm('localhost')
|
|
355
|
+
expect(result).not_to be_empty
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
it 'raises TypeError for non-string argument' do
|
|
359
|
+
expect { krb5.get_host_realm(123) }.to raise_error(TypeError)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
it 'raises ArgumentError when called without arguments' do
|
|
363
|
+
expect { krb5.get_host_realm }.to raise_error(ArgumentError)
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
describe '#expand_hostname' do
|
|
368
|
+
it 'responds to expand_hostname' do
|
|
369
|
+
expect(krb5).to respond_to(:expand_hostname)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
it 'returns a string' do
|
|
373
|
+
result = krb5.expand_hostname('localhost')
|
|
374
|
+
expect(result).to be_a(String)
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
it 'returns a non-empty string' do
|
|
378
|
+
result = krb5.expand_hostname('localhost')
|
|
379
|
+
expect(result.size).to be > 0
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
it 'raises TypeError for non-string argument' do
|
|
383
|
+
expect { krb5.expand_hostname(123) }.to raise_error(TypeError)
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
it 'raises ArgumentError when called without arguments' do
|
|
387
|
+
expect { krb5.expand_hostname }.to raise_error(ArgumentError)
|
|
388
|
+
end
|
|
224
389
|
end
|
|
225
390
|
end
|
data/spec/policy_spec.rb
CHANGED
|
@@ -21,6 +21,10 @@ RSpec.describe 'Kerberos::Kadm5::Policy', :kadm5 do
|
|
|
21
21
|
it 'must be present' do
|
|
22
22
|
expect { klass.new(max_life: 10000) }.to raise_error(ArgumentError)
|
|
23
23
|
end
|
|
24
|
+
it 'rejects positional option hashes and unknown keywords' do
|
|
25
|
+
expect { klass.new({name: 'test'}) }.to raise_error(ArgumentError)
|
|
26
|
+
expect { klass.new(name: 'test', unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
27
|
+
end
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
describe 'min_life' do
|
data/spec/principal_spec.rb
CHANGED
|
@@ -5,20 +5,51 @@ require 'rkerberos'
|
|
|
5
5
|
|
|
6
6
|
RSpec.describe Kerberos::Krb5::Principal do
|
|
7
7
|
let(:name) { 'Jon' }
|
|
8
|
-
subject(:princ) { described_class.new(name) }
|
|
8
|
+
subject(:princ) { described_class.new(name: name) }
|
|
9
9
|
|
|
10
10
|
describe 'constructor' do
|
|
11
|
-
it 'requires a string
|
|
12
|
-
expect { described_class.new(1) }.to raise_error(TypeError)
|
|
13
|
-
expect { described_class.new(true) }.to raise_error(TypeError)
|
|
11
|
+
it 'requires name to be a string' do
|
|
12
|
+
expect { described_class.new(name: 1) }.to raise_error(TypeError)
|
|
13
|
+
expect { described_class.new(name: true) }.to raise_error(TypeError)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
it 'accepts
|
|
17
|
-
expect{ described_class.new
|
|
16
|
+
it 'accepts no arguments' do
|
|
17
|
+
expect{ described_class.new }.not_to raise_error
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
it 'works as expected with
|
|
21
|
-
expect(described_class.new
|
|
20
|
+
it 'works as expected with no name argument' do
|
|
21
|
+
expect(described_class.new.principal).to be_nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'rejects positional arguments' do
|
|
25
|
+
expect { described_class.new('Jon') }.to raise_error(ArgumentError)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'accepts a context keyword argument' do
|
|
29
|
+
ctx = Kerberos::Krb5::Context.new
|
|
30
|
+
expect { described_class.new(name: 'Jon', context: ctx) }.not_to raise_error
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'rejects positional option hashes and unknown keywords' do
|
|
34
|
+
expect { described_class.new({name: 'Jon'}) }.to raise_error(ArgumentError)
|
|
35
|
+
expect { described_class.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'uses the same realm when a context is provided' do
|
|
39
|
+
ctx = Kerberos::Krb5::Context.new
|
|
40
|
+
p1 = described_class.new(name: 'Jon')
|
|
41
|
+
p2 = described_class.new(name: 'Jon', context: ctx)
|
|
42
|
+
expect(p2.realm).to eq(p1.realm)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'raises TypeError for non-Context context argument' do
|
|
46
|
+
expect { described_class.new(name: 'Jon', context: "bad") }.to raise_error(TypeError)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'raises error for a closed context' do
|
|
50
|
+
ctx = Kerberos::Krb5::Context.new
|
|
51
|
+
ctx.close
|
|
52
|
+
expect { described_class.new(name: 'Jon', context: ctx) }.to raise_error(Kerberos::Krb5::Exception)
|
|
22
53
|
end
|
|
23
54
|
end
|
|
24
55
|
|
|
@@ -27,8 +58,34 @@ RSpec.describe Kerberos::Krb5::Principal do
|
|
|
27
58
|
expect(subject.realm).to eq('EXAMPLE.COM')
|
|
28
59
|
end
|
|
29
60
|
|
|
30
|
-
it 'raises an error if
|
|
31
|
-
expect{ described_class.new
|
|
61
|
+
it 'raises an error if no name was provided' do
|
|
62
|
+
expect{ described_class.new.realm }.to raise_error(Kerberos::Krb5::Exception, /no principal/)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe '#close' do
|
|
67
|
+
it 'releases a borrowed context and prevents further native operations' do
|
|
68
|
+
context = Kerberos::Krb5::Context.new
|
|
69
|
+
principal = described_class.new(name: name, context: context)
|
|
70
|
+
|
|
71
|
+
expect(principal.close).to equal(principal)
|
|
72
|
+
expect { principal.realm }.to raise_error(Kerberos::Krb5::Exception)
|
|
73
|
+
expect { context.close }.not_to raise_error
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'can be called multiple times' do
|
|
77
|
+
expect { 2.times { princ.close } }.not_to raise_error
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe '#==' do
|
|
82
|
+
it 'returns true for equivalent principals' do
|
|
83
|
+
expect(princ).to eq(described_class.new(name: name))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'returns false for objects of another type' do
|
|
87
|
+
expect(princ == name).to be false
|
|
88
|
+
expect(princ == nil).to be false
|
|
32
89
|
end
|
|
33
90
|
end
|
|
34
91
|
|
|
@@ -83,4 +140,53 @@ RSpec.describe Kerberos::Krb5::Principal do
|
|
|
83
140
|
expect { princ.mod_date }.not_to raise_error
|
|
84
141
|
end
|
|
85
142
|
end
|
|
143
|
+
|
|
144
|
+
describe '#principal_type' do
|
|
145
|
+
it 'returns an integer for a named principal' do
|
|
146
|
+
p = described_class.new(name: 'user@EXAMPLE.COM')
|
|
147
|
+
expect(p.principal_type).to be_a(Integer)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it 'returns KRB5_NT_PRINCIPAL (1) for a simple name' do
|
|
151
|
+
p = described_class.new(name: 'user@EXAMPLE.COM')
|
|
152
|
+
expect(p.principal_type).to eq(1)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it 'raises an error when no principal has been established' do
|
|
156
|
+
p = described_class.new
|
|
157
|
+
expect { p.principal_type }.to raise_error(Kerberos::Krb5::Exception, /no principal/)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe '#components' do
|
|
162
|
+
it 'responds to components' do
|
|
163
|
+
expect(princ).to respond_to(:components)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it 'returns an array of strings' do
|
|
167
|
+
result = princ.components
|
|
168
|
+
expect(result).to be_a(Array)
|
|
169
|
+
result.each { |c| expect(c).to be_a(String) }
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it 'returns one component for a simple principal' do
|
|
173
|
+
p = described_class.new(name: 'user@EXAMPLE.COM')
|
|
174
|
+
expect(p.components).to eq(['user'])
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it 'returns multiple components for a compound principal' do
|
|
178
|
+
p = described_class.new(name: 'admin/instance@EXAMPLE.COM')
|
|
179
|
+
expect(p.components).to eq(['admin', 'instance'])
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it 'returns three components for a three-part principal' do
|
|
183
|
+
p = described_class.new(name: 'a/b/c@EXAMPLE.COM')
|
|
184
|
+
expect(p.components).to eq(['a', 'b', 'c'])
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it 'raises an error when no principal has been established' do
|
|
188
|
+
p = described_class.new
|
|
189
|
+
expect { p.components }.to raise_error(Kerberos::Krb5::Exception, /no principal/)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
86
192
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rkerberos
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Berger
|
|
@@ -66,6 +66,7 @@ extensions:
|
|
|
66
66
|
extra_rdoc_files: []
|
|
67
67
|
files:
|
|
68
68
|
- CHANGES.md
|
|
69
|
+
- EXAMPLES.md
|
|
69
70
|
- Gemfile
|
|
70
71
|
- LICENSE
|
|
71
72
|
- MANIFEST.md
|
|
@@ -93,17 +94,17 @@ files:
|
|
|
93
94
|
- spec/policy_spec.rb
|
|
94
95
|
- spec/principal_spec.rb
|
|
95
96
|
- spec/spec_helper.rb
|
|
96
|
-
homepage:
|
|
97
|
+
homepage: https://github.com/rkerberos/rkerberos
|
|
97
98
|
licenses:
|
|
98
99
|
- Artistic-2.0
|
|
99
100
|
metadata:
|
|
100
|
-
homepage_uri: https://github.com/rkerberos/rkerberos
|
|
101
101
|
bug_tracker_uri: https://github.com/rkerberos/rkerberos/issues
|
|
102
|
-
changelog_uri: https://github.com/rkerberos/rkerberos/blob/
|
|
102
|
+
changelog_uri: https://github.com/rkerberos/rkerberos/blob/master/CHANGES.md
|
|
103
103
|
documentation_uri: https://github.com/rkerberos/rkerberos/wiki
|
|
104
|
+
homepage_uri: https://github.com/rkerberos/rkerberos
|
|
104
105
|
source_code_uri: https://github.com/rkerberos/rkerberos
|
|
105
106
|
wiki_uri: https://github.com/rkerberos/rkerberos/wiki
|
|
106
|
-
github_repo: https://github.com/
|
|
107
|
+
github_repo: https://github.com/rkerberos/rkerberos
|
|
107
108
|
funding_uri: https://github.com/sponsors/rkerberos
|
|
108
109
|
rubygems_mfa_required: 'true'
|
|
109
110
|
rdoc_options: []
|
|
@@ -113,16 +114,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
113
114
|
requirements:
|
|
114
115
|
- - ">="
|
|
115
116
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: '
|
|
117
|
+
version: '3.2'
|
|
117
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
119
|
requirements:
|
|
119
120
|
- - ">="
|
|
120
121
|
- !ruby/object:Gem::Version
|
|
121
122
|
version: '0'
|
|
122
123
|
requirements: []
|
|
123
|
-
rubygems_version: 4.0.
|
|
124
|
+
rubygems_version: 4.0.18
|
|
124
125
|
specification_version: 4
|
|
125
|
-
summary: A Ruby interface for the
|
|
126
|
+
summary: A Ruby interface for the Kerberos library
|
|
126
127
|
test_files:
|
|
127
128
|
- spec/config_spec.rb
|
|
128
129
|
- spec/context_spec.rb
|