rkerberos 0.2.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a969c8a989d5d310bd6906a8023acdd1bd511524cdf85e1b8df35b9e51a424e
4
- data.tar.gz: 8792c83e657bd1ddc3da150a2989906050ea48bc2631a2de9e95fe5a8983f2c1
3
+ metadata.gz: 7d95bc44b05fe9b2d7d50af063944d2464a39e2387c6af3c9b8dbefd68025e94
4
+ data.tar.gz: 8dcdcec07fcdd598065fc7e826dda60b66a683c0cfb500aaa594fdbe5b5c3326
5
5
  SHA512:
6
- metadata.gz: 41e50b69c30e64a0ca78548cb189ad6627b41b951abb906caac1e27d2746afbd81df6b96e1cbb1910b1b0c535c5fddd752e5246ff4eab16af860e1797b599374
7
- data.tar.gz: 1b3a230983ff08f515412a0bf2055f1152c8e3d757cda4d017d2ec72a53210c077a4874117a0d56256b42535b83d5495c4ec0e315d02cf2e6be9220384d0ac8f
6
+ metadata.gz: ee3844d89f82e24b9447f67538e40f9af8d4df630c3e3da757e0ce8c3d54b1ba1d3a57d48db0c2ed4001a687dd1ccfbcb2e3c5ef6eb120b5eed5802964a47f74
7
+ data.tar.gz: 93003f70201a17ecbc3f158cf4fa997657ee1d25b1c28d3e3019207f3b3664d880db4d3297a8a542d54343ad4fe2f38afa607b028ea161d6bbb50a1a526f4e63
@@ -1,3 +1,15 @@
1
+ = 0.2.1 - 1-Mar-2026
2
+ * Added the verify_init_creds and an authenticate! methods.
3
+ * The Context constructor now accepts optional :secure and/or :profile arguments
4
+ for different types of contexts.
5
+ * Minor fix for the CredentialsCache constructor.
6
+ * Minor fix for the get_init_creds_keytab method.
7
+ * Fixed a mistake in an rb_funcall in the Policy class (thanks Ondřej Gajdušek).
8
+ * Update gemspec so that releases don't include Docker related files (thanks Ondřej Gajdušek).
9
+ * Add a spec:compose task for convenience.
10
+ * The rake-compiler gem is now a development dependency, not a runtime
11
+ dependency (thanks Ondřej Gajdušek).
12
+
1
13
  = 0.2.0 - 14-Feb-2026
2
14
  * Added Docker and Podman support for running tests in isolated environments with Kerberos and OpenLDAP services.
3
15
  * Updated documentation with modern testing and development workflows, including container-based instructions.
@@ -1,6 +1,6 @@
1
- CHANGES
1
+ CHANGES.md
2
2
  rkerberos.gemspec
3
- MANIFEST
3
+ MANIFEST.md
4
4
  Rakefile
5
5
  README
6
6
  ext/ccache.c
data/README.md CHANGED
@@ -1,5 +1,44 @@
1
+ [![Ruby](https://github.com/rkerberos/rkerberos/actions/workflows/ci.yml/badge.svg)](https://github.com/rkerberos/rkerberos/actions/workflows/ci.yml)
2
+
1
3
  # Description
2
- The rkerberos library provides a Ruby interface for Kerberos.
4
+ The rkerberos library provides a Ruby interface for Kerberos.
5
+
6
+ ## Code synopsis
7
+
8
+ Some basic usage:
9
+
10
+ ```ruby
11
+ require 'rkerberos'
12
+
13
+ # Client
14
+ krb = Kerberos::Krb5.new
15
+ puts krb.default_realm
16
+ puts krb.default_principal
17
+ puts krb.get_permitted_enctypes.keys.join(',')
18
+
19
+ # Credentials cache
20
+ cc = Kerberos::Krb5::CredentialsCache.new
21
+ krb.verify_init_creds(nil, nil, cc)
22
+ puts cc.primary_principal
23
+
24
+ # Keytab
25
+ kt_name = Kerberos::Krb5::Keytab.new.default_name # e.g. "FILE:/etc/krb5.keytab"
26
+ krb.get_init_creds_keytab('host/server.example.com', kt_name)
27
+ krb.get_init_creds_keytab('host/server.example.com', kt_name, nil, cc) # or write to cache
28
+
29
+ # Admin
30
+ Kerberos::Kadm5.new(principal: ENV['KRB5_ADMIN_PRINCIPAL'], password: ENV['KRB5_ADMIN_PASSWORD']) do |kadmin|
31
+ kadmin.create_principal('newuser@EXAMPLE.COM', 'initialpass')
32
+ kadmin.set_password('newuser@EXAMPLE.COM', 'betterpass')
33
+ kadmin.delete_principal('newuser@EXAMPLE.COM')
34
+ end
35
+
36
+ # Contexts
37
+ ctx = Kerberos::Krb5::Context.new # standard context
38
+ ctx = Kerberos::Krb5::Context.new(profile: '/etc/krb5.conf') # or use a profile
39
+ ctx = Kerberos::Krb5::Context.new(secure: true) # or use a secure context
40
+ ctx.close
41
+ ```
3
42
 
4
43
  # Requirements
5
44
 
@@ -91,6 +130,19 @@ If you make changes to the Ruby code or C extensions:
91
130
  podman-compose run --rm rkerberos-test
92
131
  ```
93
132
 
133
+ Alternatively, you can just run containerized tests via the `spec:compose`
134
+ Rake task. This task runs the same containerized workflow used above and
135
+ prefers `podman-compose` with a `docker-compose` fallback.
136
+
137
+ ```bash
138
+ # build image and run RSpec inside the test container
139
+ rake spec:compose
140
+ # skip the build step by passing a positional or named argument:
141
+ # (equivalent forms)
142
+ rake spec:compose[true]
143
+ rake "spec:compose[fast=true]"
144
+ ```
145
+
94
146
  The test environment includes:
95
147
  - MIT Kerberos KDC (Key Distribution Center)
96
148
  - OpenLDAP server for directory services
@@ -112,8 +164,8 @@ The test environment includes:
112
164
 
113
165
  # Authors
114
166
  * Daniel Berger
115
- * Dominic Cleal (maintainer)
116
- * Simon Levermann (maintainer)
167
+ * Dominic Cleal
168
+ * Simon Levermann
117
169
 
118
170
  # License
119
171
  rkerberos is distributed under the Artistic-2.0 license.
data/Rakefile CHANGED
@@ -77,6 +77,38 @@ RSpec::Core::RakeTask.new(:spec) do |t|
77
77
  t.pattern = 'spec/**/*_spec.rb'
78
78
  end
79
79
 
80
+ # Run specs inside the project container using podman-compose (or docker-compose).
81
+ namespace :spec do
82
+ desc 'Build test image and run RSpec inside container (podman-compose or docker-compose)'
83
+ task :compose, [:fast] do |t, args|
84
+ # allow either positional or named argument (e.g. "fast=true")
85
+ fast = args[:fast]
86
+ if fast && fast.include?("=")
87
+ k,v = fast.split("=",2)
88
+ fast = v if k == 'fast'
89
+ end
90
+ fast = true if fast == 'true'
91
+
92
+ compose = `which podman-compose`.strip
93
+ compose = 'docker-compose' if compose.empty?
94
+
95
+ if fast
96
+ puts "Using #{compose} to run containerized specs (fast)..."
97
+ else
98
+ puts "Using #{compose} to run containerized specs..."
99
+ end
100
+
101
+ FileUtils.rm_rf('Gemfile.lock')
102
+ begin
103
+ sh "#{compose} build --no-cache rkerberos-test" unless fast
104
+ sh "#{compose} run --rm rkerberos-test"
105
+ ensure
106
+ # redirect stderr so missing-container messages don't appear
107
+ sh "#{compose} down -v 2>/dev/null" rescue nil
108
+ end
109
+ end
110
+ end
111
+
80
112
  # Clean up afterwards
81
113
  Rake::Task[:spec].enhance do
82
114
  Rake::Task[:clean].invoke
@@ -57,10 +57,17 @@ static VALUE rkrb5_ccache_initialize(int argc, VALUE* argv, VALUE self){
57
57
 
58
58
  rb_scan_args(argc, argv, "02", &v_principal, &v_name);
59
59
 
60
- // Convert the principal name to a principal object
61
- if(RTEST(v_principal)){
60
+ if(RTEST(v_principal))
62
61
  Check_Type(v_principal, T_STRING);
63
62
 
63
+ // Initialize the context
64
+ kerror = krb5_init_context(&ptr->ctx);
65
+
66
+ if(kerror)
67
+ rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
68
+
69
+ // Convert the principal name to a principal object
70
+ if(RTEST(v_principal)){
64
71
  kerror = krb5_parse_name(
65
72
  ptr->ctx,
66
73
  StringValueCStr(v_principal),
@@ -71,12 +78,6 @@ static VALUE rkrb5_ccache_initialize(int argc, VALUE* argv, VALUE self){
71
78
  rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
72
79
  }
73
80
 
74
- // Initialize the context
75
- kerror = krb5_init_context(&ptr->ctx);
76
-
77
- if(kerror)
78
- rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
79
-
80
81
  // Set the credentials cache using the default cache if no name is provided
81
82
  if(NIL_P(v_name)){
82
83
  kerror = krb5_cc_default(ptr->ctx, &ptr->ccache);
@@ -1,5 +1,7 @@
1
1
  #include <rkerberos.h>
2
2
 
3
+ #include <profile.h>
4
+
3
5
  VALUE cKrb5Context;
4
6
 
5
7
  // Free function for the Kerberos::Krb5::Context class.
@@ -51,23 +53,76 @@ static VALUE rkrb5_context_close(VALUE self){
51
53
 
52
54
  /*
53
55
  * call-seq:
54
- * Kerberos::Context.new
56
+ * Kerberos::Context.new(options = {})
55
57
  *
56
58
  * Creates and returns a new Kerberos::Context object.
57
59
  *
58
- * This class is not typically instantiated directly, but is used internally
59
- * by the krb5-auth library.
60
+ * The options hash may be one or both of the following keys:
61
+ *
62
+ * :secure => true|false # Use config files only, ignore env variables
63
+ * :profile => '/path/to/krb5.conf' # Use the specified profile file
60
64
  */
61
- static VALUE rkrb5_context_initialize(VALUE self){
65
+ static VALUE rkrb5_context_initialize(int argc, VALUE *argv, VALUE self){
62
66
  RUBY_KRB5_CONTEXT* ptr;
67
+ VALUE v_opts;
68
+ VALUE v_secure, v_profile;
63
69
  krb5_error_code kerror;
64
70
 
65
71
  TypedData_Get_Struct(self, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ptr);
66
72
 
67
- kerror = krb5_init_context(&ptr->ctx);
73
+ rb_scan_args(argc, argv, "01", &v_opts);
74
+
75
+ // Default behavior is a normal context that may respect environment.
76
+ if (NIL_P(v_opts)) {
77
+ kerror = krb5_init_context(&ptr->ctx);
78
+ if(kerror)
79
+ rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
80
+
81
+ return self;
82
+ }
83
+
84
+ Check_Type(v_opts, T_HASH);
85
+
86
+ v_secure = rb_hash_aref2(v_opts, ID2SYM(rb_intern("secure")));
87
+ v_profile = rb_hash_aref2(v_opts, ID2SYM(rb_intern("profile")));
88
+
89
+ /*
90
+ * If a profile path is supplied, load it via profile_init_path() and
91
+ * create a context from that profile. The KRB5_INIT_CONTEXT_SECURE flag
92
+ * is used when the :secure option is truthy.
93
+ */
94
+ if (!NIL_P(v_profile)){
95
+ Check_Type(v_profile, T_STRING);
96
+
97
+ const char *profile_path = StringValueCStr(v_profile);
98
+ profile_t profile = NULL;
99
+ long pres = profile_init_path(profile_path, &profile);
100
+
101
+ if(pres != 0)
102
+ rb_raise(cKrb5Exception, "profile_init_path: %ld", pres);
103
+
104
+ krb5_flags flags = RTEST(v_secure) ? KRB5_INIT_CONTEXT_SECURE : 0;
105
+ kerror = krb5_init_context_profile(profile, flags, &ptr->ctx);
106
+
107
+ profile_release(profile);
108
+
109
+ if(kerror)
110
+ rb_raise(cKrb5Exception, "krb5_init_context_profile: %s", error_message(kerror));
111
+
112
+ return self;
113
+ }
68
114
 
69
- if(kerror)
70
- rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
115
+ // No profile given, choose secure or normal init.
116
+ if (RTEST(v_secure)){
117
+ kerror = krb5_init_secure_context(&ptr->ctx);
118
+ if(kerror)
119
+ rb_raise(cKrb5Exception, "krb5_init_secure_context: %s", error_message(kerror));
120
+ }
121
+ else{
122
+ kerror = krb5_init_context(&ptr->ctx);
123
+ if(kerror)
124
+ rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
125
+ }
71
126
 
72
127
  return self;
73
128
  }
@@ -80,7 +135,7 @@ void Init_context(void){
80
135
  rb_define_alloc_func(cKrb5Context, rkrb5_context_allocate);
81
136
 
82
137
  // Constructor
83
- rb_define_method(cKrb5Context, "initialize", rkrb5_context_initialize, 0);
138
+ rb_define_method(cKrb5Context, "initialize", rkrb5_context_initialize, -1);
84
139
 
85
140
  // Instance Methods
86
141
  rb_define_method(cKrb5Context, "close", rkrb5_context_close, 0);
@@ -142,7 +142,6 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
142
142
  }
143
143
 
144
144
  if(RTEST(v_password)){
145
- #ifdef KADM5_API_VERSION_3
146
145
  kerror = kadm5_init_with_password(
147
146
  ptr->ctx,
148
147
  user,
@@ -154,24 +153,11 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
154
153
  ptr->db_args,
155
154
  &ptr->handle
156
155
  );
157
- #else
158
- kerror = kadm5_init_with_password(
159
- user,
160
- pass,
161
- service,
162
- NULL,
163
- KADM5_STRUCT_VERSION,
164
- KADM5_API_VERSION_2,
165
- ptr->db_args,
166
- &ptr->handle
167
- );
168
- #endif
169
156
 
170
157
  if(kerror)
171
158
  rb_raise(cKadm5Exception, "kadm5_init_with_password: %s", error_message(kerror));
172
159
  }
173
160
  else if(RTEST(v_keytab)){
174
- #ifdef KADM5_API_VERSION_3
175
161
  kerror = kadm5_init_with_skey(
176
162
  ptr->ctx,
177
163
  user,
@@ -183,18 +169,6 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
183
169
  ptr->db_args,
184
170
  &ptr->handle
185
171
  );
186
- #else
187
- kerror = kadm5_init_with_skey(
188
- user,
189
- keytab,
190
- service,
191
- NULL,
192
- KADM5_STRUCT_VERSION,
193
- KADM5_API_VERSION_2,
194
- ptr->db_args,
195
- &ptr->handle
196
- );
197
- #endif
198
172
 
199
173
  if(kerror)
200
174
  rb_raise(cKadm5Exception, "kadm5_init_with_skey: %s", error_message(kerror));
@@ -59,7 +59,7 @@ static VALUE rkadm5_policy_init(VALUE self, VALUE v_options){
59
59
 
60
60
  Check_Type(v_options, T_HASH);
61
61
 
62
- if(RTEST(rb_funcall(v_options, rb_intern("empty?"), 0, 0)))
62
+ if(RTEST(rb_funcall(v_options, rb_intern("empty?"), 0)))
63
63
  rb_raise(rb_eArgError, "no policy options provided");
64
64
 
65
65
  v_name = rb_hash_aref2(v_options, rb_str_new_cstr("name"));
@@ -158,7 +158,6 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
158
158
 
159
159
  krb5_error_code kerror;
160
160
  krb5_get_init_creds_opt* opt;
161
- krb5_creds cred;
162
161
 
163
162
  TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
164
163
 
@@ -247,7 +246,7 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
247
246
 
248
247
  kerror = krb5_get_init_creds_keytab(
249
248
  ptr->ctx,
250
- &cred,
249
+ &ptr->creds,
251
250
  ptr->princ,
252
251
  ptr->keytab,
253
252
  0,
@@ -394,6 +393,110 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
394
393
  return Qtrue;
395
394
  }
396
395
 
396
+ /*
397
+ * call-seq:
398
+ * krb5.authenticate!(user, password, service = nil)
399
+ *
400
+ * Convenience method that: acquires initial credentials via password and
401
+ * immediately verifies those credentials using `verify_init_creds` with
402
+ * AP-REQ verification enabled (ap_req_nofail). This protects against
403
+ * KDC-forging/Zanarotti-style attacks by ensuring the ticket is verified
404
+ * against the KDC before it's treated as authenticated.
405
+ *
406
+ * Returns true on success and raises `Kerberos::Krb5::Exception` on error.
407
+ */
408
+ static VALUE rkrb5_authenticate_bang(int argc, VALUE* argv, VALUE self){
409
+ RUBY_KRB5* ptr;
410
+ VALUE v_user, v_pass, v_service;
411
+ char* user;
412
+ char* pass;
413
+ char* service;
414
+ krb5_error_code kerror;
415
+ krb5_principal server_princ = NULL;
416
+
417
+ TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
418
+
419
+ if(!ptr->ctx)
420
+ rb_raise(cKrb5Exception, "no context has been established");
421
+
422
+ // Require user and password, optional service
423
+ rb_scan_args(argc, argv, "21", &v_user, &v_pass, &v_service);
424
+
425
+ Check_Type(v_user, T_STRING);
426
+ Check_Type(v_pass, T_STRING);
427
+ user = StringValueCStr(v_user);
428
+ pass = StringValueCStr(v_pass);
429
+
430
+ if(NIL_P(v_service)){
431
+ service = NULL;
432
+ }
433
+ else{
434
+ Check_Type(v_service, T_STRING);
435
+ service = StringValueCStr(v_service);
436
+ }
437
+
438
+ // Acquire initial credentials (same as get_init_creds_password)
439
+ kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ);
440
+
441
+ if(kerror)
442
+ rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
443
+
444
+ kerror = krb5_get_init_creds_password(
445
+ ptr->ctx,
446
+ &ptr->creds,
447
+ ptr->princ,
448
+ pass,
449
+ 0,
450
+ NULL,
451
+ 0,
452
+ service,
453
+ NULL
454
+ );
455
+
456
+ if(kerror)
457
+ rb_raise(cKrb5Exception, "krb5_get_init_creds_password: %s", error_message(kerror));
458
+
459
+ /*
460
+ * Try strict verification first (AP-REQ nofail). If strict verification
461
+ * cannot be performed (e.g. missing keytab or other environment issue),
462
+ * fall back to the standard verification so authenticate! remains useful
463
+ * in minimal test environments.
464
+ */
465
+ krb5_verify_init_creds_opt vicopt;
466
+ krb5_error_code kerror_strict = 0;
467
+
468
+ krb5_verify_init_creds_opt_init(&vicopt);
469
+ krb5_verify_init_creds_opt_set_ap_req_nofail(&vicopt, TRUE);
470
+
471
+ // If caller supplied a service principal string, use it for verification.
472
+ if(service){
473
+ kerror = krb5_parse_name(ptr->ctx, service, &server_princ);
474
+
475
+ if(kerror)
476
+ rb_raise(cKrb5Exception, "krb5_parse_name(service): %s", error_message(kerror));
477
+ }
478
+
479
+ // First, attempt strict verification
480
+ kerror = krb5_verify_init_creds(ptr->ctx, &ptr->creds, server_princ, NULL, NULL, &vicopt);
481
+
482
+ if(kerror){
483
+ /* strict verification failed — try a best-effort standard verify */
484
+ kerror_strict = kerror;
485
+ kerror = krb5_verify_init_creds(ptr->ctx, &ptr->creds, server_princ, NULL, NULL, NULL);
486
+ if(kerror){
487
+ if(server_princ)
488
+ krb5_free_principal(ptr->ctx, server_princ);
489
+ /* raise the original strict-verification error to inform caller */
490
+ rb_raise(cKrb5Exception, "krb5_verify_init_creds: %s", error_message(kerror_strict));
491
+ }
492
+ }
493
+
494
+ if(server_princ)
495
+ krb5_free_principal(ptr->ctx, server_princ);
496
+
497
+ return Qtrue;
498
+ }
499
+
397
500
  /*
398
501
  * call-seq:
399
502
  * krb5.close
@@ -518,6 +621,88 @@ static VALUE rkrb5_get_permitted_enctypes(VALUE self){
518
621
  return v_enctypes;
519
622
  }
520
623
 
624
+ /*
625
+ * call-seq:
626
+ * krb5.verify_init_creds(server = nil, keytab = nil, ccache = nil)
627
+ *
628
+ * Verifies the initial credentials currently stored in the internal
629
+ * credentials structure. Optionally a server principal string, a
630
+ * `Kerberos::Krb5::Keytab` and/or a `Kerberos::Krb5::CredentialsCache` may
631
+ * be supplied to influence verification. Returns true on success and raises
632
+ * `Kerberos::Krb5::Exception` on error.
633
+ */
634
+ static VALUE rkrb5_verify_init_creds(int argc, VALUE* argv, VALUE self){
635
+ RUBY_KRB5* ptr;
636
+ VALUE v_server, v_keytab, v_ccache;
637
+ krb5_error_code kerror;
638
+ krb5_principal server_princ = NULL;
639
+ RUBY_KRB5_KEYTAB* ktptr = NULL;
640
+ RUBY_KRB5_CCACHE* ccptr = NULL;
641
+ krb5_keytab keytab = NULL;
642
+ krb5_ccache *ccache_ptr = NULL;
643
+
644
+ rb_scan_args(argc, argv, "03", &v_server, &v_keytab, &v_ccache);
645
+
646
+ TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
647
+
648
+ if(!ptr->ctx)
649
+ rb_raise(cKrb5Exception, "no context has been established");
650
+
651
+ // Validate argument types first so callers get TypeError before other errors
652
+ if(!NIL_P(v_server)){
653
+ Check_Type(v_server, T_STRING);
654
+ }
655
+
656
+ if(!NIL_P(v_keytab)){
657
+ // Will raise TypeError if object isn't the expected Keytab typed data
658
+ TypedData_Get_Struct(v_keytab, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ktptr);
659
+ keytab = ktptr->keytab;
660
+ }
661
+
662
+ if(!NIL_P(v_ccache)){
663
+ // Will raise TypeError if object isn't the expected CCache typed data
664
+ TypedData_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, &rkrb5_ccache_data_type, ccptr);
665
+ ccache_ptr = &ccptr->ccache;
666
+ }
667
+
668
+ // Ensure we have credentials to verify (check after validating args)
669
+ if(ptr->creds.client == NULL)
670
+ rb_raise(cKrb5Exception, "no credentials have been acquired");
671
+
672
+ // Optional server principal (parse after context & arg validation)
673
+ if(!NIL_P(v_server)){
674
+ kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_server), &server_princ);
675
+ if(kerror)
676
+ rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
677
+ }
678
+
679
+ kerror = krb5_verify_init_creds(ptr->ctx, &ptr->creds, server_princ, keytab, ccache_ptr, NULL);
680
+
681
+ if(server_princ)
682
+ krb5_free_principal(ptr->ctx, server_princ);
683
+
684
+ if(kerror)
685
+ rb_raise(cKrb5Exception, "krb5_verify_init_creds: %s", error_message(kerror));
686
+
687
+ /* If the caller supplied a CredentialsCache object, store the verified
688
+ credentials there so Ruby-level callers can inspect the cache. */
689
+ if(ccache_ptr && *ccache_ptr){
690
+ krb5_error_code k2;
691
+
692
+ k2 = krb5_cc_initialize(ptr->ctx, *ccache_ptr, ptr->creds.client);
693
+
694
+ if(k2)
695
+ rb_raise(cKrb5Exception, "krb5_cc_initialize: %s", error_message(k2));
696
+
697
+ k2 = krb5_cc_store_cred(ptr->ctx, *ccache_ptr, &ptr->creds);
698
+
699
+ if(k2)
700
+ rb_raise(cKrb5Exception, "krb5_cc_store_cred: %s", error_message(k2));
701
+ }
702
+
703
+ return Qtrue;
704
+ }
705
+
521
706
  void Init_rkerberos(void){
522
707
  mKerberos = rb_define_module("Kerberos");
523
708
  cKrb5 = rb_define_class_under(mKerberos, "Krb5", rb_cObject);
@@ -530,6 +715,7 @@ void Init_rkerberos(void){
530
715
  rb_define_method(cKrb5, "initialize", rkrb5_initialize, 0);
531
716
 
532
717
  // Krb5 Methods
718
+ rb_define_method(cKrb5, "authenticate!", rkrb5_authenticate_bang, -1);
533
719
  rb_define_method(cKrb5, "change_password", rkrb5_change_password, 2);
534
720
  rb_define_method(cKrb5, "close", rkrb5_close, 0);
535
721
  rb_define_method(cKrb5, "get_default_realm", rkrb5_get_default_realm, 0);
@@ -538,13 +724,14 @@ void Init_rkerberos(void){
538
724
  rb_define_method(cKrb5, "get_default_principal", rkrb5_get_default_principal, 0);
539
725
  rb_define_method(cKrb5, "get_permitted_enctypes", rkrb5_get_permitted_enctypes, 0);
540
726
  rb_define_method(cKrb5, "set_default_realm", rkrb5_set_default_realm, -1);
727
+ rb_define_method(cKrb5, "verify_init_creds", rkrb5_verify_init_creds, -1);
541
728
 
542
729
  // Aliases
543
730
  rb_define_alias(cKrb5, "default_realm", "get_default_realm");
544
731
  rb_define_alias(cKrb5, "default_principal", "get_default_principal");
545
732
 
546
- /* 0.2.0: The version of the custom rkerberos library */
547
- rb_define_const(cKrb5, "VERSION", rb_str_new2("0.2.0"));
733
+ /* 0.2.1: The version of the custom rkerberos library */
734
+ rb_define_const(cKrb5, "VERSION", rb_str_new2("0.2.1"));
548
735
 
549
736
  // Encoding type constants
550
737
 
@@ -20,6 +20,8 @@ extern "C" {
20
20
 
21
21
  // Make the ccache data type visible to other C files
22
22
  extern const rb_data_type_t rkrb5_ccache_data_type;
23
+ // Make the keytab data type visible to other C files
24
+ extern const rb_data_type_t rkrb5_keytab_data_type;
23
25
 
24
26
  #ifdef __cplusplus
25
27
  }
data/rkerberos.gemspec CHANGED
@@ -2,20 +2,17 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'rkerberos'
5
- spec.version = '0.2.0'
5
+ spec.version = '0.2.1'
6
6
  spec.authors = ['Daniel Berger', 'Dominic Cleal', 'Simon Levermann']
7
7
  spec.license = 'Artistic-2.0'
8
8
  spec.email = ['djberg96@gmail.com', 'dominic@cleal.org', 'simon-rubygems@slevermann.de']
9
- spec.homepage = 'http://github.com/domcleal/rkerberos'
9
+ spec.homepage = 'http://github.com/rkerberos/rkerberos'
10
10
  spec.summary = 'A Ruby interface for the the Kerberos library'
11
11
  spec.test_files = Dir['spec/**/*_spec.rb']
12
12
  spec.extensions = ['ext/rkerberos/extconf.rb']
13
- spec.files = `git ls-files`.split("\n").reject { |f| f.include?('git') }
14
-
15
- spec.extra_rdoc_files = ['README.md', 'CHANGES', 'MANIFEST', 'LICENSE'] + Dir['ext/rkerberos/*.c']
16
-
17
- spec.add_dependency('rake-compiler')
13
+ spec.files = Dir['**/*'].grep_v(%r{\A(?:\.git|docker|Dockerfile)})
18
14
 
15
+ spec.add_development_dependency('rake-compiler')
19
16
  spec.add_development_dependency('rspec', '>= 3.0')
20
17
  spec.add_development_dependency('net-ldap')
21
18
 
@@ -23,4 +20,16 @@ Gem::Specification.new do |spec|
23
20
  The rkerberos library is an interface for the Kerberos 5 network
24
21
  authentication protocol. It wraps the Kerberos C API.
25
22
  EOF
23
+
24
+ spec.metadata = {
25
+ 'homepage_uri' => 'https://github.com/rkerberos/rkerberos',
26
+ 'bug_tracker_uri' => 'https://github.com/rkerberos/rkerberos/issues',
27
+ 'changelog_uri' => 'https://github.com/rkerberos/rkerberos/blob/main/CHANGES.md',
28
+ 'documentation_uri' => 'https://github.com/rkerberos/rkerberos/wiki',
29
+ 'source_code_uri' => 'https://github.com/rkerberos/rkerberos',
30
+ 'wiki_uri' => 'https://github.com/rkerberos/rkerberos/wiki',
31
+ 'github_repo' => 'https://github.com/djberg96/rkerberos',
32
+ 'funding_uri' => 'https://github.com/sponsors/rkerberos',
33
+ 'rubygems_mfa_required' => 'true'
34
+ }
26
35
  end
data/spec/context_spec.rb CHANGED
@@ -18,6 +18,42 @@ RSpec.describe Kerberos::Krb5::Context do
18
18
  end
19
19
  end
20
20
 
21
+ describe 'constructor options' do
22
+ it 'accepts secure: true to use a secure context' do
23
+ expect { described_class.new(secure: true) }.not_to raise_error
24
+ end
25
+
26
+ it 'accepts a profile path via :profile' do
27
+ profile_path = ENV['KRB5_CONFIG'] || '/etc/krb5.conf'
28
+ expect(File).to exist(profile_path)
29
+ expect { described_class.new(profile: profile_path) }.not_to raise_error
30
+ end
31
+
32
+ it 'validates profile argument type' do
33
+ expect { described_class.new(profile: 123) }.to raise_error(TypeError)
34
+ end
35
+
36
+ it 'ignores environment when secure: true' do
37
+ begin
38
+ orig = ENV['KRB5_CONFIG']
39
+ ENV['KRB5_CONFIG'] = '/no/such/file'
40
+ expect { described_class.new(secure: true) }.not_to raise_error
41
+ ensure
42
+ ENV['KRB5_CONFIG'] = orig
43
+ end
44
+ end
45
+
46
+ it 'accepts secure: true together with profile' do
47
+ profile_path = ENV['KRB5_CONFIG'] || '/etc/krb5.conf'
48
+ expect(File).to exist(profile_path)
49
+
50
+ ctx = nil
51
+ expect { ctx = described_class.new(secure: true, profile: profile_path) }.not_to raise_error
52
+ expect(ctx).to be_a(described_class)
53
+ expect { ctx.close }.not_to raise_error
54
+ end
55
+ end
56
+
21
57
  after(:each) do
22
58
  context.close
23
59
  end
data/spec/krb5_spec.rb CHANGED
@@ -3,6 +3,8 @@
3
3
 
4
4
  require 'rkerberos'
5
5
  require 'open3'
6
+ require 'pty'
7
+ require 'expect'
6
8
 
7
9
  RSpec.describe Kerberos::Krb5 do
8
10
  before(:all) do
@@ -10,6 +12,7 @@ RSpec.describe Kerberos::Krb5 do
10
12
  Open3.popen3('klist') { |_, _, stderr| @cache_found = false unless stderr.gets.nil? }
11
13
  @krb5_conf = ENV['KRB5_CONFIG'] || '/etc/krb5.conf'
12
14
  @realm = IO.read(@krb5_conf).split("\n").grep(/default_realm/).first.split('=').last.lstrip.chomp
15
+
13
16
  end
14
17
 
15
18
  subject(:krb5) { described_class.new }
@@ -18,7 +21,7 @@ RSpec.describe Kerberos::Krb5 do
18
21
  let(:service) { 'kadmin/admin' }
19
22
 
20
23
  it 'has the correct version constant' do
21
- expect(Kerberos::Krb5::VERSION).to eq('0.2.0')
24
+ expect(Kerberos::Krb5::VERSION).to eq('0.2.1')
22
25
  end
23
26
 
24
27
  it 'accepts a block and yields itself' do
@@ -44,4 +47,107 @@ RSpec.describe Kerberos::Krb5 do
44
47
  expect(krb5.method(:default_realm)).to eq(krb5.method(:get_default_realm))
45
48
  end
46
49
  end
50
+
51
+ describe '#verify_init_creds' do
52
+ # Some KDC setups may not correctly set the initial password during
53
+ # entrypoint startup; enforce it here via the admin API so the test is
54
+ # deterministic.
55
+ before do
56
+ user = "testuser1@#{@realm}"
57
+ Kerberos::Kadm5.new(
58
+ principal: ENV.fetch('KRB5_ADMIN_PRINCIPAL', 'admin/admin@EXAMPLE.COM'),
59
+ password: ENV.fetch('KRB5_ADMIN_PASSWORD', 'adminpassword')
60
+ ) do |kadmin|
61
+ kadmin.set_password(user, 'changeme')
62
+ end
63
+ end
64
+
65
+ it 'responds to verify_init_creds' do
66
+ expect(krb5).to respond_to(:verify_init_creds)
67
+ end
68
+
69
+ it 'raises when no credentials have been acquired' do
70
+ expect { krb5.verify_init_creds }.to raise_error(Kerberos::Krb5::Exception)
71
+ end
72
+
73
+ it 'validates argument types' do
74
+ expect { krb5.verify_init_creds(true) }.to raise_error(TypeError)
75
+ expect { krb5.verify_init_creds(nil, true) }.to raise_error(TypeError)
76
+ expect { krb5.verify_init_creds(nil, nil, true) }.to raise_error(TypeError)
77
+ end
78
+
79
+ it 'verifies credentials obtained via password' do
80
+ krb5.get_init_creds_password(user, 'changeme')
81
+ expect(krb5.verify_init_creds).to be true
82
+ end
83
+
84
+ it 'accepts a server principal string' do
85
+ krb5.get_init_creds_password(user, 'changeme')
86
+ expect(krb5.verify_init_creds("kadmin/admin@#{@realm}")).to be true
87
+ end
88
+
89
+ it 'accepts a Keytab object' do
90
+ krb5.get_init_creds_password(user, 'changeme')
91
+ kt = Kerberos::Krb5::Keytab.new
92
+ expect(krb5.verify_init_creds(nil, kt)).to be true
93
+ end
94
+
95
+ it 'stores additional credentials in provided CredentialsCache' do
96
+ ccache = Kerberos::Krb5::CredentialsCache.new
97
+ krb5.get_init_creds_password(user, 'changeme')
98
+ expect(krb5.verify_init_creds(nil, nil, ccache)).to be true
99
+ expect(ccache.primary_principal).to be_a(String)
100
+ expect(ccache.primary_principal).to include('@')
101
+ end
102
+
103
+ it 'provides authenticate! which acquires and verifies (Zanarotti mitigation)' do
104
+ expect(krb5).to respond_to(:authenticate!)
105
+ expect(krb5.authenticate!(user, 'changeme')).to be true
106
+ expect(krb5.verify_init_creds).to be true
107
+ end
108
+
109
+ it 'accepts an optional service argument' do
110
+ expect { krb5.authenticate!(user, 'changeme', 'kadmin/changepw') }.not_to raise_error
111
+ expect(krb5.verify_init_creds).to be true
112
+ end
113
+
114
+ it 'validates argument types for authenticate!' do
115
+ expect { krb5.authenticate!(true, true) }.to raise_error(TypeError)
116
+ end
117
+ end
118
+
119
+ describe '#get_init_creds_keytab' do
120
+ before(:each) do
121
+ @kt_file = File.join(Dir.tmpdir, "test_get_init_creds_#{Process.pid}_#{rand(10000)}.keytab")
122
+
123
+ PTY.spawn('ktutil') do |reader, writer, _|
124
+ reader.expect(/ktutil:\s+/)
125
+ writer.puts("add_entry -password -p testuser1@#{@realm} -k 1 -e aes128-cts-hmac-sha1-96")
126
+ reader.expect(/Password for #{Regexp.quote("testuser1@#{@realm}")}:\s+/)
127
+ writer.puts('changeme')
128
+ reader.expect(/ktutil:\s+/)
129
+ writer.puts("wkt #{@kt_file}")
130
+ reader.expect(/ktutil:\s+/)
131
+ writer.puts('quit')
132
+ end
133
+ end
134
+
135
+ it 'responds to get_init_creds_keytab' do
136
+ expect(krb5).to respond_to(:get_init_creds_keytab)
137
+ end
138
+
139
+ it 'acquires credentials for a principal from a supplied keytab file' do
140
+ kt_name = "FILE:#{@kt_file}"
141
+ expect { krb5.get_init_creds_keytab(user, kt_name) }.not_to raise_error
142
+ expect(krb5.verify_init_creds).to be true
143
+ end
144
+
145
+ it 'accepts a CredentialsCache to receive credentials' do
146
+ ccache = Kerberos::Krb5::CredentialsCache.new
147
+ kt_name = "FILE:#{@kt_file}"
148
+ expect { krb5.get_init_creds_keytab(user, kt_name, nil, ccache) }.not_to raise_error
149
+ expect(ccache.primary_principal).to be_a(String)
150
+ expect(ccache.primary_principal).to include('@')
151
+ end
152
+ end
47
153
  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.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Berger
@@ -18,7 +18,7 @@ dependencies:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0'
21
- type: :runtime
21
+ type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
@@ -63,34 +63,14 @@ email:
63
63
  executables: []
64
64
  extensions:
65
65
  - ext/rkerberos/extconf.rb
66
- extra_rdoc_files:
67
- - CHANGES
68
- - LICENSE
69
- - MANIFEST
70
- - README.md
71
- - ext/rkerberos/ccache.c
72
- - ext/rkerberos/config.c
73
- - ext/rkerberos/context.c
74
- - ext/rkerberos/kadm5.c
75
- - ext/rkerberos/keytab.c
76
- - ext/rkerberos/keytab_entry.c
77
- - ext/rkerberos/policy.c
78
- - ext/rkerberos/principal.c
79
- - ext/rkerberos/rkerberos.c
66
+ extra_rdoc_files: []
80
67
  files:
81
- - CHANGES
82
- - Dockerfile
68
+ - CHANGES.md
83
69
  - Gemfile
84
70
  - LICENSE
85
- - MANIFEST
71
+ - MANIFEST.md
86
72
  - README.md
87
73
  - Rakefile
88
- - docker-compose.yml
89
- - docker/Dockerfile.kdc
90
- - docker/docker-entrypoint.sh
91
- - docker/kadm5.acl
92
- - docker/kdc.conf
93
- - docker/krb5.conf
94
74
  - ext/rkerberos/ccache.c
95
75
  - ext/rkerberos/config.c
96
76
  - ext/rkerberos/context.c
@@ -112,10 +92,19 @@ files:
112
92
  - spec/krb5_spec.rb
113
93
  - spec/policy_spec.rb
114
94
  - spec/principal_spec.rb
115
- homepage: http://github.com/domcleal/rkerberos
95
+ homepage: http://github.com/rkerberos/rkerberos
116
96
  licenses:
117
97
  - Artistic-2.0
118
- metadata: {}
98
+ metadata:
99
+ homepage_uri: https://github.com/rkerberos/rkerberos
100
+ bug_tracker_uri: https://github.com/rkerberos/rkerberos/issues
101
+ changelog_uri: https://github.com/rkerberos/rkerberos/blob/main/CHANGES.md
102
+ documentation_uri: https://github.com/rkerberos/rkerberos/wiki
103
+ source_code_uri: https://github.com/rkerberos/rkerberos
104
+ wiki_uri: https://github.com/rkerberos/rkerberos/wiki
105
+ github_repo: https://github.com/djberg96/rkerberos
106
+ funding_uri: https://github.com/sponsors/rkerberos
107
+ rubygems_mfa_required: 'true'
119
108
  rdoc_options: []
120
109
  require_paths:
121
110
  - lib
@@ -130,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
119
  - !ruby/object:Gem::Version
131
120
  version: '0'
132
121
  requirements: []
133
- rubygems_version: 4.0.6
122
+ rubygems_version: 4.0.3
134
123
  specification_version: 4
135
124
  summary: A Ruby interface for the the Kerberos library
136
125
  test_files:
data/Dockerfile DELETED
@@ -1,42 +0,0 @@
1
- # Dockerfile for rkerberos Ruby gem testing
2
- FROM ruby:3.4
3
-
4
- # Install MIT Kerberos, KDC, admin server, and build tools
5
- RUN apt-get update && \
6
- apt-get install -y --no-install-recommends \
7
- libkrb5-dev krb5-user krb5-kdc krb5-admin-server rake build-essential && \
8
- rm -rf /var/lib/apt/lists/*
9
-
10
- # Set up a working directory
11
- WORKDIR /app
12
-
13
- # Set admin credentials for tests (matches docker-compose.yml)
14
- ENV KRB5_ADMIN_PRINCIPAL=admin/admin@EXAMPLE.COM
15
- ENV KRB5_ADMIN_PASSWORD=adminpassword
16
-
17
- # Copy the gemspec and Gemfile for dependency installation
18
- COPY Gemfile rkerberos.gemspec ./
19
-
20
-
21
- # Install gem dependencies and RSpec
22
- RUN bundle install && gem install rspec
23
-
24
-
25
- # Create a more complete krb5.conf for testing (with kadmin support)
26
- RUN echo "[libdefaults]\n default_realm = EXAMPLE.COM\n dns_lookup_realm = false\n dns_lookup_kdc = false\n ticket_lifetime = 24h\n renew_lifetime = 7d\n forwardable = true\n[realms]\n EXAMPLE.COM = {\n kdc = kerberos-kdc\n admin_server = kerberos-kdc\n default_domain = example.com\n }\n[domain_realm]\n .example.com = EXAMPLE.COM\n example.com = EXAMPLE.COM\n[kadmin]\n default_keys = des-cbc-crc:normal des-cbc-md5:normal aes256-cts:normal aes128-cts:normal rc4-hmac:normal\n admin_server = kerberos-kdc\n" > /etc/krb5.conf
27
-
28
-
29
- # Create a minimal KDC and admin server config, and a permissive ACL for kadmin
30
- RUN mkdir -p /etc/krb5kdc && \
31
- echo "[kdcdefaults]\n kdc_ports = 88\n[kdc]\n profile = /etc/krb5.conf\n" > /etc/krb5kdc/kdc.conf && \
32
- echo "admin/admin@EXAMPLE.COM *" > /etc/krb5kdc/kadm5.acl
33
-
34
-
35
- # Copy the rest of the code
36
- COPY . .
37
-
38
- # Compile the C extension
39
- RUN rake compile
40
-
41
- # Run RSpec tests
42
- CMD ["bundle", "exec", "rspec"]
@@ -1,16 +0,0 @@
1
- FROM debian:bullseye
2
-
3
- RUN apt-get update && \
4
- apt-get install -y krb5-kdc krb5-admin-server krb5-user krb5-kdc-ldap ldap-utils expect && \
5
- rm -rf /var/lib/apt/lists/*
6
-
7
- # Copy configuration files
8
- COPY krb5.conf /etc/krb5.conf
9
- COPY kdc.conf /etc/krb5kdc/kdc.conf
10
- COPY kadm5.acl /etc/krb5kdc/kadm5.acl
11
-
12
- # Copy entrypoint
13
- COPY docker-entrypoint.sh /docker-entrypoint.sh
14
- RUN chmod +x /docker-entrypoint.sh
15
-
16
- ENTRYPOINT ["/docker-entrypoint.sh"]
@@ -1,23 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Initialize KDC DB if not already present
5
- if [ ! -f /etc/krb5kdc/.k5.EXAMPLE.COM ]; then
6
- printf "masterpassword\nmasterpassword\n" | krb5_newrealm
7
- kadmin.local -q "addprinc -pw adminpassword admin/admin"
8
- fi
9
-
10
- # Create standard test principals for keytab/credential cache tests
11
- kadmin.local -q "addprinc -pw changeme testuser1@EXAMPLE.COM"
12
- kadmin.local -q "addprinc -pw changeme zztop@EXAMPLE.COM"
13
- kadmin.local -q "addprinc -pw changeme martymcfly@EXAMPLE.COM"
14
- kadmin.local -q "ktadd -k /etc/krb5.keytab testuser1@EXAMPLE.COM"
15
- kadmin.local -q "ktadd -k /etc/krb5.keytab zztop@EXAMPLE.COM"
16
- kadmin.local -q "ktadd -k /etc/krb5.keytab martymcfly@EXAMPLE.COM"
17
-
18
- # Start KDC and admin server
19
- krb5kdc
20
- kadmind
21
-
22
- # Keep container running
23
- trap : TERM INT; sleep infinity & wait
data/docker/kadm5.acl DELETED
@@ -1 +0,0 @@
1
- admin/admin@EXAMPLE.COM *
data/docker/kdc.conf DELETED
@@ -1,13 +0,0 @@
1
- [kdcdefaults]
2
- kdc_ports = 88
3
-
4
- [realms]
5
- EXAMPLE.COM = {
6
- admin_keytab = /etc/krb5kdc/kadm5.keytab
7
- acl_file = /etc/krb5kdc/kadm5.acl
8
- dict_file = /usr/share/dict/words
9
- key_stash_file = /etc/krb5kdc/.k5.EXAMPLE.COM
10
- kdc_ports = 88
11
- max_life = 10h 0m 0s
12
- max_renewable_life = 7d 0h 0m 0s
13
- }
data/docker/krb5.conf DELETED
@@ -1,14 +0,0 @@
1
- [libdefaults]
2
- default_realm = EXAMPLE.COM
3
- dns_lookup_realm = false
4
- dns_lookup_kdc = false
5
-
6
- [realms]
7
- EXAMPLE.COM = {
8
- kdc = kerberos-kdc
9
- admin_server = kerberos-kdc
10
- }
11
-
12
- [domain_realm]
13
- .example.com = EXAMPLE.COM
14
- example.com = EXAMPLE.COM
data/docker-compose.yml DELETED
@@ -1,44 +0,0 @@
1
- version: '3.8'
2
- services:
3
- kerberos-kdc:
4
- build:
5
- context: ./docker
6
- dockerfile: Dockerfile.kdc
7
- container_name: kerberos-kdc
8
- ports:
9
- - "1088:88"
10
- - "1749:749"
11
- volumes:
12
- - krb5-keytab:/etc/krb5.keytab
13
- depends_on:
14
- - ldap
15
-
16
- rkerberos-test:
17
- build: .
18
- container_name: rkerberos-test
19
- environment:
20
- - LANG=C.UTF-8
21
- - KRB5_CONFIG=/etc/krb5.conf
22
- - KRB5_ADMIN_PRINCIPAL=admin/admin@EXAMPLE.COM
23
- - KRB5_ADMIN_PASSWORD=adminpassword
24
- # LDAP test variables for integration tests
25
- - KRB5_LDAP_PRINCIPAL=admin@ldap
26
- - KRB5_LDAP_PASSWORD=admin
27
- - KRB5_LDAP_DRIVER=ou=People,dc=example,dc=com:foobar:uid
28
- working_dir: /app
29
- depends_on:
30
- - kerberos-kdc
31
-
32
- ldap:
33
- image: osixia/openldap:latest
34
- container_name: ldap
35
- environment:
36
- LDAP_ORGANISATION: "Example Org"
37
- LDAP_DOMAIN: "example.com"
38
- LDAP_BASE_DN: "dc=example,dc=com"
39
- LDAP_ADMIN_PASSWORD: "admin"
40
- ports:
41
- - "1389:389"
42
-
43
- volumes:
44
- krb5-keytab: