rkerberos 0.1.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.
data/CHANGES ADDED
@@ -0,0 +1,3 @@
1
+ = 0.1.0 - 28-Apr-2011
2
+ * Initial release. This is effectively a re-release of my own custom branch
3
+ of the krb5-auth library, with some minor changes.
data/MANIFEST ADDED
@@ -0,0 +1,16 @@
1
+ CHANGES
2
+ rkerberos.gemspec
3
+ MANIFEST
4
+ Rakefile
5
+ README
6
+ ext/ccache.c
7
+ ext/context.c
8
+ ext/extconf.rb
9
+ ext/kadm5.c
10
+ ext/keytab.c
11
+ ext/keytab_entry.c
12
+ ext/rkerberos.c
13
+ ext/rkerberos.h
14
+ ext/policy.c
15
+ ext/principal.c
16
+ test/test_krb5.rb
data/README ADDED
@@ -0,0 +1,51 @@
1
+ = Description
2
+ The rkerberos library provides a Ruby interface for Kerberos.
3
+
4
+ = Requirements
5
+ Kerberos 1.7.0 or later, including admin header and library files.
6
+
7
+ = Synopsis
8
+ require 'rkerberos'
9
+
10
+ # Get the default realm name
11
+ krb5 = Kerberos::Krb5.new
12
+ puts krb5.default_realm
13
+ krb5.close
14
+
15
+ # Get the default keytab name
16
+ keytab = Kerberos::Krb5::Keytab.new
17
+ puts keytab.default_name
18
+ keytab.close
19
+
20
+ # Set the password for a given principal
21
+ kadm5 = Kerberos::Kadm5.new(:principal => 'foo/admin', :password => 'xxxx')
22
+ kadm5.set_password('someuser', 'abc123')
23
+ kadm5.close
24
+
25
+ # Using the block form
26
+ Kerberos::Kadm5.new(:principal => 'foo/admin', :password => 'xxxx') do |kadm5|
27
+ p kadm5.get_principal('someuser')
28
+ kadm5.set_password('someuser', 'abc123')
29
+ end
30
+
31
+ = Notes
32
+ The rkerberos library is a repackaging of my custom branch of the krb5_auth
33
+ library. Eventually the gem djberg96-krb5_auth will be removed from the gem
34
+ index.
35
+
36
+ = MIT vs Heimdal
37
+ This code was written for the MIT Kerberos library. It has not been tested
38
+ with the Heimdal Kerberos library.
39
+
40
+ = TODO
41
+ Create a separate class for the replay cache.
42
+ Better credentials cache support.
43
+ Ability to add and delete keytab entries.
44
+
45
+ = Known Issues
46
+ OS X users will probably need to install Kerberos manually and specify
47
+ the dir-config option because it ships with old Kerberos header files,
48
+ and none of the admin headers or libraries by default.
49
+
50
+ = Author
51
+ Daniel Berger
data/Rakefile ADDED
@@ -0,0 +1,148 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/extensiontask'
4
+ require 'rake/clean'
5
+ require 'rbconfig'
6
+ include Config
7
+
8
+ Rake::ExtensionTask.new('rkerberos')
9
+
10
+ CLEAN.include(
11
+ '**/*.gem', # Gem files
12
+ '**/*.rbc', # Rubinius
13
+ '**/*.o', # C object file
14
+ '**/*.log', # Ruby extension build log
15
+ '**/Makefile', # C Makefile
16
+ '**/conftest.dSYM', # OS X build directory
17
+ "**/*.#{CONFIG['DLEXT']}" # C shared object
18
+ )
19
+
20
+ desc 'Create a tarball of the source'
21
+ task :archive do
22
+ spec = eval(IO.read('rkerberos.gemspec'))
23
+ prefix = "rkerberos-#{spec.version}/"
24
+ Dir['*.tar*'].each{ |f| File.delete(f) }
25
+ sh "git archive --prefix=#{prefix} --format=tar HEAD > rkerberos-#{spec.version}.tar"
26
+ sh "gzip rkerberos-#{spec.version}.tar"
27
+ end
28
+
29
+ namespace :gem do
30
+ desc 'Delete any existing gem files in the project.'
31
+ task :clean do
32
+ Dir['*.gem'].each{ |f| File.delete(f) }
33
+ rm_rf 'lib'
34
+ end
35
+
36
+ desc 'Create the gem'
37
+ task :create => [:clean] do
38
+ spec = eval(IO.read('rkerberos.gemspec'))
39
+ Gem::Builder.new(spec).build
40
+ end
41
+
42
+ desc 'Install the gem'
43
+ task :install => [:create] do
44
+ file = Dir["*.gem"].first
45
+ sh "gem install #{file}"
46
+ end
47
+
48
+ desc 'Create a binary gem'
49
+ task :binary => [:clean, :compile] do
50
+ spec = eval(IO.read('rkerberos.gemspec'))
51
+ spec.platform = Gem::Platform::CURRENT
52
+ spec.extensions = nil
53
+ spec.files = spec.files.reject{ |f| f.include?('ext') }
54
+
55
+ Gem::Builder.new(spec).build
56
+ end
57
+ end
58
+
59
+ namespace :sample do
60
+ desc "Run the sample configuration display program"
61
+ task :config => [:compile] do
62
+ sh "ruby -Ilib samples/sample_config_display.rb"
63
+ end
64
+ end
65
+
66
+ namespace 'test' do
67
+ Rake::TestTask.new('all') do |t|
68
+ task :all => [:clean, :compile]
69
+ t.libs << 'ext'
70
+ t.warning = true
71
+ t.verbose = true
72
+ end
73
+
74
+ Rake::TestTask.new('context') do |t|
75
+ task :context => [:clean, :compile]
76
+ t.libs << 'ext'
77
+ t.test_files = FileList['test/test_context.rb']
78
+ t.warning = true
79
+ t.verbose = true
80
+ end
81
+
82
+ Rake::TestTask.new('ccache') do |t|
83
+ task :ccache => [:clean, :compile]
84
+ t.libs << 'ext'
85
+ t.test_files = FileList['test/test_credentials_cache.rb']
86
+ t.warning = true
87
+ t.verbose = true
88
+ end
89
+
90
+ Rake::TestTask.new('krb5') do |t|
91
+ task :krb5 => [:clean, :compile]
92
+ t.libs << 'ext'
93
+ t.test_files = FileList['test/test_krb5.rb']
94
+ t.warning = true
95
+ t.verbose = true
96
+ end
97
+
98
+ Rake::TestTask.new('keytab') do |t|
99
+ task :keytab => [:clean, :compile]
100
+ t.libs << 'ext'
101
+ t.test_files = FileList['test/test_krb5_keytab.rb']
102
+ t.warning = true
103
+ t.verbose = true
104
+ end
105
+
106
+ Rake::TestTask.new('keytab_entry') do |t|
107
+ task :keytab_entry => [:clean, :compile]
108
+ t.libs << 'ext'
109
+ t.test_files = FileList['test/test_keytab_entry.rb']
110
+ t.warning = true
111
+ t.verbose = true
112
+ end
113
+
114
+ Rake::TestTask.new('principal') do |t|
115
+ task :principal => [:clean, :compile]
116
+ t.libs << 'ext'
117
+ t.test_files = FileList['test/test_principal.rb']
118
+ t.warning = true
119
+ t.verbose = true
120
+ end
121
+
122
+ Rake::TestTask.new('kadm5') do |t|
123
+ task :kadm5 => [:clean, :compile]
124
+ t.libs << 'ext'
125
+ t.test_files = FileList['test/test_kadm5.rb']
126
+ t.warning = true
127
+ t.verbose = true
128
+ end
129
+
130
+ Rake::TestTask.new('config') do |t|
131
+ task :config => [:clean, :compile]
132
+ t.libs << 'ext'
133
+ t.test_files = FileList['test/test_config.rb']
134
+ t.warning = true
135
+ t.verbose = true
136
+ end
137
+
138
+ Rake::TestTask.new('policy') do |t|
139
+ task :policy => [:clean, :compile]
140
+ t.libs << 'ext'
141
+ t.test_files = FileList['test/test_policy.rb']
142
+ t.warning = true
143
+ t.verbose = true
144
+ end
145
+ end
146
+
147
+ task :default => ['test:all']
148
+ task :test => ['test:all']
@@ -0,0 +1,250 @@
1
+ #include <rkerberos.h>
2
+
3
+ VALUE cKrb5CCache;
4
+
5
+ // Free function for the Kerberos::Krb5::CCache class.
6
+ static void rkrb5_ccache_free(RUBY_KRB5_CCACHE* ptr){
7
+ if(!ptr)
8
+ return;
9
+
10
+ if(ptr->ccache)
11
+ krb5_cc_close(ptr->ctx, ptr->ccache);
12
+
13
+ if(ptr->principal)
14
+ krb5_free_principal(ptr->ctx, ptr->principal);
15
+
16
+ if(ptr->ctx)
17
+ krb5_free_context(ptr->ctx);
18
+
19
+ free(ptr);
20
+ }
21
+
22
+ // Allocation function for the Kerberos::Krb5::CCache class.
23
+ static VALUE rkrb5_ccache_allocate(VALUE klass){
24
+ RUBY_KRB5_CCACHE* ptr = malloc(sizeof(RUBY_KRB5_CCACHE));
25
+ memset(ptr, 0, sizeof(RUBY_KRB5_CCACHE));
26
+ return Data_Wrap_Struct(klass, 0, rkrb5_ccache_free, ptr);
27
+ }
28
+
29
+ /*
30
+ * call-seq:
31
+ * Kerberos::CredentialsCache.new(principal = nil, cache_name = nil)
32
+ *
33
+ * Creates and returns a new Kerberos::CredentialsCache object. If cache_name
34
+ * is specified, then that cache is used, which must be in "type:residual"
35
+ * format, where 'type' is a type known to Kerberos (typically 'FILE').
36
+ *
37
+ * If a +principal+ is specified, then it creates or refreshes the credentials
38
+ * cache with the primary principal set to +principal+. If the credentials
39
+ * cache already exists, its contents are destroyed.
40
+ *
41
+ * Note that the principal's credentials are not set via the constructor.
42
+ * It merely creates the cache and sets the default principal.
43
+ */
44
+ static VALUE rkrb5_ccache_initialize(int argc, VALUE* argv, VALUE self){
45
+ RUBY_KRB5_CCACHE* ptr;
46
+ krb5_error_code kerror;
47
+ VALUE v_principal, v_name;
48
+
49
+ Data_Get_Struct(self, RUBY_KRB5_CCACHE, ptr);
50
+
51
+ rb_scan_args(argc, argv, "02", &v_principal, &v_name);
52
+
53
+ // Convert the principal name to a principal object
54
+ if(RTEST(v_principal)){
55
+ Check_Type(v_principal, T_STRING);
56
+
57
+ kerror = krb5_parse_name(
58
+ ptr->ctx,
59
+ StringValuePtr(v_principal),
60
+ &ptr->principal
61
+ );
62
+
63
+ if(kerror)
64
+ rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
65
+ }
66
+
67
+ // Initialize the context
68
+ kerror = krb5_init_context(&ptr->ctx);
69
+
70
+ if(kerror)
71
+ rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
72
+
73
+ // Set the credentials cache using the default cache if no name is provided
74
+ if(NIL_P(v_name)){
75
+ kerror = krb5_cc_default(ptr->ctx, &ptr->ccache);
76
+
77
+ if(kerror)
78
+ rb_raise(cKrb5Exception, "krb5_cc_default: %s", error_message(kerror));
79
+ }
80
+ else{
81
+ Check_Type(v_name, T_STRING);
82
+ kerror = krb5_cc_resolve(ptr->ctx, StringValuePtr(v_name), &ptr->ccache);
83
+
84
+ if(kerror)
85
+ rb_raise(cKrb5Exception, "krb5_cc_resolve: %s", error_message(kerror));
86
+ }
87
+
88
+ // Initialize the credentials cache if a principal was provided
89
+ if(RTEST(v_principal)){
90
+ kerror = krb5_cc_initialize(ptr->ctx, ptr->ccache, ptr->principal);
91
+
92
+ if(kerror)
93
+ rb_raise(cKrb5Exception, "krb5_cc_initialize: %s", error_message(kerror));
94
+ }
95
+
96
+ return self;
97
+ }
98
+
99
+ /*
100
+ * call-seq:
101
+ * ccache.close
102
+ *
103
+ * Closes the ccache object. Once the ccache object is closed no more
104
+ * methods may be called on it, or an exception will be raised.
105
+ *
106
+ * Note that unlike ccache.destroy, this does not delete the cache.
107
+ */
108
+ static VALUE rkrb5_ccache_close(VALUE self){
109
+ RUBY_KRB5_CCACHE* ptr;
110
+
111
+ Data_Get_Struct(self, RUBY_KRB5_CCACHE, ptr);
112
+
113
+ if(!ptr->ctx)
114
+ return self;
115
+
116
+ if(ptr->ccache)
117
+ krb5_cc_close(ptr->ctx, ptr->ccache);
118
+
119
+ if(ptr->principal)
120
+ krb5_free_principal(ptr->ctx, ptr->principal);
121
+
122
+ if(ptr->ctx)
123
+ krb5_free_context(ptr->ctx);
124
+
125
+ ptr->ccache = NULL;
126
+ ptr->ctx = NULL;
127
+ ptr->principal = NULL;
128
+
129
+ return self;
130
+ }
131
+
132
+ /*
133
+ * call-seq:
134
+ * ccache.default_name
135
+ *
136
+ * Returns the name of the default credentials cache.
137
+ *
138
+ * This is typically a file under /tmp with a name like 'krb5cc_xxxx',
139
+ * where 'xxxx' is the uid of the current process owner.
140
+ */
141
+ static VALUE rkrb5_ccache_default_name(VALUE self){
142
+ RUBY_KRB5_CCACHE* ptr;
143
+
144
+ Data_Get_Struct(self, RUBY_KRB5_CCACHE, ptr);
145
+
146
+ if(!ptr->ctx)
147
+ rb_raise(cKrb5Exception, "no context has been established");
148
+
149
+ return rb_str_new2(krb5_cc_default_name(ptr->ctx));
150
+ }
151
+
152
+ /*
153
+ * call-seq:
154
+ * ccache.primary_principal
155
+ *
156
+ * Returns the name of the primary principal of the credentials cache.
157
+ */
158
+ static VALUE rkrb5_ccache_primary_principal(VALUE self){
159
+ RUBY_KRB5_CCACHE* ptr;
160
+ krb5_error_code kerror;
161
+ char* name;
162
+
163
+ Data_Get_Struct(self, RUBY_KRB5_CCACHE, ptr);
164
+
165
+ if(!ptr->ctx)
166
+ rb_raise(cKrb5Exception, "no context has been established");
167
+
168
+ kerror = krb5_cc_get_principal(ptr->ctx, ptr->ccache, &ptr->principal);
169
+
170
+ if(kerror)
171
+ rb_raise(cKrb5Exception, "krb5_cc_get_principal: %s", error_message(kerror));
172
+
173
+ kerror = krb5_unparse_name(ptr->ctx, ptr->principal, &name);
174
+
175
+ if(kerror)
176
+ rb_raise(cKrb5Exception, "krb5_unparse_name: %s", error_message(kerror));
177
+
178
+ return rb_str_new2(name);
179
+ }
180
+
181
+ /*
182
+ * call-seq:
183
+ * ccache.destroy
184
+ *
185
+ * Destroy the credentials cache of the current principal. This also closes
186
+ * the object and it cannot be reused.
187
+ *
188
+ * If the cache was destroyed then true is returned. If there is no cache
189
+ * then false is returned.
190
+ */
191
+ static VALUE rkrb5_ccache_destroy(VALUE self){
192
+ RUBY_KRB5_CCACHE* ptr;
193
+ krb5_error_code kerror;
194
+ VALUE v_bool = Qtrue;
195
+
196
+ Data_Get_Struct(self, RUBY_KRB5_CCACHE, ptr);
197
+
198
+ if(!ptr->ctx)
199
+ rb_raise(cKrb5Exception, "no context has been established");
200
+
201
+ kerror = krb5_cc_destroy(ptr->ctx, ptr->ccache);
202
+
203
+ // Don't raise an error if there's no cache. Just return false.
204
+ if(kerror){
205
+ if((kerror == KRB5_CC_NOTFOUND) || (kerror == KRB5_FCC_NOFILE)){
206
+ v_bool = Qfalse;
207
+ }
208
+ else{
209
+ if(ptr->principal)
210
+ krb5_free_principal(ptr->ctx, ptr->principal);
211
+
212
+ if(ptr->ctx)
213
+ krb5_free_context(ptr->ctx);
214
+
215
+ rb_raise(cKrb5Exception, "krb5_cc_destroy: %s", error_message(kerror));
216
+ }
217
+ }
218
+
219
+ if(ptr->principal)
220
+ krb5_free_principal(ptr->ctx, ptr->principal);
221
+
222
+ if(ptr->ctx)
223
+ krb5_free_context(ptr->ctx);
224
+
225
+ ptr->ccache = NULL;
226
+ ptr->ctx = NULL;
227
+ ptr->principal = NULL;
228
+
229
+ return v_bool;
230
+ }
231
+
232
+ void Init_ccache(){
233
+ /* The Kerberos::Krb5::CredentialsCache class encapsulates a Kerberos credentials cache. */
234
+ cKrb5CCache = rb_define_class_under(cKrb5, "CredentialsCache", rb_cObject);
235
+
236
+ // Allocation Function
237
+ rb_define_alloc_func(cKrb5CCache, rkrb5_ccache_allocate);
238
+
239
+ // Constructor
240
+ rb_define_method(cKrb5CCache, "initialize", rkrb5_ccache_initialize, -1);
241
+
242
+ // Instance Methods
243
+ rb_define_method(cKrb5CCache, "close", rkrb5_ccache_close, 0);
244
+ rb_define_method(cKrb5CCache, "default_name", rkrb5_ccache_default_name, 0);
245
+ rb_define_method(cKrb5CCache, "destroy", rkrb5_ccache_destroy, 0);
246
+ rb_define_method(cKrb5CCache, "primary_principal", rkrb5_ccache_primary_principal, 0);
247
+
248
+ // Aliases
249
+ rb_define_alias(cKrb5CCache, "delete", "destroy");
250
+ }