09-26-2023 08:59 AM
Hello Sir,
I am trying to create using /admin/v1/users it shows {
"code":40103,
"message":"Invalid signature in request credentials",
"stat":"FAIL"
}
The canonical string I’m generating for use in the HMAC :
Tue, 26 Sep 2023 21:52:23 +0600
POST
/admin/v1/users
email=abc%40example.com&username=newuser
HMAC-SHA1 hex String:
be16c29b840f0618bb947d7e2574f892b82889b7
And the endpoint I’m hitting ends up looking like this:
https://api-d221a358.duosecurity.com/admin/v1/users?email=abc%40example.com&username=newuser
Here is my java code:
public class DuoCreateUsers {
private static SortedMap<String, Object> params = new TreeMap<String, Object>();
public static void main(String[] args) throws IOException {
String ikey = "x";
String skey = "x";
String host = "x";
String httpMethod = "POST";
String requestPath = "/admin/v1/users";
String timestamp = OffsetDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME);
String username = "newuser";
String email = "abc@example.com";
params.put("username",username);
params.put("email",email);
String queryString = canonQueryString();
String canonicalRequest = timestamp + "\n" + httpMethod + "\n" + requestPath + "\n" + queryString;
System.out.println("canonicalRequest = " + canonicalRequest);
String signature = sign1(canonicalRequest, skey);
// System.out.println("signature = " + signature);
String url = "https://" + host + requestPath+"?"+queryString;
System.out.println("url = " + url);
HttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Date", timestamp);
httpPost.setHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString((ikey + ":" + signature).getBytes()));
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setEntity(new StringEntity(params.toString()));
// Make the request
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
String responseContent = entity != null ? EntityUtils.toString(entity) : "";
String rs = "Response Status Code: " + response.getStatusLine().getStatusCode() + "\nResponse Content:\n" + responseContent;
System.out.println("rs = " + rs);
}
public static String canonQueryString()
throws UnsupportedEncodingException {
ArrayList<String> args = new ArrayList<String>();
for (String key : params.keySet()) {
String name = URLEncoder
.encode(key, "UTF-8")
.replace("+", "%20")
.replace("*", "%2A")
.replace("%7E", "~");
String value = URLEncoder
.encode(params.get(key).toString(), "UTF-8")
.replace("+", "%20")
.replace("*", "%2A")
.replace("%7E", "~");
args.add(name + "=" + value);
}
return com.duosecurity.client.Util.join(args.toArray(), "&");
}
private static String sign1(String data, String secretKey) {
try {
// Create an HMAC-SHA1 key from the secret key
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
// Initialize the HMAC-SHA1 algorithm
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(secretKeySpec);
// Calculate the HMAC-SHA1 hash
byte[] hmacSha1Bytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
// Convert the result to a hexadecimal string
String hmacSha1Hex = bytesToHex(hmacSha1Bytes);
// Print the HMAC-SHA1 hash
System.out.println("HMAC-SHA1: " + hmacSha1Hex);
return hmacSha1Hex;
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
// Helper method to convert bytes to a hexadecimal string
private static String bytesToHex(byte[] bytes) {
StringBuilder hexStringBuilder = new StringBuilder();
for (byte b : bytes) {
hexStringBuilder.append(String.format("%02x", b));
}
return hexStringBuilder.toString();
}
}
Please help what is the wrong of my code?
09-26-2023 12:26 PM - edited 09-26-2023 12:26 PM
The canonical string I’m generating for use in the HMAC :
Tue, 26 Sep 2023 21:52:23 +0600
POST
/admin/v1/users
email=abc%40example.com&username=newuser
are you leaving out the third line of five which is your API hostname? From the Admin API doc example:
09-26-2023 12:42 PM - edited 09-26-2023 12:44 PM
Hi @DuoKristina
Thanks you very much for your reply.
I have also added this third line same things happen.
Wed, 27 Sep 2023 01:39:43 +0600
POST
api-d221a358.duosecurity.com
/admin/v1/users
email=enamul.haque%40gmail.com&username=ehaque
Here is the code..
String canonicalRequest = timestamp + "\n" + httpMethod + "\n" + host+"\n"+ requestPath + "\n" + queryString;
System.out.println("canonicalRequest = " + canonicalRequest);
String signature = sign1(canonicalRequest, skey);
System.out.println("signature = " + signature);
String url = "https://" + host + requestPath+"?"+queryString;
System.out.println("url = " + url);
String authString ="Basic " + Base64.getEncoder().encodeToString((ikey + ":" + signature).getBytes());
System.out.println("authString = " + authString);
HttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Authorization", authString);
httpPost.setHeader("Date", timestamp);
httpPost.setHeader("Host",host);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setEntity(new StringEntity(canonJSONBody()));
// Make the request
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
String responseContent = entity != null ? EntityUtils.toString(entity) : "";
09-26-2023 01:15 PM - edited 09-26-2023 01:16 PM
Hi @DuoKristina
I have tried many ways. But every way shows Invalid signature.
Is it right way which I did below?
genetateSignature(canonicalString, skey):
HMAC-SHA1 Key (genetateSignature): afffa7f9cb019b4d9eceacd3d16d7afe4461d028
signature b4encode of HMAC-SHA1 Key = YWZmZmE3ZjljYjAxOWI0ZDllY2VhY2QzZDE2ZDdhZmU0NDYxZDAyOA==
Authorization heraders:
String authString ="Basic " + Base64.getEncoder().encodeToString((ikey + ":" + signature).getBytes());
Header Request:
httpPost.setHeader("Authorization", authString);
httpPost.setHeader("Date", timestamp);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
09-26-2023 03:14 PM
Oh, I see you are the same person from the similar earlier post. Your last response to your separate, earlier post was removed for your protection because you accidentally posted what looked like a valid ikey and skey in your last response. Be sure to scrub any of your Duo account's details from your posts to the community!
I did get a chance to see in the other thread that even with our Java API client you still received the 40103. This is a weird thought, but I wonder if the issue is that you are already URL encoding the param and then our client also encodes them as well?
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide