rkerberos 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }