JTP
JTP

Reputation: 31

Connecting to Azure Table Storage in R

I've been trying to connect to Azure Table Storage in R. Google Searching has returned nothing on people using R to connect to the Rest APIs for table storage. The documentation is here. I've tried taking an existing question about blob storage to connect( I couldn't connect to even a blob using this) and re working it for table storage queries. Below:

library(httr)
url <- "https://rpoc.table.core.windows.net:443/dummytable(PartitionKey='0dfe725b-bd43-4d9d-b58a-90654d1d8741',RowKey='00b7595d-97c3-4f29-93de-c1146bcd3d33')?$select=<comma-separated-property-names>"
sak<-"u4RzASEJ3qbxSpf5VL1nY08MwRz4VKJXsyYKV2wSFlhf/1ZYV6eGkKD3UALSblXsloCs8k4lvCS6sDE9wfVIDg=="
requestdate<- http_date(Sys.time())
signaturestring<-paste0("GET",paste(rep("\n",12),collapse=""),
                        "x-ms-date:",requestdate,"
                        x-ms-version:2015-12-11")

headerstuff<-add_headers(Authorization=paste0("SharedKey rpoc:",
                                              RCurl::base64(digest::hmac(key=RCurl::base64Decode(sak, mode="raw"),
                                                                         object=enc2utf8(signaturestring),
                                                                         algo= "sha256", raw=TRUE))),
                         `x-ms-date`=requestdate,
                         `x-ms-version`= "2015-12-11",
                         `DataServiceVersion` = "3.0;NetFx",  
                         `MaxDataServiceVersion` = "3.0;NetFx" )
content(GET(url,config = headerstuff, verbose() ))

Console output:

-> GET /dummytable(PartitionKey='0dfe725b-bd43-4d9d-b58a-90654d1d8741',RowKey='00b7595d-97c3-4f29-93de-c1146bcd3d33')?$select=<comma-separated-property-names> HTTP/1.1
-> Host: rpoc.table.core.windows.net
-> User-Agent: libcurl/7.53.1 r-curl/2.6 httr/1.2.1
-> Accept-Encoding: gzip, deflate
-> Accept: application/json, text/xml, application/xml, */*
-> Authorization: SharedKey rpoc:nQWNoPc1l/kXydUw4rNq8MBIf/arJXkI3jZv+NttqMs=
-> x-ms-date: Mon, 24 Jul 2017 18:49:52 GMT
-> x-ms-version: 2015-12-11
-> DataServiceVersion: 3.0;NetFx
-> MaxDataServiceVersion: 3.0;NetFx
-> 
<- HTTP/1.1 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
<- Content-Length: 299
<- Content-Type: application/json
<- Server: Microsoft-HTTPAPI/2.0
<- x-ms-request-id: 2c74433e-0002-00b3-5aad-04d4db000000
<- Date: Mon, 24 Jul 2017 18:49:53 GMT
<- 
$odata.error
$odata.error$code
[1] "AuthenticationFailed"

$odata.error$message
$odata.error$message$lang
[1] "en-US"

$odata.error$message$value
[1] "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:2c74433e-0002-00b3-5aad-04d4db000000\nTime:2017-07-24T18:49:54.3878127Z"

The issue looks to be the authentication headers. Any help on how I could resolve this would appreciated. I'm really surprised more people don't use ATS with R since its so versatile.

Upvotes: 3

Views: 1075

Answers (3)

Hong Ooi
Hong Ooi

Reputation: 57686

Somewhat late to the party, but: there is now an AzureTableStor package, which is also on CRAN.

library(AzureTableStor)

# storage account endpoint
endp <- table_endpoint("https://mystorageacct.table.core.windows.net", key="mykey")
# Cosmos DB w/table API endpoint
endp <- table_endpoint("https://mycosmosdb.table.cosmos.azure.com:443", key="mykey")

list_storage_tables(endp)

tab <- storage_table(endp, "mytable")

insert_table_entity(tab, list(
    RowKey="row1",
    PartitionKey="partition1",
    firstname="Bill",
    lastname="Gates"
))

get_table_entity(tab, "row1", "partition1")

Disclaimer: I'm the developer of this package.

Upvotes: 0

juanmah
juanmah

Reputation: 1189

I based my solution in PUT blob question (Azure PUT Blob authentication fails in R), then I adapted to use GET instead of PUT and table instead of blob.

library(httr)  

account <- "account"
container <- "container"  
key <- "u4RzASEJ..9wfVIDg=="  

url <- paste0("https://", account, ".table.core.windows.net/", container)
requestdate <- format(Sys.time(),"%a, %d %b %Y %H:%M:%S %Z", tz="GMT")
content_length <- 0

signature_string <- paste0("GET", "\n",            # HTTP Verb
                           "\n",                   # Content-MD5
                           "text/plain", "\n",     # Content-Type
                           requestdate, "\n",                   # Date
                           # Here comes the Canonicalized Resource
                           "/",account, "/",container)

headerstuff <- add_headers(Authorization=paste0("SharedKey ",account,":", 
                                                RCurl::base64(digest::hmac(key = 
                                                                             RCurl::base64Decode(key, mode = "raw"),
                                                                           object = enc2utf8(signature_string),
                                                                           algo = "sha256", raw = TRUE))),
                           `x-ms-date`= requestdate,
                           `x-ms-version`= "2015-02-21",
                           `Content-Type`="text/plain")

xml_body = content(GET(url, config = headerstuff, verbose()))

Upvotes: 3

Peter Pan
Peter Pan

Reputation: 24138

According to the REST reference for the Authentication of Azure Storage, based on your error information & code, the issue AuthenticationFailed should be caused by the incorrect signature string for Table Service without 12 repeat symbol \n, which is different from that for Blob, Queue and File services. Please see the reference Authentication for the Azure Storage Services carefully to know the difference format for Table service, as below.

Table Service (Shared Key Authentication)

StringToSign = VERB + "\n" +   
           Content-MD5 + "\n" +   
           Content-Type + "\n" +  
           Date + "\n" +  
           CanonicalizedResource;  

Table Service (Shared Key Lite Authentication)

StringToSign = Date + "\n"   
           CanonicalizedResource  

Hope it helps.

Upvotes: 1

Related Questions