I want to get data using JIRA REST api with provided JIRA OAuth authentication
service.
Basically I'm able to achieve this task using ScribeJava
with Groovy
. But I want to decoupled all the process as below :-
HTTPBuilder
So I'm able to achieve above mentioned first three steps using ScribeJava
and storing the accessToken
into Database
for further request for data as below :-
import java.security.KeyFactory
import java.security.PrivateKey
import java.security.spec.PKCS8EncodedKeySpec
import com.github.scribejava.core.builder.api.DefaultApi10a
import com.github.scribejava.core.model.OAuth1RequestToken
import com.github.scribejava.core.services.RSASha1SignatureService
import com.github.scribejava.core.services.SignatureService
class JiraOauthProvider extends DefaultApi10a {
private String authURL
private String requestTokenURL
private String accessTokenURL
private String consumerPrivateKey
private JiraOauthProvider(authURL, requestTokenURL, accessTokenURL, consumerPrivateKey) {
this.authURL = authURL
this.requestTokenURL = requestTokenURL
this.accessTokenURL = accessTokenURL
this.consumerPrivateKey = consumerPrivateKey
}
private static JiraOauthProvider instance = null
public static JiraOauthProvider instance(Map map) {
if(instance == null) {
instance = new JiraOauthProvider(map.authURL,
map.requestTokenURL,
map.accessTokenURL,
map.consumerPrivateKey)
}
return instance
}
@Override
public String getAccessTokenEndpoint() {
return accessTokenURL
}
@Override
public String getRequestTokenEndpoint() {
return requestTokenURL
}
@Override
public String getAuthorizationUrl(OAuth1RequestToken requestToken) {
return String.format(authURL, requestToken.getToken())
}
@Override
public SignatureService getSignatureService() {
return new RSASha1SignatureService(getPrivateKey())
}
private PrivateKey getPrivateKey() {
byte[] key = Base64.getDecoder().decode(consumerPrivateKey)
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key)
KeyFactory kf = KeyFactory.getInstance("RSA")
return kf.generatePrivate(keySpec)
}
Now I'm building OAuthService
as :-
private static final String CALLBACK_URI = "callback-url"
protected static final String CONSUMER_KEY = "consumer-key"
protected static final String CONSUMER_PRIVATE_KEY = "private-key"
Map oAuthMap = [
"authURL" :"auth-url=%s",
"requestTokenURL":"request-token-url",
"accessTokenURL":"access-token-url",
"consumerPrivateKey":CONSUMER_PRIVATE_KEY
]
//Buid oauth service to get request token, auth url and access token
OAuth10aService service = ServiceBuilder()
.apiKey(CONSUMER_KEY)
.apiSecret(CONSUMER_PRIVATE_KEY).callback(CALLBACK_URI)
.build(JiraOauthProvider.instance(oAuthMap))
OAuth1RequestToken requestToken = service.getRequestToken()
def authURL = service.getAuthorizationUrl(requestToken)
//Now after redirect to this authURL and providing credential I'm getting oauthVerifier code to get accessToken and secretToken
def oauthVerifier = "oauth verifier code"
//Now calling to get accessToken
OAuth1AccessToken oAuth1AccessToken = service.getAccessToken(requestToken, oauthVerifier);
def accessToken = oAuth1AccessToken.getToken()
def secretToken = oAuth1AccessToken.getTokenSecret()
//now I'm storing this `accessToken`and `secretToken` into DB for further future data request.
So after all above stuff I'm able to achieve above mentioned three steps and storing the access token into db
for future request only for data
.
So to achieve 4th step to getting actual data using HTTPBuilder
I'm doing some thing as below :-
def http = new HTTPBuilder('base-url')
http.auth.oauth CONSUMER_KEY, CONSUMER_PRIVATE_KEY, accessToken, secretToken
http.request(Method.GET, ContentType.JSON) { req ->
uri.path = 'path'
response.success = { resp, json ->
println json
}
response.failure = { resp, json -> print json }
}
}
But I'm getting response as :-
{oauth_problem=signature_method_rejected}
So, could anyone suggest me how can I get actual data using HTTPBuilder
with OAuth
authentication using accessToken
and secretToken?
Note:- I can get actual data as well using ScribeJava
Api with OAuthRequest
but requirement is to get actual data using HTTPBuilder
I just want a pointer that how to achieve it.
After lot of search I have got the solution from here. Actually HTTPBuilder
internally using Signpost
which signing the request using HmacSha Signer
while Jira rest api
supports RSA-SHA1 Signer
to validate the HttpRequest
that's why it's giving response as :-
{oauth_problem=signature_method_rejected}
So, basically I have to do custom RSA-SHA1 Signer
to get the signature to http request. To achive this I'm using Google Data (GData) APIs
to sign the data using RSA-SHA1 Signer
before HttprRequest
as below :-
private static PrivateKey getPrivateKey(String consumerKey) {
try {
byte[] key = Base64.getDecoder().decode(consumerKey)
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key)
KeyFactory kf = KeyFactory.getInstance("RSA")
return kf.generatePrivate(keySpec)
} catch (Exception e) {
throw new RuntimeException(e)
}
}
import com.google.gdata.client.authn.oauth.OAuthParameters
import com.google.gdata.client.authn.oauth.OAuthRsaSha1Signer
import com.google.gdata.client.authn.oauth.OAuthUtil
import com.google.gdata.client.authn.oauth.RsaSha1PrivateKeyHelper
OAuthRsaSha1Signer rsaSigner = new OAuthRsaSha1Signer()
rsaSigner.setPrivateKey(getPrivateKey(CONSUMER_PRIVATE_KEY))
OAuthParameters params = new OAuthParameters()
params.setOAuthConsumerKey(CONSUMER_KEY)
params.setOAuthNonce(OAuthUtil.getNonce())
params.setOAuthTimestamp(OAuthUtil.getTimestamp())
params.setOAuthSignatureMethod("RSA-SHA1")
params.setOAuthType(OAuthParameters.OAuthType.TWO_LEGGED_OAUTH)
params.setOAuthToken(accessToken)
String paramString = params.getBaseParameters().sort().collect{it}.join('&')
String baseString = [
OAuthUtil.encode("GET"),
OAuthUtil.encode('base-url' + 'path'),
OAuthUtil.encode(paramString)
].join('&')
String signature = rsaSigner.getSignature(baseString, params);
params.addCustomBaseParameter("oauth_signature", signature);
//Now calling using HTTPBuilder with signed data
def http = new HTTPBuilder('base-url')
http.request(Method.GET, ContentType.JSON) { req ->
uri.path = 'path'
uri.query = params.getBaseParameters()
response.success = { resp, json ->
println json
}
response.failure = { resp, json -> print json }
}
}