I want to implement OAuth 1.0 protocol in order to work with COPY. But when i implemented OAuth protocol in C++ in order to get Request Token and sent that request to copy it's return that signature is invalid and i can't figure out what's wrong in my signature. Here are all parameters that i generate by my program:
oauth_nonce=xoviybpokqnxdwlnkeoorawfijgezr
oauth_timestamp=1381745375
oauth_callback=http%3A%2F%2Fcopy-oauth.local%2Fget_access_token.php
oauth_signature_method=HMAC-SHA1
This is base string that i used in order to generate token:
GET&https%3A%2F%2Fapi.copy.com%2Foauth%2Frequest&oauth_consumer_key%3D[my
32 symbols
key]%26oauth_nonce%3Dxoviybpokqnxdwlnkeoorawfijgezr%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1381745375%26oauth_tokey%3D
It's key for generating signature:
[My consumer secret, 48 symbols]&
Here is signature that i received after base64 and percent encoded:
lNaaOaWyGtkJWj%2BVLjLlKTVGYL0%3D
And the last thing is sending all parameters to server. For this purpose i use libcurl:
char * abc="https://api.copy.com/oauth/request/?oauth_callback=http%3A%2F%2Fcopy-oauth.local%2Fget_access_token.php&oauth_consumer_key=[my 32 symbols key]&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1381745375&oauth_nonce=xoviybpokqnxdwlnkeoorawfijgezr&oauth_signature=lNaaOaWyGtkJWj%2BVLjLlKTVGYL0%3D";
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, TRUE);
curl_easy_setopt(curl, CURLOPT_CAINFO, "C:\\a\\a\\a\\cacert.pem");
curl_easy_setopt(curl, CURLOPT_URL, abc);
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
Then my console will output:
oauth_error_message=oauth_problem%3Dsignature_invalid%26debug_sbs...
What's wrong in my implementation?
The main problem was that oauth_callback should be two time percent encoded in order to create signature base string. This is string that I send in request:
oauth_callback="http://copy-oauth.local/get_access_token.php"
And this is string that I add to signature base string:
http%253A%252F%252Fcopy-oauth.local%252Fget_access_token.php
Here are a few things that immediately spring to mind:
Your signature base string should include the oauth_callback parameter
oauth_token should not be included in the signature base string as you are not including it in your querystring parameters
The path of your url should not end in a forward slash unless you also include for this in your signature base string:
char * abc="https://api.copy.com/oauth/request?oauth_callback= ...
You should remove the '&' character from the end of your querystring
Related
I'm trying to create a login function via curl for my C++ application. Upon successful data being passed to the server, the server should return the response code 200. My information is the same as whats in the database aswell. I am using Visual Studio 2019 and C++ 17. I am also on Windows.
Note: The link I pass to the api is correct, I know it because I looked at Visual Studios debugger and the value was correct.
My code:
std::string API = "http://api.mywebsitenameishere.xyz/ovixau.php?username=" + username + "&password=" + password + "&hwid=TEST&authv=1";
CURL* curl = curl_easy_init();
if (!curl)
printf("Curl failed to init.\n");
else
{
int curl_code = curl_easy_perform(curl);
long http_code = 0;
curl_easy_setopt(curl, CURLOPT_URL, API.c_str());
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if (http_code == 200 && curl_code != CURLE_ABORTED_BY_CALLBACK)
{
printf("Succesfully logged in!\n");
}
else
{
printf("Failed to log in, response code %ld", http_code);
}
}
If there is something else I need to specify, feel free to ask. Thanks.
As Igor said, I was sending a request before I set the url of the api. I needed to switch curl_easy_setopt and curl_easy_perform. It works perfectly now, thank you Igor!
Libcurl is putting Accept on the http header with the default value Accept: */*.
I want to avoid libcurl putting Accept in the http header. How I can do that?
You set a header with no "contents" on the right of the colon to remove it from libcurl's request (see the CURLOPT_HTTPHEADER docs):
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Accept:");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
res = curl_easy_perform(curl);
For a slightly more complete example in C using custom headers, see httpcustomheader.c
I am writing a piece of c++ code with libcurl to call Amazon s3 RESTful service as follows:
void SampleOfS3Get()
{
//Init curl
curl_global_init(CURL_GLOBAL_ALL);
CURL* curlHandle = curl_easy_init();
//Init var
char* curlErrStr = (char*)malloc(CURL_ERROR_SIZE);
curl_slist* httpHeaders = NULL;
const char* date = getDateForHeader();
httpHeaders = curl_slist_append(httpHeaders, "Host: s3.amazonaws.com");//Set Host
httpHeaders = curl_slist_append(httpHeaders, date);//Set Date
httpHeaders = curl_slist_append(httpHeaders, getAuthorizationForHeader("AKIAISZALBSY-----XGQ","tIzCC----------/Jsn5KqTfuCAWyD1eyeOKStx0",date));//Set authorization
//Execute
if(curlHandle)
{
curl_easy_setopt(curlHandle, CURLOPT_VERBOSE, CURLOPT_STDERR);//Set verbose mode
curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION,1);//Set automaticallly redirection
curl_easy_setopt(curlHandle, CURLOPT_MAXREDIRS,1);//Set max redirection times
curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, curlErrStr);//Set error buffer
curl_easy_setopt(curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);//Set http version 1.1
curl_easy_setopt(curlHandle, CURLOPT_HEADER, httpHeaders);//Set headers
curl_easy_setopt(curlHandle, CURLOPT_URL, "http://s3.amazonaws.com/");//Set URL
CURLcode curlErr = curl_easy_perform(curlHandle);//Perform
if(curlErr)
{
cout<<curl_easy_strerror(curlErr)<<endl;
}
//Output redirection url
if(CURLE_OK == curlErr)
{
char *url;
curlErr = curl_easy_getinfo(curlHandle, CURLINFO_EFFECTIVE_URL, &url);
if((CURLE_OK == curlErr) && url)
cout<<"CURLINFO_EFFECTIVE_URL: "<<url<<endl;
}
/* Clean-up libcurl */
curl_global_cleanup();
}
}
This function calls the "GET SERVICE" to get the list of all buckets for a specified user.But the HTTP response of this HTTP request turns out to be "a temporary redirect to http://aws.amazon.com/s3" with http state code 307.
Then I find it in the official document which implies that caller should handle the redirection himself,so I add CURLOPT_FOLLOWLOCATION attribute as well.Then the result turns out to be a webpage content of amazon s3.
More details:http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html?r=1821
When I use the example accessID and accessKey in the above link,i get the right signature as "Example List All My Buckets" shows.It confused me that the server redirect my request instead of returning the expected all bucket list of my own(using my own accessID and accessKey).
Somebody encounter the similar problem like mine?SOS...
You should really start by reading http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAPI.html first, as your current code contains many issues. Especially make sure you fully understand how Signing and Authenticating REST Requests work.
This small C++ project seems to do cURL based File PUTs to AWS S3.
with CMake, one can generate VC++ Project/solutions and build it into .LIB static library, or, use it as source code, in your VC++ Solution.
I used it in a VC++ 2013 MFC Project.
Hope it helps.
https://github.com/cedricve/AWS-S3-Cpp-REST-API
Ive a problem and i cant figure at all how i can manage to solve the following problem:
I would like to send multiple http request to an axis camera.
Here's my code:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http:/root:309#IPADDRESS");
/* example.com is redirected, so we tell libcurl to follow redirection */
// curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
res=curl_easy_perform(curl);
curl_easy_setopt(curl, CURLOPT_URL, "http:/IPADDRESS/axis-cgi/com/ptz.cgi?move=left");
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
All i want to do in this example, is to keep my session alive after being logged to the IPaddress, and then send the order "move=left" to this very ip address.
When i execute this program, i got those messages:
<HTML>
<HEAD>
<META HTTP-EQUIV="Expires" CONTENT="Tue, 01 Jan 1980 1:00:00 GMT">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Refresh" CONTENT="0; URL=/view/index.shtml">
Your browser has JavaScript turned off.<br>For the user interface to work effectively, you must enable JavaScript in your browser and reload/refresh this page.
</noscript>
</HEAD>
<BODY>
</BODY>
</HTML>
<HTML><HEAD><TITLE>401 Unauthorized</TITLE></HEAD>
<BODY><H1>401 Unauthorized</H1>
Your client does not have permission to get URL /axis-cgi/com/ptz.cgi from this server.
</BODY></HTML>
I assume that i wasnt even logged to the ipaddress...
I never really used this kind of method before... Can you help me with this?
Thank you a lot.
You need to add these two options:
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookie.txt");
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookie.txt");
From documentation:
CURLOPT_COOKIEFILE
Pass a pointer to a zero terminated string as parameter. It should
contain the name of your file holding cookie data to read. The cookie
data may be in Netscape / Mozilla cookie data format or just regular
HTTP-style headers dumped to a file.
Given an empty or non-existing file or by passing the empty string
(""), this option will enable cookies for this curl handle, making it
understand and parse received cookies and then use matching cookies in
future requests.
If you use this option multiple times, you just add more files to
read. Subsequent files will add more cookies.
CURLOPT_COOKIEJAR
Pass a file name as char *, zero terminated. This will make libcurl
write all internally known cookies to the specified file when
curl_easy_cleanup(3) is called. If no cookies are known, no file will
be created. Specify "-" to instead have the cookies written to stdout.
Using this option also enables cookies for this session, so if you for
example follow a location it will make matching cookies get sent
accordingly.
If the cookie jar file can't be created or written to (when the
curl_easy_cleanup(3) is called), libcurl will not and cannot report an
error for this. Using CURLOPT_VERBOSE or CURLOPT_DEBUGFUNCTION will
get a warning to display, but that is the only visible feedback you
get about this possibly lethal situation
Read more at: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
I am using the CURL c++ api to get quotes from Yahoo's financial API. The curl api and my code seem to be working fine, however I am getting a "301" redirect message when I tell CURL to visit the url I want. How can I get CURL to follow through to the 301 redirect and get the data I want?
Here is the URL I am using:
http://download.finance.yahoo.com/d/quotes.csv?e=.csv&s=WSF,WSH&f=b2b3s
Here is the response I am getting:
<HEAD><TITLE>Redirect</TITLE></HEAD>
<BODY BGCOLOR="white" FGCOLOR="black">
<FONT FACE="Helvetica,Arial"><B>
"<em>http://download.finance.yahoo.com/d/quotes.csv?e=.csv&s=WSF,WSH,WSM,WSO,WST,WTI,WTM,WTR,WTS,WTU,WTW,WU,WWE,WWW,WX,WXS,WY,WYN,X,XAA,XCJ,XCO,XEC,XEL,XEL-A,XEL-E,XFB,XFD,XFH,XFJ,XFP,XFR,XIN,XJT,XKE,XKK,XKN,XKO,XL,XL-Y,XOM,XRM,XRX,XVF,XVG,Y,YGE,YPF,YSI,YUM,YZC,ZB-A,ZB-B,ZB-C,ZEP,ZF,ZLC,ZMH,ZNH,ZQK,ZTR,ZZ,ZZC&f=b2b3ccd1d2ghjkk2k3l2l3mm2m3m4m5m6m7m8opst7vw</em>".<p></B></FONT>
<!-- default "Redirect" response (301) -->
</BODY>
Here are my CURL init options
CURL *eh = curl_easy_init();
curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, cb);
curl_easy_setopt(eh, CURLOPT_HEADER, 0L);
curl_easy_setopt(eh, CURLOPT_URL, url);
curl_easy_setopt(eh, CURLOPT_PRIVATE, url);
curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L);
curl_multi_add_handle(cm, eh);
I didn't post my code, as it is all working, I just need the general method of following through woth the 301's with CURL.
In the PHP world, the option is named CURLOPT_FOLLOWLOCATION. I assume the constant names are standardized and come from the same header file, so this should work for you.
curl_easy_setopt(eh, CURLOPT_FOLLOWLOCATION, 1);
(or whatever "boolean true" is in this context.)
Alternatively, when receiving a 30x status code, you can parse the Location header manually for the new address. Obviously though, the "follow location" option is much easier, as it doesn't require a second request.