I'm trying to use the Jira Jave Rest Client to log time against a ticket automatically with information from another system. This other system has the same usernames as jira so I want to log time using the actual user.
I need a way to authenticate as any user of Jria, without them needing to authorise me (this will be a trused application) I've setup an application link which seems to be what I need to do this, but I cannot find any example of what I need to use for the Java Rest Client. So far I have:
final OAuthParameters params = new OAuthParameters();
params.setConsumerKey("MyApplication");
params.setSignatureMethod("RSA-SHA1");
final OAuthSecrets secrets = new OAuthSecrets();
final JerseyJiraRestClientFactory factory = new JerseyJiraRestClientFactory();
final URI jiraServerUri = new URI(uri);
return factory.create(jiraServerUri, new OAuthAuthenticationHandler(params, secrets));
I can't find any example of what else I need to do.
Community moderators have prevented the ability to post new answers.
After much playing around, and reading the source code of most of that project I've been able to get my desired solution working. I'll go over everyting here, first with a few answers to people should be aware of
Here is my solution:
For anyone else that wants to implement, you need to generate your public/private keys as linked to above and create the trusted application through the Jira gui. Make sure you enable 2 legged oauth. Next, create the following class:
import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URISyntaxException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import net.oauth.OAuth; import net.oauth.OAuthAccessor; import net.oauth.OAuthConsumer; import net.oauth.OAuthException; import net.oauth.OAuthMessage; import net.oauth.OAuthServiceProvider; import net.oauth.http.HttpMessage; import net.oauth.signature.RSA_SHA1; import com.atlassian.jira.rest.client.AuthenticationHandler; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.ClientRequest; import com.sun.jersey.api.client.ClientRequest.Builder; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.filter.ClientFilter; import com.sun.jersey.api.client.filter.Filterable; import com.sun.jersey.api.uri.UriComponent; import com.sun.jersey.client.apache.config.ApacheHttpClientConfig; public class TrusedApplicationTwoLeggedOAuthAuthenticationHandler implements AuthenticationHandler { private final String consumerKey; private final String userKey; private final String privateKey; private final String baseUri; public TrusedApplicationTwoLeggedOAuthAuthenticationHandler(final String consumerKey, final String userKey, final String privateKey, final String baseUri) { super(); this.consumerKey = consumerKey; this.userKey = userKey; this.privateKey = privateKey; this.baseUri = baseUri; } @Override public void configure(final ApacheHttpClientConfig apacheHttpClientConfig) { } @Override public void configure(final Filterable filterable, final Client client) { final TrustedApplicationClientFilter filter = new TrustedApplicationClientFilter(); filterable.addFilter(filter); } private class TrustedApplicationClientFilter extends ClientFilter { public TrustedApplicationClientFilter() { super(); } @Override public ClientResponse handle(final ClientRequest request) throws ClientHandlerException { try { final OAuthServiceProvider serviceProvider = new OAuthServiceProvider(baseUri + "/plugins/servlet/oauth/request-token", baseUri + "/plugins/servlet/oauth/authorize", baseUri + "/plugins/servlet/oauth/access-token"); final OAuthConsumer consumer = new OAuthConsumer("oob", consumerKey, null, serviceProvider); consumer.setProperty(RSA_SHA1.PRIVATE_KEY, privateKey); consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1); final OAuthAccessor accessor = new OAuthAccessor(consumer); accessor.accessToken = ""; final Map<String, String> parameters = new HashMap<String, String>(); for (final Entry<String, List<String>> entry : UriComponent.decodeQuery(request.getURI(), true).entrySet()) { parameters.put(entry.getKey(), entry.getValue().get(0)); } parameters.put("user_id", userKey); final OAuthMessage message = accessor.newRequestMessage(request.getMethod(), request.getURI().toString(), parameters.entrySet(), new ByteArrayInputStream(request.getEntity().toString().getBytes())); final Builder requestBuilder = ClientRequest.create(); // TODO This does not support multi value params for (final Entry<String, List<Object>> entry : request.getHeaders().entrySet()) { requestBuilder.header(entry.getKey(), entry.getValue()); } requestBuilder.entity(request.getEntity()); final HttpMessage httpRequest = HttpMessage.newRequest(message, net.oauth.ParameterStyle.BODY); return getNext().handle(requestBuilder.build(httpRequest.url.toURI(), request.getMethod())); } catch (final URISyntaxException e) { throw new ClientHandlerException(e); } catch (final OAuthException e) { throw new ClientHandlerException(e); } catch (final IOException e) { throw new ClientHandlerException(e); } } } }
Finally, use it the following way:
String uri = "http://my.jira.uri"; final JerseyJiraRestClientFactory factory = new JerseyJiraRestClientFactory(); final URI jiraServerUri = new URI(uri); return factory.create(jiraServerUri, new TrusedApplicationTwoLeggedOAuthAuthenticationHandler("ConsumerName", "JiraUserName", "private key", uri));
I hope this works for anyone else wanting to do this, and do reply if you have any problems/questions
Hi Martin, Could you please let me know for which version of JRJC does this implementation work? I am using JRJC v2.0.0-m31 and this implementation does not work for me since the interface AuthenticationHandler only has one method configure(com.atlassian.httpclient.api.Request). Could you please provide an implementation for OAuthAuthenticationHandler for this version?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Martin,
Are you using the below dependencies:
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-rest-java-client-core</artifactId>
<version>5.0.4</version>
</dependency>
<dependency>
<groupId>net.oauth.core</groupId>
<artifactId>oauth</artifactId>
<version>20100527</version>
</dependency>
I'm not able to compile your code, would you please help.
Thanks!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
OK, this is my approach, it is very hacky but it is compatible with JiraRestClientFactory.
First follow JIRA REST API Tutorial to get your access token. Read their source code to understand exactly what they do, as my code is based on their code. Their code uses net.oauth library. Since this library is not under central maven repository, you need to add its repository to your maven file:
<repository> <id>oauth</id> <url>http://oauth.googlecode.com/svn/code/maven/</url> </repository> ... <dependency> <groupId>net.oauth.core</groupId> <artifactId>oauth</artifactId> <version>20100527</version> </dependency> <dependency> <groupId>net.oauth.core</groupId> <artifactId>oauth-consumer</artifactId> <version>20100527</version> </dependency> <dependency> <groupId>net.oauth.core</groupId> <artifactId>oauth-httpclient4</artifactId> <version>20090913</version> </dependency>
Now, we need to combine what the tutorial did to make authenticated request with the new AuthenticationHandler.
@Test public void test() throws Exception { final JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory(); final URI jiraServerUri = new URI("https://your.jira.instance"); JiraRestClient restClient = null; // restClient = factory.createWithBasicHttpAuthentication(jiraServerUri, "user", "pass"); // old way of doing it restClient = factory.create(jiraServerUri, new AuthenticationHandler() { @Override public void configure(Request request) { try { OAuthAccessor accessor = getAccessor(); accessor.accessToken = access_token; OAuthMessage request2 = accessor.newRequestMessage(null, request.getUri().toString(), Collections.<Map.Entry<?, ?>>emptySet()); Object accepted = accessor.consumer.getProperty(OAuthConsumer.ACCEPT_ENCODING); if (accepted != null) { request2.getHeaders().add(new OAuth.Parameter(HttpMessage.ACCEPT_ENCODING, accepted.toString())); } Object ps = accessor.consumer.getProperty(OAuthClient.PARAMETER_STYLE); ParameterStyle style = (ps == null) ? ParameterStyle.BODY : Enum.valueOf(ParameterStyle.class, ps.toString()); HttpMessage httpRequest = HttpMessage.newRequest(request2, style); for ( Entry<String, String> ap : httpRequest.headers) request.setHeader(ap.getKey(), ap.getValue()); request.setUri( httpRequest.url.toURI() ); } catch (Exception e) { e.printStackTrace(); } } }); final int buildNumber = restClient.getMetadataClient().getServerInfo().claim().getBuildNumber(); assertTrue(buildNumber > 0); } private final OAuthAccessor getAccessor() { if (accessor == null) { OAuthServiceProvider serviceProvider = new OAuthServiceProvider(getRequestTokenUrl(), getAuthorizeUrl(), getAccessTokenUrl()); OAuthConsumer consumer = new OAuthConsumer(callback, consumerKey, null, serviceProvider); consumer.setProperty(RSA_SHA1.PRIVATE_KEY, privateKey); consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1); accessor = new OAuthAccessor(consumer); } return accessor; } private String getAccessTokenUrl() { return baseUrl + SERVLET_BASE_URL + "/oauth/access-token"; } private String getRequestTokenUrl() { return baseUrl + SERVLET_BASE_URL + "/oauth/request-token"; } public String getAuthorizeUrlForToken(String token) { return getAuthorizeUrl() + "?oauth_token=" + token; } private String getAuthorizeUrl() {return baseUrl + SERVLET_BASE_URL + "/oauth/authorize";}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Abbas,
your code seems to work good, thank you. But where do you impersonate a user?
I'm trying to set parameter like xoauth_requestor_id, user_id, oauth_user_id, xoauth_user_id but without any success.
Are you able to send request to JIRA with 2-legged authentication and user impersonation?
If yes could you let me know how to do please?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Are you able to send request with user impersonation now..?
Do you have any solution for this..?
if yes could you please provide me your solutiion.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
JerseyJiraRestClientFactory factory = new JerseyJiraRestClientFactory(); OAuthParameters oAuthParameters = new OAuthParameters(); oAuthParameters.setSignatureMethod(OAuth.RSA_SHA1); oAuthParameters.setVersion("1.0"); oAuthParameters.setConsumerKey(consumerKey); oAuthParameters.setToken(accessToken); OAuthSecrets oAuthSecrets = new OAuthSecrets(); oAuthSecrets.setConsumerSecret(privateKey); AuthenticationHandler authenticationHandler = new OAuthAuthenticationHandler(oAuthParameters, oAuthSecrets ); bc =factory.create(jiraUri, authenticationHandler );
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Whe does the access token come from? I'm wanting 2 legged oauth for any user.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Have a look at this and if you have question ask me
https://developer.atlassian.com/display/JIRADEV/JIRA%20REST%20API%20Example%20-%20OAuth%20authentication
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I've look at that example already, it only shows the 3 legged approach.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I think if from the only difference is that from Jira's side you should allow 2 legged and that you just ask for request token then ask for access token without waiting for user to authorize
OAuthServiceProvider serviceProvider = new OAuthServiceProvider(requestTokenURL, userAuthorizationURL, accessTokenURL); OAuthConsumer consumer = new OAuthConsumer(null, "consumerkey", null, serviceProvider ); consumer.setProperty(RSA_SHA1.PRIVATE_KEY, privateKey); consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1); OAuthAccessor accessor = new OAuthAccessor(consumer); OAuthClient client = new OAuthClient(new HttpClient4()); OAuthMessage m = client.getRequestTokenResponse(accessor, "POST", null); String requestToken = m.getParameter(OAuth.OAUTH_TOKEN); OAuthMessage msg = client.getAccessToken(accessor, "POST",null); accessToken= msg.getParameter(OAuth.OAUTH_TOKEN);
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I've tried to implement that but am getting a 500 on the request token request. The following is from the jira log
Caused by: java.security.SignatureException: Signature length not correct: got 256 but was expecting 128
at sun.security.rsa.RSASignature.engineVerify(Unknown Source)
at java.security.Signature$Delegate.engineVerify(Unknown Source)
at java.security.Signature.verify(Unknown Source)
at net.oauth.signature.RSA_SHA1.verify(RSA_SHA1.java:240)
at net.oauth.signature.RSA_SHA1.isValid(RSA_SHA1.java:209)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
From the error it seems there is a problem with the RSA keys
You should put the your public key in Jira and the private key on the client side.
try using the public and private keys from here just for testing:
https://bitbucket.org/atlassian_tutorial/atlassian-oauth-examples/src
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
OK, getting as far as the access token request which is returning permission_unknown
net.oauth.OAuthProblemException: permission_unknown
at net.oauth.client.OAuthResponseMessage.toOAuthProblemException(OAuthResponseMessage.java:83)
at net.oauth.client.OAuthClient.invoke(OAuthClient.java:306)
at net.oauth.client.OAuthClient.invoke(OAuthClient.java:260)
at net.oauth.client.OAuthClient.getAccessToken(OAuthClient.java:229)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
so did u get the access token back?
if not then maybe you didnt use the request token you got back
this is how you should use it
http://JIRA_URI/plugins/servlet/oauth/authorize?oauth_token=request_Token_you_got
go to url and authorize the token then after it request the access token
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I got the request token back ok. I am doing 2 legged oauth though as mentioned above. The permission error is coming back when sending the access token request.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Here it is, the uri is the Jira base uri and the username is the username I'm trying to authenticate as:
private static String getAccessToken(final String uri, final String username) throws IOException, OAuthException, URISyntaxException { final OAuthServiceProvider serviceProvider = new OAuthServiceProvider(uri + "/plugins/servlet/oauth/request-token", uri + "/plugins/servlet/oauth/authorize", uri + "/plugins/servlet/oauth/access-token"); final OAuthConsumer consumer = new OAuthConsumer(null, "MuleBridge", null, serviceProvider); consumer.setProperty(RSA_SHA1.PRIVATE_KEY, CONSUMER_PRIVATE_KEY); consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1); consumer.setProperty("user_id", username); final OAuthAccessor accessor = new OAuthAccessor(consumer); final OAuthClient client = new OAuthClient(new HttpClient4()); final OAuthMessage message = client.getRequestTokenResponse(accessor, OAuthMessage.POST, null); accessor.requestToken = message.getParameter(OAuth.OAUTH_TOKEN); accessor.tokenSecret = message.getParameter(OAuth.OAUTH_TOKEN_SECRET); final OAuthMessage msg = client.getAccessToken(accessor, OAuthMessage.POST, null); return msg.getParameter(OAuth.OAUTH_TOKEN); }
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
consumer.setProperty(
"user_id"
, username);
I dont think this is how you set the user, but I am not sure what is the right way either :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Neither do I, I was guessing after I saw this: https://answers.atlassian.com/questions/250024/atlassian-connect-how-to-use-an-jira-authentication-header
Do you have any idea why I'm getting back the permission_unknown error?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Can you try
"xoauth_requestor_id"
instead of user_id and tell me what you get?
source https://bitbucket.org/atlassian/atlassian-oauth/commits/2c4072a5dfe8ddb1b873dfcd8b378466e945b045
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I've been able to work this out, and have posted the solution as a new answer below.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Martin,
Where is your solution for the JIRA authentication? Are you using the 2 legger trusted application approach?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
2 legged trusted application yes. See my solution above: https://answers.atlassian.com/questions/263719/using-oauth-and-the-jira-java-rest-client?page=1#288617
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Martin,
Can you please let me know how you worked this out? I am getting stuck in authentication big time
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Srikanth, I worked this out by debugging a locally running jira instance, obtaining the source code for the relevent classes from BitBucket https://bitbucket.org/atlassian/atlassian-oauth.gitso I was able to step through and see what was going on.
If the solution I posted doesn't help, debugging in the same way should help you find out why.
Hope this helps
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Blanka,
I believe that Abbas's code can do user impersonation, you just need to use the correct access token. To do so, you will need to ask the users to give your 3rd party application the permission to read/write data on their behalf. After that you can swap the request tokens for access tokens and use them.
I'm currently having a problem using this code: The class AsynchronousJiraRestClientFactory is not included in the Jar I am using. Also there are 2 "configure" methods that I must override:
I would like to ask about the exact Jar versions that you are using. I am working on Gradle project and here are my dependencies:
compile 'net.oauth.core:oauth:20100527'
compile 'net.oauth.core:oauth-consumer:20100527'
compile 'net.oauth.core:oauth-httpclient4:20090913'
compile 'com.atlassian.jira:jira-rest-java-client:0.5'
compile group: 'com.atlassian.jira', name: 'jira-api', version: '7.0.0'
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Youssef,
I'm sorry, I have already not been on the project so I can't have a look at it.
I just remember we created some hack on it.. because we didn't want to ask users for permission.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
OK, getting as far as the access token request which is returning permission_unknown
net.oauth.OAuthProblemException: permission_unknown
at net.oauth.client.OAuthResponseMessage.toOAuthProblemException(OAuthResponseMessage.java:83)
at net.oauth.client.OAuthClient.invoke(OAuthClient.java:306)
at net.oauth.client.OAuthClient.invoke(OAuthClient.java:260)
at net.oauth.client.OAuthClient.getAccessToken(OAuthClient.java:229)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I've look at that example already, it only shows the 3 legged approach.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I have the same question did anyone manage to get it to work with OAuth ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Community moderators have prevented the ability to post new answers.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.