Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# - WebRequest HTTP POST with Cookie (port from curl script)

The IBM RTC RESTful api gives an example of a shell script for authenticating with the server:

COOKIES=./cookies.txt

USER=my_user
PASSWORD=my_password
HOST="https://myJazzServer:9092/jazz"

curl -k -c $COOKIES "$HOST/authenticated/identity"

curl -k -L -b $COOKIES -c $COOKIES -d j_username=$USER -d j_password=$PASSWORD "$HOST/authenticated/j_security_check"

This works perfectly, however i need to authenticate with the server using c#.

So far i have the following, but it isn't working (returns the authorization failed page):

    CookieContainer _cookie;

    public string _RTC()
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://myJazzServer.com:9092/jazz/authenticated/identity");
        if (_cookie == null)
        {
            _cookie = new CookieContainer();
        }
        string a;
        request.CookieContainer = _cookie;
        using (var response = request.GetResponse())
        {
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                a = sr.ReadToEnd();
            }
        }




        byte[] data = (new ASCIIEncoding()).GetBytes("j_username=myUser&j_password=MyPass");

        request = (HttpWebRequest)WebRequest.Create("https://myJazzServer.com:9092/jazz/authenticated/j_security_check");

        request.Method = "POST";
        request.ContentType = "text/html";
        request.ContentLength = data.Length;
        request.CookieContainer = _cookie;
        Stream reqStream = request.GetRequestStream();
        reqStream.Write(data,0,data.Length);

        string b;

        using (var response = request.GetResponse())
        {
            using (var reader = new StreamReader(response.GetResponseStream()))
            {
                b = reader.ReadToEnd();
            }
        }
    }
like image 427
Paul Creasey Avatar asked Jul 15 '10 17:07

Paul Creasey


2 Answers

I would suggest you try the following:

public class WebClientEx : WebClient
{
    private CookieContainer _cookieContainer = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);
        if (request is HttpWebRequest)
        {
            (request as HttpWebRequest).CookieContainer = _cookieContainer;
        }
        return request;
    }
}

class Program
{
    static void Main()
    {
        using (var client = new WebClientEx())
        {
            var response1 = client.DownloadString("https://myJazzServer.com:9092/jazz/authenticated/identity");

            var data = new NameValueCollection
            {
                { "j_username", "myUser" },
                { "j_password", "MyPass" },
            };
            var response2 = client.UploadValues("https://myJazzServer.com:9092/jazz/authenticated/j_security_check", data);
            Console.WriteLine(Encoding.Default.GetString(response2));
        }
    }
}

Also to simplify debugging you could activate tracing by putting this in your app.config:

<configuration>

  <system.diagnostics>
    <sources>
      <source name="System.Net.Sockets" tracemode="protocolonly">
        <listeners>
          <add name="System.Net.Sockets" type="System.Diagnostics.TextWriterTraceListener" initializeData="network.log" />
        </listeners>
      </source>
    </sources>

    <switches>
      <add name="System.Net.Sockets" value="Verbose"/>
    </switches>

    <trace autoflush="true" />
  </system.diagnostics>
</configuration>

This will create a detailed log file of the network activity which might simplify debugging.

like image 56
Darin Dimitrov Avatar answered Nov 03 '22 15:11

Darin Dimitrov


Here is an alternative method if you want to use HttpWebResponse/HttpWebRequest:

public static HttpWebResponse requestSecureDocument(HttpWebRequest _request, string _rtcServerURL, string _userName, string _password)
{
    //FormBasedAuth Step1: Request the resource and clone the request to be used later
    HttpWebRequest _requestClone = WebRequestExtensions.CloneRequest(_request, _request.RequestUri);
    //(HttpWebRequest)WebRequest.Create(request.RequestUri);

    //store the response in _docResponse variable
    HttpWebResponse _docResponse = (HttpWebResponse)_request.GetResponse();

    //HttpStatusCode.OK indicates that the request succeeded and that the requested information is in the response.
    if (_docResponse.StatusCode == HttpStatusCode.OK)
    {
        //X-com-ibm-team-repository-web-auth-msg header signifies form based authentication is being used
        string _rtcAuthHeader = _docResponse.Headers["X-com-ibm-team-repository-web-auth-msg"];
        if (_rtcAuthHeader != null && _rtcAuthHeader.Equals("authrequired"))
        {
            _docResponse.GetResponseStream().Flush();
            _docResponse.Close();

            //Prepare form for authentication as _rtcAuthHeader = authrequired
            HttpWebRequest _formPost = (HttpWebRequest)WebRequest.Create(_rtcServerURL + "/j_security_check");
            _formPost.Method = "POST";
            _formPost.Timeout = 30000;
            _formPost.CookieContainer = _request.CookieContainer;
            _formPost.Accept = "text/xml";
            _formPost.ContentType = "application/x-www-form-urlencoded";

            String _authString = "j_username=" + _userName + "&amp;j_password=" + _password;
            //create authentication string
            Byte[] _outBuffer = Encoding.UTF8.GetBytes(_authString); //store in byte buffer
            _formPost.ContentLength = _outBuffer.Length;
            Stream _str = _formPost.GetRequestStream();
            _str.Write(_outBuffer, 0, _outBuffer.Length); //update form
            _str.Close();

            //FormBasedAuth Step2:submit the login form and get the response from the server
            HttpWebResponse _formResponse = (HttpWebResponse)_formPost.GetResponse();

            _rtcAuthHeader = _formResponse.Headers["X-com-ibm-team-repository-web-auth-msg"];
            //check if authentication has failed
            if (_rtcAuthHeader != null && _rtcAuthHeader.Equals("authfailed"))
            {
                //authentication failed. You can write code to handle the authentication failure.
                //if (DEBUG) Console.WriteLine("Authentication Failure");
            }
            else
            {
                //login successful
                _formResponse.GetResponseStream().Flush();
                _formResponse.Close();
                //FormBasedAuth Step3: Resend the request for the protected resource.
                //if (DEBUG) Console.WriteLine("&gt;&gt; Response " + request.RequestUri);
                return (HttpWebResponse)_requestClone.GetResponse();
            }
        }
    }
    //already authenticated return original response_docResponse
    return _docResponse;
}

You can call this function in your code -

string _serverURL = https://localhost:9443/ccm; 
string _resourceURL = "https://localhost:9443/ccm/rootservices";

string mediatype = "application/xml";
string username = "username";                                    
string password = "password";
try
{
    CookieContainer _cookies = new CookieContainer();//create cookie container
    HttpWebRequest documentGet = (HttpWebRequest)WebRequest.Create(_resourceURL);
    documentGet.Method = "GET"; //method
    documentGet.CookieContainer = _cookies; //set container for HttpWebRequest 
    documentGet.Accept = mediatype;
    documentGet.Headers.Set("OSLC-Core-Version", "3.0"); //for RTC 3.0.1.2
    documentGet.Timeout = 300000;
    HttpWebResponse response = requestSecureDocument(documentGet, _serverURL, username, password);

    if (response.StatusCode != HttpStatusCode.OK)
    {
        Console.WriteLine(" Error: " + response.StatusDescription);
        response.Close();
    }
}
catch (Exception ex)
{
}

You can read more at my blog.

like image 2
Navneet Kumar Avatar answered Nov 03 '22 14:11

Navneet Kumar