1

regarding to this post Apache NTLM Auth from C# client do not work with self defined NetworkCredentials I added a method to authenticate. I thought I am done with my work for today :) but I run into another problem.

Code:

public static void Authenticate()
{
  Stream requestStream = null;
  string loginUrl = Common.WindowAuthentication ? Common.PortalUrl + Common.IoiLoginWin : Common.PortalUrl + Common.IoiLogin;

  var request = (HttpWebRequest)WebRequest.Create(loginUrl);
  request.Method = WebRequestMethods.Http.Post;
  request.AllowAutoRedirect = true;
  request.CookieContainer = Common.Cookies;
  request.Accept = @"*/*";

  if (Common.WindowAuthentication)
  {
    if (Common.UserName.Length > 0)
    {
      string[] domainuser;
      string username;
      string domain;

      if (Common.UserName.Contains("@"))
      {
        domainuser = Common.UserName.Split('@');
        username = domainuser[0];
        domain = domainuser[1];
      }
      else
      {
        domainuser = Common.UserName.Split('\\');
        username = domainuser[1];
        domain = domainuser[0];
      }
      var nc = new NetworkCredential(username, Common.Password, domain);
      var cache = new CredentialCache();
      cache.Add(request.RequestUri, "NTLM", nc);
      request.Credentials = cache;
    }
    else
    {
      request.Credentials = CredentialCache.DefaultNetworkCredentials;
    }
  }
  else
  {
    string payload = Common.ParmLogin + Common.UserName + "&" + Common.ParmPass + Common.Password;
    StringBuilder urlEncoded = new StringBuilder();
    Char[] reserved = { '?', '=', '&' };
    byte[] byteBuffer;

    if (payload != null)
    {
      int i = 0, j;
      while (i < payload.Length)
      {
        j = payload.IndexOfAny(reserved, i);
        if (j == -1)
        {
          urlEncoded.Append(HttpUtility.UrlEncode(payload.Substring(i, payload.Length - i)));
          break;
        }
        urlEncoded.Append(HttpUtility.UrlEncode(payload.Substring(i, j - i)));
        urlEncoded.Append(payload.Substring(j, 1));
        i = j + 1;
      }
      byteBuffer = Encoding.UTF8.GetBytes(urlEncoded.ToString());
      request.ContentLength = byteBuffer.Length;
      requestStream = request.GetRequestStream();
      requestStream.Write(byteBuffer, 0, byteBuffer.Length);
      requestStream.Close();
    }
    else
    {
      request.ContentLength = 0;
    }
    if (Common.LogCommunicatin)
      LogCommunication(loginUrl, payload);
  }

  using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
  {
    if (response.StatusCode.ToString() == "OK") {
      WebHeaderCollection c = response.Headers;
      Common.SessionCookie = Common.Cookies.GetCookies(new Uri(loginUrl))["_ror_session"].Value;
      if (Common.LogCommunicatin)
        LogCommunication(loginUrl, "Cookie: " + Common.SessionCookie); 
    }
  }
}

When I use CredentialCache.DefaultNetworkCredentials the server (Ruby on Rails over Apache/Thin) is able to fetch Username and remote address.

Code (part of the ruby code server side):

begin
  cookies[:user] = { :value => user.strusername, :expires => 1.month.from_now }
  session[:current_user_id] = user.id
  session_record = request.env['rack.session.record']
  session_record.update_attributes({
    :username => user.strusername,
    :client_ip => (request.env['HTTP_X_FORWARDED_FOR']||request.env['REMOTE_ADDR'])
  })
rescue => e
end

But when I use own credentials the server don't get username and client_ip from the httpwebrequest.

So what do I wrong or what do I miss ?

UPDATE:

I inserted some ruby debug code to inspect the session and headers. In fact the user and client ip are sent in browser and the httpwebrequest. But for any reason the session_record.update_attributes don't update/save the values.

So it is a ruby issue which I have to investigate... no c# thingy...

Here is a RoR inspection of the header of a browser where client_ip and username are successfully updated:

{"SERVER_SOFTWARE"=>"thin 1.2.11 codename Bat-Shit Crazy", "SERVER_NAME"=>"thorx64", "rack.input"=>#<StringIO:0x9f4db08>, "rack.version"=>[1, 0], "rack.errors"=>#<IO:<STDERR>>, "rack.multithread"=>false, "rack.multiprocess"=>false, "rack.run_once"=>false, "REQUEST_METHOD"=>"GET", "REQUEST_PATH"=>"/ror/login.json", "PATH_INFO"=>"/login.json", "REQUEST_URI"=>"/ror/login.json", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_HOST"=>"thorx64", "HTTP_ACCEPT"=>"image/jpeg, image/gif, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*", "HTTP_ACCEPT_LANGUAGE"=>"de-DE", "HTTP_USER_AGENT"=>"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET4.0C; .NET4.0E; .NET CLR 3.5.30729; .NET CLR 3.0.30729)", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate", "HTTP_AUTHORIZATION"=>"NTLM TlRMTVNTUAADAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAABcKIogYBsR0AAAAPB3e6Q1YIzZ10PiKm2g/S6A==", "HTTP_COOKIE"=>"user=Administrator", "HTTP_X_ISRW_PROXY_AUTH_USER"=>"Administrator", "HTTP_MAX_FORWARDS"=>"10", "HTTP_X_FORWARDED_FOR"=>"192.168.14.21", "HTTP_X_FORWARDED_HOST"=>"thorx64", "HTTP_X_FORWARDED_SERVER"=>"thorx64", "HTTP_CONNECTION"=>"Keep-Alive", "GATEWAY_INTERFACE"=>"CGI/1.2", "SERVER_PORT"=>"80", "QUERY_STRING"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "rack.url_scheme"=>"http", "SCRIPT_NAME"=>"/ror", "REMOTE_ADDR"=>"127.0.0.1", "async.callback"=>#<Method: Thin::Connection#post_process>, "async.close"=>#<EventMachine::DefaultDeferrable:0x9f4c4d0>, "action_dispatch.parameter_filter"=>[:password], "action_dispatch.secret_token"=>"a1ef5e037607d12742a40a0793de973a5e68605ccf087ad1baedaee6d811687b82a0671b94da2c4a9af2b481a5346585649e83d2f56f2838a4aca8eedbfc93b7", "action_dispatch.show_exceptions"=>true, "action_dispatch.remote_ip"=>127.0.0.1, "rack.session"=>{}, "rack.session.options"=>{:path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :id=>nil}, "rack.request.cookie_string"=>"user=Administrator", "rack.request.cookie_hash"=>{"user"=>"Administrator"}, "action_dispatch.request.path_parameters"=>{:controller=>"login", :action=>"index", :format=>"json"}, "action_controller.instance"=>#<LoginController:0xb6d59a0 @action_has_layout=true, @view_context_class=nil, @_headers={"Content-Type"=>"text/html"}, @_status=200, @_response=#<ActionDispatch::Response:0xb6d5760 @writer=#<Proc:0xb6d54f0@D:/Informer/ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.10/lib/action_dispatch/http/response.rb:43 (lambda)>, @block=nil, @length=0, @header={}, @status=200, @body=[], @cookie=[], @sending_file=false, @blank=false, @cache_control={}, @etag=nil, @request=#<ActionDispatch::Request:0xb6d5778 @env={...}, @request_method="GET", @filtered_parameters={"controller"=>"login", "action"=>"index", "format"=>"json"}, @method="GET", @fullpath="/ror/login.json">>, @_request=#<ActionDispatch::Request:0xb6d5778 @env={...}, @request_method="GET", @filtered_parameters={"controller"=>"login", "action"=>"index", "format"=>"json"}, @method="GET", @fullpath="/ror/login.json">, @_env={...}, @lookup_context=#<ActionView::LookupContext:0xb6c3d60 @details_key=nil, @details={:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:html, :text, :js, :css, :ics, :csv, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :flv, :file, :image, :auto, :sourcefile, :sourceimage, :sourceauto, :legacy, :edit], :locale=>[:de, :de]}, @skip_default_locale=false, @frozen_formats=false, @view_paths=[d:/Informer/company/latest/ror/app/views, d:/Informer/company/latest/ror/vendor/plugins/will_paginate/app/views, d:/Informer/company/latest/ror/vendor/plugins/usesguid/app/views, d:/Informer/company/latest/ror/vendor/plugins/acts_as_tree/app/views]>, @_action_name="index", @_response_body=nil, @_config={}, @_params={"controller"=>"login", "action"=>"index", "format"=>"json"}, @_current_user=nil>, "action_dispatch.request.content_type"=>nil, "action_dispatch.request.request_parameters"=>{}, "rack.request.query_string"=>"", "rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request.parameters"=>{"controller"=>"login", "action"=>"index", "format"=>"json"}, "action_dispatch.request.formats"=>[application/json]}

And here from the web request where I have client_ip and username as well but the database don't get updated:

{"SERVER_SOFTWARE"=>"thin 1.2.11 codename Bat-Shit Crazy", "SERVER_NAME"=>"thorx64", "rack.input"=>#<StringIO:0xa3a3778>, "rack.version"=>[1, 0], "rack.errors"=>#<IO:<STDERR>>, "rack.multithread"=>false, "rack.multiprocess"=>false, "rack.run_once"=>false, "REQUEST_METHOD"=>"POST", "REQUEST_PATH"=>"/ror/login.json", "PATH_INFO"=>"/login.json", "REQUEST_URI"=>"/ror/login.json", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_HOST"=>"thorx64", "HTTP_ACCEPT"=>"*/*", "HTTP_X_REQUESTED_WITH"=>"XMLHttpRequest", "HTTP_USER_AGENT"=>"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET4.0C; .NET4.0E; .NET CLR 3.5.30729; .NET CLR 3.0.30729)", "HTTP_AUTHORIZATION"=>"NTLM TlRMTVNTUAADAAAAGAAYAH4AAACgAaABlgAAAAwADABYAAAADAAMAGQAAAAOAA4AcAAAAAAAAAA2AgAABYKIogYBsR0AAAAPGyWqqmBHFtGQTE/QMlHT7XQAcQBzAG8AZgB0AHIAYQB1AHMAYwBoAFQASABPAFIAWAA2ADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoZP5isSr442bUTMoUknN3QEBAAAAAAAAZCgelIW2zQH2AaAgXe6DYQAAAAACAAwAVABRAFMATwBGAFQAAQAOAFQASABPAFIAWAA2ADQABAAsAGYAcgBhAC4AZwBlAHIAbQBhAG4AeQAuAHQAcQBzAG8AZgB0AC4AbgBlAHQAAwA8AFQASABPAFIAeAA2ADQALgBmAHIAYQAuAGcAZQByAG0AYQBuAHkALgB0AHEAcwBvAGYAdAAuAG4AZQB0AAUALABmAHIAYQAuAGcAZQByAG0AYQBuAHkALgB0AHEAcwBvAGYAdAAuAG4AZQB0AAcACABkKB6UhbbNAQYABAACAAAACAAwADAAAAAAAAAAAAAAAAAwAAAgXEA1/+dnAlRife8JhCuzKyRGkcsJKXvyXzrION0KdwoAEAAAAAAAAAAAAAAAAAAAAAAACQBGAEgAVABUAFAALwBUAEgATwBSAHgANgA0AC4AZgByAGEALgBnAGUAcgBtAGEAbgB5AC4AdABxAHMAbwBmAHQALgBuAGUAdAAAAAAAAAAAAAAAAAA=", "HTTP_X_ISRW_PROXY_AUTH_USER"=>"rausch", "HTTP_MAX_FORWARDS"=>"10", "HTTP_X_FORWARDED_FOR"=>"192.168.14.21", "HTTP_X_FORWARDED_HOST"=>"thorx64", "HTTP_X_FORWARDED_SERVER"=>"thorx64", "HTTP_CONNECTION"=>"Keep-Alive", "GATEWAY_INTERFACE"=>"CGI/1.2", "SERVER_PORT"=>"80", "QUERY_STRING"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "rack.url_scheme"=>"http", "SCRIPT_NAME"=>"/ror", "REMOTE_ADDR"=>"127.0.0.1", "async.callback"=>#<Method: Thin::Connection#post_process>, "async.close"=>#<EventMachine::DefaultDeferrable:0xa3a28f0>, "action_dispatch.parameter_filter"=>[:password], "action_dispatch.secret_token"=>"a1ef5e037607d12742a40a0793de973a5e68605ccf087ad1baedaee6d811687b82a0671b94da2c4a9af2b481a5346585649e83d2f56f2838a4aca8eedbfc93b7", "action_dispatch.show_exceptions"=>true, "action_dispatch.remote_ip"=>127.0.0.1, "rack.session"=>{}, "rack.session.options"=>{:path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :id=>nil}, "rack.request.form_input"=>#<StringIO:0xa3a3778>, "rack.request.form_hash"=>{}, "rack.request.form_vars"=>"", "action_dispatch.request.path_parameters"=>{:controller=>"login", :action=>"index", :format=>"json"}, "action_controller.instance"=>#<LoginController:0xb9d86a0 @action_has_layout=true, @view_context_class=nil, @_headers={"Content-Type"=>"text/html"}, @_status=200, @_response=#<ActionDispatch::Response:0xb9d8460 @writer=#<Proc:0xb9d8388@D:/Informer/ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.10/lib/action_dispatch/http/response.rb:43 (lambda)>, @block=nil, @length=0, @header={}, @status=200, @body=[], @cookie=[], @sending_file=false, @blank=false, @cache_control={}, @etag=nil, @request=#<ActionDispatch::Request:0xb9d8478 @env={...}, @request_method="POST", @filtered_parameters={"controller"=>"login", "action"=>"index", "format"=>"json"}, @method="POST", @fullpath="/ror/login.json">>, @_request=#<ActionDispatch::Request:0xb9d8478 @env={...}, @request_method="POST", @filtered_parameters={"controller"=>"login", "action"=>"index", "format"=>"json"}, @method="POST", @fullpath="/ror/login.json">, @_env={...}, @lookup_context=#<ActionView::LookupContext:0xb9d55f8 @details_key=nil, @details={:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:html, :text, :js, :css, :ics, :csv, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :flv, :file, :image, :auto, :sourcefile, :sourceimage, :sourceauto, :legacy, :edit], :locale=>[:de, :de]}, @skip_default_locale=false, @frozen_formats=false, @view_paths=[d:/Informer/company/latest/ror/app/views, d:/Informer/company/latest/ror/vendor/plugins/will_paginate/app/views, d:/Informer/company/latest/ror/vendor/plugins/usesguid/app/views, d:/Informer/company/latest/ror/vendor/plugins/acts_as_tree/app/views]>, @_action_name="index", @_response_body=nil, @_config={}, @_params={"controller"=>"login", "action"=>"index", "format"=>"json"}, @_current_user=nil>, "action_dispatch.request.request_parameters"=>{}, "rack.request.query_string"=>"", "rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request.parameters"=>{"controller"=>"login", "action"=>"index", "format"=>"json"}, "action_dispatch.request.formats"=>[application/json], "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: nil, session_id: "14e03319c61b707318dd50066340be95", client_ip: nil, username: nil, data: nil, created_at: nil, updated_at: nil>, "action_dispatch.request.flash_hash"=>nil}
Community
  • 1
  • 1
YvesR
  • 5,173
  • 6
  • 38
  • 65

1 Answers1

0

Ok, after more testing I find finally the problem: We use protect_from_forgery in our application controller.

So it helped to set skip_before_filter :verify_authenticity_token in my logn controller.

But this looks like a workaround to me and I don't have a good feeling with it.

I am no rails pro, but I wonder why I have to send a token with my very first request which goes directly to the login controller from my httpwebrequest.

EDIT 1:

Anyone have a clue, explanation or link how to manage this correct? Or in other words: As my login controller ONLY authenticate it is ok from the point of security to disable the auth token on this controller?

EDIT 2:

I found this: Understanding the Rails Authenticity Token. But now I need to know how to get the token and store it in my C# client to resend it with every request. Or not necessary at all?

Community
  • 1
  • 1
YvesR
  • 5,173
  • 6
  • 38
  • 65