Constructing the hashed token signature for cosmos DB - azure

I am trying to create hashed token for creating a document in cosmos db but I am always getting 405 method not allowed, can someone verify whether the below format I provided is correct or not?
url = https://cosmos-test-cache.documents.azure.com/dbs/FamilyDB/colls/FamilyCollection/docs/123456
ResourceLink = /dbs/FamilyDB/colls/FamilyCollection/docs/123456
ResourceType = docs
HTTP verb = POST
Response
{
"code": "MethodNotAllowed",
"message": "RequestHandler.Post"
}

If you observe the official cosmos db rest api,you could find that url sample of Creating Document is https://{databaseaccount}.documents.azure.com/dbs/{db-id}/colls/{coll-id}/docs
However,your url is
https://cosmos-test-cache.documents.azure.com/dbs/FamilyDB/colls/FamilyCollection/docs/123456 which is for Get Document,not Create Document. So,it is identified as a Get request rather than a POST request.
Then the error 405 "MethodNotAllowed" occurs.
Updates:
Let me fix it.
If you use sdk, you could set the disableAutomaticIdGeneration property to avoid setting the id.It will generate id automatically for you.
Like:
But according to the rest api document,the id property is Required. The ID field is automatically added when a document is created without specifying the ID value.
Please refer to sample java rest code:
import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.json.JSONObject;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
public class CreateDocumentRest {
private static final String account = "***";
private static final String key = "***";
public static void main(String args[]) throws Exception {
String urlString = "https://" + account + ".documents.azure.com/dbs/db/colls/coll/docs";
//prepare for the json body
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "A");
jsonObject.put("id", "123");
String jsonStr = jsonObject.toString();
String encoding = "UTF-8";
System.out.println(jsonStr);
byte[] data = jsonStr.getBytes(encoding);
HttpURLConnection conn = (HttpURLConnection) (new URL(urlString)).openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
getFileRequest(conn, data);
OutputStream outStream = conn.getOutputStream();
outStream.write(data);
outStream.flush();
outStream.close();
System.out.println(conn.getResponseCode());
System.out.println(conn.getResponseMessage());
BufferedReader br = null;
if (conn.getResponseCode() != 200) {
br = new BufferedReader(new InputStreamReader((conn.getErrorStream())));
} else {
br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
}
System.out.println("Response body : " + br.readLine());
}
public static void getFileRequest(HttpURLConnection request, byte[] data)
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 = "POST".toLowerCase() + "\n"
+ "docs".toLowerCase() + "\n"
+ "dbs/db/colls/coll" + "\n"
+ date.toLowerCase() + "\n"
+ "" + "\n";
System.out.println("stringToSign : " + stringToSign);
String auth = getAuthenticationString(stringToSign);
request.setRequestMethod("POST");
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("x-ms-version", "2017-02-22");
request.setRequestProperty("Authorization", auth);
request.setRequestProperty("Content-Length", String.valueOf(data.length));
request.setRequestProperty("Content-Type", "application/json");
}
private static String getAuthenticationString(String stringToSign) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
String authKey = Base64.encode(mac.doFinal(stringToSign.getBytes("UTF-8")));
System.out.println("authkey:" + authKey);
String auth = "type=master&ver=1.0&sig=" + authKey;
auth = URLEncoder.encode(auth);
System.out.println("authString:" + auth);
return auth;
}
}
Per my observation,please adjust your ResourceLink as dbs/FamilyDB/colls/FamilyCollection and url as https://cosmos-test-cache.documents.azure.com/dbs/FamilyDB/colls/FamilyCollection/docs

To add to the above answer, for post calls to create hash token
Resource method:Post
Resource Id:dbs/{dbs}/colls/{colls}
Resource Type:docs
and the url should be
dbs/{dbs}/colls/{colls}/docs

Related

Azure storage server auto includes x-ms-request-id header in get blob operation

I am trying list blob operation followed by get blob operation. List blob works well but when it comes to get blob , the server auto includes x-ms-request-id in the header string resulting in unmatched calculated string.
Error goes like:
The MAC signature found in the HTTP request is not the same as any computed signature. Server used following string to sign: 'GET
Is there a way to stop server from auto including x-ms-request-id ?
package com.azure;
//import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
//import java.util.Calendar;
//import java.util.TimeZone;
//import java.util.Date;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
//import java.text.DateFormat;
public class Util {
// static SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
// static Date now= new Date();
// static String strDate = fmt.format(now);
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public static String signGetBlobRequestSK(String request, String account, String key,String now) throws Exception
{
//static 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 signedStr = Util.unsignedGetBlobRequestSK(account, now);
Mac mac = Mac.getInstance("HmacSHA256");
Decoder decoder = Base64.getDecoder();
Encoder encoder = Base64.getEncoder();
mac.init(new SecretKeySpec(decoder.decode(key), "HmacSHA256"));
String authKey = new String(encoder.encode(mac.doFinal(signedStr.getBytes("UTF-8"))));
//Byte authKeyDecoded = Byte.decode(authKey);
String auth = "SharedKey " + account + ":" + authKey;
return auth;
}
public static String unsignedGetBlobRequestSK(String account, String now) throws Exception
{
//fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
// String currentTimestamp = fmt.format(now) + " GMT";
StringBuilder sb = new StringBuilder();
sb.append("GET\n"); // method
sb.append('\n'); // content encoding
sb.append('\n'); // content language
sb.append('\n'); // content length
sb.append('\n'); // md5 (optional)
sb.append('\n'); // content type
sb.append('\n'); // legacy date
sb.append('\n'); // if-modified-since
sb.append('\n'); // if-match
sb.append('\n'); // if-none-match
sb.append('\n'); // if-unmodified-since
sb.append('\n'); // range
sb.append("x-ms-date:" + now +'\n'); // headers
sb.append("x-ms-version:2019-12-12\n");
sb.append("/" + account + '/'+ "test" + "/Test%20File%20for%20GMS.xml");
return sb.toString();
}

Authentication Failed for get file using file service REST API Azure

I am trying to get a file using the shared key. I already get a list of files and directories by the shared key, but when I request to receive a specific file, I encounter this problem.
Code to generate shared key:
using System;
using System.Collections.Specialized;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Web;
namespace StorageRestApiAuth
{
internal static class AzureStorageAuthenticationHelper
{
internal static AuthenticationHeaderValue GetAuthorizationHeader(
string storageAccountName, string storageAccountKey, DateTime now,
HttpRequestMessage httpRequestMessage, string ifMatch = "", string md5 = "")
{
// This is the raw representation of the message signature.
HttpMethod method = httpRequestMessage.Method;
String MessageSignature = String.Format("{0}\n\n\n{1}\n{5}\n\n\n\n{2}\n\n\n\n{3}{4}",
method.ToString(),
(method == HttpMethod.Get || method == HttpMethod.Head) ? String.Empty
: httpRequestMessage.Content.Headers.ContentLength.ToString(),
ifMatch,
GetCanonicalizedHeaders(httpRequestMessage),
GetCanonicalizedResource(httpRequestMessage.RequestUri, storageAccountName),
md5);
byte[] SignatureBytes = Encoding.UTF8.GetBytes(MessageSignature);
HMACSHA256 SHA256 = new HMACSHA256(Convert.FromBase64String(storageAccountKey));
string signature = Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));
returned.
AuthenticationHeaderValue authHV = new AuthenticationHeaderValue("SharedKey",
storageAccountName + ":" + Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes)));
return authHV;
}
private static string GetCanonicalizedHeaders(HttpRequestMessage httpRequestMessage)
{
var headers = from kvp in httpRequestMessage.Headers
where kvp.Key.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase)
orderby kvp.Key
select new { Key = kvp.Key.ToLowerInvariant(), kvp.Value };
StringBuilder sb = new StringBuilder();
foreach (var kvp in headers)
{
StringBuilder headerBuilder = new StringBuilder(kvp.Key);
char separator = ':';
foreach (string headerValues in kvp.Value)
{
string trimmedValue = headerValues.TrimStart().Replace("\r\n", String.Empty);
headerBuilder.Append(separator).Append(trimmedValue);
separator = ',';
}
sb.Append(headerBuilder.ToString()).Append("\n");
}
return sb.ToString();
}
private static string GetCanonicalizedResource(Uri address, string storageAccountName)
{
StringBuilder sb = new StringBuilder("/").Append(storageAccountName).Append(address.AbsolutePath);
NameValueCollection values = HttpUtility.ParseQueryString(address.Query);
foreach (var item in values.AllKeys.OrderBy(k => k))
{
sb.Append('\n').Append(item).Append(':').Append(values[item]);
}
return sb.ToString().ToLower();
}
}
}
With this code I can get a list of directories and files, but I can’t get a specific file.
I'm use this url to request: https://myaccount.file.core.windows.net/myshare/mydirectorypath/myfile
Error sending request:
{
"Error": {
"Code": "AuthenticationFailed",
"Message": "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:4c9ca5be-301a-0045-29c9-f20135000000\nTime:2020-03-05T08:36:05.9908405Z",
"AuthenticationErrorDetail": "The MAC signature found in the HTTP request 'here is my key' is not the same as any computed signature. Server used following string to sign: 'GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Thu, 05 Mar 2020 08:36:05 GMT\nx-ms-version:2017-04-17\n/my storage account/my share/myfile.JPG'."
}
}
I test in my site with your code and it works well. With your AzureStorageAuthenticationHelper and here it the following code that I get file content.
static void Main(string[] args)
{
GetFileContentAsyncREST("youraccount", "yourkey", CancellationToken.None).GetAwaiter().GetResult();
Console.WriteLine("Press any key to continue.");
Console.ReadLine();
}
private static async Task GetFileContentAsyncREST(string storageAccountName, string storageAccountKey, CancellationToken cancellationToken)
{
string uri = "https://xxxxx.file.core.windows.net/helloworld/directory/helloworld.txt";
Byte[] requestPayload = null;
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri)
{
Content = (requestPayload == null) ? null : new ByteArrayContent(requestPayload) })
{
DateTime now = DateTime.UtcNow;
httpRequestMessage.Headers.Add("x-ms-date", now.ToString("R", CultureInfo.InvariantCulture));
httpRequestMessage.Headers.Add("x-ms-version", "2017-04-17");
httpRequestMessage.Headers.Authorization = AzureStorageAuthenticationHelper.GetAuthorizationHeader(
storageAccountName, storageAccountKey, now, httpRequestMessage);
using (HttpResponseMessage httpResponseMessage = await new HttpClient().SendAsync(httpRequestMessage, cancellationToken))
{
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
{
string content = await httpResponseMessage.Content.ReadAsStringAsync();
Console.Write(content);
}
}
}
}
}
For more details, you could refer to this storage rest api with auth sample.

Implementation of RFC3161 in Groovy script

I need to get timestamp from a TSA in a Groovy script, in a SoapUI project. I try to use following script to get timestamp.
import org.bouncycastle.asn1.*
import org.bouncycastle.asn1.cmp.*
import org.bouncycastle.operator.*
import org.bouncycastle.tsp.*
import com.google.inject.AbstractModule
import com.google.inject.Provides
import com.google.inject.Inject
public interface TSAClient {
public byte[] getToken(byte[] imprint)
}
class TSAModule extends AbstractModule {
private String url
private String username
private String password
public TSAModule(String url, String username, String password) {
this.url = url
this.username = username
this.password = password
}
#Override
protected void configure() {
}
#Provides
TSAClient tsaClient() {
new TSAClientImpl(url, username, password)
}
}
public class TSAClientImpl implements TSAClient {
String tsaURL = "http://localhost:5050/timestamp"
String tsaUsername
String tsaPassword
public TSAClientImpl() {
}
public TSAClientImpl(String url, String username, String password) {
this.tsaURL = url
this.tsaUsername = username
this.tsaPassword = password
}
#Override
public byte[] getToken(byte[] imprint) {
byte[] respBytes = null
def algoFinder = new DefaultDigestAlgorithmIdentifierFinder()
def algoIdentifier = algoFinder.find("SHA-256")
// Setup the time stamp request
def tsqGenerator = new TimeStampRequestGenerator()
tsqGenerator.certReq = true
//tsqGenerator.reqPolicy = new ASN1ObjectIdentifier("1.3.6.1.4.1.13762.3")
def nonce = BigInteger.valueOf(System.currentTimeMillis())
def request = tsqGenerator.generate(algoIdentifier.objectId, imprint, nonce)
byte[] requestBytes = request.encoded
// Call the communications layer
respBytes = getTSAResponse(requestBytes)
// Handle the TSA response
def response = new TimeStampResponse(respBytes)
// validate communication level attributes (RFC 3161 PKIStatus)
response.validate(request)
def failure = response.failInfo
int value = (failure == null) ? 0 : failure.intValue()
if (value != 0) {
throw new IOException("TSA failure: ${value} (${response.statusString})")
}
// extract just the time stamp token (removes communication status info)
def tsToken = response.timeStampToken
if (tsToken == null) {
throw new IOException("TSA failed to return token: ${response.status} (${response.statusString})")
}
def tsTokenInfo = tsToken.timeStampInfo
byte[] encoded = tsToken.encoded
encoded
}
def getTSAResponse(byte[] requestBytes) {
// Setup the TSA connection
def tsaConnection = new URL(tsaURL).openConnection()
tsaConnection.doInput = true
tsaConnection.doOutput = true
tsaConnection.useCaches = false
tsaConnection.setRequestProperty("Content-Type", "application/timestamp-query")
//tsaConnection.setRequestProperty("Content-Transfer-Encoding", "base64")
tsaConnection.setRequestProperty("Content-Transfer-Encoding", "binary")
if (tsaUsername != null && tsaUsername != "") {
String userPassword = tsaUsername + ":" + tsaPassword
tsaConnection.setRequestProperty("Authorization", "Basic " +
userPassword.bytes.encodeBase64().toString())
}
def out = tsaConnection.outputStream
out << requestBytes
out.close()
// Get TSA response as a byte array
def inp = tsaConnection.inputStream
def baos = new ByteArrayOutputStream()
baos << inp
byte[] respBytes = baos.toByteArray()
def encoding = tsaConnection.getContentEncoding()
if (encoding != null && encoding.equalsIgnoreCase("base64")) {
respBytes = new String(respBytes).decodeBase64()
}
respBytes
}
}
I imported bcprov-jdk15on-1.62.jar, bcpkix-jdk15on-1.62.jar, guice-4.2.2.jar and javax.inject-1.jar dependencies to SOAPUI_HOME/bin/ext folder.
I get following error message during execution:
java.lang.NoClassDefFoundError: Unable to load class
com.google.inject.AbstractModule due to missing dependency
[Lorg/aopalliance/intercept/MethodInterceptor;
Source of code: https://github.com/carohadad/seginf/tree/master/Sinapuli-service/src/main/groovy/garantito/sinapuli/tsa
Update:
I added all the needed dependency jar files, but got following error message:
groovy.lang.GroovyRuntimeException: Failed to create Script instance
for class: interface TSAClient. Reason:
java.lang.InstantiationException: TSAClient

Error: Couldnt connect with Foursquare webservice

I tried to connect to the Foursquare webservice to parse look for some locations, but my program couldn't connect with Foursquare webservice. Here is my code:
public class GetLocation
{
public static void main (String [] args ) throws IOException
{
//Set up for output locations in a .txt file
String fileNameOut = "locations.txt" ;
FileOutputStream fos = new FileOutputStream( fileNameOut );
PrintStream ps = new PrintStream(fos);
String client_id = "Y2LZCJTR4LJBXZOXAB3F22VOLAV3GXRS5TSXRXXXXXXXXXXX";
String client_secret = "PJY2QM4CLZITAUMGOQCM2QYTOKATTCH3VXXXXXXXXXXX";
double latitude = 33.823712;
double longtitude = -117.958931;
String restaurantName = "Cafe Casse Croute";
String V = "20121205";
String API_URL = "http://api.foursquare.com/v2/venues/search?ll=";
String queryStatement = latitude+","+longtitude+"&match="+restaurantName;
try {
String url = (API_URL+queryStatement+"&client_id="+client_id+"&client_secret="+client_secret + "&v="+V);
URL url = new URL(sURL);
URLConnection httpc = url.openConnection();
//HttpURLConnection httpc = (HttpURLConnection) url.openConnection();
httpc.setDoInput(true);
httpc.connect();
BufferedReader in = new BufferedReader(new InputStreamReader(httpc.getInputStream()));
String inputLine = "";
String content="";
while ((inputLine = in.readLine()) != null){
content=content+inputLine;
}
in.close();
return content;
} catch (Exception e) {
return ("Exception: " + e.getMessage());
}
}
}
I also try to use URLConnection httpc = (URLConnection) url.openConnection();
but it does not connect to the FoureSquare Service.
Is there other way to connect to the FoureSquare Service ?

Google Docs API - Impersonate User File Download

Using the Google Docs Java API with a Google Apps account, is it possible to impersonate a user and download a file?
When I run the program below, it is clearly logging on to the domain and impersonating the user because it retrieves the details of one of the files and prints out the file title. However, when it tries to download the file, a ServiceForbiddenException is thrown.
If it is not possible with the Java API, does anyone know if it is possible for my program to write an HTTP request to download the file using the Protocol API?
public class AuthExample {
private static DocsService docService = new DocsService("Auth Example");
public static void main(String[] args)
throws Exception
{
String adminUser = args[0];
String adminPassword = args[1];
String authToken = args[2];
String impersonatedUser = args[3];
loginToDomain(adminUser, adminPassword, authToken);
URL url = new URL( "https://docs.google.com/feeds/" + impersonatedUser + "/private/full" );
DocumentListFeed feed = docService.getFeed(url, DocumentListFeed.class);
DocumentListEntry entry = feed.getEntries().get(0);
String title = entry.getTitle().getPlainText();
System.out.println( title );
String type = entry.getType();
if ( type.equals("document") )
{
String encodedAdminUser = URLEncoder.encode(adminUser);
String resourceId = entry.getResourceId();
String resourceIdNoPrefix = resourceId.substring( resourceId.indexOf(':')+1 );
String downloadUrl =
"https://docs.google.com/feeds/download/documents/Export" +
"?xoauth_requestor=" + encodedAdminUser +
"&docId=" + resourceIdNoPrefix +
"&exportFormat=doc";
downloadFile( downloadUrl, title + ".doc" );
}
}
private static void loginToDomain(String adminUser, String adminPassword, String authToken)
throws OAuthException, AuthenticationException
{
String domain = adminUser.substring( adminUser.indexOf('#')+1 );
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(domain);
oauthParameters.setOAuthConsumerSecret(authToken);
oauthParameters.setOAuthType(OAuthType.TWO_LEGGED_OAUTH);
oauthParameters.setScope("https://docs.google.com/feeds/ http://spreadsheets.google.com/feeds/ http://docs.googleusercontent.com/");
docService.useSsl();
docService.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
docService.setUserCredentials(adminUser, adminPassword);
}
// Method pasted directly from Google documentation
public static void downloadFile(String exportUrl, String filepath)
throws IOException, MalformedURLException, ServiceException
{
System.out.println("Exporting document from: " + exportUrl);
MediaContent mc = new MediaContent();
mc.setUri(exportUrl);
MediaSource ms = docService.getMedia(mc);
InputStream inStream = null;
FileOutputStream outStream = null;
try {
inStream = ms.getInputStream();
outStream = new FileOutputStream(filepath);
int c;
while ((c = inStream.read()) != -1) {
outStream.write(c);
}
} finally {
if (inStream != null) {
inStream.close();
}
if (outStream != null) {
outStream.flush();
outStream.close();
}
}
}
}
Impersonation will work as intended if you use Oauth2 with ServiceAccounts

Resources