Search code examples
c#html.netjenkinsjenkins-plugins

Logging into Jenkins Programmatically in C#


I have jobs in Jenkins that i cannot access unless i log in first using a my username and password.

For example if i try to access "localhost:xxx/job/some_job_1" i will get a 404 Error unless i log in first. And i say this because i have tried the following using WebRequest class:

string formParams = "j_username=bobbyLee&j_password=SecretPassword25&from=%2F&json=%7B%22j_username%22%3A+%bobbyLee%22%2C+%22j_password%22%3A+%22SecretPassword%25%22%2C+%22remember_me%22%3A+false%2C+%22from%22%3A+%22%2F%22%7D&Submit=log+in";
        // ***this is the exact string that is sent when i log in normally, obtained using Fiddler***

        string formUrl = "http://serverName:PortNum/j_acegi_security_check";
        // ***I have also tried http://serverName:PortNum/login***
        string cookieHeader;
        WebRequest req = WebRequest.Create(formUrl);
        req.ContentType = "application/x-www-form-urlencoded";
        req.Method = "POST";
        byte[] bytes = Encoding.ASCII.GetBytes(formParams);
        req.ContentLength = bytes.Length;
        using (Stream os = req.GetRequestStream())
        {
            os.Write(bytes, 0, bytes.Length);
        }
        WebResponse resp = req.GetResponse();
        cookieHeader = resp.Headers["Set-cookie"];

        string pageSource;
        string getUrl = "http://serverName:portNum/job/some_job/";
        WebRequest getRequest = WebRequest.Create(getUrl);
        getRequest.Headers.Add("Cookie", cookieHeader);
        WebResponse getResponse = getRequest.GetResponse();
        using (StreamReader sr = new StreamReader(getResponse.GetResponseStream()))
        {
            pageSource = sr.ReadToEnd();
        }

The response that i get back from the POST request is "HTML OK", and cookieHeader is not null. But when i then try to make a GET request to get what i want, i get a 404 error when attempting to access the job "http://serverName:portNum/job/some_job/", as if i didn't log in successfully.

So what is the correct way to log into Jenkins from c#, and get the HTML source code of the jobs that only appears after logging in?


Solution

  • The RESTAPI is your best friend here.

    It is an incredibly rich source of information. I have written a system that will show an entire program of work on a page with full deployment traceability.

    I am going to assume you have some security in place in your Jenkins instance which means requests need to be authenticated.

    I use the following class for this:

    using System;
    using System.Net;
    using System.Text;
    
    namespace Core.REST
    {
        public class HttpAdapter
        {
            private const string ApiToken = "3abcdefghijklmnopqrstuvwxyz12345";  // you will need to change this to the real value
    
            private const string UserName = "restapi";
    
            public string Get(string url)
            {
                try
                {
                    const string credentials = UserName + ":" + ApiToken;
                    var authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes(credentials));
                    using (var wc = new WebClient())
                    {
                        wc.Headers[HttpRequestHeader.Authorization] = "Basic " + authorization;
                        var htmlResult = wc.DownloadString(string.Format(url));
                        return htmlResult;
                    }
                }
                catch (WebException e)
                {
                    Console.WriteLine("Could not retrieve REST API response");
                    throw e;
                }
            }
        }
    }
    

    restapi is a dedicated user I created. I think I gave it admin access just so I didn't have to worry about it. I was admin but all the other developers and testers in the 3 crews had highly controlled and limited access to only what they needed and nothing more. It is also better practice to have a dedicated users for functions like this.

    I constructed my c# classes to consume (deserialise) data from any page that supports the api/json suffix.