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.
- checksums.yaml +4 -4
- data/CHANGES.md +15 -0
- data/EXAMPLES.md +1015 -0
- data/MANIFEST.md +17 -12
- data/README.md +5 -5
- data/ext/rkerberos/ccache.c +101 -26
- data/ext/rkerberos/config.c +53 -7
- data/ext/rkerberos/context.c +70 -7
- data/ext/rkerberos/kadm5.c +280 -87
- data/ext/rkerberos/keytab.c +210 -64
- data/ext/rkerberos/policy.c +25 -23
- data/ext/rkerberos/principal.c +108 -10
- data/ext/rkerberos/rkerberos.c +229 -28
- data/ext/rkerberos/rkerberos.h +8 -0
- data/rkerberos.gemspec +10 -7
- data/spec/config_spec.rb +33 -0
- data/spec/context_spec.rb +51 -0
- data/spec/credentials_cache_spec.rb +79 -26
- data/spec/kadm5_spec.rb +278 -5
- data/spec/krb5_keytab_spec.rb +224 -20
- data/spec/krb5_spec.rb +131 -20
- data/spec/policy_spec.rb +4 -0
- data/spec/principal_spec.rb +90 -10
- metadata +9 -8
|
@@ -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(
|
|
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
|
|
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
|
|
54
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
expect { subject.new(
|
|
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
|
|
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
|