class Thrift::SaslClientTransport

Constants

AUTH_MECHANISM
NEGOTIATION_STATUS
PAYLOAD_LENGTH_BYTES
STATUS_BYTES

Attributes

challenge[R]
sasl_complete[R]

Public Class Methods

new(transport, sasl_params={}) click to toggle source
Calls superclass method
   # File lib/thrift/sasl_client_transport.rb
16 def initialize(transport, sasl_params={})
17   super(transport)
18   @challenge = nil
19   @sasl_username = sasl_params.fetch(:username, 'anonymous')
20   @sasl_password = sasl_params.fetch(:password, 'anonymous')
21   @sasl_mechanism = sasl_params.fetch(:mechanism, 'PLAIN')
22   raise 'Unknown SASL mechanism: #{@sasl_mechanism}' unless ['PLAIN', 'GSSAPI'].include? @sasl_mechanism
23   if @sasl_mechanism == 'GSSAPI'
24     require 'gssapi'
25     @sasl_remote_principal = sasl_params[:remote_principal]
26     @sasl_remote_host = sasl_params[:remote_host]
27     @gsscli = GSSAPI::Simple.new(@sasl_remote_host, @sasl_remote_principal)
28   end
29 end

Public Instance Methods

read(sz) click to toggle source
   # File lib/thrift/sasl_client_transport.rb
31 def read(sz)
32   len, = @transport.read(PAYLOAD_LENGTH_BYTES).unpack('l>') if @rbuf.nil?
33   sz = len if len && sz > len
34   @index += sz
35   ret = @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer
36   if ret.length < sz
37     sz -= ret.length
38     read_into_buffer(@rbuf, [sz, len || 0].max)
39     @index = sz
40     ret += @rbuf.slice(0, sz) || Bytes.empty_byte_buffer
41   end
42   ret
43 end
read_byte() click to toggle source
   # File lib/thrift/sasl_client_transport.rb
45 def read_byte
46   reset_buffer! if @index >= @rbuf.size
47   @index += 1
48   Bytes.get_string_byte(@rbuf, @index - 1)
49 end
read_into_buffer(buffer, size) click to toggle source
   # File lib/thrift/sasl_client_transport.rb
51 def read_into_buffer(buffer, size)
52   i = 0
53   while i < size
54     reset_buffer! if @index >= @rbuf.size
55     byte = Bytes.get_string_byte(@rbuf, @index)
56     Bytes.set_string_byte(buffer, i, byte)
57     @index += 1
58     i += 1
59   end
60   i
61 end
write(buf) click to toggle source
   # File lib/thrift/sasl_client_transport.rb
63 def write(buf)
64   initiate_hand_shake unless sasl_complete
65   header = [buf.length].pack('l>')
66   @wbuf << (header + Bytes.force_binary_encoding(buf))
67 end

Protected Instance Methods

initiate_hand_shake() click to toggle source
   # File lib/thrift/sasl_client_transport.rb
71 def initiate_hand_shake
72   if @sasl_mechanism == 'GSSAPI'
73     initiate_hand_shake_gssapi
74   else
75     initiate_hand_shake_plain
76   end
77 end
initiate_hand_shake_gssapi() click to toggle source
    # File lib/thrift/sasl_client_transport.rb
 79 def initiate_hand_shake_gssapi
 80   token = @gsscli.init_context
 81   header = [NEGOTIATION_STATUS[:START], @sasl_mechanism.length].pack('cl>')
 82   @transport.write header + @sasl_mechanism
 83   header = [NEGOTIATION_STATUS[:OK], token.length].pack('cl>')
 84   @transport.write header + token
 85   status, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
 86   case status
 87   when NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]
 88     raise @transport.to_io.read(len)
 89   when NEGOTIATION_STATUS[:COMPLETE]
 90     raise "Not expecting COMPLETE at initial stage"
 91   when NEGOTIATION_STATUS[:OK]
 92     challenge = @transport.to_io.read len
 93     unless @gsscli.init_context(challenge)
 94       raise "GSSAPI: challenge provided by server could not be verified"
 95     end
 96     header = [NEGOTIATION_STATUS[:OK], 0].pack('cl>')
 97     @transport.write header
 98     status2, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
 99     case status2
100     when NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]
101       raise @transport.to_io.read(len)
102     when NEGOTIATION_STATUS[:COMPLETE]
103       raise "Not expecting COMPLETE at second stage"
104     when NEGOTIATION_STATUS[:OK]
105       challenge = @transport.to_io.read len
106       unwrapped = @gsscli.unwrap_message(challenge)
107       rewrapped = @gsscli.wrap_message(unwrapped)
108       header = [NEGOTIATION_STATUS[:COMPLETE], rewrapped.length].pack('cl>')
109       @transport.write header + rewrapped
110       status3, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
111       case status3
112       when NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]
113         raise @transport.to_io.read(len)
114       when NEGOTIATION_STATUS[:COMPLETE]
115         s = @transport.to_io.read len
116         @sasl_complete = true
117       when NEGOTIATION_STATUS[:OK]
118         raise "Failed to complete GSS challenge exchange"
119       end
120     end
121   end
122   @sasl_complete = true
123 end
initiate_hand_shake_plain() click to toggle source
    # File lib/thrift/sasl_client_transport.rb
125 def initiate_hand_shake_plain
126   header = [NEGOTIATION_STATUS[:START], AUTH_MECHANISM.length].pack('cl>')
127   @transport.write header + AUTH_MECHANISM
128   message = "[#{AUTH_MECHANISM}]\u0000#{@sasl_username}\u0000#{@sasl_password}"
129   header = [NEGOTIATION_STATUS[:OK], message.length].pack('cl>')
130   @transport.write header + message
131   status, len = @transport.read(STATUS_BYTES + PAYLOAD_LENGTH_BYTES).unpack('cl>')
132   case status
133   when NEGOTIATION_STATUS[:BAD], NEGOTIATION_STATUS[:ERROR]
134     raise @transport.to_io.read(len)
135   when NEGOTIATION_STATUS[:COMPLETE]
136     @challenge = @transport.to_io.read len
137   when NEGOTIATION_STATUS[:OK]
138     raise "Failed to complete challenge exchange: only NONE supported currently"
139   end
140   @sasl_complete = true
141 end

Private Instance Methods

reset_buffer!() click to toggle source
    # File lib/thrift/sasl_client_transport.rb
145 def reset_buffer!
146   len, = @transport.read(PAYLOAD_LENGTH_BYTES).unpack('l>')
147   @rbuf = @transport.read(len)
148   while @rbuf.size < len
149     @rbuf << @transport.read(len - @rbuf.size)
150   end
151   @index = 0
152 end