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/config_spec.rb
CHANGED
|
@@ -11,6 +11,47 @@ RSpec.describe 'Kerberos::Kadm5::Config', :kadm5 do
|
|
|
11
11
|
expect(config).to be_frozen
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
describe 'constructor' do
|
|
15
|
+
it 'can be called with no arguments' do
|
|
16
|
+
expect { klass.new }.not_to raise_error
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'accepts a context option' do
|
|
20
|
+
ctx = Kerberos::Krb5::Context.new
|
|
21
|
+
expect { klass.new(context: ctx) }.not_to raise_error
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'returns same realm with or without context' do
|
|
25
|
+
ctx = Kerberos::Krb5::Context.new
|
|
26
|
+
c1 = klass.new
|
|
27
|
+
c2 = klass.new(context: ctx)
|
|
28
|
+
expect(c2.realm).to eq(c1.realm)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'releases its context lease after copying the configuration' do
|
|
32
|
+
ctx = Kerberos::Krb5::Context.new
|
|
33
|
+
config = klass.new(context: ctx)
|
|
34
|
+
|
|
35
|
+
expect { ctx.close }.not_to raise_error
|
|
36
|
+
expect(config.realm).to be_a(String)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'raises TypeError for non-Context context argument' do
|
|
40
|
+
expect { klass.new(context: "bad") }.to raise_error(TypeError)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'raises error for a closed context' do
|
|
44
|
+
ctx = Kerberos::Krb5::Context.new
|
|
45
|
+
ctx.close
|
|
46
|
+
expect { klass.new(context: ctx) }.to raise_error(Kerberos::Krb5::Exception)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'rejects positional option hashes and unknown keywords' do
|
|
50
|
+
expect { klass.new({context: nil}) }.to raise_error(ArgumentError)
|
|
51
|
+
expect { klass.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
14
55
|
describe 'realm' do
|
|
15
56
|
it 'responds to realm' do
|
|
16
57
|
expect(config).to respond_to(:realm)
|
data/spec/context_spec.rb
CHANGED
|
@@ -16,6 +16,51 @@ RSpec.describe Kerberos::Krb5::Context do
|
|
|
16
16
|
it 'can be called multiple times without error' do
|
|
17
17
|
expect { 3.times { context.close } }.not_to raise_error
|
|
18
18
|
end
|
|
19
|
+
|
|
20
|
+
it 'raises while a dependent wrapper remains open' do
|
|
21
|
+
krb5 = Kerberos::Krb5.new(context: context)
|
|
22
|
+
|
|
23
|
+
expect { context.close }
|
|
24
|
+
.to raise_error(Kerberos::Krb5::Exception, /1 dependent wrapper/)
|
|
25
|
+
expect(context.default_realm).to be_a(String)
|
|
26
|
+
|
|
27
|
+
krb5.close
|
|
28
|
+
expect { context.close }.not_to raise_error
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'tracks multiple dependent wrappers independently' do
|
|
32
|
+
first = Kerberos::Krb5.new(context: context)
|
|
33
|
+
second = Kerberos::Krb5::Principal.new(name: 'user', context: context)
|
|
34
|
+
|
|
35
|
+
expect { context.close }
|
|
36
|
+
.to raise_error(Kerberos::Krb5::Exception, /2 dependent wrappers/)
|
|
37
|
+
|
|
38
|
+
first.close
|
|
39
|
+
expect { context.close }
|
|
40
|
+
.to raise_error(Kerberos::Krb5::Exception, /1 dependent wrapper/)
|
|
41
|
+
|
|
42
|
+
second.close
|
|
43
|
+
expect { context.close }.not_to raise_error
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'supports a forced logical close with deferred native cleanup' do
|
|
47
|
+
krb5 = Kerberos::Krb5.new(context: context)
|
|
48
|
+
realm = krb5.default_realm
|
|
49
|
+
|
|
50
|
+
expect(context.close(force: true)).to equal(context)
|
|
51
|
+
expect { context.default_realm }.to raise_error(Kerberos::Krb5::Exception)
|
|
52
|
+
expect { Kerberos::Krb5.new(context: context) }
|
|
53
|
+
.to raise_error(Kerberos::Krb5::Exception, /context is closed/)
|
|
54
|
+
expect(krb5.default_realm).to eq(realm)
|
|
55
|
+
|
|
56
|
+
expect { krb5.close }.not_to raise_error
|
|
57
|
+
expect { context.close }.not_to raise_error
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'requires close options to be keywords and rejects unknown keywords' do
|
|
61
|
+
expect { context.close({force: true}) }.to raise_error(ArgumentError)
|
|
62
|
+
expect { context.close(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
63
|
+
end
|
|
19
64
|
end
|
|
20
65
|
|
|
21
66
|
describe 'constructor options' do
|
|
@@ -51,6 +96,57 @@ RSpec.describe Kerberos::Krb5::Context do
|
|
|
51
96
|
expect(ctx).to be_a(described_class)
|
|
52
97
|
expect { ctx.close }.not_to raise_error
|
|
53
98
|
end
|
|
99
|
+
|
|
100
|
+
it 'rejects positional option hashes and unknown keywords' do
|
|
101
|
+
expect { described_class.new({secure: true}) }.to raise_error(ArgumentError)
|
|
102
|
+
expect { described_class.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe '#default_realm' do
|
|
107
|
+
it 'responds to default_realm' do
|
|
108
|
+
expect(context).to respond_to(:default_realm)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'returns a string' do
|
|
112
|
+
expect(context.default_realm).to be_a(String)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'returns a non-empty realm' do
|
|
116
|
+
expect(context.default_realm.size).to be > 0
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'raises when context is closed' do
|
|
120
|
+
context.close
|
|
121
|
+
expect { context.default_realm }.to raise_error(Kerberos::Krb5::Exception)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
describe '#default_realm=' do
|
|
126
|
+
it 'responds to default_realm=' do
|
|
127
|
+
expect(context).to respond_to(:default_realm=)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it 'can set and read back a custom realm' do
|
|
131
|
+
context.default_realm = 'TEST.REALM'
|
|
132
|
+
expect(context.default_realm).to eq('TEST.REALM')
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it 'accepts nil to reset to the default' do
|
|
136
|
+
original = context.default_realm
|
|
137
|
+
context.default_realm = 'TEMP.REALM'
|
|
138
|
+
context.default_realm = nil
|
|
139
|
+
expect(context.default_realm).to eq(original)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'raises TypeError for non-string argument' do
|
|
143
|
+
expect { context.default_realm = 123 }.to raise_error(TypeError)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'raises when context is closed' do
|
|
147
|
+
context.close
|
|
148
|
+
expect { context.default_realm = 'X' }.to raise_error(Kerberos::Krb5::Exception)
|
|
149
|
+
end
|
|
54
150
|
end
|
|
55
151
|
|
|
56
152
|
after(:each) do
|
|
@@ -36,43 +36,77 @@ 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
|
+
expect { ctx.close }.to raise_error(Kerberos::Krb5::Exception, /dependent wrapper/)
|
|
77
|
+
c.close
|
|
78
|
+
expect { ctx.close }.not_to raise_error
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'raises TypeError for non-Context context argument' do
|
|
82
|
+
expect { described_class.new(context: "bad") }.to raise_error(TypeError)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'raises error for a closed context' do
|
|
86
|
+
ctx = Kerberos::Krb5::Context.new
|
|
87
|
+
ctx.close
|
|
88
|
+
expect { described_class.new(context: ctx) }.to raise_error(Kerberos::Krb5::Exception)
|
|
55
89
|
end
|
|
56
90
|
end
|
|
57
91
|
|
|
58
92
|
describe '#close' do
|
|
59
93
|
it 'responds to close' do
|
|
60
|
-
expect(described_class.new(princ)).to respond_to(:close)
|
|
94
|
+
expect(described_class.new(principal: princ)).to respond_to(:close)
|
|
61
95
|
end
|
|
62
96
|
|
|
63
97
|
it 'does not delete credentials cache' do
|
|
64
|
-
c = described_class.new(princ)
|
|
98
|
+
c = described_class.new(principal: princ)
|
|
65
99
|
expect { c.close }.not_to raise_error
|
|
66
100
|
expect(cache_found?).to be true
|
|
67
101
|
end
|
|
68
102
|
|
|
69
103
|
it 'can be called multiple times without error' do
|
|
70
|
-
c = described_class.new(princ)
|
|
104
|
+
c = described_class.new(principal: princ)
|
|
71
105
|
expect { 3.times { c.close } }.not_to raise_error
|
|
72
106
|
end
|
|
73
107
|
|
|
74
108
|
it 'raises error when calling method on closed object' do
|
|
75
|
-
c = described_class.new(princ)
|
|
109
|
+
c = described_class.new(principal: princ)
|
|
76
110
|
c.close
|
|
77
111
|
expect { c.default_name }.to raise_error(Kerberos::Krb5::Exception)
|
|
78
112
|
end
|
|
@@ -80,20 +114,20 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
|
|
|
80
114
|
|
|
81
115
|
describe '#default_name' do
|
|
82
116
|
it 'responds to default_name' do
|
|
83
|
-
c = described_class.new(princ)
|
|
117
|
+
c = described_class.new(principal: princ)
|
|
84
118
|
expect(c).to respond_to(:default_name)
|
|
85
119
|
expect { c.default_name }.not_to raise_error
|
|
86
120
|
end
|
|
87
121
|
|
|
88
122
|
it 'returns a string' do
|
|
89
|
-
c = described_class.new(princ)
|
|
123
|
+
c = described_class.new(principal: princ)
|
|
90
124
|
expect(c.default_name).to be_a(String)
|
|
91
125
|
end
|
|
92
126
|
end
|
|
93
127
|
|
|
94
128
|
describe '#cache_name and #cache_type' do
|
|
95
129
|
it 'returns the ccache name and type' do
|
|
96
|
-
c = described_class.new(princ)
|
|
130
|
+
c = described_class.new(principal: princ)
|
|
97
131
|
expect(c).to respond_to(:cache_name)
|
|
98
132
|
expect(c).to respond_to(:cache_type)
|
|
99
133
|
|
|
@@ -108,7 +142,7 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
|
|
|
108
142
|
|
|
109
143
|
describe '#principal' do
|
|
110
144
|
it 'is an alias for primary_principal' do
|
|
111
|
-
c = described_class.new(princ)
|
|
145
|
+
c = described_class.new(principal: princ)
|
|
112
146
|
expect(c).to respond_to(:principal)
|
|
113
147
|
expect(c.principal).to eq(c.primary_principal)
|
|
114
148
|
end
|
|
@@ -116,13 +150,13 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
|
|
|
116
150
|
|
|
117
151
|
describe '#primary_principal' do
|
|
118
152
|
it 'responds to primary_principal' do
|
|
119
|
-
c = described_class.new(princ)
|
|
153
|
+
c = described_class.new(principal: princ)
|
|
120
154
|
expect(c).to respond_to(:primary_principal)
|
|
121
155
|
expect { c.primary_principal }.not_to raise_error
|
|
122
156
|
end
|
|
123
157
|
|
|
124
158
|
it 'returns expected results' do
|
|
125
|
-
c = described_class.new(princ)
|
|
159
|
+
c = described_class.new(principal: princ)
|
|
126
160
|
expect(c.primary_principal).to be_a(String)
|
|
127
161
|
expect(c.primary_principal.size).to be > 0
|
|
128
162
|
expect(c.primary_principal).to include('@')
|
|
@@ -131,18 +165,18 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
|
|
|
131
165
|
|
|
132
166
|
describe '#destroy' do
|
|
133
167
|
it 'responds to destroy' do
|
|
134
|
-
c = described_class.new(princ)
|
|
168
|
+
c = described_class.new(principal: princ)
|
|
135
169
|
expect(c).to respond_to(:destroy)
|
|
136
170
|
end
|
|
137
171
|
|
|
138
172
|
it 'deletes credentials cache' do
|
|
139
|
-
c = described_class.new(princ)
|
|
173
|
+
c = described_class.new(principal: princ)
|
|
140
174
|
expect { c.destroy }.not_to raise_error
|
|
141
175
|
expect(cache_found?).to be false
|
|
142
176
|
end
|
|
143
177
|
|
|
144
178
|
it 'delete is an alias for destroy' do
|
|
145
|
-
c = described_class.new(princ)
|
|
179
|
+
c = described_class.new(principal: princ)
|
|
146
180
|
expect(c).to respond_to(:delete)
|
|
147
181
|
expect(c.method(:delete)).to eq(c.method(:destroy))
|
|
148
182
|
end
|
|
@@ -153,20 +187,20 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
|
|
|
153
187
|
end
|
|
154
188
|
|
|
155
189
|
it 'raises error when calling method on destroyed object' do
|
|
156
|
-
c = described_class.new(princ)
|
|
190
|
+
c = described_class.new(principal: princ)
|
|
157
191
|
c.destroy
|
|
158
192
|
expect { c.default_name }.to raise_error(Kerberos::Krb5::Exception)
|
|
159
193
|
end
|
|
160
194
|
|
|
161
195
|
it 'does not accept arguments' do
|
|
162
|
-
c = described_class.new(princ)
|
|
196
|
+
c = described_class.new(principal: princ)
|
|
163
197
|
expect { c.destroy(true) }.to raise_error(ArgumentError)
|
|
164
198
|
end
|
|
165
199
|
end
|
|
166
200
|
|
|
167
201
|
describe '#dup' do
|
|
168
202
|
it 'returns a new cache object with the same properties' do
|
|
169
|
-
c = described_class.new(princ)
|
|
203
|
+
c = described_class.new(principal: princ)
|
|
170
204
|
c2 = c.dup
|
|
171
205
|
expect(c2).to be_a(described_class)
|
|
172
206
|
expect(c2.default_name).to eq(c.default_name)
|
|
@@ -174,23 +208,45 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
|
|
|
174
208
|
end
|
|
175
209
|
|
|
176
210
|
it 'closing original does not affect duplicate' do
|
|
177
|
-
c = described_class.new(princ)
|
|
211
|
+
c = described_class.new(principal: princ)
|
|
178
212
|
c2 = c.dup
|
|
179
213
|
c.close
|
|
180
214
|
expect { c2.default_name }.not_to raise_error
|
|
181
215
|
end
|
|
182
216
|
|
|
183
217
|
it 'closing duplicate does not affect original' do
|
|
184
|
-
c = described_class.new(princ)
|
|
218
|
+
c = described_class.new(principal: princ)
|
|
185
219
|
c2 = c.dup
|
|
186
220
|
c2.close
|
|
187
221
|
expect { c.default_name }.not_to raise_error
|
|
188
222
|
end
|
|
189
223
|
|
|
190
224
|
it 'raises when duping closed cache' do
|
|
191
|
-
c = described_class.new(princ)
|
|
225
|
+
c = described_class.new(principal: princ)
|
|
192
226
|
c.close
|
|
193
227
|
expect { c.dup }.to raise_error(Kerberos::Krb5::Exception)
|
|
194
228
|
end
|
|
195
229
|
end
|
|
230
|
+
|
|
231
|
+
describe '#full_name' do
|
|
232
|
+
it 'returns a string including the type prefix' do
|
|
233
|
+
cc = described_class.new(principal: princ)
|
|
234
|
+
name = cc.full_name
|
|
235
|
+
expect(name).to be_a(String)
|
|
236
|
+
expect(name).to match(/\A\w+:/)
|
|
237
|
+
cc.close
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it 'includes FILE: for a file-based cache' do
|
|
241
|
+
cc = described_class.new(principal: princ, cache_name: cfile)
|
|
242
|
+
expect(cc.full_name).to start_with('FILE:')
|
|
243
|
+
cc.close
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it 'raises when the context is closed' do
|
|
247
|
+
cc = described_class.new(principal: princ)
|
|
248
|
+
cc.close
|
|
249
|
+
expect { cc.full_name }.to raise_error(Kerberos::Krb5::Exception)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
196
252
|
end
|