gssapi 0.0.2
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/COPYING.txt +674 -0
- data/README.textile +10 -0
- data/Rakefile +29 -0
- data/VERSION +1 -0
- data/examples/gss_client.rb +26 -0
- data/examples/gss_server.rb +32 -0
- data/gssapi.gemspec +33 -0
- data/lib/gssapi.rb +22 -0
- data/lib/gssapi/exceptions.rb +22 -0
- data/lib/gssapi/lib_gssapi.rb +409 -0
- data/lib/gssapi/simple.rb +196 -0
- data/preamble +19 -0
- metadata +95 -0
@@ -0,0 +1,196 @@
|
|
1
|
+
#############################################################################
|
2
|
+
# Copyright © 2010 Dan Wanek <dan.wanek@gmail.com>
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# This file is part of the Ruby GSSAPI library.
|
6
|
+
#
|
7
|
+
# GSSAPI is free software: you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or (at
|
10
|
+
# your option) any later version.
|
11
|
+
#
|
12
|
+
# GSSAPI is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
15
|
+
# Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License along
|
18
|
+
# with GSSAPI. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#############################################################################
|
20
|
+
module GSSAPI
|
21
|
+
|
22
|
+
# This class is a simple wrapper around the most common usage of GSSAPI. If you are looking at doing
|
23
|
+
# something a bit more advanced you may want to check out the LibGSSAPI module.
|
24
|
+
class Simple
|
25
|
+
|
26
|
+
# Initialize a new GSSAPI::Simple object
|
27
|
+
# @param [String] host_name the fully qualified host name
|
28
|
+
# @param [String] service_name the service name. This can either be in the form svc@example.org
|
29
|
+
# or just svc. If there is no '@example.org' part the host_name will be appended. If no
|
30
|
+
# service_name is given at all the default service of 'host' will be used.
|
31
|
+
def initialize(host_name, service_name=nil, keytab=nil)
|
32
|
+
@host = host_name
|
33
|
+
@service = service_name.nil? ? "host@#{@host}" : (service_name.include?('@') ? service_name : "#{service_name}@#{@host}")
|
34
|
+
@int_svc_name = import_name(@service)
|
35
|
+
@context = nil # the security context
|
36
|
+
@scred = nil # the service credentials. really only used for the server-side via acquire_credentials
|
37
|
+
set_keytab(keytab) unless keytab.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Convert a String to a GSSAPI usable buffer (gss_buffer_desc)
|
42
|
+
# @param [String] str the string to convert
|
43
|
+
def import_name(str)
|
44
|
+
buff_str = LibGSSAPI::GssBufferDesc.new
|
45
|
+
buff_str.value = str
|
46
|
+
name = FFI::MemoryPointer.new :pointer # gss_name_t
|
47
|
+
min_stat = FFI::MemoryPointer.new :uint32
|
48
|
+
|
49
|
+
maj_stat = LibGSSAPI.gss_import_name(min_stat, buff_str.pointer, LibGSSAPI.GSS_C_NT_HOSTBASED_SERVICE, name)
|
50
|
+
raise GssApiError, "gss_import_name did not return GSS_S_COMPLETE. Error code: maj: #{maj_stat}, min: #{min_stat.read_int}" if maj_stat != 0
|
51
|
+
|
52
|
+
LibGSSAPI::GssNameT.new(name.get_pointer(0))
|
53
|
+
end
|
54
|
+
|
55
|
+
# Initialize the GSS security context (client initiator). If there was a previous call that issued a
|
56
|
+
# continue you can pass the continuation token in via the token param.
|
57
|
+
# @param [String] in_token an input token sent from the remote service in a continuation.
|
58
|
+
# @return [String, true] if a continuation flag is set it will return the output token that is needed to send
|
59
|
+
# to the remote host. Otherwise it returns true and the GSS security context has been established.
|
60
|
+
def init_context(in_token = nil)
|
61
|
+
min_stat = FFI::MemoryPointer.new :uint32
|
62
|
+
ctx = (@context.nil? ? LibGSSAPI::GssCtxIdT.gss_c_no_context.address_of : @context.address_of)
|
63
|
+
mech = LibGSSAPI::GssOID.gss_c_no_oid
|
64
|
+
in_tok = LibGSSAPI::GssBufferDesc.new
|
65
|
+
in_tok.value = in_token
|
66
|
+
out_tok = LibGSSAPI::GssBufferDesc.new
|
67
|
+
out_tok.value = nil
|
68
|
+
|
69
|
+
|
70
|
+
maj_stat = LibGSSAPI.gss_init_sec_context(min_stat,
|
71
|
+
nil,
|
72
|
+
ctx,
|
73
|
+
@int_svc_name,
|
74
|
+
mech,
|
75
|
+
(LibGSSAPI::GSS_C_MUTUAL_FLAG | LibGSSAPI::GSS_C_SEQUENCE_FLAG),
|
76
|
+
0,
|
77
|
+
nil,
|
78
|
+
in_tok.pointer,
|
79
|
+
nil,
|
80
|
+
out_tok.pointer,
|
81
|
+
nil,
|
82
|
+
nil)
|
83
|
+
|
84
|
+
raise GssApiError, "gss_init_sec_context did not return GSS_S_COMPLETE. Error code: maj: #{maj_stat}, min: #{min_stat.read_int}" if maj_stat > 1
|
85
|
+
|
86
|
+
@context = LibGSSAPI::GssCtxIdT.new(ctx.get_pointer(0))
|
87
|
+
maj_stat == 1 ? out_tok.value : true
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# Accept a security context that was initiated by a remote peer.
|
92
|
+
# @param [String] in_token The token sent by the remote client to initiate the context
|
93
|
+
# @return [String, true] If this is part of a continuation it will return a token to be passed back to the remote
|
94
|
+
# otherwise it will simply return true.
|
95
|
+
def accept_context(in_token)
|
96
|
+
raise GssApiError, "No credentials yet acquired. Call #{self.class.name}#acquire_credentials first" if @scred.nil?
|
97
|
+
|
98
|
+
min_stat = FFI::MemoryPointer.new :uint32
|
99
|
+
ctx = (@context.nil? ? LibGSSAPI::GssCtxIdT.gss_c_no_context.address_of : @context.address_of)
|
100
|
+
no_chn_bind = LibGSSAPI::GSS_C_NO_CHANNEL_BINDINGS
|
101
|
+
client = FFI::MemoryPointer.new :pointer # Will hold the initiating client name after the call
|
102
|
+
mech = FFI::MemoryPointer.new :pointer # Will hold the mech being used after the call
|
103
|
+
in_tok = GSSAPI::LibGSSAPI::GssBufferDesc.new
|
104
|
+
in_tok.value = in_token
|
105
|
+
out_tok = GSSAPI::LibGSSAPI::GssBufferDesc.new
|
106
|
+
out_tok.value = nil
|
107
|
+
maj_stat = LibGSSAPI.gss_accept_sec_context(min_stat,
|
108
|
+
ctx,
|
109
|
+
@scred,
|
110
|
+
in_tok.pointer,
|
111
|
+
no_chn_bind,
|
112
|
+
client,
|
113
|
+
mech,
|
114
|
+
out_tok.pointer,
|
115
|
+
nil, nil, nil)
|
116
|
+
|
117
|
+
raise GssApiError, "gss_accept_sec_context did not return GSS_S_COMPLETE. Error code: maj: #{maj_stat}, min: #{min_stat.read_int}" if maj_stat > 1
|
118
|
+
|
119
|
+
@context = LibGSSAPI::GssCtxIdT.new(ctx.get_pointer(0))
|
120
|
+
out_tok.length > 0 ? out_tok.value : true
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# Acquire security credentials. This does not log you in. It grabs the credentials from a cred cache or keytab.
|
125
|
+
# @param [Hash] opts options to pass to the gss_acquire_cred function.
|
126
|
+
# @option opts [String] :usage The credential usage type ('accept', 'initiate', 'both'). It defaults to 'accept' since
|
127
|
+
# this method is most usually called on the server only.
|
128
|
+
# @return [true] It will return true if everything succeeds and the @scred variable will be set for future methods. If
|
129
|
+
# an error ocurrs an exception will be raised.
|
130
|
+
def acquire_credentials(opts = {:usage => 'accept'})
|
131
|
+
min_stat = FFI::MemoryPointer.new :uint32
|
132
|
+
scred = FFI::MemoryPointer.new :pointer
|
133
|
+
|
134
|
+
case opts[:usage]
|
135
|
+
when 'accept'
|
136
|
+
usage = LibGSSAPI::GSS_C_ACCEPT
|
137
|
+
when 'initiate'
|
138
|
+
usage = LibGSSAPI::GSS_C_INITIATE
|
139
|
+
when 'both'
|
140
|
+
usage = LibGSSAPI::GSS_C_BOTH
|
141
|
+
else
|
142
|
+
raise GssApiError, "Bad option passed to #{self.class.name}#acquire_credentials"
|
143
|
+
end
|
144
|
+
|
145
|
+
maj_stat = LibGSSAPI.gss_acquire_cred(min_stat, @int_svc_name, 0, LibGSSAPI::GSS_C_NO_OID_SET, usage, scred, nil, nil)
|
146
|
+
raise GssApiError, "gss_acquire_cred did not return GSS_S_COMPLETE. Error code: maj: #{maj_stat}, min: #{min_stat.read_int}" if maj_stat != 0
|
147
|
+
|
148
|
+
@scred = LibGSSAPI::GssCredIdT.new(scred.get_pointer(0))
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
152
|
+
# Wrap a message using gss_wrap. It can either encrypt the message (confidentiality) or simply sign it (integrity).
|
153
|
+
# @param [String] msg The message to wrap
|
154
|
+
# @param [Boolean] encrypt Whether or not to encrypt the message or just sign it. The default is to encrypt.
|
155
|
+
# @return [String] The wrapped message. It will raise an exception on error
|
156
|
+
def wrap_message(msg, encrypt = true)
|
157
|
+
min_stat = FFI::MemoryPointer.new :uint32
|
158
|
+
conf_req = (encrypt ? 1 : 0)
|
159
|
+
qop_req = GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT
|
160
|
+
in_buff = GSSAPI::LibGSSAPI::GssBufferDesc.new
|
161
|
+
in_buff.value = msg
|
162
|
+
conf_state = FFI::MemoryPointer.new :uint32
|
163
|
+
out_buff = GSSAPI::LibGSSAPI::GssBufferDesc.new
|
164
|
+
out_buff.value = nil
|
165
|
+
maj_stat = GSSAPI::LibGSSAPI.gss_wrap(min_stat, @context, conf_req, qop_req, in_buff.pointer, conf_state, out_buff.pointer)
|
166
|
+
raise GssApiError, "Failed to gss_wrap message. Error code: maj: #{maj_stat}, min: #{min_stat.read_int}" if maj_stat != 0
|
167
|
+
out_buff.value
|
168
|
+
end
|
169
|
+
|
170
|
+
# Unwrap a message previously wrapped with gss_wrap.
|
171
|
+
# @param [String] msg The message to unwrap
|
172
|
+
# @param [Boolean] encrypted Whether or not this message was encrypted (true) or just signed (false)
|
173
|
+
def unwrap_message(msg, encrypted = true)
|
174
|
+
min_stat = FFI::MemoryPointer.new :uint32
|
175
|
+
in_buff = GSSAPI::LibGSSAPI::GssBufferDesc.new
|
176
|
+
in_buff.value = msg
|
177
|
+
out_buff = GSSAPI::LibGSSAPI::GssBufferDesc.new
|
178
|
+
conf_state = FFI::MemoryPointer.new :int
|
179
|
+
conf_state.write_int((encrypted ? 1 : 0))
|
180
|
+
q_op = FFI::MemoryPointer.new :uint32
|
181
|
+
q_op.write_int(0)
|
182
|
+
maj_stat = GSSAPI::LibGSSAPI.gss_unwrap(min_stat, @context, in_buff.pointer, out_buff.pointer, conf_state, q_op)
|
183
|
+
raise GssApiError, "Failed to gss_unwrap message. Error code: maj: #{maj_stat}, min: #{min_stat.read_int}" if maj_stat != 0
|
184
|
+
out_buff.value
|
185
|
+
end
|
186
|
+
|
187
|
+
# Add a path to a custom keytab file
|
188
|
+
# @param [String] keytab the path to the keytab
|
189
|
+
def set_keytab(keytab)
|
190
|
+
maj_stat = LibGSSAPI.krb5_gss_register_acceptor_identity(keytab)
|
191
|
+
raise GssApiError, "krb5_gss_register_acceptor_identity did not return GSS_S_COMPLETE. Error code: maj: #{maj_stat}, min: #{min_stat.read_int}" if maj_stat != 0
|
192
|
+
true
|
193
|
+
end
|
194
|
+
|
195
|
+
end # Simple
|
196
|
+
end # GSSAPI
|
data/preamble
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#############################################################################
|
2
|
+
# Copyright © 2010 Dan Wanek <dan.wanek@gmail.com>
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# This file is part of the Ruby GSSAPI library.
|
6
|
+
#
|
7
|
+
# GSSAPI is free software: you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or (at
|
10
|
+
# your option) any later version.
|
11
|
+
#
|
12
|
+
# GSSAPI is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
15
|
+
# Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License along
|
18
|
+
# with GSSAPI. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#############################################################################
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gssapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Dan Wanek
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-16 00:00:00 -06:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: ffi
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 0
|
31
|
+
- 1
|
32
|
+
version: 1.0.1
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: " A FFI wrapper around the system GSSAPI library. Please make sure and read the\n Yard docs or standard GSSAPI documentation if you have any questions.\n \n There is also a class called GSSAPI::Simple that wraps many of the common features\n used for GSSAPI.\n"
|
36
|
+
email: dan.wanek@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.textile
|
43
|
+
- COPYING.txt
|
44
|
+
files:
|
45
|
+
- COPYING.txt
|
46
|
+
- README.textile
|
47
|
+
- Rakefile
|
48
|
+
- VERSION
|
49
|
+
- examples/gss_client.rb
|
50
|
+
- examples/gss_server.rb
|
51
|
+
- gssapi.gemspec
|
52
|
+
- lib/gssapi.rb
|
53
|
+
- lib/gssapi/exceptions.rb
|
54
|
+
- lib/gssapi/lib_gssapi.rb
|
55
|
+
- lib/gssapi/simple.rb
|
56
|
+
- preamble
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/zenchild/gssapi
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- -x
|
64
|
+
- test/
|
65
|
+
- -x
|
66
|
+
- examples/
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 1
|
76
|
+
- 9
|
77
|
+
- 1
|
78
|
+
version: 1.9.1
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
segments:
|
85
|
+
- 0
|
86
|
+
version: "0"
|
87
|
+
requirements: []
|
88
|
+
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.3.7
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: A FFI wrapper around the system GSSAPI library.
|
94
|
+
test_files: []
|
95
|
+
|