Reputation: 185
I'm trying to create a directory using REST API. Below is the code for Signature. Can you help me to find the issue in the code:
string storageKey = 'storage key';
string storageName = '<storageName>';
Datetime dt = Datetime.now();
string formattedDate = dt.formatGMT('EEE, dd MMM yyyy HH:mm:ss')+ ' GMT';
system.debug('formattedDate--'+formattedDate);
string CanonicalizedHeaders = 'x-ms-date:'+formattedDate+'\nx-ms-version:2016-05-31';
string CanonicalizedResource = '/' + storageName + '/<myShareName>/<DirectoryName>\nrestype:directory';
string StringToSign = 'PUT\n\n\n\n\napplication/xml;charset=utf-8\n\n\n\n\n\n\n' + CanonicalizedHeaders+'\n'+CanonicalizedResource;
system.debug('StringToSign--'+StringToSign);
Blob temp = EncodingUtil.base64Decode(storageKey);
Blob hmac = Crypto.generateMac('HmacSHA256',Blob.valueOf(StringToSign),temp ); //StringToSign
system.debug('oo-'+EncodingUtil.base64Encode(hmac));
HttpRequest req = new HttpRequest();
req.setMethod('PUT');
req.setHeader('content-type', 'application/xml;charset=utf-8');
req.setHeader('content-length', '0');
req.setHeader('x-ms-version','2016-05-31' );
req.setHeader('x-ms-date', formattedDate);
string signature = EncodingUtil.base64Encode(hmac);
string authHeader = 'SharedKey <storageName>'+':'+signature;
req.setHeader('Authorization',authHeader);
req.setEndpoint('https://<storageName>.file.core.windows.net/<myShareName>/<DirectoryName>&restype=directory');
Http http = new Http();
HTTPResponse res= http.send(req);
Refer the link for azure documentation: https://learn.microsoft.com/en-us/rest/api/storageservices/create-directory
Upvotes: 0
Views: 540
Reputation: 23782
I wrote the following java code for your reference, and it works well for me.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.microsoft.windowsazure.core.utils.Base64;
public class CreateDirectory {
private static final String account = "jaygong";
private static final String key = "******";
public static void main(String args[]) throws Exception {
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
String urlString = "http://" + account + ".file.core.windows.net/testshare/testdirectory?restype=directory";
// Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP,new InetSocketAddress("127.0.0.1", 8888));
// URL serverUrl = new URL(urlString);
// HttpURLConnection connection = (HttpURLConnection) serverUrl.openConnection(proxy);
HttpURLConnection connection = (HttpURLConnection) (new URL(urlString)).openConnection();
getFileRequest(connection, account, key);
connection.connect();
System.out.println("Response message : " + connection.getResponseMessage());
System.out.println("Response code : " + connection.getResponseCode());
BufferedReader br = null;
if (connection.getResponseCode() != 200) {
br = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
} else {
br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
}
System.out.println("Response body : " + br.readLine());
}
public static void getFileRequest(HttpURLConnection request, String account, String key) throws Exception {
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
String stringToSign = "PUT\n" + "\n" // content encoding
+ "\n" // content language
+ "\n"// content length
+ "\n" // content md5
+ "\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n" // range
+ "x-ms-date:" + date + "\nx-ms-version:2015-02-21\n" // headers
+ "/" + account + request.getURL().getPath()+"\nrestype:directory"; // resources
System.out.println("stringToSign : " + stringToSign);
String auth = getAuthenticationString(stringToSign);
System.out.println(auth);
request.setRequestMethod("PUT");
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("x-ms-version", "2015-02-21");
request.setRequestProperty("Authorization", auth);
request.setRequestProperty("Content-Length", "0");
}
private static String getAuthenticationString(String stringToSign) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
String authKey = new String(Base64.encode(mac.doFinal(stringToSign.getBytes("UTF-8"))));
String auth = "SharedKey " + account + ":" + authKey;
return auth;
}
}
Notes:
Please note that System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
in the above code is necessary.
I found a parameter called allowRestrictedHeaders
from source code, which was originally designed to limit the use of Http Header for security in the design of API.All of the following are limited:
private static final String[] restrictedHeaders = {
/* Restricted by XMLHttpRequest2 */
//"Accept-Charset",
//"Accept-Encoding",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Connection", /* close is allowed */
"Content-Length",
//"Cookie",
//"Cookie2",
"Content-Transfer-Encoding",
//"Date",
"Expect",
"Host",
"Keep-Alive",
"Origin",
// "Referer",
// "TE",
"Trailer",
"Transfer-Encoding",
"Upgrade",
//"User-Agent",
"Via"
};
allowRestrictedHeaders = ((Boolean)java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"sun.net.http.allowRestrictedHeaders"))).booleanValue();
Hope it helps you.
Upvotes: 1