0

We are trying to insert a json object to an Azure table, but we keep getting the following exception when making the rest call:

Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

The created Authorization header matches the format given in https://learn.microsoft.com/en-us/azure/storage/common/storage-rest-api-auth?toc=%2Fazure%2Fstorage%2Ftables%2Ftoc.json

"SharedKey <storage account name>:<signature>"

With some slight modifications, we can get this basic script create a blob in blob storage, but we need to save the json object to table storage. The following solution works for blob storage but we have not gotten it to work with table storage: Simple PHP cURL file upload to Azure storage blob

We believe the following snippet should work, however, we still get the above mentioned authorization exception.

function sendTableEntries($jsonData, $storageAccount, $tablename, $destinationURL, $accesskey) {

    echo $jsonData, $storageAccount, $tablename, $destinationURL, $accesskey;
    $currentDate = gmdate("D, d M Y H:i:s T", time());
    
    $contLen = strlen($jsonData);

    $headerResource = "x-ms-blob-cache-control:max-age=3600\nx-ms-blob-type:BlockBlob\nx-ms-date:$currentDate\nx-ms-version:2017-07-29";
    $urlResource = "/$storageAccount/$tablename";

    $arraysign = array();
    $arraysign[] = 'POST';               /*HTTP Verb*/  
    $arraysign[] = '';                  /*Content-Encoding*/  
    $arraysign[] = '';                  /*Content-Language*/  
    $arraysign[] = $contLen;            /*Content-Length (include value when zero)*/  
    $arraysign[] = '';                  /*Content-MD5*/  
    $arraysign[] = 'application/json';  /*Content-Type*/  
    $arraysign[] = '';                  /*Date*/  
    $arraysign[] = '';                  /*If-Modified-Since */  
    $arraysign[] = '';                  /*If-Match*/  
    $arraysign[] = '';                  /*If-None-Match*/  
    $arraysign[] = '';                  /*If-Unmodified-Since*/  
    $arraysign[] = '';                  /*Range*/  
    $arraysign[] = $headerResource;     /*CanonicalizedHeaders*/
    $arraysign[] = $urlResource;        /*CanonicalizedResource*/

    $str2sign = implode("\n", $arraysign);

    $sig = base64_encode(hash_hmac('sha256', urldecode(utf8_encode($str2sign)), base64_decode($accesskey), true));  
    $authHeader = "SharedKey $storageAccount:$sig";
    
    //echo "sig is " . $sig;
    //echo " Auth header is " . $authHeader;

    $headers = array( 'Authorization: ' . $authHeader,
        'x-ms-blob-cache-control: max-age=3600',
        'x-ms-blob-type: BlockBlob',
        'x-ms-date: ' . $currentDate,
        'x-ms-version: 2017-07-29',
        'Content-Type: application/json',
        'Content-Length: ' . $contLen );

    $ch = curl_init($destinationURL);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSLVERSION, 6);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);
    
    $result = curl_exec($ch);
    
    echo ('Result<br/>');
    print_r($result);

    echo ('Error<br/>');
    print_r(curl_error($ch));

    curl_close($ch);
}

$accesskey = "ACCESSKEY";
$storageAccount = 'storageaccount';
$tablename = 'tablename';

$temp = array();
$temp["PartitionKey"] = "5432";
$temp["RowKey"] =  "234235";
$temp["value"] = 3455;
$temp["valid"] = 1;

$content = json_encode($temp);

$destinationTable = "https://$storageAccount.table.core.windows.net/$tablename";

sendTableEntries($content, $storageAccount, $tablename, $destinationTable, $accesskey);

Does anyone know what is wrong with the above code so that we can successfully insert json to azure tables? Note that the php version is too old to support the Azure SDK for PHP.

3
  • 1
    Few things: 1) Please see here regarding how to create string to sign for table resources and 2) Please see here for insert entity REST API operation. Currently there are a lot of differences between documentation and what you are doing. Commented Nov 15, 2022 at 5:11
  • Thank you @GauravMantri reducing the str2sign to just those elements listed here worked. Commented Nov 15, 2022 at 18:54
  • Awesome! Please post your solution as an answer. It might help other users. Commented Nov 15, 2022 at 18:57

1 Answer 1

1

The solution was to reduce the number of elements in $arraysign to just those listed here as suggested in the comments above.

The following is a working example:

function sendTableEntries($jsonData, $storageAccount, $tablename, $destinationURL, $accesskey) {

    $currentDate = gmdate("D, d M Y H:i:s T", time());

    $urlResource = "/$storageAccount/$tablename";

    $arraysign = array();
    $arraysign[] = 'POST';               /*HTTP Verb*/ 
    $arraysign[] = '';                  /*Content-MD5*/  
    $arraysign[] = 'application/json';  /*Content-Type*/  
    $arraysign[] = $currentDate;        /*Date*/  
    $arraysign[] = $urlResource;        /*CanonicalizedResource*/

    $str2sign = implode("\n", $arraysign);

    $sig = base64_encode(hash_hmac('sha256', urldecode(utf8_encode($str2sign)), base64_decode($accesskey), true));  
    $authHeader = "SharedKey $storageAccount:$sig";

    $headers = array( 'Authorization: ' . $authHeader,
        'x-ms-date: ' . $currentDate,
        'x-ms-version: 2021-08-06',
        'Content-Type: application/json');

    $ch = curl_init($destinationURL);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSLVERSION, 6);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);    
    $result = curl_exec($ch);
    
    echo ('Result<br/>');
    print_r($result);

    echo ('Error<br/>');
    print_r(curl_error($ch));

    curl_close($ch);
}

$accesskey = "ACCESSKEY";
$storageAccount = 'storageaccount';
$tablename = 'tablename';

$temp = array();
$temp["PartitionKey"] = "5432";
$temp["RowKey"] =  "234235";
$temp["value"] = 3455;
$temp["valid"] = 1;

$content = json_encode($temp);

$destinationTable = "https://$storageAccount.table.core.windows.net/$tablename";

sendTableEntries($content, $storageAccount, $tablename, $destinationTable, $accesskey);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.