Class: Win32::SSPI::NegotiateAuth
- Inherits:
-
Object
- Object
- Win32::SSPI::NegotiateAuth
- Defined in:
- lib/win32/sspi.rb
Overview
Handles “Negotiate” type authentication. Geared towards authenticating with a proxy server over HTTP
Constant Summary collapse
- REQUEST_FLAGS =
Default request flags for SSPI functions
ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION
- B64_TOKEN_PREFIX =
NTLM tokens start with this header always. Encoding alone adds “==” and newline, so remove those
Base64.encode64("NTLMSSP").delete("=\n")
Instance Attribute Summary collapse
-
#context ⇒ Object
Returns the value of attribute context.
-
#contextAttributes ⇒ Object
Returns the value of attribute contextAttributes.
-
#credentials ⇒ Object
Returns the value of attribute credentials.
-
#domain ⇒ Object
Returns the value of attribute domain.
-
#user ⇒ Object
Returns the value of attribute user.
Class Method Summary collapse
-
.proxy_auth_get(http, path, user = nil, domain = nil) ⇒ Object
Given a connection and a request path, performs authentication as the current user and returns the response from a GET request.
Instance Method Summary collapse
-
#complete_authentication(token) ⇒ Object
Takes a token and gets the next token in the Negotiate authentication chain.
-
#get_initial_token(auth_type) ⇒ Object
Gets the initial Negotiate token.
-
#initialize(user = nil, domain = nil) ⇒ NegotiateAuth
constructor
Creates a new instance ready for authentication as the given user in the given domain.
Constructor Details
#initialize(user = nil, domain = nil) ⇒ NegotiateAuth
243 244 245 246 247 248 249 250 251 |
# File 'lib/win32/sspi.rb', line 243 def initialize(user = nil, domain = 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"] @domain = domain || ENV["USERDOMAIN"] @cleaned_up = nil end |
Instance Attribute Details
#context ⇒ Object
Returns the value of attribute context.
210 211 212 |
# File 'lib/win32/sspi.rb', line 210 def context @context end |
#contextAttributes ⇒ Object
Returns the value of attribute contextAttributes.
210 211 212 |
# File 'lib/win32/sspi.rb', line 210 def contextAttributes @contextAttributes end |
#credentials ⇒ Object
Returns the value of attribute credentials.
210 211 212 |
# File 'lib/win32/sspi.rb', line 210 def credentials @credentials end |
#domain ⇒ Object
Returns the value of attribute domain.
210 211 212 |
# File 'lib/win32/sspi.rb', line 210 def domain @domain end |
#user ⇒ Object
Returns the value of attribute user.
210 211 212 |
# File 'lib/win32/sspi.rb', line 210 def user @user end |
Class Method Details
.proxy_auth_get(http, path, user = nil, domain = nil) ⇒ Object
Given a connection and a request path, performs authentication as the current user and returns the response from a GET request. The connnection should be a Net::HTTP object, and it should have been constructed using the Net::HTTP.Proxy method, but anything that responds to “get” will work. If a user and domain are given, will authenticate as the given user. Returns the response received from the get method (usually Net::HTTPResponse)
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/win32/sspi.rb', line 223 def NegotiateAuth.proxy_auth_get(http, path, user = nil, domain = nil) raise "http must respond to :get" unless http.respond_to?(:get) nego_auth = self.new user, domain resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token("Negotiate") } # Negotiate may not be supported, so we need to look for NTLM too. if resp["Proxy-Authenticate"].include? "Negotiate" resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(resp["Proxy-Authenticate"].split(" ").last.strip) } elsif resp["Proxy-Authenticate"].include? "NTLM" resp = http.get path, { "Proxy-Authorization" => "NTLM " + nego_auth.get_initial_token("NTLM") } resp = http.get path, { "Proxy-Authorization" => "NTLM " + nego_auth.complete_authentication(resp["Proxy-Authenticate"].split(" ").last.strip) } end resp 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.
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/win32/sspi.rb', line 279 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") || token.include?("NTLM") # 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 = Base64.decode64(token.strip) 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 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. clean_up unless @cleaned_up end |
#get_initial_token(auth_type) ⇒ Object
Gets the initial Negotiate token. Returns it as a base64 encoded string suitable for use in HTTP. Can be easily decoded, however.
auth_type is the authentication method being used. It is usually “Negotiate” or “NTLM”.
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/win32/sspi.rb', line 257 def get_initial_token(auth_type) raise "This object is no longer usable because its resources have been freed." if @cleaned_up get_credentials auth_type outputBuffer = SecurityBuffer.new @context = CtxtHandle.new @contextAttributes = "\0" * 4 result = SSPIResult.new(API::InitializeSecurityContext.call(@credentials.to_p, nil, nil, REQUEST_FLAGS,0, SECURITY_NETWORK_DREP, nil, 0, @context.to_p, outputBuffer.to_p, @contextAttributes, TimeStamp.new.to_p)) if result.ok? then return encode_token(outputBuffer.token) else raise "Error: #{result.to_s}" end end |