1
votes

I am using PUT Blob Rest API for uploading img/pdf- PUT Blob reference. But it is showing- Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature error (403 response code).

Below are the string to sign:

"PUT\n\n\n41676\n\nimage/png\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:Wed, 17 Feb 2021 10:24:02 GMT\nx-ms-version:2020-02-10\n/acc_name/container_name/12362_50800_13_s_1.png"

Below are the header details:

{ "x-ms-blob-type" : "BlockBlob" , "x-ms-date" : "Wed, 17 Feb 2021 10:24:02 GMT" , "x-ms-version" : "2020-02-10" , "Authorization" : "SharedKey acc_name:XXXQsR728D7aqyJzFi/HXk+qT9rpjYbplUG9KXXXX" , "Content-Type" : "image/png" , "Content-Length" : "41676"}

Below are the URL details:

https://acc_name.blob.core.windows.net/container_name/12362_50800_13_s_1.png

private BasicDBObject createAzureBlob(String storageAPIVersion, String storageAccURL, String storageAccName, String storageAcckey, String storageAccConString,
                                      String containerName, BasicDBObject clientReqObj, File outputfile) throws Exception
{
    log.info("Entry createAzureBlob in the GenericServicesDeligator");

    BasicDBObject clientResponse = null;

    String date = clientReqObj.remove(Constants.F_CREATED_DATE).toString();
    String filePath = clientReqObj.remove(Constants.F_PATH).toString();
    String contentLength = clientReqObj.remove("Content-Length").toString();
    String contentType = clientReqObj.remove("Content-Type").toString();
    
    String hostMethod = "PUT";
    StringBuilder authorization = new StringBuilder("SharedKey ").append(storageAccName).append(":").append("sharedKeySign");
    StringBuilder canonicalizedResource = new StringBuilder("/").append(storageAccName).append("/").append(containerName).append("/").append(filePath);
    
    BasicDBObject clientReqHeader = new BasicDBObject();

    // Host URL
    String hostName = clientReqHeader.size()>0l?new StringBuilder("/").append(filePath).append(prepareHostInfo(clientReqHeader)).toString():new StringBuilder("/").
                      append(filePath).toString();
    String hostURL = new StringBuilder(storageAccURL).append("/").append(containerName).append(hostName).toString().trim();
    
    // canonicalizedResource should always be in alphabetical order
    canonicalizedResource.append(prepareCanonicalizedResource(clientReqHeader));

    //canonicalizedHeader should always be in alphabetical order and include only that begin with x-ms-
    clientReqHeader.clear();
    clientReqHeader.put("x-ms-blob-type", "BlockBlob");               
    clientReqHeader.put("x-ms-date", date);
    clientReqHeader.put("x-ms-version", storageAPIVersion);

    String canonicalizedHeader = prepareCanonicalizedHeader(clientReqHeader);

    // string to sign
    String stringToSign = prepareStringToSign(hostMethod, contentLength, contentType, canonicalizedHeader, canonicalizedResource.toString());
    
    // encode the string by using the HMAC-SHA256 algorithm over the UTF-8-encoded signature string
    String signature = encodeSharedKeySignature(stringToSign, storageAcckey);

    clientReqHeader.put("Authorization", authorization.toString().replace("sharedKeySign", signature));
    clientReqHeader.put("Content-Length", contentLength);
    clientReqHeader.put("Content-Type", contentType);
    
    clientResponse = sendAzureClientRequest(hostMethod, hostURL, clientReqHeader, clientReqObj, outputfile);

    log.info("Exit createAzureBlob in the GenericServicesDeligator");

    return clientResponse;

}

private String prepareHostInfo(BasicDBObject hostNameObject) throws Exception
{
    StringBuilder hostName = new StringBuilder();
    
    for(String key: hostNameObject.keySet())
    {
        if(hostName.length() == 0l)
            hostName.append("?").append(key).append("=").append(hostNameObject.get(key));
        else
            hostName.append("&").append(key).append("=").append(hostNameObject.get(key));
    }
    
    return hostName.toString().trim();
}
private String prepareCanonicalizedResource(BasicDBObject hostNameObject) throws Exception
{
    StringBuilder canonicalizedResource = new StringBuilder();
    
    Map<String, String> canonicalizedMap = new TreeMap<String, String>();
    
    canonicalizedMap.putAll(hostNameObject.toMap());
    for(String key: canonicalizedMap.keySet())
    {
        canonicalizedResource.append("\n").append(key).append(":").append(canonicalizedMap.get(key));
    }
    
    return canonicalizedResource.toString();
}
private String prepareCanonicalizedHeader(BasicDBObject hostNameObject) throws Exception
{
    StringBuilder canonicalizedHeader = new StringBuilder();
    
    Map<String, String> canonicalizedMap = new TreeMap<String, String>();
    
    canonicalizedMap.putAll(hostNameObject.toMap());
    for(String key: canonicalizedMap.keySet())
    {
        canonicalizedHeader.append(key).append(":").append(canonicalizedMap.get(key).toString().trim()).append("\n");
    }
    
    return canonicalizedHeader.toString();
}
private String prepareStringToSign(String hostMethod, String contentLength, String contentType, String canonicalizedHeader, String canonicalizedResource) 
{
    String input = "";
    
    input =  new StringBuilder(hostMethod).append("\n").
             append("\n").                                                           // Content-Encoding + "\n" +
             append("\n").                                                           // Content-Language + "\n" +
             append(contentLength!=null?contentLength:"").append("\n").
             append("\n").                                                           // Content-MD5 + "\n" +
             append(contentType!=null?contentType:"").append("\n"). 
             append("\n").                                                           // Date
             append("\n").                                                           // If-Modified-Since + "\n" +
             append("\n").                                                           // If-Match + "\n" +
             append("\n").                                                           // If-None-Match + "\n" +
             append("\n").                                                           // If-Unmodified-Since + "\n" +
             append("\n").                                                           // Range + "\n" +
             append(canonicalizedHeader).
             append(canonicalizedResource).toString().trim();
    
    return input;
}

public String getUTCDate(Date date) throws Exception
{
    SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
   
    return (sdf.format(date) + " GMT").trim();
}

public static String getFileContentType(String fileType)
{
    String contentType = "";
    switch (fileType)
    {
        case "pdf":
            contentType = "application/pdf";
            break;
        case "txt":
            contentType = "text/plain";
            break;
        case "bmp":
            contentType = "image/bmp";
            break;
        case "gif":
            contentType = "image/gif";
            break;
        case "png":
            contentType = "image/png";
            break;
        case "jpg":
            contentType = "image/jpeg";
            break;
        case "jpeg":
            contentType = "image/jpeg";
            break;
        case "xls":
            contentType = "application/vnd.ms-excel";
            break;
        case "xlsx":
            contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            break;
        case "csv":
            contentType = "text/csv";
            break;
        case "html":
            contentType = "text/html";
            break;
        case "xml":
            contentType = "text/xml";
            break;
        case "zip":
            contentType = "application/zip";
            break;
        default:
            contentType = "application/octet-stream";
            break;
    }
    return contentType.trim();
}


private String encodeSharedKeySignature(String inputVal, String storageAcckey) throws Exception
{
     SecretKeySpec secretkey = new SecretKeySpec(new BASE64Decoder().decodeBuffer(storageAcckey), "HmacSHA256");
     
     Mac mac = Mac.getInstance("HmacSHA256");
     mac.init(secretkey);

     String hash = Base64.encodeAsString(mac.doFinal(inputVal.getBytes("UTF-8")));
     
     return hash.trim();
}

Kindly share the solution so i would upload a image/pdf. Thanks in advance

1
which programming language are you using?Ivan Yang
I am using Java- jdk 1.8Dushyant Kumar Singh
could you please show us your code? The headers and stringToSign seem correct.Ivan Yang
Yes, it's a file name.Dushyant Kumar Singh
You'd better put your completed code in your question:). When using authorization header, it's easy to make a minor mistake. So we need to go through the completed code.Ivan Yang

1 Answers

0
votes

In the private BasicDBObject createAzureBlob() method, in the following section:

//encode the string by using the HMAC-SHA256 algorithm over the UTF-8-encoded signature string
String signature = encodeSharedKeySignature(stringToSign, storageAcckey);

clientReqHeader.put("Authorization", authorization.toString().replace("sharedKeySign", storageAcckey));
clientReqHeader.put("Content-Length", contentLength);
clientReqHeader.put("Content-Type", contentType);

You should use the signature instead of storageAcckey for Authorization header, so please change this line of code

clientReqHeader.put("Authorization", authorization.toString().replace("sharedKeySign", storageAcckey));

to

clientReqHeader.put("Authorization", authorization.toString().replace("sharedKeySign", signature));