Google Cloud Storage API - StringToSign returned wrong bucket name - storage

I am trying to upload to my cloud storage using a signed url.
I had plenty of errors trying to sign the string correctly.
What I dont understand is the object which always "www.google.com" prefixing my "bucketName + objectName"
Request
curl --location --request PUT 'https://storage.googleapis.com/ABCD/disney.png?GoogleAccessId=cjl-scheduler-storage#cjl-scheduler.iam.gserviceaccount.com&Expires=1604702284&Signature=l37cl4a6lmX6AiQ%2BTi3%2FkZqm9vH0bXSYbZf4XNTwvvQKjJRdEIrEHrf55Yvci5ROso2av4krnvS7XXdaetWCFNT0oRdU%2BAGlF%2BD%2F2BZls%2BB072MP%2B8LXuvqOPCyBJWmaNcEB35%2Brv5FzM1fe7zuI7XxGF3kW6uCWjWU8%2BkMwJGBz1JeXytHErhxsjGpciBzllL5j0G9nwtHc7TbgZNaYGOUAjpjXS7NJzLCm4JQh2%2BYarvthpDzim25FRB818cKeegIFeZyy2FSi2MjfdmriVwVJbvTNvceF%2B5uXnwWcqQU9ZVIXmFNzsJq5m1eHO4zQ9HvkpSUCKtzEH3SL5Mx6uA%3D%3D' \
--header 'Content-Type: image/png' \
--data-binary '#/Users/manueldupont/Downloads/disney.png'
Response
<?xml version='1.0' encoding='UTF-8'?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message>
<StringToSign>PUT
image/png
1604702284
/www.google.com/ABCD/disney.png</StringToSign>
</Error>
Looks like storage.googleapis.com concatenate this to the object I pass. Why is that ?!
Here is the code I use to sign
String url_signature = signString(key,
verb + "\n\n" +
"image/png" + "\n" +
expirationSeconds + "\n" +
bucketName + "/" + objectName);
String signed_url = "https://storage.googleapis.com/" + bucketName + "/" + objectName +
"?GoogleAccessId=" + ((ServiceAccountCredentials) this.getCreds()).getClientEmail() +
"&Expires=" + expirationSeconds +
"&Signature=" + URLEncoder.encode(url_signature, "UTF-8");
knowing that bucketName="ABCD" and objectName="disney.png".

Related

How to include query params in the base string signature OAuth1

I need to retrieve some data through the gravity forms API (which is installed as a plugin in a WordPress server). I must implement OAuth 1.0. Some of the ruby gems available for this type of authentication don't work pretty well for me, so I decided to implement it myself.
I'm able to sign the base string if I don't add extra params but once I add them I get the error Invalid signature - provided signature does not match.
My code looks like this:
# This OAUTH implementation works without extra query params.
require 'httparty'
OAUTH_TOKEN = "API customer secret token"
OAUTH_PASSWORD = "API customer key token"
url = 'https://localhost/wp-json/gf/v2/entries'
params = "oauth_consumer_key=#{OAUTH_TOKEN}&oauth_nonce=#{SecureRandom.hex}&oauth_signature_method=HMAC-SHA1&oauth_timestamp=#{Time.now.to_i}&oauth_token=#{OAUTH_PASSWORD}&oauth_version=1.0"
base_string = 'GET&' + CGI.escape(url) + '&' + CGI.escape(params)
secret = "#{OAUTH_PASSWORD}&#{}"
oauth_signature = sign(secret, base_string)
testable_url = url + '?' + params + '&oauth_signature=' + oauth_signature
response = HTTParty.get(testable_url)
def sign( secret, base_string )
CGI.escape(Base64.encode64("#{OpenSSL::HMAC.digest('sha1', secret, base_string)}").chomp)
end
But once I add the query params I need, it crashes.
query_params = 'search={"field_filters":[{"key":"'+form['key']+'","value":"'+email+'","operator":"is"},{"key":"source_url","value":"'+form['source_url'].to_s+'","operator":"is"}]}'
I'm updating the base_string to include the query_params then I sign it again and I update the final url
base_string = 'GET&' + CGI.escape(url) + '&' + CGI.escape(query_params) + '&' + CGI.escape(params)
oauth_signature = sign(secret, base_string)
testable_url = url + '?' + query_params + '&' + params + '&oauth_signature=' + oauth_signature
As a result I get the following URL
"https://localhost/wp-json/gf/v2/entries?search={\"field_filters\":[{\"key\":\"2\",\"value\":\"some#email.com\",\"operator\":\"is\"},{\"key\":\"source_url\",\"value\":\"https://localhost/some_url_i_need/\",\"operator\":\"is\"}]}&oauth_consumer_key=APICUSTOMERSECRET&oauth_nonce=81a6ce4dcabd5ec1059f66ca7ae727e3&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1607594914&oauth_token=APICUSTOMER_TOKEN&oauth_version=1.0&oauth_signature=LIZpR27KNHsw3iWArJjSs%2FsvIek%3D"
Which doesn't work due to the Invalid signature - provided signature does not match. error.
As suggested in the documentation and other posts I've read (https://stackoverflow.com/a/4789210), I've sorted the params (basically I added search param I need at the end of the base string and that didn't solve my issue.
Note: It works in Postman, and the URL that Postman generates is pretty much like the one I get with Ruby.
One of your issue is that you forgot to escape the ampersand between your query_params and regular params:
base_string = 'GET&' + CGI.escape(url) + '&' + CGI.escape(query_params) + '&' + CGI.escape(params)
You have to turn that last '&' into '%26' or pull the concatenation into the CGI.escape.
base_string = 'GET&' + CGI.escape(url) + '&' + CGI.escape(query_params + '&' + params)
Watch out for empty params though with this.

Why do I have to specify the redirection URI when using authorization token to get access token in OAuth2?

This code works
I surf I got the code by surfing https://app.stex.com/oauth/authorize?response_type=code&client_id=144&scope=trade profile then I got a code.
I put the code on my program
Dim code = "def50200354606432acfb60c836ac40ff440dc2755164756cd7e34ddcf9cd4db8df87cabe71bf5e5c5c278c18c81b0415ba47da34f83ddaab0a84696e1722e266aec2e7942ed86e40e65b0dcf7428aad2747920de6cf8585ce281214f2ecc7353e807640320ca263013387ea0b2d466e2cc31b46c2a2e7b1dd33cdc518efa20b76b752734174f2b500450ed1ccb434611b0bdc458fcfed69a2ab2a5f91242f1f68c504d3151048c49eaf976eff6bbb922dac1acbba069fc8b57fd74069eeadf24c067edf4563aa5ad14b0d9740f1518723ba1c5637164e5e3c4d408102f49c0f63d8f3f5dfbfe11132d242a182e4af3449e811292d1ac69aadf74608a5383b9c4030de3579c98b07c4f087752f7e404f4897d8167b3d8ad266bdb42f74b539cc3fef6ce774edd35d305e655e984028614e50afe760acc754de70986dc7651ac760d5817c665ef1238d0811190763dbfd65993408d12dcf7926be6c71afb5d8a10528c174647934bdd1e4fcf1f4a800b8a74a7ae93bf60b02c602900a981bdb75e9de2b17f359ee"
Then I do
Dim token2 = CookieAwareWebClient.downloadString1("https://api3.stex.com/oauth/token", "grant_type=authorization_code&code=" + code + "&client_id=" + _apiKey1 + "&client_secret=" + _secret1 + "&redirect_uri=https://apidocs.stex.com/oauth2-redirect.html", {})
Dim jtoken1 = JToken.Parse(token2)
Dim refreshtoken = jtoken1.Item("refresh_token").ToString
And it works.
However, this code doesn't work
Dim token2 = CookieAwareWebClient.downloadString1("https://api3.stex.com/oauth/token", "grant_type=authorization_code&code=" + code + "&client_id=" + _apiKey1 + "&client_secret=" + _secret1, {})
Dim jtoken1 = JToken.Parse(token2)
Dim refreshtoken = jtoken1.Item("refresh_token").ToString
The only difference is that in the first code I added + "&redirect_uri=https://apidocs.stex.com/oauth2-redirect.html"
Basically, I am creating a stex api.
My client has only one redirect URL. So why do I have to specify that redirect URL, that is not used anymore, and the server know anyway, to the https://api3.stex.com/oauth/token url?
I think I read the RFC
4.1.3. Access Token Request
The client makes a request to the token endpoint by sending the following parameters using the "application/x-www-form-urlencoded"
format per Appendix B with a character encoding of UTF-8 in the HTTP
request entity-body:
[...]
redirect_uri
REQUIRED, if the "redirect_uri" parameter was included in the authorization request as described in Section 4.1.1, and their values
MUST be identical.
It says that the redirect_URI is required if the parameter was included.
I didn't include the parameter when I request authorization code.

Yahoo Messenger API - parameter_absent: oauth_signature

I'm just not able to solve this for days now, anyone have any ideas? Below is the request response as shown by Fiddler
The response is that the oauth_signature is absent, however it was sent. If I calculated the signature incorrectly i would expect signature_invalid
I feel like the issue is staring me in the face, but I can't see it.
GET http://developer.messenger.yahooapis.com /v1/session HTTP/1.1
Authorization: OAuth
realm: "yahooapis.com"
oauth_version: "1.0"
oauth_token: "The oauth token "
oauth_nonce: "4724376"
oauth_timestamp: "1449488987"
oauth_consumer_key: "My consumer key"
oauth_signature_method: "HMAC-SHA1"
oauth_signature: "oBjiENcrXBX6I5dE/Vr7AHj2FOA="
Content-Type: application/json;charset=utf-8
Host: developer.messenger.yahooapis.com
HTTP/1.1 401 Authorization Required
Date: Mon, 07 Dec 2015 11:49:34 GMT
WWW-Authenticate: OAuth oauth_problem="parameter_absent: oauth_signature", realm="yahooapis.com"
Connection: close
Transfer-Encoding: chunked
Content-Type: application/xml
Cache-Control: private
17b
<?xml version='1.0' encoding='UTF-8'?>
Please provide valid credentials. OAuth oauth_problem="parameter_absent: oauth_signature", realm="yahooapis.com"
Many thanks
Jon
Found the problem:
I was creating a new request header for each authentication item. All the OAuth tokens must go in the same header. ie. the Authorization header
The code below is how I add create the Authorization header, which works fine now.
string OAuthHeader = "OAuth realm=\"yahooapis.com\"," +
"oauth_consumer_key=\"" + consumerkey + "\"," +
"oauth_timestamp=\"" + timestamp + "\"," +
"oauth_nonce=\"" + nonce + "\"," +
"oauth_version=\"1.0\"," +
"oauth_signature_method=\"PLAINTEXT\"," +
"oauth_token=\"" + dictGetRequestTokenParams["oauth_token"] + "\"," +
"oauth_signature=\"" + consumerSecret + "%26" + dictGetRequestTokenParams["oauth_token_secret"] + "\",";
request.Headers.Add(HttpRequestHeader.Authorization, OAuthHeader);

404 Error when trying to post a file topic

I am trying to create content in my d2l orgUnit but I keep getting 404 Page not found back. I am calling this from the Android emulator. I've successfully created a module as well as a topic link using the POST APIs. I did look at this post 404 Posting Content to Desire2Learn which helped me get the module and link working, but I just can't get the uploading a file as a topic to work. I suspect it may be the URL as I wasn't sure what to put, so I put a relative path I created in the org unit. The post 404 Posting Content to Desire2Learn mentions to use "valid location URL to within the org unit's existing content space". I also tried the /content/enforced/... folder as URL to no avail. I'm not sure if this is the issue, or a red herring...
Here is my code:
String body = "--xxBoundaryxx " +
"Content-Type: application/json " +
"{" +
"\"Title\": \"Testing an upload\"," +
"\"ShortTitle\": \"test\"," +
"\"Type\": 1," +
"\"TopicType\": 1," +
"\"URL\": \"/test/\"," +
"\"StartDate\": null," +
"\"EndDate\": null," +
"\"IsHidden\": false," +
"\"IsLocked\": false" +
" } " +
"--xxBoundaryxx " +
"Content-Disposition: form-data; name=\"file 0\"; filename=\"test.txt\" " +
"Content-Type: text/plain " +
"This is my sample file to try it out.";
URI uri = userContext.createAuthenticatedUri("/d2l/api/le/1.1/{OrgID}/content/modules/{ModuleID}/structure/", "Post");
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost(uri);
post.addHeader("Content-Type", "multipart/mixed; boundary=xxBoundaryxx");
post.setEntity(new StringEntity(body));
HttpResponse response = httpClient.execute(post);
Log.i(TAG, "Statusline: " + response.getStatusLine());
Here is the resulting body (I put \r\n for line breaks as well, but it didn't help).
--xxBoundaryxx
Content-Type: application/json
{
"Title": "Testing an upload",
"ShortTitle": "test",
"Type": 1,
"TopicType": 1,
"URL": "/test/",
"StartDate": null,
"EndDate": null,
"IsHidden": false,
"IsLocked": false
}
--xxBoundaryxx
Content-Disposition: form-data; name="file 0"; filename="test.txt"
Content-Type: text/plain
This is my sample file to try it out.
what is going on? getStatusLine always returns 404 error... I know it is not a permission issue since I can create modules and link topics successfully using very similar code. Any guidance greatly appreciated.
You almost certainly need a terminating boundary on your POST body (--xxBoundaryxx--). For the Url property in the JSON block you send: you can send an Url that's not relative (as in the example in the docs); it also seems you can send just a file name (relative name) and the upload process puts the file in the root of the course's content area. I would fully expect that (a) if you don't have an absolute URL, it would use the course's root folder as the base part of the path, and (b) the upload API action will not create directories for you, but I haven't comprehensive testing around how the Url property gets handled.
I've tested this API action on our test servers, and it works (with a fully specified Url and just a file name for the Url). I've also updated the Valence docs to include a concrete example of the course content file topic upload packet: hope these two things help you out.

How can I use the grant_type=password oauth flow with salesforce.com?

I'm trying to get an authorization token using the Username-Password flow (as described in the final section of this article).
I'm sending the following request (using Python's httplib, in case that's relevant):
https://login.salesforce.com/services/oauth2/token
POST data:
username=<un>&client_secret=<consumer_secret>&password=<pw+token>&grant_type=password&client_id=<consumer_key>
And getting the response:
400 Bad Request
{"error":"unsupported_grant_type","error_description":"grant type not supported"}
Is the password grant_type really unsupported, or am I missing something? It seems to give this error even when I'm sending a grant_type that definitely does work (such as authorization_code).
Note that I've tried the suggestions in the answer here, and they don't work for me.
Typically this is because the content-type header has not been set to the correct value, it should be application/x-www-form-urlencoded.
Also make sure your parameters are correctly encoded (especially if you're building the POST payload by hand).
Below is detailed function/logic on how to use grant_type=password oauth flow with salesforce.com in JAVA:
// Authenticate via OAuth
JSONObject response = oauthLogin();
System.out.println("Login response: " + response.toString(2));
if (!response.has("access_token")) {
throw new Exception("OAuth failed: " + response.toString());
}
..........................
private static JSONObject oauthLogin() throws Exception {
org.eclipse.jetty.client.HttpClient jettyHttpClient = new org.eclipse.jetty.client.HttpClient();
jettyHttpClient.start();
String url = LOGIN_SERVER + "/services/oauth2/token";
ContentExchange exchange = new ContentExchange();
exchange.setMethod("POST");
exchange.setURL(url);
String message = "grant_type=password&client_id=" + CLIENT_ID
+ "&client_secret=" + CLIENT_SECRET + "&username=" + USERNAME
+ "&password=" + PASSWORD;
exchange.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
exchange.setRequestContentSource(new ByteArrayInputStream(message
.getBytes("UTF-8")));
jettyHttpClient.send(exchange);
exchange.waitForDone();
return new JSONObject(new JSONTokener(exchange.getResponseContent()));
}
You must set the grant_type as "password" in the form data. See below.
The form data should be passed ad
grant_type=password&username=nilavghosh%40gmail.com&password=******

Resources