rkerberos 0.2.1 → 0.2.3

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.
@@ -100,7 +100,10 @@ static VALUE rkrb5_get_default_realm(VALUE self){
100
100
  if(kerror)
101
101
  rb_raise(cKrb5Exception, "krb5_get_default_realm: %s", error_message(kerror));
102
102
 
103
- return rb_str_new2(realm);
103
+ VALUE v_realm = rb_str_new2(realm);
104
+ krb5_free_default_realm(ptr->ctx, realm);
105
+
106
+ return v_realm;
104
107
  }
105
108
 
106
109
  /*
@@ -164,18 +167,41 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
164
167
  if(!ptr->ctx)
165
168
  rb_raise(cKrb5Exception, "no context has been established");
166
169
 
170
+ // Free resources from a previous call to avoid leaks on repeated use.
171
+ if(ptr->keytab){
172
+ krb5_kt_close(ptr->ctx, ptr->keytab);
173
+ ptr->keytab = NULL;
174
+ }
175
+
176
+ if(ptr->princ){
177
+ krb5_free_principal(ptr->ctx, ptr->princ);
178
+ ptr->princ = NULL;
179
+ }
180
+
181
+ krb5_free_cred_contents(ptr->ctx, &ptr->creds);
182
+ memset(&ptr->creds, 0, sizeof(ptr->creds));
183
+
184
+ rb_scan_args(argc, argv, "04", &v_user, &v_keytab_name, &v_service, &v_ccache);
185
+
186
+ // Validate argument types before allocating opt, so type errors don't leak it.
187
+ if(!NIL_P(v_user))
188
+ Check_Type(v_user, T_STRING);
189
+
190
+ if(!NIL_P(v_keytab_name))
191
+ Check_Type(v_keytab_name, T_STRING);
192
+
193
+ if(!NIL_P(v_service))
194
+ Check_Type(v_service, T_STRING);
195
+
167
196
  kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt);
168
197
  if(kerror)
169
198
  rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror));
170
199
 
171
- rb_scan_args(argc, argv, "04", &v_user, &v_keytab_name, &v_service, &v_ccache);
172
-
173
200
  // We need the service information for later.
174
201
  if(NIL_P(v_service)){
175
202
  service = NULL;
176
203
  }
177
204
  else{
178
- Check_Type(v_service, T_STRING);
179
205
  service = StringValueCStr(v_service);
180
206
  }
181
207
 
@@ -195,7 +221,6 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
195
221
  }
196
222
  }
197
223
  else{
198
- Check_Type(v_user, T_STRING);
199
224
  user = StringValueCStr(v_user);
200
225
 
201
226
  kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ);
@@ -216,7 +241,6 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
216
241
  }
217
242
  }
218
243
  else{
219
- Check_Type(v_keytab_name, T_STRING);
220
244
  strncpy(keytab_name, StringValueCStr(v_keytab_name), MAX_KEYTAB_NAME_LEN - 1);
221
245
  keytab_name[MAX_KEYTAB_NAME_LEN - 1] = '\0';
222
246
  }
@@ -304,6 +328,9 @@ static VALUE rkrb5_change_password(VALUE self, VALUE v_old, VALUE v_new){
304
328
  if(!ptr->princ)
305
329
  rb_raise(cKrb5Exception, "no principal has been established");
306
330
 
331
+ krb5_free_cred_contents(ptr->ctx, &ptr->creds);
332
+ memset(&ptr->creds, 0, sizeof(ptr->creds));
333
+
307
334
  kerror = krb5_get_init_creds_password(
308
335
  ptr->ctx,
309
336
  &ptr->creds,
@@ -328,8 +355,23 @@ static VALUE rkrb5_change_password(VALUE self, VALUE v_old, VALUE v_new){
328
355
  &result_string
329
356
  );
330
357
 
331
- if(kerror)
358
+ if(kerror){
359
+ krb5_free_data_contents(ptr->ctx, &result_string);
360
+ krb5_free_data_contents(ptr->ctx, &pw_result_string);
332
361
  rb_raise(cKrb5Exception, "krb5_change_password: %s", error_message(kerror));
362
+ }
363
+
364
+ if(pw_result){
365
+ VALUE v_msg = (result_string.length > 0)
366
+ ? rb_str_new(result_string.data, result_string.length)
367
+ : rb_str_new_cstr("password change rejected");
368
+ krb5_free_data_contents(ptr->ctx, &result_string);
369
+ krb5_free_data_contents(ptr->ctx, &pw_result_string);
370
+ rb_raise(cKrb5Exception, "krb5_change_password: %s", StringValueCStr(v_msg));
371
+ }
372
+
373
+ krb5_free_data_contents(ptr->ctx, &result_string);
374
+ krb5_free_data_contents(ptr->ctx, &pw_result_string);
333
375
 
334
376
  return Qtrue;
335
377
  }
@@ -355,6 +397,15 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
355
397
  if(!ptr->ctx)
356
398
  rb_raise(cKrb5Exception, "no context has been established");
357
399
 
400
+ // Free resources from a previous call to avoid leaks on repeated use.
401
+ if(ptr->princ){
402
+ krb5_free_principal(ptr->ctx, ptr->princ);
403
+ ptr->princ = NULL;
404
+ }
405
+
406
+ krb5_free_cred_contents(ptr->ctx, &ptr->creds);
407
+ memset(&ptr->creds, 0, sizeof(ptr->creds));
408
+
358
409
  rb_scan_args(argc, argv, "21", &v_user, &v_pass, &v_service);
359
410
 
360
411
  Check_Type(v_user, T_STRING);
@@ -419,6 +470,15 @@ static VALUE rkrb5_authenticate_bang(int argc, VALUE* argv, VALUE self){
419
470
  if(!ptr->ctx)
420
471
  rb_raise(cKrb5Exception, "no context has been established");
421
472
 
473
+ // Free resources from a previous call to avoid leaks on repeated use.
474
+ if(ptr->princ){
475
+ krb5_free_principal(ptr->ctx, ptr->princ);
476
+ ptr->princ = NULL;
477
+ }
478
+
479
+ krb5_free_cred_contents(ptr->ctx, &ptr->creds);
480
+ memset(&ptr->creds, 0, sizeof(ptr->creds));
481
+
422
482
  // Require user and password, optional service
423
483
  rb_scan_args(argc, argv, "21", &v_user, &v_pass, &v_service);
424
484
 
@@ -509,6 +569,11 @@ static VALUE rkrb5_close(VALUE self){
509
569
 
510
570
  TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
511
571
 
572
+ if(ptr->keytab){
573
+ krb5_kt_close(ptr->ctx, ptr->keytab);
574
+ ptr->keytab = NULL;
575
+ }
576
+
512
577
  if(ptr->ctx)
513
578
  krb5_free_cred_contents(ptr->ctx, &ptr->creds);
514
579
 
@@ -544,6 +609,12 @@ static VALUE rkrb5_get_default_principal(VALUE self){
544
609
  if(!ptr->ctx)
545
610
  rb_raise(cKrb5Exception, "no context has been established");
546
611
 
612
+ // Free previous principal to avoid leaks on repeated calls.
613
+ if(ptr->princ){
614
+ krb5_free_principal(ptr->ctx, ptr->princ);
615
+ ptr->princ = NULL;
616
+ }
617
+
547
618
  // Get the default credentials cache
548
619
  kerror = krb5_cc_default(ptr->ctx, &ccache);
549
620
 
@@ -562,9 +633,12 @@ static VALUE rkrb5_get_default_principal(VALUE self){
562
633
  kerror = krb5_unparse_name(ptr->ctx, ptr->princ, &princ_name);
563
634
 
564
635
  if(kerror)
565
- rb_raise(cKrb5Exception, "krb5_cc_default: %s", error_message(kerror));
636
+ rb_raise(cKrb5Exception, "krb5_unparse_name: %s", error_message(kerror));
566
637
 
567
- return rb_str_new2(princ_name);
638
+ VALUE v_name = rb_str_new2(princ_name);
639
+ krb5_free_unparsed_name(ptr->ctx, princ_name);
640
+
641
+ return v_name;
568
642
  }
569
643
 
570
644
  /*
@@ -611,11 +685,15 @@ static VALUE rkrb5_get_permitted_enctypes(VALUE self){
611
685
  v_enctypes = rb_hash_new();
612
686
 
613
687
  for(i = 0; ktypes[i]; i++){
614
- if(krb5_enctype_to_string(ktypes[i], encoding, 128)){
615
- rb_raise(cKrb5Exception, "krb5_enctype_to_string: %s", error_message(kerror));
688
+ krb5_error_code enc_err = krb5_enctype_to_string(ktypes[i], encoding, 128);
689
+ if(enc_err){
690
+ krb5_free_enctypes(ptr->ctx, ktypes);
691
+ rb_raise(cKrb5Exception, "krb5_enctype_to_string: %s", error_message(enc_err));
616
692
  }
617
693
  rb_hash_aset(v_enctypes, INT2FIX(ktypes[i]), rb_str_new2(encoding));
618
694
  }
695
+
696
+ krb5_free_enctypes(ptr->ctx, ktypes);
619
697
  }
620
698
 
621
699
  return v_enctypes;
@@ -730,8 +808,8 @@ void Init_rkerberos(void){
730
808
  rb_define_alias(cKrb5, "default_realm", "get_default_realm");
731
809
  rb_define_alias(cKrb5, "default_principal", "get_default_principal");
732
810
 
733
- /* 0.2.1: The version of the custom rkerberos library */
734
- rb_define_const(cKrb5, "VERSION", rb_str_new2("0.2.1"));
811
+ /* 0.2.3: The version of the custom rkerberos library */
812
+ rb_define_const(cKrb5, "VERSION", rb_str_new2("0.2.3"));
735
813
 
736
814
  // Encoding type constants
737
815
 
data/rkerberos.gemspec CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'rkerberos'
5
- spec.version = '0.2.1'
5
+ spec.version = '0.2.3'
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']
data/spec/config_spec.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  # spec/config_spec.rb
2
2
  # RSpec tests for Kerberos::Kadm5::Config
3
3
 
4
- require 'rkerberos'
4
+ require 'spec_helper'
5
5
 
6
- RSpec.describe Kerberos::Kadm5::Config do
7
- subject(:config) { described_class.new }
6
+ RSpec.describe 'Kerberos::Kadm5::Config', :kadm5 do
7
+ subject(:klass){ Kerberos::Kadm5::Config }
8
+ let(:config) { klass.new }
8
9
 
9
10
  it 'is frozen' do
10
11
  expect(config).to be_frozen
@@ -14,6 +15,7 @@ RSpec.describe Kerberos::Kadm5::Config do
14
15
  it 'responds to realm' do
15
16
  expect(config).to respond_to(:realm)
16
17
  end
18
+
17
19
  it 'returns a String' do
18
20
  expect(config.realm).to be_a(String)
19
21
  end
@@ -23,6 +25,7 @@ RSpec.describe Kerberos::Kadm5::Config do
23
25
  it 'responds to kadmind_port' do
24
26
  expect(config).to respond_to(:kadmind_port)
25
27
  end
28
+
26
29
  it 'returns an Integer' do
27
30
  expect(config.kadmind_port).to be_a(Integer)
28
31
  end
@@ -32,6 +35,7 @@ RSpec.describe Kerberos::Kadm5::Config do
32
35
  it 'responds to kpasswd_port' do
33
36
  expect(config).to respond_to(:kpasswd_port)
34
37
  end
38
+
35
39
  it 'returns an Integer' do
36
40
  expect(config.kpasswd_port).to be_a(Integer)
37
41
  end
@@ -41,6 +45,7 @@ RSpec.describe Kerberos::Kadm5::Config do
41
45
  it 'responds to admin_server' do
42
46
  expect(config).to respond_to(:admin_server)
43
47
  end
48
+
44
49
  it 'returns a String' do
45
50
  expect(config.admin_server).to be_a(String)
46
51
  end
@@ -50,6 +55,7 @@ RSpec.describe Kerberos::Kadm5::Config do
50
55
  it 'responds to acl_file' do
51
56
  expect(config).to respond_to(:acl_file)
52
57
  end
58
+
53
59
  it 'returns a String' do
54
60
  expect(config.acl_file).to be_a(String)
55
61
  end
@@ -59,6 +65,7 @@ RSpec.describe Kerberos::Kadm5::Config do
59
65
  it 'responds to dict_file' do
60
66
  expect(config).to respond_to(:dict_file)
61
67
  end
68
+
62
69
  it 'returns a String or nil' do
63
70
  expect([String, NilClass]).to include(config.dict_file.class)
64
71
  end
@@ -68,6 +75,7 @@ RSpec.describe Kerberos::Kadm5::Config do
68
75
  it 'responds to stash_file' do
69
76
  expect(config).to respond_to(:stash_file)
70
77
  end
78
+
71
79
  it 'returns a String or nil' do
72
80
  expect([String, NilClass]).to include(config.stash_file.class)
73
81
  end
@@ -77,6 +85,7 @@ RSpec.describe Kerberos::Kadm5::Config do
77
85
  it 'responds to mkey_name' do
78
86
  expect(config).to respond_to(:mkey_name)
79
87
  end
88
+
80
89
  it 'returns a String or nil' do
81
90
  expect([String, NilClass]).to include(config.mkey_name.class)
82
91
  end
@@ -86,6 +95,7 @@ RSpec.describe Kerberos::Kadm5::Config do
86
95
  it 'responds to mkey_from_kbd' do
87
96
  expect(config).to respond_to(:mkey_from_kbd)
88
97
  end
98
+
89
99
  it 'returns an Integer or nil' do
90
100
  expect([Integer, NilClass]).to include(config.mkey_from_kbd.class)
91
101
  end
@@ -95,6 +105,7 @@ RSpec.describe Kerberos::Kadm5::Config do
95
105
  it 'responds to enctype' do
96
106
  expect(config).to respond_to(:enctype)
97
107
  end
108
+
98
109
  it 'returns an Integer' do
99
110
  expect(config.enctype).to be_a(Integer)
100
111
  end
@@ -104,8 +115,9 @@ RSpec.describe Kerberos::Kadm5::Config do
104
115
  it 'responds to max_life' do
105
116
  expect(config).to respond_to(:max_life)
106
117
  end
107
- it 'returns an Integer or nil' do
108
- expect([Integer, NilClass]).to include(config.max_life.class)
118
+
119
+ it 'returns an Integer' do
120
+ expect(config.max_life).to be_a(Integer)
109
121
  end
110
122
  end
111
123
 
@@ -113,8 +125,9 @@ RSpec.describe Kerberos::Kadm5::Config do
113
125
  it 'responds to max_rlife' do
114
126
  expect(config).to respond_to(:max_rlife)
115
127
  end
116
- it 'returns an Integer or nil' do
117
- expect([Integer, NilClass]).to include(config.max_rlife.class)
128
+
129
+ it 'returns an Integer' do
130
+ expect(config.max_rlife).to be_a(Integer)
118
131
  end
119
132
  end
120
133
 
@@ -122,6 +135,7 @@ RSpec.describe Kerberos::Kadm5::Config do
122
135
  it 'responds to expiration' do
123
136
  expect(config).to respond_to(:expiration)
124
137
  end
138
+
125
139
  it 'returns a Time or nil' do
126
140
  expect([Time, NilClass]).to include(config.expiration.class)
127
141
  end
@@ -131,6 +145,7 @@ RSpec.describe Kerberos::Kadm5::Config do
131
145
  it 'responds to kvno' do
132
146
  expect(config).to respond_to(:kvno)
133
147
  end
148
+
134
149
  it 'returns an Integer or nil' do
135
150
  expect([Integer, NilClass]).to include(config.kvno.class)
136
151
  end
@@ -140,6 +155,7 @@ RSpec.describe Kerberos::Kadm5::Config do
140
155
  it 'responds to iprop_enabled' do
141
156
  expect(config).to respond_to(:iprop_enabled)
142
157
  end
158
+
143
159
  it 'returns a boolean' do
144
160
  expect(!!config.iprop_enabled == config.iprop_enabled).to be true
145
161
  end
@@ -149,6 +165,7 @@ RSpec.describe Kerberos::Kadm5::Config do
149
165
  it 'responds to iprop_logfile' do
150
166
  expect(config).to respond_to(:iprop_logfile)
151
167
  end
168
+
152
169
  it 'returns a String' do
153
170
  expect(config.iprop_logfile).to be_a(String)
154
171
  end
@@ -158,6 +175,7 @@ RSpec.describe Kerberos::Kadm5::Config do
158
175
  it 'responds to iprop_poll_time' do
159
176
  expect(config).to respond_to(:iprop_poll_time)
160
177
  end
178
+
161
179
  it 'returns an Integer' do
162
180
  expect(config.iprop_poll_time).to be_a(Integer)
163
181
  end
@@ -167,6 +185,7 @@ RSpec.describe Kerberos::Kadm5::Config do
167
185
  it 'responds to iprop_port' do
168
186
  expect(config).to respond_to(:iprop_port)
169
187
  end
188
+
170
189
  it 'returns an Integer or nil' do
171
190
  expect([Integer, NilClass]).to include(config.iprop_port.class)
172
191
  end
@@ -176,6 +195,7 @@ RSpec.describe Kerberos::Kadm5::Config do
176
195
  it 'responds to num_keysalts' do
177
196
  expect(config).to respond_to(:num_keysalts)
178
197
  end
198
+
179
199
  it 'returns an Integer' do
180
200
  expect(config.num_keysalts).to be_a(Integer)
181
201
  end
@@ -185,9 +205,11 @@ RSpec.describe Kerberos::Kadm5::Config do
185
205
  it 'responds to keysalts' do
186
206
  expect(config).to respond_to(:keysalts)
187
207
  end
208
+
188
209
  it 'returns an Array' do
189
210
  expect(config.keysalts).to be_a(Array)
190
211
  end
212
+
191
213
  it 'contains KeySalt objects if not empty' do
192
214
  unless config.keysalts.empty?
193
215
  expect(config.keysalts.first).to be_a(Kerberos::Kadm5::KeySalt)
data/spec/context_spec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # spec/context_spec.rb
2
2
  # RSpec tests for Kerberos::Krb5::Context
3
3
 
4
- require 'rkerberos'
4
+ require 'spec_helper'
5
5
 
6
6
  RSpec.describe Kerberos::Krb5::Context do
7
7
  subject(:context) { described_class.new }
@@ -19,17 +19,18 @@ RSpec.describe Kerberos::Krb5::Context do
19
19
  end
20
20
 
21
21
  describe 'constructor options' do
22
+ let(:profile_path){ RSpec.configuration.krb5_conf }
23
+
22
24
  it 'accepts secure: true to use a secure context' do
23
25
  expect { described_class.new(secure: true) }.not_to raise_error
24
26
  end
25
27
 
26
- it 'accepts a profile path via :profile' do
27
- profile_path = ENV['KRB5_CONFIG'] || '/etc/krb5.conf'
28
+ it 'accepts a profile path via :profile', :unix do
28
29
  expect(File).to exist(profile_path)
29
30
  expect { described_class.new(profile: profile_path) }.not_to raise_error
30
31
  end
31
32
 
32
- it 'validates profile argument type' do
33
+ it 'validates profile argument type', :unix do
33
34
  expect { described_class.new(profile: 123) }.to raise_error(TypeError)
34
35
  end
35
36
 
@@ -43,10 +44,8 @@ RSpec.describe Kerberos::Krb5::Context do
43
44
  end
44
45
  end
45
46
 
46
- it 'accepts secure: true together with profile' do
47
- profile_path = ENV['KRB5_CONFIG'] || '/etc/krb5.conf'
47
+ it 'accepts secure: true together with profile', :unix do
48
48
  expect(File).to exist(profile_path)
49
-
50
49
  ctx = nil
51
50
  expect { ctx = described_class.new(secure: true, profile: profile_path) }.not_to raise_error
52
51
  expect(ctx).to be_a(described_class)
@@ -1,51 +1,55 @@
1
1
  # spec/credentials_cache_spec.rb
2
2
  # RSpec tests for Kerberos::Krb5::CredentialsCache
3
3
 
4
- require 'rkerberos'
5
- require 'etc'
4
+ require 'spec_helper'
6
5
  require 'open3'
7
- require 'tmpdir'
8
6
 
9
7
  RSpec.describe Kerberos::Krb5::CredentialsCache do
10
- let(:login) do
11
- Etc.getlogin || ENV['USER'] || (Etc.getpwuid(Process.uid).name rescue nil)
12
- end
13
8
  let(:realm) { Kerberos::Krb5.new.default_realm }
14
- let(:princ) { "#{login}@#{realm}" }
15
- let(:cfile) { File.join(Dir.tmpdir, "krb5cc_#{Etc.getpwnam(login).uid}") }
9
+ let(:princ) { RSpec.configuration.login + '@' + realm }
10
+ let(:cfile) { RSpec.configuration.krb5_cc_name }
16
11
  let(:ccache) { described_class.new }
17
12
 
18
13
  def cache_found?
19
- found = true
20
- Open3.popen3('klist') { |_, _, stderr| found = false unless stderr.gets.nil? }
21
- found
14
+ if File::ALT_SEPARATOR
15
+ File.exist?(cfile)
16
+ else
17
+ found = true
18
+ Open3.popen3('klist') { |_, _, stderr| found = false unless stderr.gets.nil? }
19
+ found
20
+ end
22
21
  end
23
22
 
24
23
  after(:each) do
25
- Open3.popen3('kdestroy') { sleep 0.1 }
24
+ Open3.popen3('kdestroy -q') { sleep 0.1 } if cache_found?
26
25
  end
27
26
 
28
27
  describe 'constructor' do
29
28
  it 'can be called with no arguments' do
30
29
  expect { described_class.new }.not_to raise_error
31
30
  end
31
+
32
32
  it 'does not create a cache with no arguments' do
33
33
  described_class.new
34
34
  expect(File.exist?(cfile)).to be false
35
35
  expect(cache_found?).to be false
36
36
  end
37
+
37
38
  it 'creates a cache with a principal' do
38
39
  expect { described_class.new(princ) }.not_to raise_error
39
40
  expect(File.exist?(cfile)).to be true
40
41
  expect(cache_found?).to be true
41
42
  end
43
+
42
44
  it 'accepts an explicit cache name' do
43
45
  expect { described_class.new(princ, cfile) }.not_to raise_error
44
46
  expect { described_class.new(nil, cfile) }.not_to raise_error
45
47
  end
48
+
46
49
  it 'raises error for non-string argument' do
47
50
  expect { described_class.new(true) }.to raise_error(TypeError)
48
51
  end
52
+
49
53
  it 'accepts only up to two arguments' do
50
54
  expect { described_class.new(princ, cfile, cfile) }.to raise_error(ArgumentError)
51
55
  end
@@ -55,15 +59,18 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
55
59
  it 'responds to close' do
56
60
  expect(described_class.new(princ)).to respond_to(:close)
57
61
  end
62
+
58
63
  it 'does not delete credentials cache' do
59
64
  c = described_class.new(princ)
60
65
  expect { c.close }.not_to raise_error
61
66
  expect(cache_found?).to be true
62
67
  end
68
+
63
69
  it 'can be called multiple times without error' do
64
70
  c = described_class.new(princ)
65
71
  expect { 3.times { c.close } }.not_to raise_error
66
72
  end
73
+
67
74
  it 'raises error when calling method on closed object' do
68
75
  c = described_class.new(princ)
69
76
  c.close
@@ -77,18 +84,43 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
77
84
  expect(c).to respond_to(:default_name)
78
85
  expect { c.default_name }.not_to raise_error
79
86
  end
87
+
80
88
  it 'returns a string' do
81
89
  c = described_class.new(princ)
82
90
  expect(c.default_name).to be_a(String)
83
91
  end
84
92
  end
85
93
 
94
+ describe '#cache_name and #cache_type' do
95
+ it 'returns the ccache name and type' do
96
+ c = described_class.new(princ)
97
+ expect(c).to respond_to(:cache_name)
98
+ expect(c).to respond_to(:cache_type)
99
+
100
+ expect(c.cache_name).to be_a(String)
101
+ expect(c.cache_type).to be_a(String)
102
+
103
+ # cache_name returns the residual portion of the cache name; default_name
104
+ # may include the type prefix (e.g. "FILE:"). ensure the suffix matches.
105
+ expect(c.cache_name).to eq(c.default_name.split(/\w{2,}:/).last)
106
+ end
107
+ end
108
+
109
+ describe '#principal' do
110
+ it 'is an alias for primary_principal' do
111
+ c = described_class.new(princ)
112
+ expect(c).to respond_to(:principal)
113
+ expect(c.principal).to eq(c.primary_principal)
114
+ end
115
+ end
116
+
86
117
  describe '#primary_principal' do
87
118
  it 'responds to primary_principal' do
88
119
  c = described_class.new(princ)
89
120
  expect(c).to respond_to(:primary_principal)
90
121
  expect { c.primary_principal }.not_to raise_error
91
122
  end
123
+
92
124
  it 'returns expected results' do
93
125
  c = described_class.new(princ)
94
126
  expect(c.primary_principal).to be_a(String)
@@ -102,28 +134,63 @@ RSpec.describe Kerberos::Krb5::CredentialsCache do
102
134
  c = described_class.new(princ)
103
135
  expect(c).to respond_to(:destroy)
104
136
  end
137
+
105
138
  it 'deletes credentials cache' do
106
139
  c = described_class.new(princ)
107
140
  expect { c.destroy }.not_to raise_error
108
141
  expect(cache_found?).to be false
109
142
  end
143
+
110
144
  it 'delete is an alias for destroy' do
111
145
  c = described_class.new(princ)
112
146
  expect(c).to respond_to(:delete)
113
147
  expect(c.method(:delete)).to eq(c.method(:destroy))
114
148
  end
149
+
115
150
  it 'returns false if no credentials cache' do
116
151
  c = described_class.new
117
152
  expect(c.destroy).to be false
118
153
  end
154
+
119
155
  it 'raises error when calling method on destroyed object' do
120
156
  c = described_class.new(princ)
121
157
  c.destroy
122
158
  expect { c.default_name }.to raise_error(Kerberos::Krb5::Exception)
123
159
  end
160
+
124
161
  it 'does not accept arguments' do
125
162
  c = described_class.new(princ)
126
163
  expect { c.destroy(true) }.to raise_error(ArgumentError)
127
164
  end
128
165
  end
166
+
167
+ describe '#dup' do
168
+ it 'returns a new cache object with the same properties' do
169
+ c = described_class.new(princ)
170
+ c2 = c.dup
171
+ expect(c2).to be_a(described_class)
172
+ expect(c2.default_name).to eq(c.default_name)
173
+ expect(c2.primary_principal).to eq(c.primary_principal)
174
+ end
175
+
176
+ it 'closing original does not affect duplicate' do
177
+ c = described_class.new(princ)
178
+ c2 = c.dup
179
+ c.close
180
+ expect { c2.default_name }.not_to raise_error
181
+ end
182
+
183
+ it 'closing duplicate does not affect original' do
184
+ c = described_class.new(princ)
185
+ c2 = c.dup
186
+ c2.close
187
+ expect { c.default_name }.not_to raise_error
188
+ end
189
+
190
+ it 'raises when duping closed cache' do
191
+ c = described_class.new(princ)
192
+ c.close
193
+ expect { c.dup }.to raise_error(Kerberos::Krb5::Exception)
194
+ end
195
+ end
129
196
  end