Invariant Properties

  • rss
  • Home

Using the JIRA REST java client: Introduction

Bear Giles | August 7, 2013

This is the first of a series of articles on using the JIRA REST java client.

Use Cases

Why would we want to use the JIRA java client? Here are three simple examples.

Webapp Exception Catchall

How many of use have seen an exception catch page that contained a stack trace? A nicer page saying that an exception occurred? An even nicer page that claimed that the failure had already been reported as a bug?

How many of us believed the last item?

It’s not hard to capture useful information in the webapp’s default exception handler, e.g. the stack trace, the identity of the current user, a sanitized version of the GET, PUT or POST data, and a sanitized version of the session attributes. What do you do with this information afterwards? Squirrel it away somewhere that nobody remembers to check? Email it to the developers and hope they don’t immediately trash it? The team isn’t deliberately ignoring the reported bugs, the bugs are just falling through the cracks since they aren’t a part of the normal workflow.

What if the information could be entered into JIRA as both a ‘bug’ and as a one-point user story in the agile backlog? (The single point is to perform the initial investigation – the dev and testing teams should add their own tasks and story points for actually fixing the bug and testing it.) It’s a lot harder to overlook an item in your backlog than a bug in bug tracking system.

Implementation note: the logger should be smart enough to avoid flooding the system with duplicate reports. A good way to handle this is to create some type of signature, e.g., an MD5 hash of the stack trace, and storing it as a custom field in the JIRA issue. The exception handler can then check for an existing issue before creating a new one. Incident-specific information is added as an attachment for the first, oh, ten instances.

Vulnerability Assessment Tracking

Everyone regularly performs vulnerability assessments. (Sticks fingers in ears and sings la-la-la-la-I-can’t-hear-you). What do you do with the results?

JIRA is flexible and allows users to define their own issue types and fields. Integration with vulnerability assessments is easy if you create three new issues, call them application (what’s being tested), build (an individual run) and defect (an individual defect). A single defect can span multiple builds, and of course a single build can contain multiple defects.

Again we can add single-point backlog stories to evaluate the results of the imported vulnerability assessment.

General Workflow Engine

JIRA is not just a bug tracker or an agile tool or whatever – it is a general workflow engine that just happens to be configured as these items by default or with standard extensions. You can easily add new types with their own workflows. Therefore there is no reason why you can’t use JIRA as a workflow engine in your application – just hide it behind a service and nobody will care.

There are two benefits to this approach. First it’s usually a lot cheaper to reuse an existing library than creating your own. Second you can use the existing JIRA UI to peek into the back-end instead of writing your own UI.

Getting JIRA

We have to start by installing JIRA. We’ll want to do this for development and testing even if we have an existing instance.

Fortunately this is a straightforward process:

  • Download JIRA from https://www.atlassian.com/software/jira/try/. The windows installer is on the main page, the OS X and Linux installers are available at https://www.atlassian.com/software/jira/download.
  • Install it.
  • Configure the admin user.

It is also possible to stand up a JIRA instance for maven integration tests. For details see the JRJC ‘test’ package.

JIRA requires a license after the trial period but the cost of an annual 10-user license is trivial. That license should be more than enough for client development.

Getting the JIRA REST Java Client (JRJC)

The easiest way to get the JIRA REST Java Client (JRJC) is to add the Atlassian repository to your settings.xml file. I add the repositories in a profile since this is easiest way to selectively enable it.

  1. <settings>
  2.   <profiles>
  3.     <profile>
  4.        <id>atlassian</id>
  5.        <repositories>
  6.          <repository>
  7.            <id>atlassian-public</id>
  8.            <url>https://m2proxy.atlassian.com/repository/public</url>
  9.            <snapshots>
  10.              <enabled>true</enabled>
  11.              <updatePolicy>daily</updatePolicy>
  12.              <checksumPolicy>warn</checksumPolicy>
  13.            </snapshots>
  14.            <releases>
  15.              <enabled>true</enabled>
  16.              <checksumPolicy>warn</checksumPolicy>
  17.            </releases>
  18.          </repository>
  19.        </repositories>
  20.  
  21.        <pluginRepositories>
  22.          <pluginRepository>
  23.            <id>atlassian-public</id>
  24.            <url>https://m2proxy.atlassian.com/repository/public</url>
  25.            <releases>
  26.              <enabled>true</enabled>
  27.              <checksumPolicy>warn</checksumPolicy>
  28.            </releases>
  29.            <snapshots>
  30.              <checksumPolicy>warn</checksumPolicy>
  31.            </snapshots>
  32.          </pluginRepository>
  33.        </pluginRepositories>
  34.     </profile>
  35.   </profiles>
  36.  
  37.   <activeProfiles>
  38.     <!-- <activeProfile>atlassian</activeProfile> -->
  39.   </activeProfiles>
  40. </settings>
<settings>
  <profiles>
    <profile>
       <id>atlassian</id>
       <repositories>
         <repository>
           <id>atlassian-public</id>
           <url>https://m2proxy.atlassian.com/repository/public</url>
           <snapshots>
             <enabled>true</enabled>
             <updatePolicy>daily</updatePolicy>
             <checksumPolicy>warn</checksumPolicy>
           </snapshots>
           <releases>
             <enabled>true</enabled>
             <checksumPolicy>warn</checksumPolicy>
           </releases>
         </repository>
       </repositories>

       <pluginRepositories>
         <pluginRepository>
           <id>atlassian-public</id>
           <url>https://m2proxy.atlassian.com/repository/public</url>
           <releases>
             <enabled>true</enabled>
             <checksumPolicy>warn</checksumPolicy>
           </releases>
           <snapshots>
             <checksumPolicy>warn</checksumPolicy>
           </snapshots>
         </pluginRepository>
       </pluginRepositories>
    </profile>
  </profiles>

  <activeProfiles>
    <!-- <activeProfile>atlassian</activeProfile> -->
  </activeProfiles>
</settings>

Since 2.0.0 is still under active development some developers may wish to download the source and build the packages locally so they can add missing functionality. The source can be obtained at https://bitbucket.org/atlassian/jira-rest-java-client/downloads and select the “tags” tab.

If you decide to build the packages locally you’ll need to use Maven 2, not Maven 3.

For more information visit the JIRA REST Java Client Library project site.

Connecting to the JIRA server

We can now connect to the JIRA server. Future entries will discuss how to do more useful things but for now it’s enough to just ping the server.

  1. package com.invariantproperties.sandbox.jira.example;
  2.  
  3. import java.io.IOException;
  4. import java.net.URI;
  5. import java.util.ResourceBundle;
  6.  
  7. import org.junit.Test;
  8.  
  9. import com.atlassian.jira.rest.client.api.JiraRestClient;
  10. import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
  11. import com.atlassian.jira.rest.client.api.domain.ServerInfo;
  12. import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
  13. import com.atlassian.util.concurrent.Promise;
  14. import com.sun.jersey.core.spi.scanning.uri.BundleSchemeScanner;
  15.  
  16. import static org.junit.Assert.assertEquals;
  17.  
  18. /**
  19.  * Simple test that does nothing but connect to a JIRA server and verifies the
  20.  * connection.
  21.  *
  22.  * @author Bear Giles <bgiles@coyotesong.com>
  23.  */
  24. public class HelloWorldTest {
  25.     private static final ResourceBundle bundle = ResourceBundle
  26.             .getBundle(HelloWorldTest.class.getName());
  27.     private static final URI serverUri = URI
  28.             .create(bundle.getString("jiraUrl"));
  29.     private static final String username = bundle.getString("username");
  30.     private static final String password = bundle.getString("password");
  31.  
  32.     @Test
  33.     public void connectToServer() throws IOException {
  34.         final JiraRestClient restClient = new AsynchronousJiraRestClientFactory()
  35.                 .createWithBasicHttpAuthentication(serverUri, username, password);
  36.  
  37.         try {
  38.             final ServerInfo info = restClient.getMetadataClient().getServerInfo().claim();
  39.             assertEquals(URI.create(bundle.getString("jiraUrl")), info.getBaseUri());
  40.         } finally {
  41.             if (restClient != null) {
  42.                 restClient.close();
  43.             }
  44.         }
  45.     }
  46. }
package com.invariantproperties.sandbox.jira.example;

import java.io.IOException;
import java.net.URI;
import java.util.ResourceBundle;

import org.junit.Test;

import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
import com.atlassian.jira.rest.client.api.domain.ServerInfo;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
import com.atlassian.util.concurrent.Promise;
import com.sun.jersey.core.spi.scanning.uri.BundleSchemeScanner;

import static org.junit.Assert.assertEquals;

/**
 * Simple test that does nothing but connect to a JIRA server and verifies the
 * connection.
 * 
 * @author Bear Giles <bgiles@coyotesong.com>
 */
public class HelloWorldTest {
    private static final ResourceBundle bundle = ResourceBundle
            .getBundle(HelloWorldTest.class.getName());
    private static final URI serverUri = URI
            .create(bundle.getString("jiraUrl"));
    private static final String username = bundle.getString("username");
    private static final String password = bundle.getString("password");

    @Test
    public void connectToServer() throws IOException {
        final JiraRestClient restClient = new AsynchronousJiraRestClientFactory()
                .createWithBasicHttpAuthentication(serverUri, username, password);

        try {
            final ServerInfo info = restClient.getMetadataClient().getServerInfo().claim();
            assertEquals(URI.create(bundle.getString("jiraUrl")), info.getBaseUri());
        } finally {
            if (restClient != null) {
                restClient.close();
            }
        }
    }
}

with a resource bundle containing suitable replacements for these values

  1. # in the real world we should use OWASP ESAPI, for instance,
  2. # to encrypt the password if not all of the properties.
  3. jiraUrl = http://localhost:8080
  4. username = bgiles
  5. password = bgiles
# in the real world we should use OWASP ESAPI, for instance,
# to encrypt the password if not all of the properties.
jiraUrl = http://localhost:8080
username = bgiles
password = bgiles

and a pom.xml file containing

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2.     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3.     <modelVersion>4.0.0</modelVersion>
  4.     <groupId>com.invariantproperties.sandbox</groupId>
  5.     <artifactId>jira</artifactId>
  6.     <version>0.0.1-SNAPSHOT</version>
  7.     <dependencies>
  8.         <!-- compilation dependency -->
  9.         <dependency>
  10.             <groupId>com.atlassian.jira</groupId>
  11.             <artifactId>jira-rest-java-client-api</artifactId>
  12.             <version>2.0.0-m25</version>
  13.         </dependency>
  14.  
  15.         <!-- runtime dependency -->
  16.         <dependency>
  17.             <groupId>com.atlassian.jira</groupId>
  18.             <artifactId>jira-rest-java-client-core</artifactId>
  19.             <version>2.0.0-m25</version>
  20.         </dependency>
  21.  
  22.         <!-- test dependencies -->
  23.         <dependency>
  24.             <groupId>junit</groupId>
  25.             <artifactId>junit</artifactId>
  26.             <version>4.8.1</version>
  27.             <scope>test</scope>
  28.         </dependency>
  29.     </dependencies>
  30. </project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.invariantproperties.sandbox</groupId>
	<artifactId>jira</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<!-- compilation dependency -->
		<dependency>
			<groupId>com.atlassian.jira</groupId>
			<artifactId>jira-rest-java-client-api</artifactId>
			<version>2.0.0-m25</version>
		</dependency>

		<!-- runtime dependency -->
		<dependency>
			<groupId>com.atlassian.jira</groupId>
			<artifactId>jira-rest-java-client-core</artifactId>
			<version>2.0.0-m25</version>
		</dependency>

		<!-- test dependencies -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
</project>

Security

The current client library has several major security concerns.

Authentication

User authentication information is passed via plaintext username and passwords. I do not know if this is a limitation of the REST server or client. If it’s the former it will be difficult to work around, if it’s the latter then a custom JiraRestClientFactory class may be necessary but it can be done.

Encryption

Issues may contain sensitive information and some sites may require the use of HTTPS connections. The current client factory does not support HTTPS connections “out of the box”. One of the constructors takes an Atlassian-enhanced HttpClient object so encryption can be added to it via the standard HttpComponents methods. I do not know if additional initializations must be performed if this approach is taken.

Proxy

Again the current client factory does not support proxy connections “out of the box” but it can be added to an HttpClient object passed to the factory.

Limitations

The final thing we need to discuss are the limitations of the library. There are two major sources:

JIRA REST API limitations. The JIRA REST API does not include all of the functionality available via the UI. For instance you cannot create, edit, or delete either projects or users. You can review the current REST API at https://docs.atlassian.com/jira/REST/latest/.

JIRA REST java client (JRJC) limitations. The JRJC library does not support all of the functionality in the JIRA REST API. Fortunately the client is fairly straightforward so it is easy to download the source and add the required functionality.

Workarounds

You have two final options if the REST API lacks required functionality.

Write a JIRA plugin. A custom JIRA plugin does not have unlimited access to the system but it will certainly have more than the REST API. It must be installed on the JIRA server though – something many sites will be reluctant to do.

Directly access the database. Eek! Sometimes this is the only possibility but it should only be done as a last resort, only to the minimum extent required, and will almost certainly require an explicit reindex afterwards. (I used this approach when migrating data from our old bug-tracking software but I only used it to reset the usernames and timestamps of issues that I created using the standard REST API.)

Categories
java
Comments rss
Comments rss
Trackback
Trackback

« Backup trick: moving user caches into /var/cache Using the JIRA REST java client: Projects »

One Response to “Using the JIRA REST java client: Introduction”

  1. how do i solve java.lang.NoClassDefFoundError: com/atlassian/jira/rest/client/internal/async/AsynchronousJiraRestClientFactory exception? - BlogoSfera says:
    July 5, 2015 at 8:58 pm

    […] but don’t no how to solve it please help. want to fetch JIRA data. I am using similar code http://invariantproperties.com/2013/08/07/using-the-jira-rest-java-client-introduction/ getting exception :: org.springframework.web.util.NestedServletException: Handler processing […]

    Log in to Reply

Leave a Reply

Click here to cancel reply.

You must be logged in to post a comment.

Archives

  • May 2020 (1)
  • March 2019 (1)
  • August 2018 (1)
  • May 2018 (1)
  • February 2018 (1)
  • November 2017 (4)
  • January 2017 (3)
  • June 2016 (1)
  • May 2016 (1)
  • April 2016 (2)
  • March 2016 (1)
  • February 2016 (3)
  • January 2016 (6)
  • December 2015 (2)
  • November 2015 (3)
  • October 2015 (2)
  • August 2015 (4)
  • July 2015 (2)
  • June 2015 (2)
  • January 2015 (1)
  • December 2014 (6)
  • October 2014 (1)
  • September 2014 (2)
  • August 2014 (1)
  • July 2014 (1)
  • June 2014 (2)
  • May 2014 (2)
  • April 2014 (1)
  • March 2014 (1)
  • February 2014 (3)
  • January 2014 (6)
  • December 2013 (13)
  • November 2013 (6)
  • October 2013 (3)
  • September 2013 (2)
  • August 2013 (5)
  • June 2013 (1)
  • May 2013 (2)
  • March 2013 (1)
  • November 2012 (1)
  • October 2012 (3)
  • September 2012 (2)
  • May 2012 (6)
  • January 2012 (2)
  • December 2011 (12)
  • July 2011 (1)
  • June 2011 (2)
  • May 2011 (5)
  • April 2011 (6)
  • March 2011 (4)
  • February 2011 (3)
  • October 2010 (6)
  • September 2010 (8)

Recent Posts

  • 8-bit Breadboard Computer: Good Encapsulation!
  • Where are all the posts?
  • Better Ad Blocking Through Pi-Hole and Local Caching
  • The difference between APIs and SPIs
  • Hadoop: User Impersonation with Kerberos Authentication

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Pages

  • About Me
  • Notebook: Common XML Tasks
  • Notebook: Database/Webapp Security
  • Notebook: Development Tips

Syndication

Java Code Geeks

Know Your Rights

Support Bloggers' Rights
Demand Your dotRIGHTS

Security

  • Dark Reading
  • Krebs On Security Krebs On Security
  • Naked Security Naked Security
  • Schneier on Security Schneier on Security
  • TaoSecurity TaoSecurity

Politics

  • ACLU ACLU
  • EFF EFF

News

  • Ars technica Ars technica
  • Kevin Drum at Mother Jones Kevin Drum at Mother Jones
  • Raw Story Raw Story
  • Tech Dirt Tech Dirt
  • Vice Vice

Spam Blocked

53,793 spam blocked by Akismet
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox