Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Integrating Crowd Authentication with Jira Rest API

Nate Jones April 27, 2014

I am developing a thick client for my organization that will be pulling in information from multiple data sources including Jira, Confluence, and custom web services. We are considering using Crowd as a SSO service. What I would like to do is only pass my credentials across the wire once, to the Crowd server, and then be able to access all of my data sources for the remainder of the session (like Oauth).

I have figured out fairly easily how to authenticate with the crowd server rest api. I now have an application token and a session token. What I would like to be able to do is call the Jira rest api with those two tokens. Is this possible? Or is there something else I should be doing?

Here is my test case (full test case project on GitHub). We are using the crowd-integration-client-rest 2.7.1 and jira-rest-java-client 1.0 libraries from Atlassian's public maven repository. The basic authentication test executes successfully, but the crowd authentication test fails when we try to call the Jira api with the Crowd token. All the crowd api calls seem to execute successfully. It's not until we call Jira that we run into any trouble. I am attempting to implement the approach described in this answer. Can anybody spot my problem?

JiraIntegrationTest.java

///... Imports and What Not ...
public class JiraIntegrationTest extends TestCase{
  @Test
  public void testCrowdAuthentication() throws Exception {
    System.out.println("\n\n****TestCrowdAuthentication****");
    RestCrowdClientFactory factory = new RestCrowdClientFactory();
    CrowdClient client = factory.newInstance("http://127.0.0.1:8095/crowd", "crowd-auth-webapp", "password");
    assertNotNull("Client should not be null", client);
    final CookieConfiguration cookieConfig = client.getCookieConfiguration();
    assertNotNull("Cookie Config should not be null", cookieConfig);
    System.out.printf("Cookie Config: %1$s, %2$s\n", cookieConfig.getDomain(), cookieConfig.getName());
    UserAuthenticationContext userAuthCtx = new UserAuthenticationContext();
    userAuthCtx.setName("test");
    userAuthCtx.setCredential(new PasswordCredential("test"));
    userAuthCtx.setApplication("crowd-auth-webapp");
    userAuthCtx.setValidationFactors(new ValidationFactor[0]);
    final String token = client.authenticateSSOUser(userAuthCtx);
    assertNotNull("Token should not be null", token);
    final Session session = client.validateSSOAuthenticationAndGetSession(token, new Vector<ValidationFactor>());
    assertNotNull("Session should not be null", session);
    assertEquals("Session token and original token should be equal", session.getToken(), token);
    System.out.printf("Session Token: %s %n", session.getToken());
    System.out.printf("Session Expires: %tc %n", session.getExpiryDate());
    
    JiraRestClientFactory jiraFactory = new com.atlassian.jira.rest.client.internal.jersey.JerseyJiraRestClientFactory();
    JiraRestClient jira = jiraFactory.create(new URI("http://127.0.0.1:8080"), new AuthenticationHandler(){
      public void configure(ApacheHttpClientConfig config) {
        config.getProperties().put(ApacheHttpClientConfig.PROPERTY_HANDLE_COOKIES, true);
        Cookie cookie = new Cookie();
        cookie.setName(cookieConfig.getName());
        cookie.setValue(token);
        cookie.setDomain("127.0.0.1:8080");
        cookie.setPath("/");
        config.getState().getHttpState().addCookie(cookie);
      }

      public void configure(Filterable filterable, Client client) {}
    });
    TestJiraClient(jira);  //Perform test access.  This is where it fails.
  }
 //...

Here is the output from running this test case: (test.txt)


5 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

0 votes
Answer accepted
Nate Jones May 6, 2014

With Eero's comment here. I've been able to get this working. The problem was that I wasn't adding the remote_address validation factor. Once I added the validation factor, everything worked as expected. You can find my working test case here.

We're still working through some syncing issues between Jira and Crowd. But this issue seems to be resolved.

Thanks for all the help Eero and Felipe! You guys and Atlassian as a whole have given me great customer support!

1 vote
eero
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
April 28, 2014

Hi Nate,

The options you have for authenticating with JIRA are HTTP Basic Auth, OAuth and cookies (as described in https://docs.atlassian.com/jira/REST/6.2/) If you are using cookies and JIRA is configured to use Crowd SSO, you need to supply both JIRA JSESSIONID and the Crowd SSO cookie. (See https://jira.atlassian.com/browse/JRA-25470)

This is getting a bit complicated, but following should work:

1. Get Crowd SSO cookie from Crowd (like you do in your code)

2. Use the Crowd SSO cookie to hit any protected resource in JIRA (dashboard might work, remember to follow redirects). This will log you in to JIRA

3. Get the JSESSIONID from the response to the request executed in step 2.

4. Use both cookies when calling JIRA rest APIs.

Cheers,

Eero

Nate Jones April 28, 2014

Thanks for the response Eero. I'll try this out and report back.

Nate Jones April 28, 2014

I was able to get the JSESSIONID cookie by pinging the dashboard, like you suggested. You can see my new setup at GitHub. Here is a portion of the output from running my test case:

Adding Cookie: JSESSIONID=4B7A93DA7B0EAFA6D6C28480D9E35C14
Adding Cookie: crowd.token_key=0v4QiQnCi33E3D0d8AE70g00
Apr 29, 2014 11:56:15 AM org.apache.commons.httpclient.HttpMethodDirector processWWWAuthChallenge
WARNING: Unable to respond to any of these challenges: {oauth=OAuth realm="http%3A%2F%2Flocalhost%3A8080"}
Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.489 sec <<< FAILURE!
testCrowdAuthentication(AtlassianTests.JiraIntegrationTest)  Time elapsed: 0.768 sec  <<< ERROR!
com.atlassian.jira.rest.client.RestClientException: You are not authenticated. Authentication required to perform this operation.

Thanks so much for all the help. Any other ideas?

eero
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
April 29, 2014

It looks like for some reason JIRA is presenting you an OAuth challenge, which is a bit weird. Next I would try executing the REST call to JIRA using a simpler client, such as curl or the postman extension for Chrome (http://www.getpostman.com/). If those do not work, we can rule out any possible problems with the Java code (which looks like correct to me). Using just the crowd cookie should work.

I'll ping the JIRA REST client developers about this problem, they might have more ideas. If I recall correctly they are in Poland, so it might take a while for them to wake up and respond.

Nate Jones April 30, 2014

After taking your advice Eero and trying to access the API's through Curl, I found that if I used a Crowd token from the Crowd Rest API it will not work with Jira. But if I use a Crowd token from a working web app, I can successfully call the Jira Rest API.

In this first example, I attempt to call the Crowd Rest API through Curl and then use the generated token to call Jira. You'll notice that no projects are returned.

No projects

But in this next example, if I copy the crowd token out of a web browser that has been authenticated with Crowd. I can then use it to access the Jira Rest API.

Jira Projects Call Success

Am I calling the Crowd API incorrectly? Does the token that is returned from the Crowd API need to be encrypted before it is stored in the cookie?

eero
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
April 30, 2014

Hi Nate,

The token you get back from the Crowd REST API is the value of the authentication cookie, so you are doing everything correctly here.

If you compare the response headers, it looks like that JIRA is treating you as an anonymous user when the session was created with the Crowd REST API.

One more thing which may cause issues is that when you create a session in Crowd, the corresponding session in JIRA is created asynchronously. So you might have to wait a little bit (we're talking about seconds here, maybe a minute at most) and/or try calling the API multiple times.

If the waiting/retrying does not help, it's really starting to look like a bug to me.

Cheers,

Eero

Nate Jones May 2, 2014

After some further digging, I found that the amount of time between getting the crowd token and accessing the Jira rest API didn't make any difference.

What I did find was that the "Require Consistent Client IP Address" option in the Crowd session config does make a difference. If that option is enabled, then a token retrieved from the Rest API will not work with Jira. But if I disable it, then I can access Jira using that token from any computer.

Here I test the access token with "Require Consistent Client IP Address" set. Notice that no projects are returned and Jira views me as anonymous.

And here we try again without the cheeckbox. Notice that we now get projects.

This narrows down the problem. But I am concerned about the security implications of leaving this unchecked. Does anyone have any suggestions?

eero
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
May 4, 2014

Hi Nate,

When the "Require Consistent Client IP address" is checked, the client IP address needs to be incluuded in the REST message to Crowd. See https://developer.atlassian.com/display/CROWDDEV/Crowd+REST+Resources#CrowdRESTResources-CrowdSSOTokenResourcefor more indormation. This is also what JIRA does when it creates a new session in Crowd, which is why the cookie copied from browser works.

In the Java APIs you can specify an array of ValidationFactors when creating the UserAuthenticationContext: https://docs.atlassian.com/crowd/current/com/atlassian/crowd/model/authentication/UserAuthenticationContext.html#UserAuthenticationContext%28java.lang.String,%20com.atlassian.crowd.embedded.api.PasswordCredential,%20com.atlassian.crowd.model.authentication.ValidationFactor[],%20java.lang.String%29

There should be no need to disable the IP address validation, unless you want to (usually you want to disable if you have lots of users using laptops and mobile phones etc. whose IP addresses are changing constantly)

Hope this helps,

Eero

0 votes
eero
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
April 28, 2014

Hi Nate,

Another thing I noticed in your code is that you are setting the cookie domain like this:

cookie.setDomain("127.0.0.1:8080");

Ports do not really work/are used in cookie domains, so I'm not sure what the client is going to do with that. Can you try using just "127.0.0.1" or "localhost" as the cookie domain?

-eero

Nate Jones April 28, 2014

Neither 127.0.0.1 nor localhost seem to make a difference in my test case. But I will keep these in mind as I move forward with my testing.

0 votes
Nate Jones April 28, 2014

Here is the output from running my test:

0 votes
Chad Freeman April 28, 2014

What type of application links do you have set up? Crowd, Jira etc. Do you have any details on that?

Also, what is the exact error you are getting?

Nate Jones April 28, 2014

I have registered an application link between my jira and my crowd application, but it doesn't seem to make a difference. I should add that I can log in using crowd through the Jira web interface. And if I pass a crowd user name and password to the Jira api using basic authentication it works fine.

The error that I get when I try to use the crowd token is this:

com.atlassian.jira.rest.client.RestClientException: You are not authenticated. Authentication required to perform this operation.

at com.atlassian.jira.rest.client.internal.jersey.AbstractJerseyRestClient.invoke(AbstractJerseyRestClient.java:68)

at com.atlassian.jira.rest.client.internal.jersey.AbstractJerseyRestClient.getAndParse(AbstractJerseyRestClient.java:80)

at com.atlassian.jira.rest.client.internal.jersey.JerseySessionRestClient.getCurrentSession(JerseySessionRestClient.java:42)

....

Nate Jones April 28, 2014

Yep. I followed those instructions and SSO seems to work through the web interface. I can log into crowd and then go to Jira and already be logged in. Plus basic authentication works with the Jira rest api using a Crowd user. Here's what my crowd.properties file looks like:

application.name                        jira
application.password                    jira
application.login.url                   http://localhost:8095/crowd/console/

crowd.server.url                        http://localhost:8095/crowd/services/
crowd.base.url                          http://localhost:8095/crowd/

session.isauthenticated                 session.isauthenticated
session.tokenkey                        session.tokenkey
session.validationinterval              2
session.lastvalidation                  session.lastvalidation

FelipeA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 28, 2014

Hi Nate,

After you set your JIRA to authenticate against Crowd, you'll also have to set up SSO on Jira. Did you also perform those steps?

Best regards,

Felipe Alencastro

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

TAGS
AUG Leaders

Atlassian Community Events