Class: Win32::SSPI::NegotiateAuth

Inherits:
Object
  • Object
show all
Defined in:
lib/winrm/win32/sspi.rb

Instance Method Summary collapse

Constructor Details

#initialize(user = nil, domain = nil, password = nil) ⇒ NegotiateAuth

Override to remember password Creates a new instance ready for authentication as the given user in the given domain. Defaults to current user and domain as defined by ENV and ENV if no arguments are supplied.



159
160
161
162
163
164
165
166
# File 'lib/winrm/win32/sspi.rb', line 159

def initialize(user = nil, domain = nil, password = nil)
  if user.nil? && domain.nil? && ENV["USERNAME"].nil? && ENV["USERDOMAIN"].nil?
    raise "A username or domain must be supplied since they cannot be retrieved from the environment"
  end
  @user = user || ENV["USERNAME"].dup
  @domain = domain || ENV["USERDOMAIN"].dup
  @password = password
end

Instance Method Details

#complete_authentication(token) ⇒ Object

Takes a token and gets the next token in the Negotiate authentication chain. Token can be Base64 encoded or not. The token can include the “Negotiate” header and it will be stripped. Does not indicate if SEC_I_CONTINUE or SEC_E_OK was returned. Token returned is Base64 encoded w/ all new lines removed.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/winrm/win32/sspi.rb', line 172

def complete_authentication(token)
  raise "This object is no longer usable because its resources have been freed." if @cleaned_up

  # Nil token OK, just set it to empty string
  token = "" if token.nil?

  if token.include? "Negotiate"
    # If the Negotiate prefix is passed in, assume we are seeing "Negotiate <token>" and get the token.
    token = token.split(" ").last
  end

  if token.include? B64_TOKEN_PREFIX
    # indicates base64 encoded token
    token = token.strip.unpack("m")[0]
  end

  outputBuffer = SecurityBuffer.new
  result = SSPIResult.new(API::InitializeSecurityContext.call(@credentials.to_p, @context.to_p, nil,
    REQUEST_FLAGS, 0, SECURITY_NETWORK_DREP, SecurityBuffer.new(token).to_p, 0,
    @context.to_p,
    outputBuffer.to_p, @contextAttributes, TimeStamp.new.to_p))

  if result.ok? then
    @auth_successful = true
    return encode_token(outputBuffer.token)
  else
    raise "Error: #{result.to_s}"
  end
ensure
  # need to make sure we don't clean up if we've already cleaned up.
  # XXX - clean up later since encrypt/decrypt needs this
  # clean_up unless @cleaned_up
end

#decrypt_payload(body) ⇒ Object



228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/winrm/win32/sspi.rb', line 228

def decrypt_payload(body)
  if @auth_successful

    matched_data = /--Encrypted Boundary\s+Content-Type:\s+application\/HTTP-SPNEGO-session-encrypted\s+OriginalContent:\s+type=\S+Length=(\d+)\s+--Encrypted Boundary\s+Content-Type:\s+application\/octet-stream\s+([\S\s]+)--Encrypted Boundary/.match(body)
    raise "Error: Unencrypted communication not supported. Please check winrm configuration winrm/config/service AllowUnencrypted flag." if matched_data.nil?

    encrypted_msg = matched_data[2]

    outputBuffer = DecryptedSecurityBuffer.new(encrypted_msg)
    result = SSPIResult.new(API::DecryptMessage.call(@context.to_p, outputBuffer.to_p, 0, 0 ))
    body = outputBuffer.buffer
  end
  body
end

#encrypt_payload(body) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/winrm/win32/sspi.rb', line 206

def encrypt_payload(body)
  if @auth_successful
    # Approach - http://msdn.microsoft.com/en-us/magazine/cc301890.aspx
    sizes = SecPkgContext_Sizes.new
    result = SSPIResult.new(API::QueryContextAttributes.call(@context.to_p, SECPKG_ATTR_SIZES, sizes.to_p))

    outputBuffer = EncryptedSecurityBuffer.new(body, sizes)
    result = SSPIResult.new(API::EncryptMessage.call(@context.to_p, 0, outputBuffer.to_p, 0 ))
    encrypted_msg = outputBuffer.buffer

    body = <<-EOF
--Encrypted Boundary\r
Content-Type: application/HTTP-SPNEGO-session-encrypted\r
OriginalContent: type=application/soap+xml;charset=UTF-8;Length=#{encrypted_msg.length - sizes.cbSecurityTrailer - 4}\r
--Encrypted Boundary\r
Content-Type: application/octet-stream\r
#{encrypted_msg}--Encrypted Boundary\r
EOF
  end
  body
end