Consuming RTC (Rational Team Concert) OSLC APIs using C#: Post 1- Authentication

This is part-1 of the article series “Consuming RTC (Rational Team Concert) OSLC APIs using C#”.  I have written these articles because I couldn’t find enough resources on the Internet on this topic. I’ll be wiring multiple articles related to performing following actions using OSLC :

  1. RTC Form based authentication
  2. Get a WorkItem
  3. Create a new WorkItem
  4. Modify an existing WorkItem
  5. Query WorkItems

You’ll be able to understand this article better if you know about RTC OSLC APIs. There is an excellent article on jazz.net which you can read here – . This article provides a summary of the OSLC CM Rest APIs, along with shell script examples based on curl that illustrate the concepts in more detail. I am also assuming that you  have basic understanding of HttpWebRequest, HttpWebResponse, WebClient classes under System.Net namespace.

Scope of this article is limited to authentication for RTC repository. The two common authentication methods for an RTC repository are Basic Authentication and Form based Authentication. I have implemented Form based authentication for connecting to RTC Server. You can use either use WebClient or HttpWebRequest/HttpWebResponse. HttpWebRequest exposes lot more stuff as compared to WebClient and gives you granular control on the cookies. I have used both WebClient and HttpWebRequest.

Form based authentication is a three step process:

1. Client requests (GET) for protected RTC repository resource (like WorkItems).
2. If the client is unauthenticated, RTC Server redirects the client to the login page. Client has to programmatically authenticate by providing username and password (POST).
3. Client is redirected to the protected RTC repository resource which was requested in step 1. For all subsequent requests client is redirected directly to the resource.

In contrast to form based authentication, basic authentication is one step process where username and password is included in GET/POST request for a protected resource.

In Appendix-A of above mentioned article, you’ll find code snippet for form based RTC authentication using CURL. Lets take a look at the code given in the article:

COOKIES=./cookies.txt

USER=username
PASSWORD=password
HOST="https://localhost:9443/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"

# If this line returns the JSON representation of work item 1, authentication was successful
#curl -k -b $COOKIES "$HOST/oslc/workitems/1.json"

In code above we are trying to access Workitem –1 using shell scripting through curl. First two commands take care of the authentication and all the cookies are written to $COOKIES variable. This is required only once per session. For all subsequent requests $COOKIES is used. This is shown in the third command above.

Now lets take a look at C# authentication code using

1. WebClient class:

public class WebClientExtension : WebClient
    {
        //cookie container
        private CookieContainer _ckContainer = new CookieContainer();

        //request server 
        protected override WebRequest GetWebRequest(Uri _url)
        {
            WebRequest _request = base.GetWebRequest(_url);
            if (_request is HttpWebRequest)
            {
                (_request as HttpWebRequest).CookieContainer = _ckContainer;
            }
            return _request;
        }
    }
   class Program
    {
        static void Main()
        {
            //create object of WebClientExtension class
            using (var _webClient = new WebClientExtension())
            {
                var _serverResponse1 = _webClient.DownloadString("https://localhost:9443/jazz/authenticated/identity");
                //set username and password
                var data = new NameValueCollection
            {
                { "j_username", "UserName" },
                { "j_password", "Password" },
            };
                //authenticate
                var _serverResponse2 = _webClient.UploadValues("https://localhost:9443/jazz/authenticated/j_security_check", data);
                Console.WriteLine(Encoding.Default.GetString(_serverResponse2));
            }
        }
    }

WebClientExtension class inherits WebClient class.  In this class we have created a cookie container and overridden GetWebRequest function. In order to authenticate we first create an object of this class, set the username and password in name/value collection and upload it to the server for the authentication. Server response is then printed using Console.WriteLine.

2. HTPWebRequest/HttpWebResponse class:
In the example below, I have used WebRequestExtenstions class for cloning HTTPWebrequest object. You don’t have to use WebRequestExtenstions class in your implementation. I have used this class as I was doing another POC related to cloning a HTTPWebrequest object.

 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 + "&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(">> Response " + request.RequestUri);
                        return (HttpWebResponse)_requestClone.GetResponse();
                    }
                }
            }
            //already authenticated return original response_docResponse
            return _docResponse;
        }

The code is mostly self explanatory. This function accepts four parameters –HttpWebRequest object for the resource being requested from the RTC Server, Server URL, username and password. Here is sample code to call this function:

            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)
            {
            }

This brings us to the end of the first article. Hope you’ll find this article helpful. In next article we will be looking at querying workitems through C# using OSLC.

About Navneet Kumar

Navneet is a seasoned IT professional with more than 9+ years of experience. He has done double Masters in Mathematics and Software Systems from prestigious Birla Institute of Technology and Science (BITS), Pilani. Navneet is currently working as a Product Manager with Saama Technologies (http://saama.com).
This entry was posted in Uncategorized and tagged , , , , , , , . Bookmark the permalink.

12 Responses to Consuming RTC (Rational Team Concert) OSLC APIs using C#: Post 1- Authentication

  1. Amit says:

    Hi Navneet,

    Can you please provide the code for download

    Thnx
    Amit

  2. Rachel says:

    Hi Navneet
    First thank you so much for this initiative, this topic is really missing from RTC-IBM, and i am glad you help.
    Did you publish the second article? i will be happy to read the WorkItem retreive and creation, since it is exactly our use case.
    Thanks

    • Navneet Kumar says:

      Thank you for reading my blog and for your comment. I got busy and never published the second article. I’ll am planning to write the second article this weekend.

      • steve says:

        Hi Navneet,

        Great to hear you will be writing the second article. hope that the other articles will be published also.

        Regards,

        Steve

    • Navneet Kumar says:

      Sorry for the delay..I will be publishing my second article this weekend !

  3. Mike says:

    Great work Navneet! I look forward to reading your second article! Very helpful!

    -Mike

  4. klpo says:

    Nice article.
    I’m currently working on consuming RTC APIs usign C# in a Windows Phone APP.
    Any idea how your code can be adapted to work for Win. Apps ?!

  5. timo says:

    Can you please help me ?
    I get the exception :
    Error : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
    on line:
    var _serverResponse1 = _webClient.DownloadString(“https://localhost:9443/jazz/authenticated/identity”);

    Best regards

  6. Wayne says:

    Any chance you’re still going to write the second article? First one got me started, but now I need to move to the next step, which is exactly what you had planned for the second article.

Leave a comment