13

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();
            }
        }
    }
Paul Creasey
  • 28,321
  • 10
  • 54
  • 90
  • Could you be a little more specific about what is "not working"? Are you getting an exception, no content in the response, unexpected http status code (e.g. 404, 407, etc) in the response, etc? – Nathan Jul 17 '10 at 17:17
  • @Nathan, it is returning an authorization failed page, i can't give details because what it returns is an ajax bootstrapper with a method called authFailed (or something like that), so i can't get the actual details. – Paul Creasey Jul 17 '10 at 17:26

2 Answers2

23

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.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Well that worked first time, apart from your offering being about 1000 times nicer than mine, i'm not really sure why it worked and mine didn't, but it's working now and thats what counts. Bounty inc in 22 hours :) Many thanks! – Paul Creasey Jul 17 '10 at 18:07
  • if there is "Set-Cookie" in response, your implementation will miss it, which could cause authentication failure. – PerlDev Aug 13 '10 at 18:59
  • I dropped this code in a small app I've been working on which fetches resources from a web site which needs authentication. All I had to change was the data sent in the POST, and it just works. Amazed! Now I need to go and figure out how it works, as it appears to be pure magic! – Greg Woods May 10 '12 at 13:05
  • can you explain in few words, why the override with the cookiecontainer does the magic? – Falco Alexander Feb 15 '17 at 16:12
2

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.

Simon MᶜKenzie
  • 8,344
  • 13
  • 50
  • 77
Navneet Kumar
  • 909
  • 7
  • 6