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.
- checksums.yaml +4 -4
- data/CHANGES.md +22 -0
- data/EXAMPLES.md +1015 -0
- data/MANIFEST.md +17 -12
- data/README.md +5 -5
- data/ext/rkerberos/ccache.c +105 -26
- data/ext/rkerberos/config.c +59 -10
- data/ext/rkerberos/context.c +76 -7
- data/ext/rkerberos/extconf.rb +16 -3
- data/ext/rkerberos/kadm5.c +301 -96
- data/ext/rkerberos/keytab.c +222 -66
- data/ext/rkerberos/keytab_entry.c +2 -1
- data/ext/rkerberos/policy.c +25 -23
- data/ext/rkerberos/principal.c +136 -10
- data/ext/rkerberos/rkerberos.c +244 -34
- data/ext/rkerberos/rkerberos.h +8 -0
- data/rkerberos.gemspec +10 -7
- data/spec/config_spec.rb +58 -3
- data/spec/context_spec.rb +57 -7
- data/spec/credentials_cache_spec.rb +106 -39
- data/spec/kadm5_spec.rb +292 -17
- data/spec/krb5_keytab_spec.rb +229 -24
- data/spec/krb5_spec.rb +142 -29
- data/spec/policy_spec.rb +12 -7
- data/spec/principal_spec.rb +102 -4
- data/spec/spec_helper.rb +34 -0
- metadata +10 -8
data/EXAMPLES.md
ADDED
|
@@ -0,0 +1,1015 @@
|
|
|
1
|
+
# rkerberos Usage Examples
|
|
2
|
+
|
|
3
|
+
This page provides comprehensive examples for each class in the rkerberos library. All examples assume you have already installed the gem and have a working Kerberos environment.
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
require 'rkerberos'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [Kerberos::Krb5](#kerberoskrb5)
|
|
14
|
+
- [Kerberos::Krb5::Context](#kerberoskrb5context)
|
|
15
|
+
- [Kerberos::Krb5::CredentialsCache](#kerberoskrb5credentialscache)
|
|
16
|
+
- [Kerberos::Krb5::Keytab](#kerberoskrb5keytab)
|
|
17
|
+
- [Kerberos::Krb5::Keytab::Entry](#kerberoskrb5keytabentry)
|
|
18
|
+
- [Kerberos::Krb5::Principal](#kerberoskrb5principal)
|
|
19
|
+
- [Kerberos::Kadm5](#kerberoskadm5)
|
|
20
|
+
- [Kerberos::Kadm5::Config](#kerberoskadm5config)
|
|
21
|
+
- [Kerberos::Kadm5::Policy](#kerberoskadm5policy)
|
|
22
|
+
- [Constants](#constants)
|
|
23
|
+
- [Error Handling](#error-handling)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Kerberos::Krb5
|
|
28
|
+
|
|
29
|
+
The main class for Kerberos client operations: authentication, credential acquisition, realm queries, and password management.
|
|
30
|
+
|
|
31
|
+
### Creating an Instance
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
# Simple instantiation
|
|
35
|
+
krb5 = Kerberos::Krb5.new
|
|
36
|
+
|
|
37
|
+
# With a shared context (see Kerberos::Krb5::Context)
|
|
38
|
+
ctx = Kerberos::Krb5::Context.new
|
|
39
|
+
krb5 = Kerberos::Krb5.new(context: ctx)
|
|
40
|
+
|
|
41
|
+
# Block form — automatically closes when the block exits
|
|
42
|
+
Kerberos::Krb5.new do |krb5|
|
|
43
|
+
puts krb5.default_realm
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Querying the Default Realm
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
krb5 = Kerberos::Krb5.new
|
|
51
|
+
puts krb5.default_realm # => "EXAMPLE.COM"
|
|
52
|
+
krb5.close
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Setting the Default Realm
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
krb5 = Kerberos::Krb5.new
|
|
59
|
+
krb5.set_default_realm('OTHER.REALM.COM')
|
|
60
|
+
puts krb5.default_realm # => "OTHER.REALM.COM"
|
|
61
|
+
|
|
62
|
+
# Reset to the default from krb5.conf
|
|
63
|
+
krb5.set_default_realm
|
|
64
|
+
krb5.close
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Authenticating with a Password
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
krb5 = Kerberos::Krb5.new
|
|
71
|
+
|
|
72
|
+
# Basic password authentication
|
|
73
|
+
krb5.get_init_creds_password(principal: 'user@EXAMPLE.COM', password: 's3cret')
|
|
74
|
+
|
|
75
|
+
# With an explicit service
|
|
76
|
+
krb5.get_init_creds_password(principal: 'user@EXAMPLE.COM', password: 's3cret', service: 'krbtgt/EXAMPLE.COM')
|
|
77
|
+
|
|
78
|
+
krb5.close
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Secure Authentication (authenticate!)
|
|
82
|
+
|
|
83
|
+
The `authenticate!` method acquires credentials **and** verifies them against the KDC, protecting against KDC-forging attacks. This is the recommended method for login flows.
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
krb5 = Kerberos::Krb5.new
|
|
87
|
+
|
|
88
|
+
begin
|
|
89
|
+
krb5.authenticate!(principal: 'user@EXAMPLE.COM', password: 's3cret')
|
|
90
|
+
puts "Authentication successful"
|
|
91
|
+
rescue Kerberos::Krb5::Exception => e
|
|
92
|
+
puts "Authentication failed: #{e.message}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
krb5.close
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Authenticating with a Keytab
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
krb5 = Kerberos::Krb5.new
|
|
102
|
+
|
|
103
|
+
# Using the default keytab (/etc/krb5.keytab)
|
|
104
|
+
krb5.get_init_creds_keytab(principal: 'host/server.example.com')
|
|
105
|
+
|
|
106
|
+
# Using a specific keytab file
|
|
107
|
+
krb5.get_init_creds_keytab(principal: 'host/server.example.com', keytab: 'FILE:/etc/app.keytab')
|
|
108
|
+
|
|
109
|
+
# With a specific service name
|
|
110
|
+
krb5.get_init_creds_keytab(principal: 'host/server.example.com', service: 'host')
|
|
111
|
+
|
|
112
|
+
# Store the resulting credentials in a cache
|
|
113
|
+
cc = Kerberos::Krb5::CredentialsCache.new
|
|
114
|
+
krb5.get_init_creds_keytab(principal: 'host/server.example.com', ccache: cc)
|
|
115
|
+
|
|
116
|
+
krb5.close
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Verifying Credentials
|
|
120
|
+
|
|
121
|
+
After acquiring credentials, you can explicitly verify them against the KDC:
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
krb5 = Kerberos::Krb5.new
|
|
125
|
+
krb5.get_init_creds_password(principal: 'user@EXAMPLE.COM', password: 's3cret')
|
|
126
|
+
|
|
127
|
+
# Basic verification
|
|
128
|
+
krb5.verify_init_creds
|
|
129
|
+
|
|
130
|
+
# Verify against a specific server principal
|
|
131
|
+
krb5.verify_init_creds(server: 'host/server.example.com@EXAMPLE.COM')
|
|
132
|
+
|
|
133
|
+
# Verify using a specific keytab and store results in a credential cache
|
|
134
|
+
keytab = Kerberos::Krb5::Keytab.new
|
|
135
|
+
cc = Kerberos::Krb5::CredentialsCache.new
|
|
136
|
+
krb5.verify_init_creds(keytab: keytab, ccache: cc)
|
|
137
|
+
puts cc.primary_principal # => "user@EXAMPLE.COM"
|
|
138
|
+
|
|
139
|
+
krb5.close
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Changing a Password
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
krb5 = Kerberos::Krb5.new
|
|
146
|
+
|
|
147
|
+
# First authenticate the user
|
|
148
|
+
krb5.get_init_creds_password(principal: 'user@EXAMPLE.COM', password: 'old_password')
|
|
149
|
+
|
|
150
|
+
# Then change the password
|
|
151
|
+
krb5.change_password('old_password', 'new_password')
|
|
152
|
+
|
|
153
|
+
krb5.close
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Getting the Default Principal
|
|
157
|
+
|
|
158
|
+
Returns the principal from the default credentials cache:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
krb5 = Kerberos::Krb5.new
|
|
162
|
+
puts krb5.default_principal # => "user@EXAMPLE.COM"
|
|
163
|
+
krb5.close
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Listing Permitted Encryption Types
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
krb5 = Kerberos::Krb5.new
|
|
170
|
+
enctypes = krb5.get_permitted_enctypes
|
|
171
|
+
|
|
172
|
+
enctypes.each do |code, description|
|
|
173
|
+
puts "#{code}: #{description}"
|
|
174
|
+
end
|
|
175
|
+
# Example output:
|
|
176
|
+
# 17: AES-128 CTS mode with 96-bit SHA-1 HMAC
|
|
177
|
+
# 18: AES-256 CTS mode with 96-bit SHA-1 HMAC
|
|
178
|
+
# 23: ArcFour with HMAC/md5
|
|
179
|
+
|
|
180
|
+
krb5.close
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Version
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
puts Kerberos::Krb5::VERSION # => "0.3.0"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Kerberos::Krb5::Context
|
|
192
|
+
|
|
193
|
+
A lightweight Kerberos context object. Useful when you need a context for configuration queries without full credential management.
|
|
194
|
+
|
|
195
|
+
### Standard Context
|
|
196
|
+
|
|
197
|
+
```ruby
|
|
198
|
+
ctx = Kerberos::Krb5::Context.new
|
|
199
|
+
# ... use ctx ...
|
|
200
|
+
ctx.close
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Secure Context
|
|
204
|
+
|
|
205
|
+
A secure context ignores environment variables like `KRB5_CONFIG` and reads only from system configuration files. Use this in setuid programs or other security-sensitive environments.
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
ctx = Kerberos::Krb5::Context.new(secure: true)
|
|
209
|
+
ctx.close
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Context with a Custom Profile
|
|
213
|
+
|
|
214
|
+
Load configuration from a specific krb5.conf file:
|
|
215
|
+
|
|
216
|
+
```ruby
|
|
217
|
+
ctx = Kerberos::Krb5::Context.new(profile: '/opt/custom/krb5.conf')
|
|
218
|
+
ctx.close
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Combining Options
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
ctx = Kerberos::Krb5::Context.new(profile: '/opt/custom/krb5.conf', secure: true)
|
|
225
|
+
ctx.close
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Sharing a Context
|
|
229
|
+
|
|
230
|
+
A Context can be shared with other rkerberos objects via the `context:` keyword argument. This avoids repeatedly parsing configuration files and allows multiple objects to operate under the same Kerberos configuration.
|
|
231
|
+
|
|
232
|
+
```ruby
|
|
233
|
+
ctx = Kerberos::Krb5::Context.new(profile: '/opt/custom/krb5.conf')
|
|
234
|
+
|
|
235
|
+
# All of these objects will share the same underlying krb5_context
|
|
236
|
+
krb5 = Kerberos::Krb5.new(context: ctx)
|
|
237
|
+
cc = Kerberos::Krb5::CredentialsCache.new(context: ctx)
|
|
238
|
+
keytab = Kerberos::Krb5::Keytab.new(context: ctx)
|
|
239
|
+
princ = Kerberos::Krb5::Principal.new(name: 'user@EXAMPLE.COM', context: ctx)
|
|
240
|
+
config = Kerberos::Kadm5::Config.new(context: ctx)
|
|
241
|
+
kadm5 = Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass', context: ctx)
|
|
242
|
+
|
|
243
|
+
# When sharing a context, the Context object owns the underlying krb5_context.
|
|
244
|
+
# The objects that borrow it will NOT free the context when they are closed
|
|
245
|
+
# or garbage collected — only closing the Context itself will release it.
|
|
246
|
+
# Make sure the Context outlives all objects that reference it.
|
|
247
|
+
|
|
248
|
+
krb5.close
|
|
249
|
+
cc.close
|
|
250
|
+
keytab.close
|
|
251
|
+
kadm5.close
|
|
252
|
+
ctx.close
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Kerberos::Krb5::CredentialsCache
|
|
258
|
+
|
|
259
|
+
Encapsulates a Kerberos credentials cache (ccache). Used for storing and managing TGTs and service tickets.
|
|
260
|
+
|
|
261
|
+
### Using the Default Cache
|
|
262
|
+
|
|
263
|
+
```ruby
|
|
264
|
+
cc = Kerberos::Krb5::CredentialsCache.new
|
|
265
|
+
puts cc.default_name # => "FILE:/tmp/krb5cc_1000"
|
|
266
|
+
|
|
267
|
+
cc.close
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Creating a Cache with a Specific Principal
|
|
271
|
+
|
|
272
|
+
```ruby
|
|
273
|
+
# Creates (or reinitializes) the default cache with this principal
|
|
274
|
+
cc = Kerberos::Krb5::CredentialsCache.new(principal: 'user@EXAMPLE.COM')
|
|
275
|
+
puts cc.primary_principal # => "user@EXAMPLE.COM"
|
|
276
|
+
|
|
277
|
+
cc.close
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Using a Named Cache
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
# Use a specific cache file
|
|
284
|
+
cc = Kerberos::Krb5::CredentialsCache.new(cache_name: 'FILE:/tmp/krb5cc_myapp')
|
|
285
|
+
puts cc.cache_name # => "/tmp/krb5cc_myapp"
|
|
286
|
+
puts cc.cache_type # => "FILE"
|
|
287
|
+
|
|
288
|
+
cc.close
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Querying Cache Properties
|
|
292
|
+
|
|
293
|
+
```ruby
|
|
294
|
+
cc = Kerberos::Krb5::CredentialsCache.new
|
|
295
|
+
|
|
296
|
+
puts cc.default_name # Default cache path for the system
|
|
297
|
+
puts cc.cache_name # Actual name of this cache instance
|
|
298
|
+
puts cc.cache_type # Cache type, e.g. "FILE", "MEMORY", "KCM"
|
|
299
|
+
puts cc.primary_principal # The principal stored in this cache
|
|
300
|
+
puts cc.principal # Alias for primary_principal
|
|
301
|
+
|
|
302
|
+
cc.close
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Duplicating a Cache
|
|
306
|
+
|
|
307
|
+
```ruby
|
|
308
|
+
cc = Kerberos::Krb5::CredentialsCache.new(principal: 'user@EXAMPLE.COM')
|
|
309
|
+
cc2 = cc.dup # Independent copy; closing one does not affect the other
|
|
310
|
+
|
|
311
|
+
cc.close
|
|
312
|
+
cc2.close
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Destroying a Cache
|
|
316
|
+
|
|
317
|
+
Destroys the cache file and invalidates the object. Returns `true` if the cache was destroyed or `false` if no cache was found.
|
|
318
|
+
|
|
319
|
+
```ruby
|
|
320
|
+
cc = Kerberos::Krb5::CredentialsCache.new(principal: 'user@EXAMPLE.COM')
|
|
321
|
+
cc.destroy # => true (also aliased as cc.delete)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Storing Verified Credentials in a Cache
|
|
325
|
+
|
|
326
|
+
```ruby
|
|
327
|
+
krb5 = Kerberos::Krb5.new
|
|
328
|
+
cc = Kerberos::Krb5::CredentialsCache.new
|
|
329
|
+
|
|
330
|
+
krb5.get_init_creds_password(principal: 'user@EXAMPLE.COM', password: 's3cret')
|
|
331
|
+
krb5.verify_init_creds(ccache: cc)
|
|
332
|
+
|
|
333
|
+
puts cc.primary_principal # => "user@EXAMPLE.COM"
|
|
334
|
+
|
|
335
|
+
cc.close
|
|
336
|
+
krb5.close
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Kerberos::Krb5::Keytab
|
|
342
|
+
|
|
343
|
+
Provides access to Kerberos keytab files for reading entries and performing keytab-based authentication.
|
|
344
|
+
|
|
345
|
+
### Opening the Default Keytab
|
|
346
|
+
|
|
347
|
+
```ruby
|
|
348
|
+
keytab = Kerberos::Krb5::Keytab.new
|
|
349
|
+
puts keytab.name # => "FILE:/etc/krb5.keytab"
|
|
350
|
+
puts keytab.default_name # => "FILE:/etc/krb5.keytab"
|
|
351
|
+
puts keytab.keytab_name # Canonical name from the library
|
|
352
|
+
puts keytab.keytab_type # => "FILE"
|
|
353
|
+
|
|
354
|
+
keytab.close
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Opening a Specific Keytab
|
|
358
|
+
|
|
359
|
+
```ruby
|
|
360
|
+
keytab = Kerberos::Krb5::Keytab.new(name: 'FILE:/etc/app.keytab')
|
|
361
|
+
puts keytab.name # => "FILE:/etc/app.keytab"
|
|
362
|
+
|
|
363
|
+
keytab.close
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Iterating Over Entries
|
|
367
|
+
|
|
368
|
+
```ruby
|
|
369
|
+
keytab = Kerberos::Krb5::Keytab.new
|
|
370
|
+
|
|
371
|
+
keytab.each do |entry|
|
|
372
|
+
puts "Principal: #{entry.principal}"
|
|
373
|
+
puts "Timestamp: #{entry.timestamp}"
|
|
374
|
+
puts "Version: #{entry.vno}"
|
|
375
|
+
puts "Key Type: #{entry.key}"
|
|
376
|
+
puts "---"
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
keytab.close
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Using the Singleton foreach Method
|
|
383
|
+
|
|
384
|
+
Iterate over keytab entries without creating an instance:
|
|
385
|
+
|
|
386
|
+
```ruby
|
|
387
|
+
# Default keytab
|
|
388
|
+
Kerberos::Krb5::Keytab.foreach do |entry|
|
|
389
|
+
puts entry.principal
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# Specific keytab
|
|
393
|
+
Kerberos::Krb5::Keytab.foreach('FILE:/etc/app.keytab') do |entry|
|
|
394
|
+
puts entry.principal
|
|
395
|
+
end
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Looking Up a Specific Entry
|
|
399
|
+
|
|
400
|
+
```ruby
|
|
401
|
+
keytab = Kerberos::Krb5::Keytab.new
|
|
402
|
+
|
|
403
|
+
# Find the first entry matching a principal
|
|
404
|
+
entry = keytab.get_entry('host/server.example.com@EXAMPLE.COM')
|
|
405
|
+
puts entry.principal
|
|
406
|
+
puts entry.vno
|
|
407
|
+
|
|
408
|
+
# Find with a specific version number
|
|
409
|
+
entry = keytab.get_entry('host/server.example.com@EXAMPLE.COM', 2)
|
|
410
|
+
|
|
411
|
+
# Find with a specific version number and encryption type
|
|
412
|
+
entry = keytab.get_entry(
|
|
413
|
+
'host/server.example.com@EXAMPLE.COM',
|
|
414
|
+
0,
|
|
415
|
+
Kerberos::Krb5::ENCTYPE_AES256_CTS_HMAC_SHA1_96
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
keytab.close
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Duplicating a Keytab
|
|
422
|
+
|
|
423
|
+
```ruby
|
|
424
|
+
keytab = Kerberos::Krb5::Keytab.new
|
|
425
|
+
keytab2 = keytab.dup # Independent handle; closing one doesn't affect the other
|
|
426
|
+
|
|
427
|
+
keytab.close
|
|
428
|
+
keytab2.close
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## Kerberos::Krb5::Keytab::Entry
|
|
434
|
+
|
|
435
|
+
Represents a single entry in a keytab. These objects are yielded by `Keytab#each` and `Keytab.foreach`, or returned by `Keytab#get_entry`.
|
|
436
|
+
|
|
437
|
+
### Attributes
|
|
438
|
+
|
|
439
|
+
```ruby
|
|
440
|
+
keytab = Kerberos::Krb5::Keytab.new
|
|
441
|
+
|
|
442
|
+
keytab.each do |entry|
|
|
443
|
+
entry.principal # => "host/server.example.com@EXAMPLE.COM"
|
|
444
|
+
entry.timestamp # => 2026-03-01 12:00:00 -0500 (Time object)
|
|
445
|
+
entry.vno # => 1 (key version number)
|
|
446
|
+
entry.key # => 18 (encryption type, e.g. AES-256)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
keytab.close
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Inspecting an Entry
|
|
453
|
+
|
|
454
|
+
```ruby
|
|
455
|
+
keytab = Kerberos::Krb5::Keytab.new
|
|
456
|
+
|
|
457
|
+
entry = keytab.get_entry('host/server.example.com@EXAMPLE.COM')
|
|
458
|
+
puts entry.inspect
|
|
459
|
+
# => #<Kerberos::Krb5::Keytab::Entry principal="host/server.example.com@EXAMPLE.COM" timestamp=2026-03-01 12:00:00 -0500 vno=1 key=18>
|
|
460
|
+
|
|
461
|
+
keytab.close
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## Kerberos::Krb5::Principal
|
|
467
|
+
|
|
468
|
+
Represents a Kerberos principal with associated metadata. Typically returned by `Kadm5#get_principal` or `Kadm5#find_principal`, but can also be created standalone.
|
|
469
|
+
|
|
470
|
+
### Creating a Principal
|
|
471
|
+
|
|
472
|
+
```ruby
|
|
473
|
+
principal = Kerberos::Krb5::Principal.new(name: 'user@EXAMPLE.COM')
|
|
474
|
+
puts principal.principal # => "user@EXAMPLE.COM"
|
|
475
|
+
puts principal.name # => "user@EXAMPLE.COM" (alias)
|
|
476
|
+
puts principal.realm # => "EXAMPLE.COM"
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### Using a Block
|
|
480
|
+
|
|
481
|
+
```ruby
|
|
482
|
+
principal = Kerberos::Krb5::Principal.new(name: 'user@EXAMPLE.COM') do |p|
|
|
483
|
+
p.expire_time = Time.now + 86400 * 365
|
|
484
|
+
p.max_life = 36000
|
|
485
|
+
end
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Changing the Realm
|
|
489
|
+
|
|
490
|
+
```ruby
|
|
491
|
+
principal = Kerberos::Krb5::Principal.new(name: 'user@EXAMPLE.COM')
|
|
492
|
+
puts principal.realm # => "EXAMPLE.COM"
|
|
493
|
+
|
|
494
|
+
principal.realm = 'OTHER.REALM.COM'
|
|
495
|
+
puts principal.realm # => "OTHER.REALM.COM"
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Comparing Principals
|
|
499
|
+
|
|
500
|
+
```ruby
|
|
501
|
+
p1 = Kerberos::Krb5::Principal.new(name: 'user@EXAMPLE.COM')
|
|
502
|
+
p2 = Kerberos::Krb5::Principal.new(name: 'user@EXAMPLE.COM')
|
|
503
|
+
p3 = Kerberos::Krb5::Principal.new(name: 'admin@EXAMPLE.COM')
|
|
504
|
+
|
|
505
|
+
p1 == p2 # => true
|
|
506
|
+
p1 == p3 # => false
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Attributes from Kadm5
|
|
510
|
+
|
|
511
|
+
When retrieved via `Kadm5#get_principal`, the Principal object is populated with additional metadata:
|
|
512
|
+
|
|
513
|
+
```ruby
|
|
514
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
515
|
+
princ = kadm5.get_principal('user@EXAMPLE.COM')
|
|
516
|
+
|
|
517
|
+
puts princ.principal # => "user@EXAMPLE.COM"
|
|
518
|
+
puts princ.attributes # => Bitmask of principal flags
|
|
519
|
+
puts princ.aux_attributes # => Auxiliary attributes
|
|
520
|
+
puts princ.expire_time # => Time or nil
|
|
521
|
+
puts princ.fail_auth_count # => Integer
|
|
522
|
+
puts princ.kvno # => Key version number
|
|
523
|
+
puts princ.last_failed # => Time or nil
|
|
524
|
+
puts princ.last_password_change # => Time or nil
|
|
525
|
+
puts princ.last_success # => Time or nil
|
|
526
|
+
puts princ.max_life # => Max ticket life in seconds
|
|
527
|
+
puts princ.max_renewable_life # => Max renewable life in seconds
|
|
528
|
+
puts princ.mod_date # => Time or nil
|
|
529
|
+
puts princ.mod_name # => "admin/admin@EXAMPLE.COM"
|
|
530
|
+
puts princ.password_expiration # => Time or nil
|
|
531
|
+
puts princ.policy # => "default" or nil
|
|
532
|
+
end
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
## Kerberos::Kadm5
|
|
538
|
+
|
|
539
|
+
The admin interface for managing principals, policies, and passwords. Requires admin credentials.
|
|
540
|
+
|
|
541
|
+
### Connecting with a Password
|
|
542
|
+
|
|
543
|
+
```ruby
|
|
544
|
+
# Block form (recommended) — automatically closes when done
|
|
545
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
546
|
+
# ... admin operations ...
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# Manual form
|
|
550
|
+
kadm5 = Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass')
|
|
551
|
+
# ... admin operations ...
|
|
552
|
+
kadm5.close
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Connecting with a Keytab
|
|
556
|
+
|
|
557
|
+
```ruby
|
|
558
|
+
# Using the default keytab (/etc/krb5.keytab)
|
|
559
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', keytab: true) do |kadm5|
|
|
560
|
+
# ...
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
# Using a specific keytab file
|
|
564
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', keytab: '/etc/admin.keytab') do |kadm5|
|
|
565
|
+
# ...
|
|
566
|
+
end
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Using a Shared Context
|
|
570
|
+
|
|
571
|
+
```ruby
|
|
572
|
+
ctx = Kerberos::Krb5::Context.new(profile: '/opt/custom/krb5.conf')
|
|
573
|
+
|
|
574
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass', context: ctx) do |kadm5|
|
|
575
|
+
# The admin connection uses the custom Kerberos configuration
|
|
576
|
+
princ = kadm5.get_principal('user@EXAMPLE.COM')
|
|
577
|
+
puts princ.principal
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
ctx.close
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Specifying a Custom Service
|
|
584
|
+
|
|
585
|
+
```ruby
|
|
586
|
+
Kerberos::Kadm5.new(
|
|
587
|
+
principal: 'admin/admin',
|
|
588
|
+
password: 'admin_pass',
|
|
589
|
+
service: 'kadmin/changepw'
|
|
590
|
+
) do |kadm5|
|
|
591
|
+
# ...
|
|
592
|
+
end
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
### Using Database Arguments
|
|
596
|
+
|
|
597
|
+
```ruby
|
|
598
|
+
# Single db_arg
|
|
599
|
+
Kerberos::Kadm5.new(
|
|
600
|
+
principal: 'admin/admin',
|
|
601
|
+
password: 'admin_pass',
|
|
602
|
+
db_args: 'tktpolicy=default'
|
|
603
|
+
) do |kadm5|
|
|
604
|
+
# ...
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
# Multiple db_args
|
|
608
|
+
Kerberos::Kadm5.new(
|
|
609
|
+
principal: 'admin/admin',
|
|
610
|
+
password: 'admin_pass',
|
|
611
|
+
db_args: ['arg1=value1', 'arg2=value2']
|
|
612
|
+
) do |kadm5|
|
|
613
|
+
# ...
|
|
614
|
+
end
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Creating a Principal
|
|
618
|
+
|
|
619
|
+
```ruby
|
|
620
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
621
|
+
kadm5.create_principal(name: 'newuser@EXAMPLE.COM', password: 'initial_password')
|
|
622
|
+
|
|
623
|
+
# With database arguments
|
|
624
|
+
kadm5.create_principal(
|
|
625
|
+
name: 'ldapuser@EXAMPLE.COM',
|
|
626
|
+
password: 'password',
|
|
627
|
+
db_args: 'tktpolicy=default'
|
|
628
|
+
)
|
|
629
|
+
end
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Deleting a Principal
|
|
633
|
+
|
|
634
|
+
```ruby
|
|
635
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
636
|
+
kadm5.delete_principal('newuser@EXAMPLE.COM')
|
|
637
|
+
end
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Getting Principal Information
|
|
641
|
+
|
|
642
|
+
```ruby
|
|
643
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
644
|
+
# Raises PrincipalNotFoundException if not found
|
|
645
|
+
princ = kadm5.get_principal('user@EXAMPLE.COM')
|
|
646
|
+
puts princ.inspect
|
|
647
|
+
end
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Finding a Principal (nil if not found)
|
|
651
|
+
|
|
652
|
+
```ruby
|
|
653
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
654
|
+
princ = kadm5.find_principal('user@EXAMPLE.COM')
|
|
655
|
+
|
|
656
|
+
if princ
|
|
657
|
+
puts princ.principal
|
|
658
|
+
else
|
|
659
|
+
puts "Principal not found"
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### Listing Principals
|
|
665
|
+
|
|
666
|
+
```ruby
|
|
667
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
668
|
+
# List all principals
|
|
669
|
+
all = kadm5.get_principals
|
|
670
|
+
all.each { |name| puts name }
|
|
671
|
+
|
|
672
|
+
# List principals matching a pattern
|
|
673
|
+
matches = kadm5.get_principals('host/*')
|
|
674
|
+
matches.each { |name| puts name }
|
|
675
|
+
|
|
676
|
+
# Other pattern examples
|
|
677
|
+
kadm5.get_principals('user*') # Starts with "user"
|
|
678
|
+
kadm5.get_principals('*/admin@*') # Admin instances
|
|
679
|
+
end
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
### Setting a Password
|
|
683
|
+
|
|
684
|
+
```ruby
|
|
685
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
686
|
+
kadm5.set_password('user@EXAMPLE.COM', 'new_password')
|
|
687
|
+
end
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### Setting Password Expiration
|
|
691
|
+
|
|
692
|
+
```ruby
|
|
693
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
694
|
+
# Set password to expire at a specific Unix timestamp
|
|
695
|
+
expire_time = (Time.now + 86400 * 90).to_i # 90 days from now
|
|
696
|
+
kadm5.set_pwexpire('user@EXAMPLE.COM', expire_time)
|
|
697
|
+
end
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### Generating Random Keys
|
|
701
|
+
|
|
702
|
+
```ruby
|
|
703
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
704
|
+
num_keys = kadm5.generate_random_key('host/server.example.com@EXAMPLE.COM')
|
|
705
|
+
puts "Generated #{num_keys} random key(s)"
|
|
706
|
+
end
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
### Checking Admin Privileges
|
|
710
|
+
|
|
711
|
+
```ruby
|
|
712
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
713
|
+
# Get privileges as a bitmask
|
|
714
|
+
privs = kadm5.get_privileges
|
|
715
|
+
puts privs # => 15 (all privileges)
|
|
716
|
+
|
|
717
|
+
# Get privileges as human-readable strings
|
|
718
|
+
privs = kadm5.get_privileges(true)
|
|
719
|
+
puts privs.inspect # => ["GET", "ADD", "MODIFY", "DELETE"]
|
|
720
|
+
end
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
### Complete Lifecycle Example
|
|
724
|
+
|
|
725
|
+
```ruby
|
|
726
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
727
|
+
# Create a new user
|
|
728
|
+
kadm5.create_principal(name: 'jdoe@EXAMPLE.COM', password: 'temp_password')
|
|
729
|
+
|
|
730
|
+
# Look up the user
|
|
731
|
+
princ = kadm5.get_principal('jdoe@EXAMPLE.COM')
|
|
732
|
+
puts "Created: #{princ.principal}, kvno: #{princ.kvno}"
|
|
733
|
+
|
|
734
|
+
# Reset their password
|
|
735
|
+
kadm5.set_password('jdoe@EXAMPLE.COM', 'better_password')
|
|
736
|
+
|
|
737
|
+
# Set password expiration to 90 days
|
|
738
|
+
kadm5.set_pwexpire('jdoe@EXAMPLE.COM', (Time.now + 86400 * 90).to_i)
|
|
739
|
+
|
|
740
|
+
# Generate random keys (e.g. for a service principal)
|
|
741
|
+
kadm5.create_principal(name: 'HTTP/webapp.example.com@EXAMPLE.COM', password: 'temp')
|
|
742
|
+
kadm5.generate_random_key('HTTP/webapp.example.com@EXAMPLE.COM')
|
|
743
|
+
|
|
744
|
+
# Clean up
|
|
745
|
+
kadm5.delete_principal('jdoe@EXAMPLE.COM')
|
|
746
|
+
kadm5.delete_principal('HTTP/webapp.example.com@EXAMPLE.COM')
|
|
747
|
+
end
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
---
|
|
751
|
+
|
|
752
|
+
## Kerberos::Kadm5::Config
|
|
753
|
+
|
|
754
|
+
A read-only snapshot of the Kerberos admin configuration. The returned object is frozen.
|
|
755
|
+
|
|
756
|
+
### Reading Configuration
|
|
757
|
+
|
|
758
|
+
```ruby
|
|
759
|
+
config = Kerberos::Kadm5::Config.new
|
|
760
|
+
|
|
761
|
+
puts config.realm # => "EXAMPLE.COM"
|
|
762
|
+
puts config.admin_server # => "kdc.example.com"
|
|
763
|
+
puts config.kadmind_port # => 749
|
|
764
|
+
puts config.kpasswd_port # => 464
|
|
765
|
+
puts config.acl_file # => "/var/kerberos/krb5kdc/kadm5.acl"
|
|
766
|
+
puts config.dict_file # => nil (or path to dictionary file)
|
|
767
|
+
puts config.stash_file # => "/var/kerberos/krb5kdc/.k5.EXAMPLE.COM"
|
|
768
|
+
puts config.mkey_name # => "K/M"
|
|
769
|
+
puts config.enctype # => 18 (AES-256)
|
|
770
|
+
puts config.max_life # => 36000 (seconds)
|
|
771
|
+
puts config.max_rlife # => 604800 (seconds)
|
|
772
|
+
puts config.expiration # => Time object or nil
|
|
773
|
+
puts config.flags # => Integer bitmask
|
|
774
|
+
puts config.kvno # => 1
|
|
775
|
+
puts config.iprop_enabled # => true or false
|
|
776
|
+
puts config.iprop_logfile # => path or nil
|
|
777
|
+
puts config.iprop_poll_time # => Integer (seconds) or nil
|
|
778
|
+
puts config.iprop_port # => Integer or nil
|
|
779
|
+
puts config.num_keysalts # => Integer
|
|
780
|
+
puts config.keysalts # => Array of KeySalt objects or nil
|
|
781
|
+
|
|
782
|
+
puts config.inspect
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### Using a Shared Context
|
|
786
|
+
|
|
787
|
+
```ruby
|
|
788
|
+
ctx = Kerberos::Krb5::Context.new(profile: '/opt/custom/krb5.conf')
|
|
789
|
+
config = Kerberos::Kadm5::Config.new(context: ctx)
|
|
790
|
+
|
|
791
|
+
puts config.realm
|
|
792
|
+
puts config.admin_server
|
|
793
|
+
|
|
794
|
+
ctx.close
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### Inspecting KeySalt Entries
|
|
798
|
+
|
|
799
|
+
```ruby
|
|
800
|
+
config = Kerberos::Kadm5::Config.new
|
|
801
|
+
|
|
802
|
+
if config.keysalts
|
|
803
|
+
config.keysalts.each do |ks|
|
|
804
|
+
puts "Enctype: #{ks.enctype}, Salttype: #{ks.salttype}"
|
|
805
|
+
end
|
|
806
|
+
end
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
---
|
|
810
|
+
|
|
811
|
+
## Kerberos::Kadm5::Policy
|
|
812
|
+
|
|
813
|
+
Represents a Kerberos password policy. Policy objects are created in Ruby and then applied via the Kadm5 admin interface.
|
|
814
|
+
|
|
815
|
+
### Creating a Policy Object
|
|
816
|
+
|
|
817
|
+
```ruby
|
|
818
|
+
policy = Kerberos::Kadm5::Policy.new(
|
|
819
|
+
name: 'strict',
|
|
820
|
+
min_life: 3600, # Minimum password lifetime: 1 hour
|
|
821
|
+
max_life: 7776000, # Maximum password lifetime: 90 days
|
|
822
|
+
min_length: 12, # Minimum password length
|
|
823
|
+
min_classes: 3, # Require at least 3 character classes
|
|
824
|
+
history_num: 5 # Remember last 5 passwords
|
|
825
|
+
)
|
|
826
|
+
|
|
827
|
+
puts policy.name # => "strict" (alias for policy.policy)
|
|
828
|
+
puts policy.policy # => "strict"
|
|
829
|
+
puts policy.min_life # => 3600
|
|
830
|
+
puts policy.max_life # => 7776000
|
|
831
|
+
puts policy.min_length # => 12
|
|
832
|
+
puts policy.min_classes # => 3
|
|
833
|
+
puts policy.history_num # => 5
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
### Creating a Policy in Kerberos
|
|
837
|
+
|
|
838
|
+
```ruby
|
|
839
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
840
|
+
# Using a Policy object
|
|
841
|
+
policy = Kerberos::Kadm5::Policy.new(name: 'standard', min_length: 8, min_classes: 2)
|
|
842
|
+
kadm5.create_policy(policy)
|
|
843
|
+
|
|
844
|
+
# Using keywords directly
|
|
845
|
+
kadm5.create_policy(name: 'simple', min_length: 6)
|
|
846
|
+
end
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
### Retrieving a Policy
|
|
850
|
+
|
|
851
|
+
```ruby
|
|
852
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
853
|
+
# Raises an exception if not found
|
|
854
|
+
policy = kadm5.get_policy('standard')
|
|
855
|
+
puts policy.inspect
|
|
856
|
+
|
|
857
|
+
# Returns nil if not found
|
|
858
|
+
policy = kadm5.find_policy('nonexistent')
|
|
859
|
+
puts policy.nil? # => true
|
|
860
|
+
end
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
### Modifying a Policy
|
|
864
|
+
|
|
865
|
+
```ruby
|
|
866
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
867
|
+
policy = kadm5.get_policy('standard')
|
|
868
|
+
policy.min_length = 10
|
|
869
|
+
policy.min_classes = 3
|
|
870
|
+
kadm5.modify_policy(policy)
|
|
871
|
+
end
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
### Listing Policies
|
|
875
|
+
|
|
876
|
+
```ruby
|
|
877
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
878
|
+
# List all policies
|
|
879
|
+
kadm5.get_policies.each { |name| puts name }
|
|
880
|
+
|
|
881
|
+
# List policies matching a pattern
|
|
882
|
+
kadm5.get_policies('s*').each { |name| puts name }
|
|
883
|
+
end
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
### Deleting a Policy
|
|
887
|
+
|
|
888
|
+
```ruby
|
|
889
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
890
|
+
kadm5.delete_policy('standard')
|
|
891
|
+
end
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
### Policy Lifecycle Example
|
|
895
|
+
|
|
896
|
+
```ruby
|
|
897
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'admin_pass') do |kadm5|
|
|
898
|
+
# Create a policy
|
|
899
|
+
kadm5.create_policy(name: 'webusers', min_length: 10, min_classes: 2, max_life: 7776000)
|
|
900
|
+
|
|
901
|
+
# Verify it was created
|
|
902
|
+
policy = kadm5.get_policy('webusers')
|
|
903
|
+
puts "Policy '#{policy.name}' created with min_length=#{policy.min_length}"
|
|
904
|
+
|
|
905
|
+
# Modify it
|
|
906
|
+
policy.min_length = 12
|
|
907
|
+
kadm5.modify_policy(policy)
|
|
908
|
+
|
|
909
|
+
# Clean up
|
|
910
|
+
kadm5.delete_policy('webusers')
|
|
911
|
+
end
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
---
|
|
915
|
+
|
|
916
|
+
## Constants
|
|
917
|
+
|
|
918
|
+
### Encryption Type Constants
|
|
919
|
+
|
|
920
|
+
Available on `Kerberos::Krb5`:
|
|
921
|
+
|
|
922
|
+
| Constant | Value | Description |
|
|
923
|
+
|---|---|---|
|
|
924
|
+
| `ENCTYPE_NULL` | 0 | None |
|
|
925
|
+
| `ENCTYPE_DES_CBC_CRC` | 1 | DES cbc mode with CRC-32 |
|
|
926
|
+
| `ENCTYPE_DES_CBC_MD4` | 2 | DES cbc mode with RSA-MD4 |
|
|
927
|
+
| `ENCTYPE_DES_CBC_MD5` | 3 | DES cbc mode with RSA-MD5 |
|
|
928
|
+
| `ENCTYPE_DES_CBC_RAW` | 4 | DES cbc mode raw |
|
|
929
|
+
| `ENCTYPE_DES3_CBC_SHA` | 5 | DES-3 cbc mode with NIST-SHA |
|
|
930
|
+
| `ENCTYPE_DES3_CBC_RAW` | 6 | DES-3 cbc mode raw |
|
|
931
|
+
| `ENCTYPE_DES_HMAC_SHA1` | 8 | HMAC SHA1 |
|
|
932
|
+
| `ENCTYPE_DES3_CBC_SHA1` | 16 | DES3 CBC SHA1 |
|
|
933
|
+
| `ENCTYPE_AES128_CTS_HMAC_SHA1_96` | 17 | AES-128 CTS mode with 96-bit SHA-1 HMAC |
|
|
934
|
+
| `ENCTYPE_AES256_CTS_HMAC_SHA1_96` | 18 | AES-256 CTS mode with 96-bit SHA-1 HMAC |
|
|
935
|
+
| `ENCTYPE_ARCFOUR_HMAC` | 23 | ArcFour with HMAC/md5 |
|
|
936
|
+
| `ENCTYPE_ARCFOUR_HMAC_EXP` | 24 | ArcFour HMAC EXP |
|
|
937
|
+
| `ENCTYPE_UNKNOWN` | 511 | Unknown |
|
|
938
|
+
|
|
939
|
+
### Kadm5 Attribute Constants
|
|
940
|
+
|
|
941
|
+
Available on `Kerberos::Kadm5`:
|
|
942
|
+
|
|
943
|
+
| Constant | Description |
|
|
944
|
+
|---|---|
|
|
945
|
+
| `DISALLOW_POSTDATED` | Disallow postdated tickets |
|
|
946
|
+
| `DISALLOW_FORWARDABLE` | Disallow forwardable tickets |
|
|
947
|
+
| `DISALLOW_TGT_BASED` | Disallow TGT-based requests |
|
|
948
|
+
| `DISALLOW_RENEWABLE` | Disallow renewable tickets |
|
|
949
|
+
| `DISALLOW_PROXIABLE` | Disallow proxiable tickets |
|
|
950
|
+
| `DISALLOW_DUP_SKEY` | Disallow duplicate session keys |
|
|
951
|
+
| `DISALLOW_ALL_TIX` | Disallow all tickets |
|
|
952
|
+
| `REQUIRES_PRE_AUTH` | Require pre-authentication |
|
|
953
|
+
| `REQUIRES_HW_AUTH` | Require hardware authentication |
|
|
954
|
+
| `REQUIRES_PWCHANGE` | Require password change |
|
|
955
|
+
| `DISALLOW_SVR` | Disallow service tickets |
|
|
956
|
+
| `PWCHANGE_SERVICE` | Password change service |
|
|
957
|
+
| `SUPPORT_DESMD5` | Support DES-MD5 |
|
|
958
|
+
| `NEW_PRINC` | New principal |
|
|
959
|
+
|
|
960
|
+
---
|
|
961
|
+
|
|
962
|
+
## Error Handling
|
|
963
|
+
|
|
964
|
+
The library raises specific exception classes depending on the component:
|
|
965
|
+
|
|
966
|
+
```ruby
|
|
967
|
+
begin
|
|
968
|
+
krb5 = Kerberos::Krb5.new
|
|
969
|
+
krb5.get_init_creds_password(principal: 'user@EXAMPLE.COM', password: 'wrong_password')
|
|
970
|
+
rescue Kerberos::Krb5::Exception => e
|
|
971
|
+
puts "Krb5 error: #{e.message}"
|
|
972
|
+
ensure
|
|
973
|
+
krb5&.close
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
begin
|
|
977
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'wrong') do |kadm5|
|
|
978
|
+
# ...
|
|
979
|
+
end
|
|
980
|
+
rescue Kerberos::Kadm5::Exception => e
|
|
981
|
+
puts "Kadm5 error: #{e.message}"
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
# Principal not found (specific subclass)
|
|
985
|
+
begin
|
|
986
|
+
Kerberos::Kadm5.new(principal: 'admin/admin', password: 'pass') do |kadm5|
|
|
987
|
+
kadm5.get_principal('nonexistent@EXAMPLE.COM')
|
|
988
|
+
end
|
|
989
|
+
rescue Kerberos::Kadm5::PrincipalNotFoundException => e
|
|
990
|
+
puts "Principal not found: #{e.message}"
|
|
991
|
+
rescue Kerberos::Kadm5::Exception => e
|
|
992
|
+
puts "Other admin error: #{e.message}"
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
# Keytab-specific errors
|
|
996
|
+
begin
|
|
997
|
+
keytab = Kerberos::Krb5::Keytab.new(name: 'FILE:/nonexistent/path')
|
|
998
|
+
rescue Kerberos::Krb5::Keytab::Exception => e
|
|
999
|
+
puts "Keytab error: #{e.message}"
|
|
1000
|
+
end
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
### Exception Hierarchy
|
|
1004
|
+
|
|
1005
|
+
```
|
|
1006
|
+
StandardError
|
|
1007
|
+
├── Kerberos::Krb5::Exception
|
|
1008
|
+
│ └── (general Kerberos errors)
|
|
1009
|
+
├── Kerberos::Krb5::Keytab::Exception
|
|
1010
|
+
│ └── (keytab-specific errors)
|
|
1011
|
+
├── Kerberos::Kadm5::Exception
|
|
1012
|
+
│ └── (admin errors)
|
|
1013
|
+
└── Kerberos::Kadm5::PrincipalNotFoundException
|
|
1014
|
+
└── (principal lookup failures)
|
|
1015
|
+
```
|