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 +3 -0
- data/MANIFEST +16 -0
- data/README +51 -0
- data/Rakefile +148 -0
- data/ext/rkerberos/ccache.c +250 -0
- data/ext/rkerberos/config.c +312 -0
- data/ext/rkerberos/context.c +77 -0
- data/ext/rkerberos/extconf.rb +14 -0
- data/ext/rkerberos/kadm5.c +991 -0
- data/ext/rkerberos/keytab.c +509 -0
- data/ext/rkerberos/keytab_entry.c +84 -0
- data/ext/rkerberos/policy.c +196 -0
- data/ext/rkerberos/principal.c +263 -0
- data/ext/rkerberos/rkerberos.c +566 -0
- data/ext/rkerberos/rkerberos.h +95 -0
- data/rkerberos.gemspec +28 -0
- data/test/test_config.rb +129 -0
- data/test/test_context.rb +33 -0
- data/test/test_credentials_cache.rb +153 -0
- data/test/test_kadm5.rb +424 -0
- data/test/test_keytab_entry.rb +66 -0
- data/test/test_krb5.rb +198 -0
- data/test/test_krb5_keytab.rb +294 -0
- data/test/test_policy.rb +123 -0
- data/test/test_principal.rb +134 -0
- metadata +155 -0
data/CHANGES
ADDED
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
|
+
}
|