class GSSAPI::Simple
This class is a simple wrapper around the most common usage of GSSAPI. If you are looking at doing
something a bit more advanced you may want to check out the LibGSSAPI module.
Attributes
Public Class Methods
Initialize a new GSSAPI::Simple object @param [String] host_name the fully qualified host name @param [String] service_name The service name. This can either be a
GSS_KRB5_NT_PRINCIPAL_NAME in the form of srvc/fqdn@REALM or GSS_C_NT_HOSTBASED_SERVICE in the form of srvc@fqdn If there is no '@fqdn' part, the host_name will be appended. If no service_name is given at all the default service of 'host@fqdn' will be used.
# File lib/gssapi/simple.rb, line 23 def initialize(host_name, service_name=nil, keytab=nil) @host = host_name @service = service_name.nil? ? "host@#{@host}" : (service_name.include?('@') ? service_name : "#{service_name}@#{@host}") @int_svc_name = import_name(@service) @context = nil # the security context @scred = nil # the service credentials. really only used for the server-side via acquire_credentials set_keytab(keytab) unless keytab.nil? @delegated_credentials = nil end
Public Instance Methods
Accept a security context that was initiated by a remote peer. @param [String] in_token The token sent by the remote client to initiate the context @return [String, true] If this is part of a continuation it will return a token to be passed back to the remote
otherwise it will simply return true.
# File lib/gssapi/simple.rb, line 111 def accept_context(in_token) raise GssApiError, "No credentials yet acquired. Call #{self.class.name}#acquire_credentials first" if @scred.nil? min_stat = FFI::MemoryPointer.new :OM_uint32 pctx = (@context.nil? ? LibGSSAPI::GssCtxIdT.gss_c_no_context.address_of : @context.address_of) no_chn_bind = LibGSSAPI::GSS_C_NO_CHANNEL_BINDINGS @client = FFI::MemoryPointer.new :pointer # Will hold the initiating client name after the call mech = FFI::MemoryPointer.new :pointer # Will hold the mech being used after the call in_tok = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new in_tok.value = in_token out_tok = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new ret_flags = FFI::MemoryPointer.new :OM_uint32 delegated_cred_handle = FFI::MemoryPointer.new :pointer maj_stat = LibGSSAPI.gss_accept_sec_context(min_stat, pctx, @scred, in_tok.pointer, no_chn_bind, @client, mech, out_tok.pointer, ret_flags, nil, delegated_cred_handle) raise GssApiError.new(maj_stat, min_stat), "gss_accept_sec_context did not return GSS_S_COMPLETE" if maj_stat > 1 if (ret_flags.read_uint32 & LibGSSAPI::GSS_C_DELEG_FLAG) != 0 @delegated_credentials = LibGSSAPI::GssCredIdT.new(delegated_cred_handle.get_pointer(0)) end # The returned context may be equal to the passed in @context. If so, we # must not create another AutoPointer to the same gss_buffer_t. If we do # we will double delete it. ctx = pctx.get_pointer(0) @context = LibGSSAPI::GssCtxIdT.new(ctx) if ctx != @context out_tok.length > 0 ? out_tok.value : true end
Acquire security credentials. This does not log you in. It grabs the credentials from a cred cache or keytab. @param [Hash] opts options to pass to the gss_acquire_cred function. @option opts [String] :usage The credential usage type (:accept, :initiate, :both). It defaults to 'accept' since
this method is most usually called on the server only.
@return [true] It will return true if everything succeeds and the @scred variable will be set for future methods. If
an error ocurrs an exception will be raised.
# File lib/gssapi/simple.rb, line 193 def acquire_credentials(princ = @int_svc_name, opts = {:usage => :accept}) min_stat = FFI::MemoryPointer.new :OM_uint32 scred = FFI::MemoryPointer.new :pointer case opts[:usage] when :accept usage = LibGSSAPI::GSS_C_ACCEPT when :initiate usage = LibGSSAPI::GSS_C_INITIATE when :both usage = LibGSSAPI::GSS_C_BOTH else raise GssApiError, "Bad option passed to #{self.class.name}#acquire_credentials" end maj_stat = LibGSSAPI.gss_acquire_cred(min_stat, princ, 0, LibGSSAPI::GSS_C_NO_OID_SET, usage, scred, nil, nil) raise GssApiError.new(maj_stat, min_stat), "gss_acquire_cred did not return GSS_S_COMPLETE" if maj_stat != 0 @scred = LibGSSAPI::GssCredIdT.new(scred.get_pointer(0)) true end
Get textual representation of internal GSS name @return [String] textual representation of internal GSS name
# File lib/gssapi/simple.rb, line 168 def display_name raise GssApiError.new(), "No context accepted yet. Call #{self.class.name}#accept_context(in_token) first" if @client.nil? output_name = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new min_stat = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_display_name(min_stat, @client.get_pointer(0), output_name.pointer, nil) if maj_stat != GSSAPI::LibGSSAPI::GSS_S_COMPLETE raise GssApiError.new(maj_stat, min_stat), "gss_display_name did not return GSS_S_COMPLETE but #{ maj_stat }" end output_name.value end
# File lib/gssapi/simple.rb, line 153 def get_mic(token) min_stat = FFI::MemoryPointer.new :OM_uint32 qop_req = GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT in_buff = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new in_buff.value = token out_buff = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new maj_stat = GSSAPI::LibGSSAPI.gss_get_mic(min_stat, @context, qop_req, in_buff.pointer, out_buff.pointer) raise GssApiError.new(maj_stat, min_stat), "Failed to gss_get_mic" if maj_stat != 0 out_buff.value end
Convert a String to a GSSAPI usable buffer (gss_buffer_desc) @param [String] str the string to convert
# File lib/gssapi/simple.rb, line 36 def import_name(str) buff_str = LibGSSAPI::UnManagedGssBufferDesc.new buff_str.value = str # Choose the appropriate mechanism based on the string passed. if (str =~ /[A-Za-z0-9]+\/[^@]+@.+$/) mech = LibGSSAPI::GssOID.gss_c_no_oid else mech = LibGSSAPI::GSS_C_NT_HOSTBASED_SERVICE end name = FFI::MemoryPointer.new :pointer # gss_name_t min_stat = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_import_name(min_stat, buff_str.pointer, mech, name) raise GssApiError.new(maj_stat, min_stat), "gss_import_name did not return GSS_S_COMPLETE" if maj_stat != 0 LibGSSAPI::GssNameT.new(name.get_pointer(0)) end
Initialize the GSS security context (client initiator). If there was a previous call that issued a
continue you can pass the continuation token in via the token param. If no flags are set the default flags are LibGSSAPI::GSS_C_MUTUAL_FLAG | LibGSSAPI::GSS_C_SEQUENCE_FLAG
@param [String] in_token an input token sent from the remote service in a continuation. @param [Hash] opts misc opts to be set @option opts [Fixnum] :flags override all other flags. If you set the :delegate option this option will override it.
@see http://tools.ietf.org/html/rfc4121#section-4.1.1.1
@option opts [Boolean] :delegate if true set the credential delegate flag @return [String, true] if a continuation flag is set it will return the output token that is needed to send
to the remote host. Otherwise it returns true and the GSS security context has been established.
# File lib/gssapi/simple.rb, line 64 def init_context(in_token = nil, opts = {}) min_stat = FFI::MemoryPointer.new :OM_uint32 pctx = (@context.nil? ? LibGSSAPI::GssCtxIdT.gss_c_no_context.address_of : @context.address_of) mech = LibGSSAPI::GssOID.gss_c_no_oid if(opts[:flags]) flags = opts[:flags] else flags = (LibGSSAPI::GSS_C_MUTUAL_FLAG | LibGSSAPI::GSS_C_SEQUENCE_FLAG | LibGSSAPI::GSS_C_CONF_FLAG | LibGSSAPI::GSS_C_INTEG_FLAG) flags |= LibGSSAPI::GSS_C_DELEG_FLAG if opts[:delegate] flags |= LibGSSAPI::GSS_C_DELEG_POLICY_FLAG if opts[:delegate] end in_tok = LibGSSAPI::UnManagedGssBufferDesc.new in_tok.value = in_token out_tok = LibGSSAPI::ManagedGssBufferDesc.new ret_flags = FFI::MemoryPointer.new :OM_uint32 maj_stat = LibGSSAPI.gss_init_sec_context(min_stat, nil, pctx, @int_svc_name, mech, flags, 0, nil, in_tok.pointer, nil, out_tok.pointer, ret_flags, nil) raise GssApiError.new(maj_stat, min_stat), "gss_init_sec_context did not return GSS_S_COMPLETE" if maj_stat > 1 # The returned context may be equal to the passed in @context. If so, we # must not create another AutoPointer to the same gss_buffer_t. If we do # we will double delete it. ctx = pctx.get_pointer(0) @context = LibGSSAPI::GssCtxIdT.new(ctx) if ctx != @context maj_stat == 1 ? out_tok.value : true end
Add a path to a custom keytab file @param [String] keytab the path to the keytab
# File lib/gssapi/simple.rb, line 251 def set_keytab(keytab) maj_stat = LibGSSAPI.krb5_gss_register_acceptor_identity(keytab) raise GssApiError.new(maj_stat, min_stat), "krb5_gss_register_acceptor_identity did not return GSS_S_COMPLETE" if maj_stat != 0 true end
Unwrap a message previously wrapped with gss_wrap. @param [String] msg The message to unwrap @param [Boolean] encrypted Whether or not this message was encrypted (true) or just signed (false)
# File lib/gssapi/simple.rb, line 235 def unwrap_message(msg, encrypted = true) min_stat = FFI::MemoryPointer.new :OM_uint32 in_buff = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new in_buff.value = msg out_buff = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new conf_state = FFI::MemoryPointer.new :int conf_state.write_int((encrypted ? 1 : 0)) q_op = FFI::MemoryPointer.new :OM_uint32 q_op.write_int(0) maj_stat = GSSAPI::LibGSSAPI.gss_unwrap(min_stat, @context, in_buff.pointer, out_buff.pointer, conf_state, q_op) raise GssApiError.new(maj_stat, min_stat), "Failed to gss_unwrap message" if maj_stat != 0 out_buff.value end
Wrap a message using gss_wrap. It can either encrypt the message (confidentiality) or simply sign it (integrity). @param [String] msg The message to wrap @param [Boolean] encrypt Whether or not to encrypt the message or just sign it. The default is to encrypt. @return [String] The wrapped message. It will raise an exception on error
# File lib/gssapi/simple.rb, line 219 def wrap_message(msg, encrypt = true) min_stat = FFI::MemoryPointer.new :OM_uint32 conf_req = (encrypt ? 1 : 0) qop_req = GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT in_buff = GSSAPI::LibGSSAPI::UnManagedGssBufferDesc.new in_buff.value = msg conf_state = FFI::MemoryPointer.new :OM_uint32 out_buff = GSSAPI::LibGSSAPI::ManagedGssBufferDesc.new maj_stat = GSSAPI::LibGSSAPI.gss_wrap(min_stat, @context, conf_req, qop_req, in_buff.pointer, conf_state, out_buff.pointer) raise GssApiError.new(maj_stat, min_stat), "Failed to gss_wrap message" if maj_stat != 0 out_buff.value end