With the following SOAP query I'm trying to get all the entities in the solution but it doesn't return entity. Maybe a second eye could help. Do you see anything wrong that I can't see? Thank you !
JCL.RetrieveAllEntitiesRequest = function (fnCallBack) {
/// Returns a sorted array of entities
var request = "";
request += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
request += " <s:Body>";
request += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
request += " <request i:type=\"a:RetrieveAllEntitiesRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">";
request += " <a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>EntityFilters</b:key>";
request += " <b:value i:type=\"c:EntityFilters\" xmlns:c=\"http://schemas.microsoft.com/xrm/2011/Metadata\">Entity</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>RetrieveAsIfPublished</b:key>";
request += " <b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">true</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " </a:Parameters>";
request += " <a:RequestId i:nil=\"true\" />";
request += " <a:RequestName>RetrieveAllEntities</a:RequestName>";
request += " </request>";
request += " </Execute>";
request += " </s:Body>";
request += "</s:Envelope>";
return JCL._ExecuteRequest(request, "Execute", JCL._RetrieveAllEntitiesResponse, fnCallBack);
};
JCL._ExecuteRequest = function (sXml, sMessage, fInternalCallback, fUserCallback) {
'use strict';
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", JCL.server + "/XRMServices/2011/Organization.svc/web", (fUserCallback !== null));
xmlhttp.setRequestHeader("Accept", "application/xml, text/xml, */*");
xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlhttp.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/" + sMessage);
if (fUserCallback !== null) {
// asynchronous: register callback function, then send the request.
xmlhttp.onreadystatechange = function () {
fInternalCallback.call(this, xmlhttp, fUserCallback);
};
xmlhttp.send(sXml);
} else {
// synchronous: send request, then call the callback function directly
xmlhttp.send(sXml);
return fInternalCallback.call(this, xmlhttp, null);
}
};
Update after #Paul Way replied to me:
This is the error message I get when I select the entity that I need to investigate in CRM Data Detective. I can't add any field to this entity that's why I am using CRM Data Detective to find out which field I could delete, but it happens that the solution couldn't also handle an entity with a maximum number of attributes. Could you please have a look Paul? thank you So much !
Well, I'm embarrassed :)
I've updated the CRM Data Detective and JCL libraries to support CRM 2011 pre UR 12.
https://crmdatadetective.codeplex.com/
https://github.com/paul-way/JCL
The problem has to do with how the returned XML is parsed. Let me know if this fixes your problems...
The CRM 2011 SDK includes some good sample code to do this...
http://msdn.microsoft.com/en-us/library/gg594428.aspx
Related
have spent lot of hours trying to figure this out with Paypal Simulator, Sandbox but the result is same. My handler function(handleIpn) gets called and processed, with "Verified" "Complete" status but the IPN history as well as the simulator ends up in the HTTP 404 error. On IPN Simulator page the error is - "We're sorry, but there's an HTTP error. Please try again." My set up is Java-Spring MVC.
#RequestMapping(value = "/ipnHandler.html")
public void handleIpn (HttpServletRequest request) throws IpnException {
logger.info("inside ipn");
IpnInfo ipnInfo = new IpnInfo();
Enumeration reqParamNames = request.getParameterNames();
StringBuilder cmd1 = new StringBuilder();
String pName;
String pValue;
cmd1.append("cmd=_notify-validate");
while (reqParamNames.hasMoreElements()) {
pName = (String) reqParamNames.nextElement();
pValue = request.getParameter(pName);
try{
cmd1.append("&").append(pName).append("=").append(pValue);
}
catch(Exception e){
e.printStackTrace();
}
}
try
{
URL u = new URL("https://www.sandbox.paypal.com/cgi-bin/webscr");
HttpsURLConnection con = (HttpsURLConnection) u.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Host", "www.sandbox.paypal.com/cgi-bin/webscr");
con.setRequestProperty("Content-length", String.valueOf(cmd1.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(cmd1.toString());
output.flush();
output.close();
//4. Read response from Paypal
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String res = in.readLine();
in.close();
//5. Capture Paypal IPN information
ipnInfo.setLogTime(System.currentTimeMillis());
ipnInfo.setItemName(request.getParameter("item_name"));
ipnInfo.setItemNumber(request.getParameter("item_number"));
ipnInfo.setPaymentStatus(request.getParameter("payment_status"));
ipnInfo.setPaymentAmount(request.getParameter("mc_gross"));
ipnInfo.setPaymentCurrency(request.getParameter("mc_currency"));
ipnInfo.setTxnId(request.getParameter("txn_id"));
ipnInfo.setReceiverEmail(request.getParameter("receiver_email"));
ipnInfo.setPayerEmail(request.getParameter("payer_email"));
ipnInfo.setResponse(res);
// ipnInfo.setRequestParams(reqParamNames);
//6. Validate captured Paypal IPN Information
if (res.equals("VERIFIED")) {
//6.1. Check that paymentStatus=Completed
if(ipnInfo.getPaymentStatus() == null || !ipnInfo.getPaymentStatus().equalsIgnoreCase("COMPLETED"))
ipnInfo.setError("payment_status IS NOT COMPLETED {" + ipnInfo.getPaymentStatus() + "}");
//6.2. Check that txnId has not been previously processed
IpnInfo oldIpnInfo = this.getIpnInfoService().getIpnInfo(ipnInfo.getTxnId());
if(oldIpnInfo != null)
ipnInfo.setError("txn_id is already processed {old ipn_info " + oldIpnInfo);
//6.3. Check that receiverEmail matches with configured {#link IpnConfig#receiverEmail}
if(!ipnInfo.getReceiverEmail().equalsIgnoreCase(this.getIpnConfig().getReceiverEmail()))
ipnInfo.setError("receiver_email " + ipnInfo.getReceiverEmail()
+ " does not match with configured ipn email " + this.getIpnConfig().getReceiverEmail());
//6.4. Check that paymentAmount matches with configured {#link IpnConfig#paymentAmount}
if(Double.parseDouble(ipnInfo.getPaymentAmount()) != Double.parseDouble(this.getIpnConfig().getPaymentAmount()))
ipnInfo.setError("payment amount mc_gross " + ipnInfo.getPaymentAmount()
+ " does not match with configured ipn amount " + this.getIpnConfig().getPaymentAmount());
//6.5. Check that paymentCurrency matches with configured {#link IpnConfig#paymentCurrency}
if(!ipnInfo.getPaymentCurrency().equalsIgnoreCase(this.getIpnConfig().getPaymentCurrency()))
ipnInfo.setError("payment currency mc_currency " + ipnInfo.getPaymentCurrency()
+ " does not match with configured ipn currency " + this.getIpnConfig().getPaymentCurrency());
}
else
ipnInfo.setError("Inavlid response {" + res + "} expecting {VERIFIED}");
logger.info("ipnInfo = " + ipnInfo);
this.getIpnInfoService().log(ipnInfo);
//7. In case of any failed validation checks, throw {#link IpnException}
if(ipnInfo.getError() != null)
throw new IpnException(ipnInfo.getError());
}
catch(Exception e)
{
if(e instanceof IpnException)
throw (IpnException) e;
logger.log(Level.FATAL, e.toString(), e);
throw new IpnException(e.toString());
}
//8. If all is well, return {#link IpnInfo} to the caller for further business logic execution
paymentController.processSuccessfulPayment(ipnInfo);
}
Any help /pointers would greatly appreciate.
thanks.
Finally, got it working! Didn't realize that my issue of redirection in Spring MVC could have impact on Paypal - IPN status. May be my lack of good understanding of HTTP redirections! In above method instead of void return am now returning a jsp page, so "void" is changed to "String" with returning value the jsp file name.
Hope it does help someone!
I am really struggling to solve this. I have trawled the web and found some examples of how to set the state and status of an object, but none of them seem to work for me.
Does anyone have some example of how the soap envelope should look and what the properties of the Msxml2.XMLHTTP object should be for a synchronous call to the web service?
Thanks in advance,
Gray
EDIT
Ok ... so for an unexplained reason I got a downvote on this, and no answer, so I thought I would describe what I have currently got, and what I am getting.
This is the main function (pretty much lifted from one of the examples I found:
function setStateCodeForEntity(entityName, entityId, stateOptionsetValue, statusOptionsetValue) {
var request = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
request += "<s:Body>";
request += "<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
request += "<request i:type=\"b:SetStateRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
request += "<a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
request += "<a:KeyValuePairOfstringanyType>";
request += "<c:key>EntityMoniker</c:key>";
request += "<c:value i:type=\"a:EntityReference\">";
request += "<a:Id>" + entityId + "</a:Id>";
request += "<a:LogicalName>" + entityName + "</a:LogicalName>";
request += "<a:Name i:nil=\"true\" />";
request += "</c:value>";
request += "</a:KeyValuePairOfstringanyType>";
request += "<a:KeyValuePairOfstringanyType>";
request += "<c:key>State</c:key>";
request += "<c:value i:type=\"a:OptionSetValue\">";
request += "<a:Value>"+stateOptionsetValue+"</a:Value>";
request += "</c:value>";
request += "</a:KeyValuePairOfstringanyType>";
request += "<a:KeyValuePairOfstringanyType>";
request += "<c:key>Status</c:key>";
request += "<c:value i:type=\"a:OptionSetValue\">";
request += "<a:Value>"+statusOptionsetValue+"</a:Value>";
request += "</c:value>";
request += "</a:KeyValuePairOfstringanyType>";
request += "</a:Parameters>";
request += "<a:RequestId i:nil=\"true\" />";
request += "<a:RequestName>SetState</a:RequestName>";
request += "</request>";
request += "</Execute>";
request += "</s:Body>";
request += "</s:Envelope>";
var ret = executeSoapRequest("execute", request);
}
The executeSoapRequest function looks like this:
function executeSoapRequest(action, xml) {
var actionUrl = "http://schemas.microsoft.com/crm/2007/WebServices/" + action;
var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction", actionUrl);
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);
return xmlHttpRequest.responseXML;
}
and I have tried calling the method described at the top with the calls (note that newGuid is assigned somewhere else, and contains the Guid of a new email record that I wish to set the state/status for):
setStateCodeForEntity("email", newGuid, 1, 2);
and
setStateCodeForEntity("email", newGuid, "Completed", 2);
What I am getting is a Server 500 error, with the following response:
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"/>\r\n<title>500 - Internal server error.</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}\r\nfieldset{padding:0 15px 10px 15px;} \r\nh1{font-size:2.4em;margin:0;color:#FFF;}\r\nh2{font-size:1.7em;margin:0;color:#CC0000;} \r\nh3{font-size:1.2em;margin:10px 0 0 0;color:#000000;} \r\n#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:\"trebuchet MS\", Verdana, sans-serif;color:#FFF;\r\nbackground-color:#555555;}\r\n#content{margin:0 0 0 2%;position:relative;}\r\n.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"header\"><h1>Server Error</h1></div>\r\n<div id=\"content\">\r\n <div class=\"content-container\"><fieldset>\r\n <h2>500 - Internal server error.</h2>\r\n <h3>There is a problem with the resource you are looking for, and it cannot be displayed.</h3>\r\n </fieldset></div>\r\n</div>\r\n</body>\r\n</html>\r\n<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><soap:Fault><faultcode>Server</faultcode><faultstring>Object reference not set to an instance of an object.</faultstring><detail><error xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><displaytitle /><displaytext /><description>Object reference not set to an instance of an object.</description><file>Not available</file><line>Not available</line><details>Not available</details><requesturl>http://[SERVERNAME]/mscrmservices/2007/CrmService.asmx</requesturl><pathAndQuery>/mscrmservices/2007/CrmService.asmx</pathAndQuery><source>SOAP</source><stacktrace /></error></detail></soap:Fault></soap:Body></soap:Envelope>"
HOWEVER ...
I have just noticed that I get a very similar responseText when I use the executeSoapRequest method that does succeed. When I make the call as described above the status of the email entity is not changed.
I am almost certainly doing something silly, but I have no idea what. Any constructive help would be a life saver at this time.
Gray
Ok ... for completeness, here is the answer:
The main function looks like this:
function setStateCodeForEntity(entityName, entityId, stateOptionsetValue, statusOptionsetValue) {
var request = [
"<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>",
GenerateAuthenticationHeader(),
"<soap:Body>",
"<Execute xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>",
"<Request xsi:type='SetStateDynamicEntityRequest'>",
"<Entity>",
"<Name xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entityName, "</Name>",
"<Id xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entityId, "</Id>",
"</Entity>",
"<State>", stateOptionsetValue, "</State>",
"<Status>", statusOptionsetValue, "</Status>",
"</Request>",
"</Execute>",
"</soap:Body>",
"</soap:Envelope>"
].join("");
var ret = executeSoapRequest("Execute", request);
}
Notice the Request type is 'SetStateDynamicEntityRequest', which seemed to be the main problem with my original attempt, but also this version is far more simple that I was originally using.
The method is called by
setStateCodeForEntity("email", newGuid, 'Completed', 2);
I was given the answer by a colleague who recommended the Crm Service Toolkit (http://crmtoolkit.codeplex.com/) and the code was pretty much lifted from there. Further information at http://danielcai.blogspot.co.uk/2010/07/crm-web-service-toolkit-for-javascript.html
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>
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.
I am trying to integrate the facebook chat into our mobile Flash/AIR application, and am using XIFF for the XMPP stuff. Of course, I had to modify some files for the newer Facebook API that uses access_token instead of sig and secret.
For those familiar with the xiff/smack API, here is how I establish the connection:
XFacebookPlatform.setFacebookSessionValues(AppData.FACEBOOK_APP_ID, AppData.getInstance().getFBSession().accessToken);
XMPPConnection.registerSASLMechanism("X-FACEBOOK-PLATFORM", XFacebookPlatform);
var con :XMPPConnection = new XMPPConnection();
con.server = "chat.facebook.com";
con.useAnonymousLogin = true;
con.connect(XMPPConnection.STREAM_TYPE_STANDARD);
.
Basically, I get to the point where I answer the challenge with what IMO should be a correct format:
var responseMap:Dictionary = new Dictionary();
responseMap.api_key = fb_api_key;
responseMap.call_id = 0;
responseMap.method = incomingChallengeMap.method;
responseMap.nonce = incomingChallengeMap.nonce;
responseMap.access_token = user_access_token;
responseMap.v = "1.0";
var challengeResponse:String = "api_key=" + responseMap.api_key;
challengeResponse += "&call_id=" + responseMap.call_id;
challengeResponse += "&method=" + responseMap.method;
challengeResponse += "&nonce=" + responseMap.nonce;
challengeResponse += "&access_token=" + responseMap.access_token;
challengeResponse += "&v=" + responseMap.v;
challengeResponse = Base64.encode( challengeResponse );
.
The response is sent, but as an answer I receive the following:
<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
This sounds like I did not grant the "xmpp_login", but I did. I checked that via the Graph API explorer, and for the same access_token it shows:
{
"data": [
{
"installed": 1,
"xmpp_login": 1,
"user_online_presence": 1,
"friends_online_presence": 1
}
]
}
This should be more than enough, I guess.
But still I get the "not-authorized" failure.
Any ideas what went wrong here?
Funny enough, the problem was this line:
var con :XMPPConnection = new XMPPConnection();
Which has to be replaced with this line:
var con :XMPPTLSConnection = new XMPPTLSConnection();
That's it. The facebook chat only authenticates with a TLS connection.
.
While that does make sense, the error message of
<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
is very misleading here, as it implies that something with the rights would be wrong.