开发者

How to create a signature using HMACSHA1 and secret key to connect to Kayako API

开发者 https://www.devze.com 2023-02-16 04:05 出处:网络
I\'m trying to connect to a third party application API using apache commons HTTP Clie开发者_StackOverflownt. The API I\'m trying to connect is http://wiki.kayako.com/display/DEV/REST+API.

I'm trying to connect to a third party application API using apache commons HTTP Clie开发者_StackOverflownt. The API I'm trying to connect is http://wiki.kayako.com/display/DEV/REST+API.

The API requires me to pass a API key and a signature along with a salt used to create the signature.

As per the API documentation these are the steps to create the signature

  1. Generate a random string to create a salt (in PHP, you would use mt_and() to do this)
  2. Generate the signature by hashing the salt using SHA256 with the secret key as the key (in PHP, you would use hash_hmac() to do this)
  3. base64 encode the signature (in PHP, you would use base64_encode() to do this)
  4. URL encode the output (in PHP, you would use urlencode() to do this)

UPDATED

As per the responses I got, I changes some of my code and created a demo account with the Kayako to test the API

I'm using the following class to generate the signature

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.util.encoders.Base64Encoder;

public class GenSign2 {
    public static void main(String[] args) throws GeneralSecurityException,
            IOException {
        String secretKey = "M2Y2YjkxZDEtYmNlOC1mYmI0LTkxZTgtOTNiY2RiMDhmN2E2YjExNGUwYjktNGJkYy1jZTM0LWQ1MWYtZGIwYWRlZTE0NGNh";
        String salt = "0123456789";

        String generateHmacSHA256Signature = generateHmacSHA256Signature(salt,
                secretKey);
        System.out.println("Signature: " + generateHmacSHA256Signature);

        String urlEncodedSign = URLEncoder.encode(generateHmacSHA256Signature,
                "UTF-8");

        System.out.println("Url encoded value: " + urlEncodedSign);
    }

    public static String generateHmacSHA256Signature(String data, String key)
            throws GeneralSecurityException, IOException {
        byte[] hmacData = null;

        try {
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"),
                    "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(secretKey);
            hmacData = mac.doFinal(data.getBytes("UTF-8"));
            ByteArrayOutputStream bout = new ByteArrayOutputStream();

            new Base64Encoder().encode(hmacData, 0, hmacData.length, bout);
            return bout.toString("UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new GeneralSecurityException(e);
        }
    }
}

And the test api is as follows

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

public class TestApi {

    public static void main(String[] args) throws ClientProtocolException,
            IOException, URISyntaxException {
        HttpClient client = new DefaultHttpClient();

        List<NameValuePair> qparams = new ArrayList<NameValuePair>();
        qparams.add(new BasicNameValuePair("apikey",
                "f165dc40-ce3f-6864-7d5e-27a7188b2e62"));
        qparams.add(new BasicNameValuePair("salt", "0123456789"));
        qparams.add(new BasicNameValuePair("signature", "mbrhpXkP0LzNMNDygHAorqMx%2FDGovl%2FauMTOMB6RNMA%3D"));

        HttpPost httpget = new HttpPost(
                "http://aruntest.kayako.com/api/index.php?e=/Core/Test");

        HttpResponse response = client.execute(httpget);
        System.out.println(response.getProtocolVersion());
        System.out.println(response.getStatusLine().getStatusCode());
        System.out.println(response.getStatusLine().getReasonPhrase());
        System.out.println(response.getStatusLine().toString());
    }

}

The demo site can be accessed using URL: http://aruntest.kayako.com/admin/

User: admin

Password: ty386rhjzz

It is throwing an unauthorized access exception when I'm trying to connect.


Try and compare your signature method with this (it works)

public static String generateHmacSHA256Signature(String data, String key)   throws GeneralSecurityException {
    byte[] hmacData = null;

    try {
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(secretKey);
        hmacData = mac.doFinal(data.getBytes("UTF-8"));
        return new BASE64Encoder().encode(hmacData);
    } catch (UnsupportedEncodingException e) {
        // TODO: handle exception
        throw new GeneralSecurityException(e);
    }
}

The result of this call, will then be the value of your attribute Signature

String signature = generateHmacSHA256Signature(salt, key);
qparams.add(new BasicNameValuePair("signature", signature));

A simple way to generate a salt/nonce

String nonce = String.valueOf(System.currentTimeMillis());

See Example:


Kayako has updated their documentation with a new java sample which works fine.


I think the entire getSaltedKey() routine is unnecessary. You're just signing the salt (it should have been called a nonce) with HMAC and signing with the provided key, it doesn't look like you're supposed to sign the key+salt.

0

精彩评论

暂无评论...
验证码 换一张
取 消