rkerberos 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +15 -0
- data/EXAMPLES.md +1015 -0
- data/MANIFEST.md +17 -12
- data/README.md +5 -5
- data/ext/rkerberos/ccache.c +101 -26
- data/ext/rkerberos/config.c +53 -7
- data/ext/rkerberos/context.c +70 -7
- data/ext/rkerberos/kadm5.c +280 -87
- data/ext/rkerberos/keytab.c +210 -64
- data/ext/rkerberos/policy.c +25 -23
- data/ext/rkerberos/principal.c +108 -10
- data/ext/rkerberos/rkerberos.c +229 -28
- data/ext/rkerberos/rkerberos.h +8 -0
- data/rkerberos.gemspec +10 -7
- data/spec/config_spec.rb +33 -0
- data/spec/context_spec.rb +51 -0
- data/spec/credentials_cache_spec.rb +79 -26
- data/spec/kadm5_spec.rb +278 -5
- data/spec/krb5_keytab_spec.rb +224 -20
- data/spec/krb5_spec.rb +131 -20
- data/spec/policy_spec.rb +4 -0
- data/spec/principal_spec.rb +90 -10
- metadata +9 -8
data/ext/rkerberos/rkerberos.c
CHANGED
|
@@ -25,6 +25,13 @@ VALUE rb_hash_aref2(VALUE v_hash, VALUE v_key){
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
// TypedData functions for RUBY_KRB5
|
|
28
|
+
static void rkrb5_typed_mark(void *ptr) {
|
|
29
|
+
if (!ptr) return;
|
|
30
|
+
RUBY_KRB5 *r = (RUBY_KRB5 *)ptr;
|
|
31
|
+
if (r->rb_context != Qnil)
|
|
32
|
+
rb_gc_mark(r->rb_context);
|
|
33
|
+
}
|
|
34
|
+
|
|
28
35
|
static void rkrb5_typed_free(void *ptr) {
|
|
29
36
|
if (!ptr) return;
|
|
30
37
|
RUBY_KRB5 *r = (RUBY_KRB5 *)ptr;
|
|
@@ -34,7 +41,7 @@ static void rkrb5_typed_free(void *ptr) {
|
|
|
34
41
|
krb5_free_cred_contents(r->ctx, &r->creds);
|
|
35
42
|
if (r->princ)
|
|
36
43
|
krb5_free_principal(r->ctx, r->princ);
|
|
37
|
-
if (r->ctx)
|
|
44
|
+
if (r->ctx && r->rb_context == Qnil)
|
|
38
45
|
krb5_free_context(r->ctx);
|
|
39
46
|
free(r);
|
|
40
47
|
}
|
|
@@ -43,9 +50,9 @@ static size_t rkrb5_typed_size(const void *ptr) {
|
|
|
43
50
|
return sizeof(RUBY_KRB5);
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
const rb_data_type_t rkrb5_data_type = {
|
|
47
54
|
"RUBY_KRB5",
|
|
48
|
-
{
|
|
55
|
+
{rkrb5_typed_mark, rkrb5_typed_free, rkrb5_typed_size,},
|
|
49
56
|
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
|
|
50
57
|
};
|
|
51
58
|
|
|
@@ -53,26 +60,63 @@ static const rb_data_type_t rkrb5_data_type = {
|
|
|
53
60
|
static VALUE rkrb5_allocate(VALUE klass){
|
|
54
61
|
RUBY_KRB5* ptr = ALLOC(RUBY_KRB5);
|
|
55
62
|
memset(ptr, 0, sizeof(RUBY_KRB5));
|
|
63
|
+
ptr->rb_context = Qnil;
|
|
56
64
|
return TypedData_Wrap_Struct(klass, &rkrb5_data_type, ptr);
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
/*
|
|
60
68
|
* call-seq:
|
|
61
|
-
* Kerberos::Krb5.new
|
|
69
|
+
* Kerberos::Krb5.new(context: nil)
|
|
62
70
|
*
|
|
63
71
|
* Creates and returns a new Kerberos::Krb5 object. This initializes the
|
|
64
72
|
* context for future method calls on that object.
|
|
73
|
+
*
|
|
74
|
+
* If a +context+ keyword argument is provided, it must be a
|
|
75
|
+
* Kerberos::Krb5::Context object. The context will be borrowed rather than
|
|
76
|
+
* creating a new one internally via krb5_init_context. The caller is
|
|
77
|
+
* responsible for keeping the Context object alive for the lifetime of
|
|
78
|
+
* this Krb5 instance.
|
|
79
|
+
*
|
|
80
|
+
* A block form is also supported. If a block is given, the object is
|
|
81
|
+
* yielded to the block and automatically closed when the block returns.
|
|
65
82
|
*/
|
|
66
|
-
static VALUE rkrb5_initialize(VALUE self){
|
|
83
|
+
static VALUE rkrb5_initialize(int argc, VALUE* argv, VALUE self){
|
|
67
84
|
RUBY_KRB5* ptr;
|
|
85
|
+
VALUE v_opts, v_context;
|
|
86
|
+
ID kw_table[1] = { rb_intern("context") };
|
|
87
|
+
VALUE kw_vals[1];
|
|
68
88
|
krb5_error_code kerror;
|
|
69
89
|
|
|
70
90
|
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
71
91
|
|
|
72
|
-
|
|
92
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
73
93
|
|
|
74
|
-
if(
|
|
75
|
-
|
|
94
|
+
if(NIL_P(v_opts))
|
|
95
|
+
v_opts = rb_hash_new();
|
|
96
|
+
|
|
97
|
+
rb_get_kwargs(v_opts, kw_table, 0, 1, kw_vals);
|
|
98
|
+
v_context = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
99
|
+
|
|
100
|
+
if(!NIL_P(v_context)){
|
|
101
|
+
RUBY_KRB5_CONTEXT* ctx_ptr;
|
|
102
|
+
|
|
103
|
+
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
104
|
+
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
105
|
+
|
|
106
|
+
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ctx_ptr);
|
|
107
|
+
|
|
108
|
+
if(!ctx_ptr->ctx)
|
|
109
|
+
rb_raise(cKrb5Exception, "context is closed");
|
|
110
|
+
|
|
111
|
+
ptr->ctx = ctx_ptr->ctx;
|
|
112
|
+
ptr->rb_context = v_context;
|
|
113
|
+
}
|
|
114
|
+
else{
|
|
115
|
+
kerror = krb5_init_context(&ptr->ctx);
|
|
116
|
+
|
|
117
|
+
if(kerror)
|
|
118
|
+
rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
|
|
119
|
+
}
|
|
76
120
|
|
|
77
121
|
if(rb_block_given_p()){
|
|
78
122
|
rb_ensure(rb_yield, self, rkrb5_close, self);
|
|
@@ -140,7 +184,7 @@ static VALUE rkrb5_set_default_realm(int argc, VALUE* argv, VALUE self){
|
|
|
140
184
|
}
|
|
141
185
|
|
|
142
186
|
/* call-seq:
|
|
143
|
-
* krb5.get_init_creds_keytab(principal
|
|
187
|
+
* krb5.get_init_creds_keytab(principal: nil, keytab: nil, service: nil, ccache: nil)
|
|
144
188
|
*
|
|
145
189
|
* Acquire credentials for +principal+ from +keytab+ using +service+. If
|
|
146
190
|
* no principal is specified, then a principal is derived from the service
|
|
@@ -154,7 +198,10 @@ static VALUE rkrb5_set_default_realm(int argc, VALUE* argv, VALUE self){
|
|
|
154
198
|
*/
|
|
155
199
|
static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
|
|
156
200
|
RUBY_KRB5* ptr;
|
|
157
|
-
VALUE v_user, v_keytab_name, v_service, v_ccache;
|
|
201
|
+
VALUE v_user = Qnil, v_keytab_name = Qnil, v_service = Qnil, v_ccache = Qnil;
|
|
202
|
+
VALUE v_kwargs = Qnil;
|
|
203
|
+
ID kw_table[4] = { rb_intern("principal"), rb_intern("keytab"), rb_intern("service"), rb_intern("ccache") };
|
|
204
|
+
VALUE kw_vals[4];
|
|
158
205
|
char* user;
|
|
159
206
|
char* service;
|
|
160
207
|
char keytab_name[MAX_KEYTAB_NAME_LEN];
|
|
@@ -181,7 +228,16 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
|
|
|
181
228
|
krb5_free_cred_contents(ptr->ctx, &ptr->creds);
|
|
182
229
|
memset(&ptr->creds, 0, sizeof(ptr->creds));
|
|
183
230
|
|
|
184
|
-
rb_scan_args(argc, argv, "
|
|
231
|
+
rb_scan_args(argc, argv, "0:", &v_kwargs);
|
|
232
|
+
|
|
233
|
+
if(NIL_P(v_kwargs))
|
|
234
|
+
v_kwargs = rb_hash_new();
|
|
235
|
+
|
|
236
|
+
rb_get_kwargs(v_kwargs, kw_table, 0, 4, kw_vals);
|
|
237
|
+
if(kw_vals[0] != Qundef) v_user = kw_vals[0];
|
|
238
|
+
if(kw_vals[1] != Qundef) v_keytab_name = kw_vals[1];
|
|
239
|
+
if(kw_vals[2] != Qundef) v_service = kw_vals[2];
|
|
240
|
+
if(kw_vals[3] != Qundef) v_ccache = kw_vals[3];
|
|
185
241
|
|
|
186
242
|
// Validate argument types before allocating opt, so type errors don't leak it.
|
|
187
243
|
if(!NIL_P(v_user))
|
|
@@ -300,7 +356,7 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
|
|
|
300
356
|
*
|
|
301
357
|
* Example:
|
|
302
358
|
*
|
|
303
|
-
* krb5.get_init_creds_password('foo', 'XXXXXX') # Authenticate 'foo' user
|
|
359
|
+
* krb5.get_init_creds_password(principal: 'foo', password: 'XXXXXX') # Authenticate 'foo' user
|
|
304
360
|
* krb5.change_password('XXXXXX', 'YYYYYY') # Change password for 'foo'
|
|
305
361
|
*/
|
|
306
362
|
static VALUE rkrb5_change_password(VALUE self, VALUE v_old, VALUE v_new){
|
|
@@ -378,19 +434,26 @@ static VALUE rkrb5_change_password(VALUE self, VALUE v_old, VALUE v_new){
|
|
|
378
434
|
|
|
379
435
|
/*
|
|
380
436
|
* call-seq:
|
|
381
|
-
* krb5.get_init_creds_password(
|
|
437
|
+
* krb5.get_init_creds_password(principal: nil, password: nil, service: nil, ccache: nil)
|
|
382
438
|
*
|
|
383
|
-
* Authenticates the credentials of +
|
|
439
|
+
* Authenticates the credentials of +principal+ using +password+ against +service+,
|
|
384
440
|
* and has the effect of setting the principal and context internally. This method
|
|
385
441
|
* must typically be called before using other methods.
|
|
442
|
+
*
|
|
443
|
+
* When +ccache+ is given, the acquired credentials will be written into the
|
|
444
|
+
* provided Kerberos::Krb5::CredentialsCache.
|
|
386
445
|
*/
|
|
387
446
|
static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
388
447
|
RUBY_KRB5* ptr;
|
|
389
|
-
VALUE v_user, v_pass, v_service;
|
|
448
|
+
VALUE v_user = Qnil, v_pass = Qnil, v_service = Qnil, v_ccache = Qnil;
|
|
449
|
+
VALUE v_kwargs = Qnil;
|
|
450
|
+
ID kw_table[4] = { rb_intern("principal"), rb_intern("password"), rb_intern("service"), rb_intern("ccache") };
|
|
451
|
+
VALUE kw_vals[4];
|
|
390
452
|
char* user;
|
|
391
453
|
char* pass;
|
|
392
454
|
char* service;
|
|
393
455
|
krb5_error_code kerror;
|
|
456
|
+
krb5_get_init_creds_opt* opt = NULL;
|
|
394
457
|
|
|
395
458
|
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
396
459
|
|
|
@@ -406,7 +469,19 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
406
469
|
krb5_free_cred_contents(ptr->ctx, &ptr->creds);
|
|
407
470
|
memset(&ptr->creds, 0, sizeof(ptr->creds));
|
|
408
471
|
|
|
409
|
-
rb_scan_args(argc, argv, "
|
|
472
|
+
rb_scan_args(argc, argv, "0:", &v_kwargs);
|
|
473
|
+
|
|
474
|
+
if(NIL_P(v_kwargs))
|
|
475
|
+
v_kwargs = rb_hash_new();
|
|
476
|
+
|
|
477
|
+
rb_get_kwargs(v_kwargs, kw_table, 0, 4, kw_vals);
|
|
478
|
+
if(kw_vals[0] != Qundef) v_user = kw_vals[0];
|
|
479
|
+
if(kw_vals[1] != Qundef) v_pass = kw_vals[1];
|
|
480
|
+
if(kw_vals[2] != Qundef) v_service = kw_vals[2];
|
|
481
|
+
if(kw_vals[3] != Qundef) v_ccache = kw_vals[3];
|
|
482
|
+
|
|
483
|
+
if(NIL_P(v_user) || NIL_P(v_pass))
|
|
484
|
+
rb_raise(rb_eArgError, "principal and password are required");
|
|
410
485
|
|
|
411
486
|
Check_Type(v_user, T_STRING);
|
|
412
487
|
Check_Type(v_pass, T_STRING);
|
|
@@ -426,6 +501,21 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
426
501
|
if(kerror)
|
|
427
502
|
rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
|
|
428
503
|
|
|
504
|
+
if(!NIL_P(v_ccache)){
|
|
505
|
+
RUBY_KRB5_CCACHE* ccptr;
|
|
506
|
+
TypedData_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, &rkrb5_ccache_data_type, ccptr);
|
|
507
|
+
|
|
508
|
+
kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt);
|
|
509
|
+
if(kerror)
|
|
510
|
+
rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror));
|
|
511
|
+
|
|
512
|
+
kerror = krb5_get_init_creds_opt_set_out_ccache(ptr->ctx, opt, ccptr->ccache);
|
|
513
|
+
if(kerror){
|
|
514
|
+
krb5_get_init_creds_opt_free(ptr->ctx, opt);
|
|
515
|
+
rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_set_out_ccache: %s", error_message(kerror));
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
429
519
|
kerror = krb5_get_init_creds_password(
|
|
430
520
|
ptr->ctx,
|
|
431
521
|
&ptr->creds,
|
|
@@ -435,9 +525,12 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
435
525
|
NULL,
|
|
436
526
|
0,
|
|
437
527
|
service,
|
|
438
|
-
|
|
528
|
+
opt
|
|
439
529
|
);
|
|
440
530
|
|
|
531
|
+
if(opt)
|
|
532
|
+
krb5_get_init_creds_opt_free(ptr->ctx, opt);
|
|
533
|
+
|
|
441
534
|
if(kerror)
|
|
442
535
|
rb_raise(cKrb5Exception, "krb5_get_init_creds_password: %s", error_message(kerror));
|
|
443
536
|
|
|
@@ -446,7 +539,7 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
446
539
|
|
|
447
540
|
/*
|
|
448
541
|
* call-seq:
|
|
449
|
-
* krb5.authenticate!(
|
|
542
|
+
* krb5.authenticate!(principal:, password:, service: nil)
|
|
450
543
|
*
|
|
451
544
|
* Convenience method that: acquires initial credentials via password and
|
|
452
545
|
* immediately verifies those credentials using `verify_init_creds` with
|
|
@@ -458,7 +551,9 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
458
551
|
*/
|
|
459
552
|
static VALUE rkrb5_authenticate_bang(int argc, VALUE* argv, VALUE self){
|
|
460
553
|
RUBY_KRB5* ptr;
|
|
461
|
-
VALUE v_user, v_pass, v_service;
|
|
554
|
+
VALUE v_kwargs, v_user, v_pass, v_service;
|
|
555
|
+
ID kw_table[3] = { rb_intern("principal"), rb_intern("password"), rb_intern("service") };
|
|
556
|
+
VALUE kw_vals[3];
|
|
462
557
|
char* user;
|
|
463
558
|
char* pass;
|
|
464
559
|
char* service;
|
|
@@ -479,8 +574,15 @@ static VALUE rkrb5_authenticate_bang(int argc, VALUE* argv, VALUE self){
|
|
|
479
574
|
krb5_free_cred_contents(ptr->ctx, &ptr->creds);
|
|
480
575
|
memset(&ptr->creds, 0, sizeof(ptr->creds));
|
|
481
576
|
|
|
482
|
-
|
|
483
|
-
|
|
577
|
+
rb_scan_args(argc, argv, "0:", &v_kwargs);
|
|
578
|
+
|
|
579
|
+
if(NIL_P(v_kwargs))
|
|
580
|
+
v_kwargs = rb_hash_new();
|
|
581
|
+
|
|
582
|
+
rb_get_kwargs(v_kwargs, kw_table, 2, 1, kw_vals);
|
|
583
|
+
v_user = kw_vals[0];
|
|
584
|
+
v_pass = kw_vals[1];
|
|
585
|
+
v_service = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
|
|
484
586
|
|
|
485
587
|
Check_Type(v_user, T_STRING);
|
|
486
588
|
Check_Type(v_pass, T_STRING);
|
|
@@ -580,11 +682,12 @@ static VALUE rkrb5_close(VALUE self){
|
|
|
580
682
|
if(ptr->princ)
|
|
581
683
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
582
684
|
|
|
583
|
-
if(ptr->ctx)
|
|
685
|
+
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
584
686
|
krb5_free_context(ptr->ctx);
|
|
585
687
|
|
|
586
688
|
ptr->ctx = NULL;
|
|
587
689
|
ptr->princ = NULL;
|
|
690
|
+
ptr->rb_context = Qnil;
|
|
588
691
|
|
|
589
692
|
return Qtrue;
|
|
590
693
|
}
|
|
@@ -701,7 +804,7 @@ static VALUE rkrb5_get_permitted_enctypes(VALUE self){
|
|
|
701
804
|
|
|
702
805
|
/*
|
|
703
806
|
* call-seq:
|
|
704
|
-
* krb5.verify_init_creds(server
|
|
807
|
+
* krb5.verify_init_creds(server: nil, keytab: nil, ccache: nil)
|
|
705
808
|
*
|
|
706
809
|
* Verifies the initial credentials currently stored in the internal
|
|
707
810
|
* credentials structure. Optionally a server principal string, a
|
|
@@ -711,7 +814,10 @@ static VALUE rkrb5_get_permitted_enctypes(VALUE self){
|
|
|
711
814
|
*/
|
|
712
815
|
static VALUE rkrb5_verify_init_creds(int argc, VALUE* argv, VALUE self){
|
|
713
816
|
RUBY_KRB5* ptr;
|
|
714
|
-
VALUE v_server, v_keytab, v_ccache;
|
|
817
|
+
VALUE v_server = Qnil, v_keytab = Qnil, v_ccache = Qnil;
|
|
818
|
+
VALUE v_kwargs = Qnil;
|
|
819
|
+
ID kw_table[3] = { rb_intern("server"), rb_intern("keytab"), rb_intern("ccache") };
|
|
820
|
+
VALUE kw_vals[3];
|
|
715
821
|
krb5_error_code kerror;
|
|
716
822
|
krb5_principal server_princ = NULL;
|
|
717
823
|
RUBY_KRB5_KEYTAB* ktptr = NULL;
|
|
@@ -719,7 +825,15 @@ static VALUE rkrb5_verify_init_creds(int argc, VALUE* argv, VALUE self){
|
|
|
719
825
|
krb5_keytab keytab = NULL;
|
|
720
826
|
krb5_ccache *ccache_ptr = NULL;
|
|
721
827
|
|
|
722
|
-
rb_scan_args(argc, argv, "
|
|
828
|
+
rb_scan_args(argc, argv, "0:", &v_kwargs);
|
|
829
|
+
|
|
830
|
+
if(NIL_P(v_kwargs))
|
|
831
|
+
v_kwargs = rb_hash_new();
|
|
832
|
+
|
|
833
|
+
rb_get_kwargs(v_kwargs, kw_table, 0, 3, kw_vals);
|
|
834
|
+
if(kw_vals[0] != Qundef) v_server = kw_vals[0];
|
|
835
|
+
if(kw_vals[1] != Qundef) v_keytab = kw_vals[1];
|
|
836
|
+
if(kw_vals[2] != Qundef) v_ccache = kw_vals[2];
|
|
723
837
|
|
|
724
838
|
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
725
839
|
|
|
@@ -781,6 +895,83 @@ static VALUE rkrb5_verify_init_creds(int argc, VALUE* argv, VALUE self){
|
|
|
781
895
|
return Qtrue;
|
|
782
896
|
}
|
|
783
897
|
|
|
898
|
+
/*
|
|
899
|
+
* call-seq:
|
|
900
|
+
* krb5.get_host_realm(hostname) -> Array
|
|
901
|
+
*
|
|
902
|
+
* Returns an array of realm names associated with +hostname+.
|
|
903
|
+
* Uses the Kerberos library's host-to-realm mapping (krb5.conf
|
|
904
|
+
* [domain_realm] section, DNS lookups, etc.).
|
|
905
|
+
*/
|
|
906
|
+
static VALUE rkrb5_get_host_realm(VALUE self, VALUE v_host){
|
|
907
|
+
RUBY_KRB5* ptr;
|
|
908
|
+
char** realms;
|
|
909
|
+
char** p;
|
|
910
|
+
krb5_error_code kerror;
|
|
911
|
+
|
|
912
|
+
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
913
|
+
|
|
914
|
+
if(!ptr->ctx)
|
|
915
|
+
rb_raise(cKrb5Exception, "no context has been established");
|
|
916
|
+
|
|
917
|
+
Check_Type(v_host, T_STRING);
|
|
918
|
+
|
|
919
|
+
kerror = krb5_get_host_realm(ptr->ctx, StringValueCStr(v_host), &realms);
|
|
920
|
+
|
|
921
|
+
if(kerror)
|
|
922
|
+
rb_raise(cKrb5Exception, "krb5_get_host_realm: %s", error_message(kerror));
|
|
923
|
+
|
|
924
|
+
VALUE v_array = rb_ary_new();
|
|
925
|
+
|
|
926
|
+
for(p = realms; p && *p; p++)
|
|
927
|
+
rb_ary_push(v_array, rb_str_new2(*p));
|
|
928
|
+
|
|
929
|
+
krb5_free_host_realm(ptr->ctx, realms);
|
|
930
|
+
|
|
931
|
+
return v_array;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/*
|
|
935
|
+
* call-seq:
|
|
936
|
+
* krb5.expand_hostname(hostname) -> String
|
|
937
|
+
*
|
|
938
|
+
* Canonicalizes +hostname+ by performing a forward DNS lookup followed
|
|
939
|
+
* by a reverse lookup, returning the canonical hostname.
|
|
940
|
+
*/
|
|
941
|
+
static VALUE rkrb5_expand_hostname(VALUE self, VALUE v_host){
|
|
942
|
+
RUBY_KRB5* ptr;
|
|
943
|
+
char* canonical;
|
|
944
|
+
krb5_error_code kerror;
|
|
945
|
+
|
|
946
|
+
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
947
|
+
|
|
948
|
+
if(!ptr->ctx)
|
|
949
|
+
rb_raise(cKrb5Exception, "no context has been established");
|
|
950
|
+
|
|
951
|
+
Check_Type(v_host, T_STRING);
|
|
952
|
+
|
|
953
|
+
kerror = krb5_expand_hostname(ptr->ctx, StringValueCStr(v_host), &canonical);
|
|
954
|
+
|
|
955
|
+
if(kerror)
|
|
956
|
+
rb_raise(cKrb5Exception, "krb5_expand_hostname: %s", error_message(kerror));
|
|
957
|
+
|
|
958
|
+
VALUE v_result = rb_str_new2(canonical);
|
|
959
|
+
krb5_free_string(ptr->ctx, canonical);
|
|
960
|
+
|
|
961
|
+
return v_result;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/*
|
|
965
|
+
* call-seq:
|
|
966
|
+
* Kerberos::Krb5.thread_safe?
|
|
967
|
+
*
|
|
968
|
+
* Returns true if the Kerberos library was built with multithread support,
|
|
969
|
+
* false otherwise.
|
|
970
|
+
*/
|
|
971
|
+
static VALUE rkrb5_s_thread_safe(VALUE klass){
|
|
972
|
+
return krb5_is_thread_safe() ? Qtrue : Qfalse;
|
|
973
|
+
}
|
|
974
|
+
|
|
784
975
|
void Init_rkerberos(void){
|
|
785
976
|
mKerberos = rb_define_module("Kerberos");
|
|
786
977
|
cKrb5 = rb_define_class_under(mKerberos, "Krb5", rb_cObject);
|
|
@@ -790,7 +981,10 @@ void Init_rkerberos(void){
|
|
|
790
981
|
rb_define_alloc_func(cKrb5, rkrb5_allocate);
|
|
791
982
|
|
|
792
983
|
// Initializers
|
|
793
|
-
rb_define_method(cKrb5, "initialize", rkrb5_initialize,
|
|
984
|
+
rb_define_method(cKrb5, "initialize", rkrb5_initialize, -1);
|
|
985
|
+
|
|
986
|
+
// Singleton Methods
|
|
987
|
+
rb_define_singleton_method(cKrb5, "thread_safe?", rkrb5_s_thread_safe, 0);
|
|
794
988
|
|
|
795
989
|
// Krb5 Methods
|
|
796
990
|
rb_define_method(cKrb5, "authenticate!", rkrb5_authenticate_bang, -1);
|
|
@@ -803,13 +997,20 @@ void Init_rkerberos(void){
|
|
|
803
997
|
rb_define_method(cKrb5, "get_permitted_enctypes", rkrb5_get_permitted_enctypes, 0);
|
|
804
998
|
rb_define_method(cKrb5, "set_default_realm", rkrb5_set_default_realm, -1);
|
|
805
999
|
rb_define_method(cKrb5, "verify_init_creds", rkrb5_verify_init_creds, -1);
|
|
1000
|
+
rb_define_method(cKrb5, "get_host_realm", rkrb5_get_host_realm, 1);
|
|
1001
|
+
rb_define_method(cKrb5, "expand_hostname", rkrb5_expand_hostname, 1);
|
|
806
1002
|
|
|
807
1003
|
// Aliases
|
|
808
1004
|
rb_define_alias(cKrb5, "default_realm", "get_default_realm");
|
|
1005
|
+
rb_define_alias(cKrb5, "default_realm=", "set_default_realm");
|
|
809
1006
|
rb_define_alias(cKrb5, "default_principal", "get_default_principal");
|
|
1007
|
+
rb_define_alias(cKrb5, "host_realm", "get_host_realm");
|
|
1008
|
+
rb_define_alias(cKrb5, "init_creds_password", "get_init_creds_password");
|
|
1009
|
+
rb_define_alias(cKrb5, "init_creds_keytab", "get_init_creds_keytab");
|
|
1010
|
+
rb_define_alias(cKrb5, "permitted_enctypes", "get_permitted_enctypes");
|
|
810
1011
|
|
|
811
|
-
/* 0.
|
|
812
|
-
rb_define_const(cKrb5, "VERSION", rb_str_new2("0.
|
|
1012
|
+
/* 0.3.0: The version of the custom rkerberos library */
|
|
1013
|
+
rb_define_const(cKrb5, "VERSION", rb_str_new2("0.3.0"));
|
|
813
1014
|
|
|
814
1015
|
// Encoding type constants
|
|
815
1016
|
|
data/ext/rkerberos/rkerberos.h
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
// Make the context data type visible to other C files
|
|
10
10
|
extern const rb_data_type_t rkrb5_context_data_type;
|
|
11
|
+
// Make the Krb5 data type visible to other C files
|
|
12
|
+
extern const rb_data_type_t rkrb5_data_type;
|
|
11
13
|
// Make the config data type visible to other C files
|
|
12
14
|
extern const rb_data_type_t rkadm5_config_data_type;
|
|
13
15
|
|
|
@@ -67,6 +69,7 @@ typedef struct {
|
|
|
67
69
|
krb5_creds creds;
|
|
68
70
|
krb5_principal princ;
|
|
69
71
|
krb5_keytab keytab;
|
|
72
|
+
VALUE rb_context;
|
|
70
73
|
} RUBY_KRB5;
|
|
71
74
|
|
|
72
75
|
// Kerberos::Context
|
|
@@ -81,6 +84,7 @@ typedef struct {
|
|
|
81
84
|
krb5_principal princ;
|
|
82
85
|
void* handle;
|
|
83
86
|
char** db_args;
|
|
87
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
84
88
|
} RUBY_KADM5;
|
|
85
89
|
|
|
86
90
|
// Kerberos::Krb5::Keytab::Entry
|
|
@@ -96,23 +100,27 @@ typedef struct {
|
|
|
96
100
|
krb5_context ctx;
|
|
97
101
|
krb5_creds creds;
|
|
98
102
|
krb5_keytab keytab;
|
|
103
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
99
104
|
} RUBY_KRB5_KEYTAB;
|
|
100
105
|
|
|
101
106
|
typedef struct {
|
|
102
107
|
krb5_context ctx;
|
|
103
108
|
krb5_principal principal;
|
|
109
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
104
110
|
} RUBY_KRB5_PRINC;
|
|
105
111
|
|
|
106
112
|
typedef struct {
|
|
107
113
|
krb5_context ctx;
|
|
108
114
|
krb5_ccache ccache;
|
|
109
115
|
krb5_principal principal;
|
|
116
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
110
117
|
} RUBY_KRB5_CCACHE;
|
|
111
118
|
|
|
112
119
|
#ifdef HAVE_KADM5_ADMIN_H
|
|
113
120
|
typedef struct {
|
|
114
121
|
krb5_context ctx;
|
|
115
122
|
kadm5_config_params config;
|
|
123
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
116
124
|
} RUBY_KADM5_CONFIG;
|
|
117
125
|
|
|
118
126
|
typedef struct {
|
data/rkerberos.gemspec
CHANGED
|
@@ -2,15 +2,18 @@ require 'rubygems'
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = 'rkerberos'
|
|
5
|
-
spec.version = '0.
|
|
5
|
+
spec.version = '0.3.0'
|
|
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 = '
|
|
10
|
-
spec.summary = 'A Ruby interface for the
|
|
9
|
+
spec.homepage = 'https://github.com/rkerberos/rkerberos'
|
|
10
|
+
spec.summary = 'A Ruby interface for the Kerberos library'
|
|
11
|
+
spec.required_ruby_version = '>= 3.2'
|
|
11
12
|
spec.test_files = Dir['spec/**/*_spec.rb']
|
|
12
13
|
spec.extensions = ['ext/rkerberos/extconf.rb']
|
|
13
|
-
spec.files = Dir['**/*']
|
|
14
|
+
spec.files = Dir['**/*']
|
|
15
|
+
.select { |file| File.file?(file) }
|
|
16
|
+
.grep_v(%r{\A(?:\.git|docker|Dockerfile|Gemfile\.lock\z|tmp(?:/|\z))|\.gem\z})
|
|
14
17
|
|
|
15
18
|
spec.add_development_dependency('rake-compiler')
|
|
16
19
|
spec.add_development_dependency('rspec', '>= 3.0')
|
|
@@ -22,13 +25,13 @@ Gem::Specification.new do |spec|
|
|
|
22
25
|
EOF
|
|
23
26
|
|
|
24
27
|
spec.metadata = {
|
|
25
|
-
'homepage_uri' => 'https://github.com/rkerberos/rkerberos',
|
|
26
28
|
'bug_tracker_uri' => 'https://github.com/rkerberos/rkerberos/issues',
|
|
27
|
-
'changelog_uri' => 'https://github.com/rkerberos/rkerberos/blob/
|
|
29
|
+
'changelog_uri' => 'https://github.com/rkerberos/rkerberos/blob/master/CHANGES.md',
|
|
28
30
|
'documentation_uri' => 'https://github.com/rkerberos/rkerberos/wiki',
|
|
31
|
+
'homepage_uri' => 'https://github.com/rkerberos/rkerberos',
|
|
29
32
|
'source_code_uri' => 'https://github.com/rkerberos/rkerberos',
|
|
30
33
|
'wiki_uri' => 'https://github.com/rkerberos/rkerberos/wiki',
|
|
31
|
-
'github_repo' => 'https://github.com/
|
|
34
|
+
'github_repo' => 'https://github.com/rkerberos/rkerberos',
|
|
32
35
|
'funding_uri' => 'https://github.com/sponsors/rkerberos',
|
|
33
36
|
'rubygems_mfa_required' => 'true'
|
|
34
37
|
}
|
data/spec/config_spec.rb
CHANGED
|
@@ -11,6 +11,39 @@ 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 'raises TypeError for non-Context context argument' do
|
|
32
|
+
expect { klass.new(context: "bad") }.to raise_error(TypeError)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'raises error for a closed context' do
|
|
36
|
+
ctx = Kerberos::Krb5::Context.new
|
|
37
|
+
ctx.close
|
|
38
|
+
expect { klass.new(context: ctx) }.to raise_error(Kerberos::Krb5::Exception)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'rejects positional option hashes and unknown keywords' do
|
|
42
|
+
expect { klass.new({context: nil}) }.to raise_error(ArgumentError)
|
|
43
|
+
expect { klass.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
14
47
|
describe 'realm' do
|
|
15
48
|
it 'responds to realm' do
|
|
16
49
|
expect(config).to respond_to(:realm)
|
data/spec/context_spec.rb
CHANGED
|
@@ -51,6 +51,57 @@ RSpec.describe Kerberos::Krb5::Context do
|
|
|
51
51
|
expect(ctx).to be_a(described_class)
|
|
52
52
|
expect { ctx.close }.not_to raise_error
|
|
53
53
|
end
|
|
54
|
+
|
|
55
|
+
it 'rejects positional option hashes and unknown keywords' do
|
|
56
|
+
expect { described_class.new({secure: true}) }.to raise_error(ArgumentError)
|
|
57
|
+
expect { described_class.new(unknown: true) }.to raise_error(ArgumentError, /unknown keyword/)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe '#default_realm' do
|
|
62
|
+
it 'responds to default_realm' do
|
|
63
|
+
expect(context).to respond_to(:default_realm)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'returns a string' do
|
|
67
|
+
expect(context.default_realm).to be_a(String)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'returns a non-empty realm' do
|
|
71
|
+
expect(context.default_realm.size).to be > 0
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'raises when context is closed' do
|
|
75
|
+
context.close
|
|
76
|
+
expect { context.default_realm }.to raise_error(Kerberos::Krb5::Exception)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe '#default_realm=' do
|
|
81
|
+
it 'responds to default_realm=' do
|
|
82
|
+
expect(context).to respond_to(:default_realm=)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'can set and read back a custom realm' do
|
|
86
|
+
context.default_realm = 'TEST.REALM'
|
|
87
|
+
expect(context.default_realm).to eq('TEST.REALM')
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'accepts nil to reset to the default' do
|
|
91
|
+
original = context.default_realm
|
|
92
|
+
context.default_realm = 'TEMP.REALM'
|
|
93
|
+
context.default_realm = nil
|
|
94
|
+
expect(context.default_realm).to eq(original)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'raises TypeError for non-string argument' do
|
|
98
|
+
expect { context.default_realm = 123 }.to raise_error(TypeError)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'raises when context is closed' do
|
|
102
|
+
context.close
|
|
103
|
+
expect { context.default_realm = 'X' }.to raise_error(Kerberos::Krb5::Exception)
|
|
104
|
+
end
|
|
54
105
|
end
|
|
55
106
|
|
|
56
107
|
after(:each) do
|