Overview

Overview of IWAAC integration for non-browser clients

Cleito IWAAC is not made only for browsers. Any HTTP client that can handle Kerberos authentication is actually able to access to web applications protected by IWAAC without entering a username and password. This is especially useful for scripts and programs that request the RESTful web APIs of modern applications such as Jira, Confluence, Bamboo, Bitbucket Server, Fisheye and Crucible.

The Atlassian REST APIs actually support Cookie-based authentication. The JSESSIONID cookie - along with the crowd.token_key and atlassian.xsrf.token cookies - obtained by logging in with a username and password can thus be used in any HTTP request to the Atlassian REST APIs. Thanks to IWAAC, that cookie can also be obtained upon successful Kerberos authentication, hence avoiding the need to hard-code a username and password in scripts and programs that request the REST APIs.

This page gives some examples of PowerShell, Python and Groovy scripts to get a JIRA issue via a simple REST request.


Prerequisites

  1. The very first prerequisite before developing and running your scripts is to make sure that you have properly configured IWAAC for regular browser clients. Please check out this page for detailed installation and configuration instructions.

  2. It is assumed in this page that the following properties have been set in the iwaac.properties file:

    iwaac.agent.include.only    Windows NT
    iwaac.uri.include.only        /login.jsp
    In such a configuration, your scripts will have to send an HTTP request to the /login.jsp page of Jira to get a valid JSESSIONID cookie (along with crowd.token_key and atlassian.xsrf.token cookies). That request will also need to carry a User-Agent header that contains the Windows NT string.

  3. Please also make sure that the machine from which you will be running your scripts does belong to your Active Directory domain. If you are planning to run your scripts from non-domain machines, please check out the non-domain machines section of this page.


PowerShell scripts

The UseDefaultCredentials option of Invoke-WebRequest makes it super easy to authenticate with Kerberos from a Windows machine in the AD domain. Thus, a PowerShell REST client will be as simple as the following code:

# URL of Jira's login page
$jiraLoginUrl = "http://jira.cleito.com:8080/login.jsp"

# URL of the Jira issue to retrieve
$jiraIssueUrl = "http://jira.cleito.com:8080/rest/api/2/issue/IWAAC-1"

# User-Agent of this script
$useragent = "Windows NT"

# Get a valid JSESSIONID cookie
Invoke-WebRequest -UseDefaultCredentials -Uri $jiraLoginUrl  -UserAgent $useragent -SessionVariable websession

# REST request
Invoke-RestMethod -Method GET -Uri $jiraIssueUrl  -UserAgent $useragent -WebSession $websession
			  
Simple PowerShell REST client with Kerberos authentication through IWAAC

Python scripts

The PycURL package allows developers to implement Kerberos authentication with very few lines of code. Please follow these instructions to install PycURL in your environment.

import pycurl
import cStringIO

# URL of Jira's login page
# The URL MUST be of the form: http://FQDN:port/login.jsp
# where FQDN is the A record of the server in Active Directory DNS
jiraLoginUrl = "http://jira.cleito.com:8080/login.jsp"

# URL of the Jira issue to retrieve
# The URL MUST be of the form: http://FQDN:port/<uri>
# where FQDN is the A record of the server in Active Directory DNS
jiraIssueUrl = "http://jira.cleito.com:8080/rest/api/2/issue/IWAAC-1"

# User-Agent of this script
useragent = "Windows NT"

# Instantiate http client
curl = pycurl.Curl()

curl.setopt(pycurl.COOKIEFILE, "")
curl.setopt(pycurl.USERAGENT, useragent)
curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_NEGOTIATE)
curl.setopt(pycurl.USERPWD, ':')

# Get a valid JSESSIONID cookie
curl.setopt(pycurl.URL, jiraLoginUrl)
curl.setopt(pycurl.WRITEFUNCTION, lambda x: None)
curl.perform()

# REST request

response = cStringIO.StringIO()

curl.setopt(pycurl.URL, jiraIssueUrl)
curl.setopt(curl.WRITEFUNCTION, response.write)
curl.perform()

curl.close()

print response.getvalue()

			  
Execute Simple Python REST client with Kerberos authentication through IWAAC on Windows Execute Simple Python REST client with Kerberos authentication through IWAAC on Mac OS

Groovy scripts

Thanks to Apache HttpComponents, Groovy makes Kerberos authentication very easy as well. Thus, a Groovy REST client will be as simple as the following code. Please note that this will only work on Windows machines in the AD domain as Apache HttpComponents relies on Windows system libraries for Kerberos authentication.

@Grab('org.apache.httpcomponents:httpclient-win:4.5.2')

import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.protocol.HttpClientContext
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.WinHttpClients
import org.apache.http.util.EntityUtils

// URL of Jira's login page
// The URL MUST be of the form: http://FQDN:port/login.jsp
// where FQDN is the A record of the server in Active Directory DNS
def jiraLoginUrl = "http://jira.cleito.com:8080/login.jsp"

// URL of the Jira issue to retrieve
// The URL MUST be of the form: http://FQDN:port/login.jsp
// where FQDN is the A record of the server in Active Directory DNS
def jiraIssueUrl = "http://jira.cleito.com:8080/rest/api/2/issue/IWAAC-1"

// User-Agent of this script
def useragent = "Windows NT"

// Check whether required Windows libraries are available
assert WinHttpClients.isWinAuthAvailable()

//Instantiate http client
def httpclient = WinHttpClients.createDefault()
def context = HttpClientContext.create() 

// Get a valid JSESSIONID cookie
def loginRequest = new HttpGet(jiraLoginUrl)
loginRequest.setHeader("User-Agent", useragent)
httpclient.execute(loginRequest, context)

// REST request
def restRequest = new HttpGet(jiraIssueUrl)
def response = httpclient.execute(restRequest, context)

println EntityUtils.toString(response.getEntity())
			  
Simple Groovy REST client with Kerberos authentication through IWAAC

Scripts running on non-domain machines

You might also want to run your Python or Groovy scripts from non-domain machines (e.g. Linux servers that do not belong to your Active Directory domain). To do so, you will need to generate a keytab file for the user running your scripts. A keytab file is a piece of cryptographic information that will enable your scripts to get the required Kerberos tickets to access to your back-end application.

  1. Edit /etc/krb5.conf on the non-domain machine:

    [libdefaults]
            default_realm = <YOURDOMAIN.COM>

    [realms]
            <YOURDOMAIN.COM> = {
                    kdc = <ad_domain_controller_fqdn>:88
            }

    [domain_realm]
            .<yourdomain.com> = <YOURDOMAIN.COM>
            <yourdomain.com> = <YOURDOMAIN.COM>
    For instance:

    krb5.conf

  2. Then run the ktutil utility:

    ktutil
    ktutil: add_entry -password -p <your_AD_username> -k 1 -e rc4-hmac OR aes128-cts-hmac-sha1-96 OR aes256-cts-hmac-sha1-96
    Password for <your_AD_username>@<YOURDOMAIN.COM>: <your_AD_user_password>
    ktutil: write_kt <keytab_file_name>
    ktutil: quit
    For instance:

    ktutil

  3. Now, run kinit -t <keytab_file_name> <your_AD_username> before running your Python script (you can run any PycURL-based script).

    For instance:

    Simple Python REST client with Kerberos authentication through IWAAC from outside domain

  4. Unlike PycURL-based Python scripts, Groovy scripts need to be modified as Apache HttpComponents cannot be used for Kerberos authentication on non-domain machines. The Java SPNEGO library is required here.

    First of all, create a login.conf file in the directory that contains your Groovy script:

    rest-client {
        com.sun.security.auth.module.Krb5LoginModule required
         storeKey=true
         useKeyTab=true
         keyTab="<keytab_file_name>"
         principal=<your_AD_username>
    };
    For instance:

    login.conf
    Then run the following Groovy script:

    @Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.1')
    
    @GrabResolver(name='net.sourceforge.spnego', root='http://repository.jspresso.org/maven2/')
    @Grab('net.sourceforge.spnego:spnego:7.0')
    
    import java.net.URL
    import net.sourceforge.spnego.SpnegoHttpURLConnection
    import groovyx.net.http.RESTClient
    
    // URL of Jira's login page
    // The URL MUST be of the form: http://FQDN:port/login.jsp
    // where FQDN is the A record of the server in Active Directory DNS
    def jiraLoginUrl = "http://jira.cleito.com:8080/login.jsp"
    
    // URL of the Jira issue to retrieve
    // The URL MUST be of the form: http://FQDN:port/<uri>
    // where FQDN is the A record of the server in Active Directory DNS
    def jiraIssueUrl = "http://jira.cleito.com:8080/rest/api/2/issue/IWAAC-1"
    
    // User-Agent of this script
    def useragent = "Windows NT"
    
    // Instantiate http client
    System.setProperty("java.security.krb5.conf", "/etc/krb5.conf")
    System.setProperty("java.security.auth.login.config", "login.conf")
              
    def httpClient = new SpnegoHttpURLConnection("rest-client")
    httpClient.setRequestProperty('User-Agent', useragent) 
    
    // Get a valid JSESSIONID cookie
    httpClient.connect(new URL(jiraLoginUrl))
               
    def header
    def cookieList = []
    for (int i=1; (header = httpClient.getHeaderFieldKey(i))!=null; i++) {
         if (header.equals('Set-Cookie')) {                  
            cookieList.add(httpClient.getHeaderField(i).tokenize(';')[0])        
        }
    }
    
    // REST request
    def request = new URL(jiraIssueUrl).openConnection() as HttpURLConnection
    request.setRequestProperty('Cookie', cookieList.join('; '))
    
    println request.inputStream.text
    					

    Simple Groovy REST client with Kerberos authentication through IWAAC from outside domain