How to use authentication details with a QNetWorkRequest in bb cascades? - blackberry-10

I want to create a BB10 application using bb cascades in which i want to pass username and password to the server with a QNetWork http request. I tried the following
QNetworkRequest request = QNetworkRequest();
request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
request.setRawHeader("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
request.setRawHeader("Content-Language", "en-US");
QString concatenated = "username:password";
QByteArray data = concatenated.toLocal8Bit().toBase64();
QString headerData = "Basic " + data;
req.setRawHeader("Authorization", headerData.toLocal8Bit());
QSslConfiguration config = request.sslConfiguration();
config.setPeerVerifyMode(QSslSocket::VerifyNone);
config.setProtocol(QSsl::TlsV1);
request.setSslConfiguration(config);
But this gives me an QNetworkReply error 202(ContentOperationNotPermittedError).What is the reason for this error? How can i solve this issue?
Thanks in Advance

This code works for me
QNetworkRequest request = QNetworkRequest();
request.setRawHeader("Authorization","Basic " + QByteArray(QString("%1:%2").arg(USER_NAME).arg(PASSWORD).toAscii()).toBase64());
request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
request.setRawHeader("Content-Language", "en-US");
QSslConfiguration config = request.sslConfiguration();
config.setPeerVerifyMode(QSslSocket::VerifyNone);
config.setProtocol(QSsl::TlsV1);
request.setSslConfiguration(config);

Related

Uploading files to Onedrive using REST API

I am trying to upload a file into OneDrive using its REST API. This is what I am trying to accomplish based on documentation available at OneDrive Rest API:
POST https://apis.live.net/v5.0/me/skydrive/files?access_token=ACCESS_TOKEN
Content-Type: multipart/form-data; boundary=A300x
--A300x
Content-Disposition: form-data; name="file"; filename="HelloWorld.txt"
Content-Type: application/octet-stream
Hello, World!
--A300x--
This is what I have:
Uri destination = new Uri(string.Format("https://apis.live.net/v5.0/{0}/files?", folder.ID));
BackgroundUploader uploader = new BackgroundUploader ();
uploader.SetRequestHeader("Authorization", "Bearer " + account.AccessToken);
uploader.SetRequestHeader("Content-Type", "multipart/form-data; boundary=\"foo_bar_baz\"");
List<BackgroundTransferContentPart> parts = new List<BackgroundTransferContentPart>();
BackgroundTransferContentPart metaDataPart = new BackgroundTransferContentPart();
metaDataPart.SetHeader("Content-Disposition", "form-data; name=\"file\";filename=\""+content.Name+"\"");
parts.Add(metaDataPart);
BackgroundTransferContentPart contentPart = new BackgroundTransferContentPart();
contentPart.SetHeader("Content-Type", content.ContentType);
// content is a StorageFile
contentPart.SetFile(content);
response.UploadOperation = await uploader.CreateUploadAsync(destination, parts, "form-data", "foo_bar_baz");
This line below causes an Access violation error and the Windows Store app crashes:
response.UploadOperation = await uploader.CreateUploadAsync(destination, parts, "form-data", "foo_bar_baz");
You are creating two BackgroundTransferContentPart and only adding the fist to your 'List'.
I think you only need one, something like this:
List<BackgroundTransferContentPart> parts = new List<BackgroundTransferContentPart>();
BackgroundTransferContentPart metaDataPart = new BackgroundTransferContentPart();
metaDataPart.SetHeader("Content-Disposition",
"form-data; name=\"file\";filename=\"" + content.Name + "\"");
metaDataPart.SetHeader("Content-Type", content.ContentType);
metaDataPart.SetFile(content);
parts.Add(metaDataPart);
UPDATE: Ok, the above code fixed the Access Violation issue. Why you are getting a 400 error is a mystery.
But another way to upload a file to OneDrive is using the PUT method:
Uri putUri = new Uri(string.Format("https://apis.live.net/v5.0/{0}/files/{1}",
"folder.a4fb14adbccd1917.A4FB14ADBCCD1917!32089",
content.Name));
BackgroundUploader uploader = new BackgroundUploader();
uploader.SetRequestHeader("Authorization", "Bearer " + accessToken);
uploader.Method = "PUT";
UploadOperation putOperation = uploader.CreateUpload(putUri, content);
await putOperation.StartAsync();
Have you tried PUT?

401 when adding customer with QB Online API v3

I keep getting a 401 when I try to add a customer with QB Online API v3. The xml works in the API Explorer, and I'm able to query customers from my program. I just can't POST. What am I doing wrong?
string reqBody = "<Customer xmlns=\"http://schema.intuit.com/finance/v3\" domain=\"QBO\" sparse=\"false\"><DisplayName>Empire Records</DisplayName>"
+ "<BillAddr><Line1>201 S King St</Line1><City>Seattle</City><CountrySubDivisionCode>WA</CountrySubDivisionCode><PostalCode>98104</PostalCode></BillAddr>"
+ "<PrimaryPhone><FreeFormNumber>425-867-5309</FreeFormNumber></PrimaryPhone><PrimaryEmailAddr><Address>helpme#thefly.con</Address></PrimaryEmailAddr></Customer>";
IConsumerRequest req = session.Request();
req = req.Post().WithRawContentType("application/xml").WithRawContent(System.Text.Encoding.ASCII.GetBytes(reqBody));
req.AcceptsType = "application/xml";
string response = req.Post().ForUrl("https://quickbooks.api.intuit.com/v3/company/" + realmID + "/customer").ToString()
OAuthConsumerContext consumerContext1 = new OAuthConsumerContext
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"].ToString(),
SignatureMethod = SignatureMethod.HmacSha1,
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"].ToString()
};
OAuthSession oSession1 = new OAuthSession(consumerContext1, "https://oauth.intuit.com/oauth/v1/get_request_token",
"https://workplace.intuit.com/Connect/Begin",
"https://oauth.intuit.com/oauth/v1/get_access_token");
oSession1.ConsumerContext.UseHeaderForOAuthParameters = true;

Windows Azure REST API Update Role Doesn't Take Effect

I'm doing some proof of concept work on azure, trying to get a role using the Get Role URL:
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments/<deployment-name>/roles/<role-name>
And then update the role using the Update Role URL:
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments/<deployment-name>/roleinstances/<role-name>
Both of those URLs are straight from the msdn pages. The GET request works and I get XML that matches what I see in the management console.
When I then add an element to the xml and send that back with a PUT on the update URL, I get a 200 response, but I never see the change in the management console. I also don't see any error message when I send gibberish. I'm connecting from C#, and a coworker suggested I could get the response with this:
var response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(response.ToString());
But that gets me a 404 error.
Is there an extra step to commit the update? And how can I see the response that msdn mentions?
2 suggestions:
When I am just doing quick SMAPI work I use AzureTools (http://blogs.msdn.com/b/kwill/archive/2013/08/26/azuretools-the-diagnostic-utility-used-by-the-windows-azure-developer-support-team.aspx). Specifically, look in the Misc Tools section under "Service Management REST API". This will show you the full response.
To answer your question about how to get the response (txtSMAPIResponse is where AzureTools puts the response info):
System.IO.Stream receiveStream;
System.IO.StreamReader readStream;
Encoding encode;
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
txtSMAPIRequest.Text = request.Headers.ToString();
txtSMAPIResponse.Text = ex.Message + Environment.NewLine + Environment.NewLine + ex.Response.Headers.ToString();
try
{
receiveStream = ex.Response.GetResponseStream();
encode = System.Text.Encoding.GetEncoding("utf-8");
// Pipes the stream to a higher level stream reader with the required encoding format.
readStream = new System.IO.StreamReader(receiveStream, encode);
txtSMAPIResponse.Text += readStream.ReadToEnd();
// Releases the resources of the response.
response.Close();
// Releases the resources of the Stream.
readStream.Close();
}
catch
{
}
return;
}
txtSMAPIRequest.Text = request.Method + " " + request.RequestUri + " " + request.ProtocolVersion + Environment.NewLine + Environment.NewLine;
txtSMAPIRequest.Text += request.Headers.ToString();
txtSMAPIResponse.Text = (int)response.StatusCode + " - " + response.StatusDescription + Environment.NewLine + Environment.NewLine;
txtSMAPIResponse.Text += response.Headers + Environment.NewLine + Environment.NewLine;
receiveStream = response.GetResponseStream();
encode = System.Text.Encoding.GetEncoding("utf-8");
// Pipes the stream to a higher level stream reader with the required encoding format.
readStream = new System.IO.StreamReader(receiveStream, encode);
txtSMAPIResponse.Text += readStream.ReadToEnd();
// Releases the resources of the response.
response.Close();
// Releases the resources of the Stream.
readStream.Close();
}
I've got the same problem. In my case EndPointACL is not getting updated. Very painful thing is for every update , we have to send the entire ConfigurationSet; There is no way to update the ACL for particular end point.
A typical update looks like this:
<?xml version="1.0"?>
<PersistentVMRole xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ConfigurationSets>
<ConfigurationSet>
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>100</LocalPort>
<Name>TCP-100</Name>
<Port>100</Port>
<Protocol>tcp</Protocol>
<EndpointACL>
<Rules>
<Rule>
<Order>1</Order>
<Action>deny</Action>
<RemoteSubnet>108.239.229.0/24</RemoteSubnet>
<Description>test-rule</Description>
</Rule>
</Rules>
</EndpointACL>
</InputEndpoint>
</InputEndpoints>
<SubnetNames>
<SubnetName>Subnet-1</SubnetName>
</SubnetNames>
</ConfigurationSet>
</ConfigurationSets>
</PersistentVMRole>

https://api.twitter.com/oauth/request_token Fails in Blackberry Native SDK

I am trying to connect to Twitter though oAuth.I am making a POST request to the API https://api.twitter.com/oauth/request_token.
Here is is example of my Base signature string
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%252Fapi.ec2.phunware.com%252Fapi%252Ftwitter%26oauth_consumer_key%3D6jq5dNZcccoPbApAJ0sOaA%26oauth_nonce%3DN2ZiMjViYzhlMDUxNDIyZWIwYjQ4NmU0ZjM1MDg4NTY%3D%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1362843354%26oauth_version%3D1.0
I used the tool http://quonos.nl/oauthTester/ to verify my base signature.
Here is the corresponding header
OAuth oauth_callback="http%3A%2F%2Fapi.ec2.phunware.com%2Fapi%2Ftwitter",oauth_consumer_key="6jq5dNZcccoPbApAJ0sOaA",oauth_nonce="N2ZiMjViYzhlMDUxNDIyZWIwYjQ4NmU0ZjM1MDg4NTY=",oauth_signature_method="HMAC-SHA1",oauth_signature="7ney2RxElbHUl2t1Jnz57pQpmFs%3D",oauth_timestamp="1362843354",oauth_version="1.0"
I tried the following command in my MAC terminal
curl --request 'POST' 'https://api.twitter.com/oauth/request_token' --header 'Authorization: OAuth oauth_callback="http%3A%2F%2Fapi.ec2.phunware.com%2Fapi%2Ftwitter",oauth_consumer_key="6jq5dNZcccoPbApAJ0sOaA",oauth_nonce="N2ZiMjViYzhlMDUxNDIyZWIwYjQ4NmU0ZjM1MDg4NTY=",oauth_signature_method="HMAC-SHA1",oauth_signature="7ney2RxElbHUl2t1Jnz57pQpmFs%3D",oauth_timestamp="1362843354",oauth_version="1.0"' --verbose
And i get 401 unauthorized error. I tried to set the oauth_callback ="oob" but I still get the same error.
Please help. I am using Blackberry Native SDK to code. I am pasting the code here. I get 204 error when I try via Blackberry 10.1 Simulator.
QByteArray Twitter::generateTimeStamp()
{
QDateTime current = QDateTime::currentDateTime();
uint seconds = current.toTime_t();
return QString::number(seconds,10).toUtf8();
}
QByteArray Twitter::generateNonce()
{
QString nonce = QUuid::createUuid().toString();
nonce.remove(QRegExp("[^a-zA-Z\\d\\s]"));
qDebug()<< nonce.toUtf8();
return nonce.toUtf8().toBase64();
}
QByteArray Twitter::generateSignatureBase(const QUrl& url, HttpMethod method, const QByteArray& timestamp, const QByteArray& nonce,bool addCallbackURL)
{
QList<QPair<QByteArray, QByteArray> > urlParameters = url.encodedQueryItems();
QList<QByteArray> normParameters;
QListIterator<QPair<QByteArray, QByteArray> > i(urlParameters);
while(i.hasNext()){
QPair<QByteArray, QByteArray> queryItem = i.next();
QByteArray normItem = queryItem.first + '=' + queryItem.second;
normParameters.append(normItem);
}
//consumer key
normParameters.append(QByteArray("oauth_consumer_key=") + consumer->consumerKey());
//token
if(accessToken != NULL){
normParameters.append(QByteArray("oauth_token=") + accessToken->oauthToken());
}
//signature method, only HMAC_SHA1
normParameters.append(QByteArray("oauth_signature_method=HMAC-SHA1"));
//time stamp
normParameters.append(QByteArray("oauth_timestamp=") + timestamp);
//nonce
normParameters.append(QByteArray("oauth_nonce=") + nonce);
//version
normParameters.append(QByteArray("oauth_version=1.0"));
//callback url
if(addCallbackURL)
normParameters.append(QByteArray("oauth_callback=") + QByteArray(CALLBACK_URL).toPercentEncoding());
//OAuth spec. 9.1.1.1
qSort(normParameters);
qDebug()<<normParameters;
QByteArray normString;
QListIterator<QByteArray> j(normParameters);
while (j.hasNext()) {
normString += j.next().toPercentEncoding();
normString += "%26";
}
normString.chop(3);
qDebug()<<normString;
//OAuth spec. 9.1.2
QString urlScheme = url.scheme();
QString urlPath = url.path();
QString urlHost = url.host();
QByteArray normUrl = urlScheme.toUtf8() + "://" + urlHost.toUtf8() + urlPath.toUtf8();
QByteArray httpm;
switch (method)
{
case GET:
httpm = "GET";
break;
case POST:
httpm = "POST";
break;
case DELETE:
httpm = "DELETE";
break;
case PUT:
httpm = "PUT";
break;
}
qDebug()<<"signature base="<<httpm + '&' + normUrl.toPercentEncoding() + '&' + normString;
//OAuth spec. 9.1.3
return httpm + '&' + normUrl.toPercentEncoding() + '&' + normString;
}
QByteArray Twitter::generateAuthorizationHeader( const QUrl& url, HttpMethod method,bool addCallbackURL )
{
QByteArray timeStamp = generateTimeStamp();
QByteArray nonce = generateNonce();
QByteArray baseString = generateSignatureBase(url, method, timeStamp, nonce,addCallbackURL);
QByteArray key = consumer->consumerSecret() + '&';
if(accessToken != NULL)
key = key + accessToken->oauthTokenSecret();
QByteArray signature = HMACSH1::hmacSha1(key,baseString).toPercentEncoding();
QByteArray header;
header += "OAuth ";
if(addCallbackURL)
header += "oauth_callback=\"" + QByteArray(CALLBACK_URL).toPercentEncoding() + "\",";
header += "oauth_consumer_key=\"" + consumer->consumerKey() + "\",";
header += "oauth_nonce=\"" + nonce + "\",";
header += "oauth_signature_method=\"HMAC-SHA1\",";
header += "oauth_signature=\"" + signature + "\",";
header += "oauth_timestamp=\"" + timeStamp + "\",";
if(accessToken != NULL)
header += "oauth_token=\"" + accessToken->oauthToken() + "\",";
header += "oauth_version=\"1.0\"";
qDebug()<<"header =" <<header;
return header;
}
void Twitter::requestForToken()
{
QUrl url(TWITTER_REQUEST_TOKEN_URL);
QByteArray oauthHeader = generateAuthorizationHeader(url, POST,true);
QNetworkRequest req(url);
req.setRawHeader("Authorization", oauthHeader);
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
req.setHeader(QNetworkRequest::ContentLengthHeader,"0");
QNetworkReply *reply = networkAccessManager->post(req, QByteArray());
connect(networkAccessManager, SIGNAL(finished ( QNetworkReply*)), this, SLOT(tokenFetchSuccessfull(QNetworkReply*)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(tokenFetchFailed(QNetworkReply::NetworkError)));
qDebug()<<"Request For Token";
}
You mentioned you are using the Native SDK, are you also using Cascades? If so, you may have better luck using the bb-cascades-oauth library from GitHub. It has built in support for OAuth1 and OAuth2.
Also, it seems that having incorrect timestamps can be a common problem, based on the tips found here, so make sure that your simulator has the correct date and time.
Another developer here found that the http://quonos.nl/oauthTester/ was requiring a double escaped header which was incorrect, and causing 401 errors when making an actual authentication request. I noticed you used the same tester, and also have the double escaping in your base signature string above, so you might want to try without the double escaping.

force.com callout exception Unable to tunnel through proxy

We make a callout from one Salesforce org to another Salesforce org using the REST API. That worked until end of november. We didn't make any changes at the affected classes or configuration.
Now, while sending a request to the rest api a callout exception will be thrown with the message : "Unable to tunnel through proxy. Proxy returns "HTTP/1.0 503 Service Unavailable".
The authorisation to the rest api is done by session id.
Does anyone have any idea what the problem is?
Here the code snipped:
final String WS_ENDPOINT = 'https://login.salesforce.com/services/Soap/c/24.0';
final String REST_ENDPOINT = 'https://eu2.salesforce.com/services/apexrest/UsageReporterService';
final String USERNAME = '*****';
final String PASSWORD = '*****';
HTTP h = new HTTP();
HTTPRequest req = new HTTPRequest();
req.setMethod('POST');
req.setEndpoint(REST_ENDPOINT);
req.setHeader('Content-Type', 'application/json');
req.setTimeout(60000);
HTTP hLogin = new HTTP();
HTTPRequest reqLogin = new HTTPRequest();
reqLogin.setMethod('POST');
reqLogin.setEndpoint(WS_ENDPOINT);
reqLogin.setHeader('Content-Type', 'text/xml');
reqLogin.setHeader('SOAPAction', 'login');
reqLogin.setTimeout(60000);
reqLogin.setCompressed(false);
// get a valid session id
String sessionId;
String loginSoap = '<?xml version="1.0" encoding="UTF-8"?>';
loginSoap += '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">';
loginSoap += '<soapenv:Body>';
loginSoap += '<urn:login>';
loginSoap += '<urn:username>' + USERNAME + '</urn:username>';
loginSoap += '<urn:password>' + PASSWORD + '</urn:password>';
loginSoap += '</urn:login>';
loginSoap += '</soapenv:Body>';
loginSoap += '</soapenv:Envelope>';
reqLogin.setBody(loginSoap);
HTTPResponse respLogin;
try {
respLogin = hLogin.send(reqLogin);
} catch(CalloutException c){
return null;
}
System.debug('++++++'+respLogin.getStatus() + ': ' + respLogin.getBody());
Dom.Document doc = new Dom.Document();
doc.load(respLogin.getBody());
Dom.XMLNode root = doc.getRootElement();
String ns = root.getNamespace();
Dom.XMLNode bodyEl = root.getChildElements()[0];
if(bodyEl.getChildElements()[0].getName().equals('loginResponse')){
sessionId = bodyEl.getChildElements()[0].getChildElement('result', ns).getChildElement('sessionId', ns).getText();
}
// finished getting session Id
if(sessionId != null){ // login was successfull
req.setHeader('Authorization', 'Bearer ' + sessionId);
// serialize data into json string
UsageReporterModel usageReporterData = new UsageReporterModel();
String inputStr = usageReporterData.serialize();
req.setBody('{ "usageReportData" : ' + inputStr + '}');
// fire!
HTTPResponse resp;
try {
resp = h.send(req);
} catch(CalloutException c){
return null;
}
}
I suspect this will relate to a change of IP addresses for one of the org's which haven't been whitelisted correctly (or added to the "network access" object). With it being Salesforce to Salesforce I would hope that Salesforce.com support can assist?