I am new to the HTTP request in java. I have been trying to send an HTTP Post request to my NODE.JS server with the parameter key:12345. However, it doesn't send anything to my server. I tried tested my NOEDJS server to see if it worked in POSTMAN, and it did. So I am sure that this is something with the java that I made. I think a look at my code would help. Here it is down below.
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class ConnectionFactory {
private double API_VERSION = 0;
private String API = "";
private String METHOD = "POST";
private String USER_AGENT = "Mozilla/5.0";
private String TYPE = "application/x-www-form-urlencoded";
private String data = "";
private URL connection;
private HttpURLConnection finalConnection;
private HashMap<String, String> fields = new HashMap<String, String>();
public ConnectionFactory(String[] endpoint, String url, double version) {
this.API_VERSION = version;
this.API = url;
fields.put("version", String.valueOf(version));
for (int i = 0; i < endpoint.length; i++) {
String[] points = endpoint[i].split(";");
for (int f = 0; f < points.length; f++) {
fields.put(points[f].split(":")[0], points[f].split(":")[1]);
}
}
}
public String buildConnection() {
StringBuilder content = new StringBuilder();
if (!this.getEndpoints().equalsIgnoreCase("") && !this.getEndpoints().isEmpty()) {
String vars = "";
String vals = "";
try {
for (Map.Entry<String, String> entry: fields.entrySet()) {
vars = entry.getKey();
vals = entry.getValue();
data += ("&" + vars + "=" + vals);
}
if (data.startsWith("&")) {
data = data.replaceFirst("&", "");
}
connection = new URL(API);
BufferedReader reader = new BufferedReader(new InputStreamReader(readWithAccess(connection, data)));
String line;
while ((line = reader.readLine()) != null) {
content.append(line + "\n");
}
reader.close();
return content.toString();
} catch (Exception e) {
System.err.println(e.getMessage());
}
} else {
return null;
}
return null;
}
private InputStream readWithAccess(URL url, String data) {
try {
byte[] out = data.toString().getBytes();
finalConnection = (HttpURLConnection) url.openConnection();
finalConnection.setRequestMethod(METHOD);
finalConnection.setDoOutput(true);
finalConnection.addRequestProperty("User-Agent", USER_AGENT);
finalConnection.addRequestProperty("Content-Type", TYPE);
finalConnection.connect();
try {
OutputStream os = finalConnection.getOutputStream();
os.write(out);
} catch (Exception e) {
System.err.println(e.getMessage());
}
return finalConnection.getInputStream();
} catch (Exception e) {
System.err.println(e.getMessage());
return null;
}
}
public String getApiVersion() {
return String.valueOf(API_VERSION);
}
public String getEndpoints() {
return fields.toString();
}
public String getEndpointValue(String key) {
return fields.get(key);
}
public void setUserAgent(String userAgent) {
this.USER_AGENT = userAgent;
}
public void setMethod(String method) {
this.METHOD = method;
}
public void setSubmissionType(String type) {
this.TYPE = type;
}
}
public class example {
public static void main(String[] args) {
double version = 0.1;
String url = "http://localhost:3000";
String[] fields = {
"key:12345"
};
ConnectionFactory connection = new ConnectionFactory(fields, url, version);
connection.setUserAgent("Mozilla/5.0");
String response = connection.buildConnection();
System.out.println(response);
}
}
Here is the code for my node.js server
var http = require('http');
var url = require('url');
var queryString = require('querystring')
var StringDecoder = require('string_decoder').StringDecoder;
var server = http.createServer(function(req, res) {
//parse the URL
var parsedURL = url.parse(req.url, true);
//get the path
var path = parsedURL.pathname;
var trimmedPath = path.replace(/^\/+|\/+$/g, '');
//queryString
var queryStringObject = parsedURL.query;
console.log(queryStringObject);
if (queryStringObject.key == 12345) {
console.log("true")
res.end("true")
} else {
console.log("failed")
res.end("false")
}
// var query = queryStringObject.split()
});
server.listen(3000, function() {
console.log("Listening on port 3000");
});
The is no problem with your java client
The problem is that you are sending the content of your POST request as ""application/x-www-form-urlencoded" and then in your nodeJS server you are reading it as a query string
Here is a correct example using ExpressJS :
const express = require('express')
const app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
app.post('/test', function(req, res) {
var key = req.body.key;
if (key==12345)
res.send(true );
else
res.send(false);
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
I have a java project in Eclipse which was written by some other developer. I am very new to Java and have made some modifications in the source code. Now i want to test the code by executing it in eclipse. How can I create a main class and execute the modified code.
Following is the class file which I want to run
public class Bio_Verify extends AbstractOutboundServiceProvider
{
public static String EndPointURL = null;
public static String ApiKey = null;
public static String Version = null;
public static String EntityId = null;
public static String requestId = null;
public static String EncryptionKey = null;
public static String SignatureKey = null;
public static String SignAlgorithm = null;
public String requestData = null;
public String requestXML = null;
public String response = null;;
public String errorMsg;
public void preprocess(IUsbMessage inputMsg)
{
LogManager.logDebug("Bio_Verify: preprocess():: inside preprocess");
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: START");
}
public IUsbMessage executeOutboundRequest(String inputMsg)
{
int i = 0;
int j = 0;
String resolution = null;
String key = null;
String criteria = null;
String position = null;
String format = null;
String data = null;
String intent = null;
String resBodyXML = null;
String outputXMLMsg = null;
String[] responseMsg = new String[2];
IUsbMessage outMsg = null;
Verify verify = new Verify();
Fingerprint fingerprint = new Fingerprint();
requestData = "CN01473|cif|UNKNOWN_FINGER|508|BMP|Qk12WeoAAAA=|verify";
//Forming requestId for Bio
Date date = Calendar.getInstance().getTime();
DateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
requestId = dateFormat.format(date);
EndPointURL = OutboundConstants.Bio_Endpoint;
ApiKey = OutboundConstants.ApiKey;
Version = OutboundConstants.Version;
EntityId = OutboundConstants.EntityId;
EncryptionKey = OutboundConstants.EncryptionKey;
SignAlgorithm = OutboundConstants.SignAlgorithm;
SignatureKey = OutboundConstants.SignatureKey;
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: Bio_Endpoint URL is " + EndPointURL);
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: Api Key is " + ApiKey);
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: Version is " + Version);
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: EntityId is " + EntityId);
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: EncryptionKey is " + EncryptionKey);
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: SignatureKey is " + SignatureKey);
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: SignAlgorithm is " + SignAlgorithm);
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: Request Id is " + requestId);
//Extraction data from the request XML
for(i=0;i<7;i++){
int x = requestData.indexOf("|");
int y = requestData.length();
if(i==0){
key = requestData.substring(0, x);
LogManager.logDebug("Key: "+key);
requestData = requestData.substring(x+1,y);
}
if(i==1){
criteria = requestData.substring(0, x);
LogManager.logDebug("Criteria: "+criteria);
requestData = requestData.substring(x+1,y);
}
if(i==2){
position = requestData.substring(0, x);
LogManager.logDebug("Position: "+position);
requestData = requestData.substring(x+1,y);
}
if(i==3){
format = requestData.substring(0, x);
LogManager.logDebug("Format: "+format);
requestData = requestData.substring(x+1,y);
}
if(i==4){
resolution = requestData.substring(0, x);
LogManager.logDebug("Resolution: "+resolution);
requestData = requestData.substring(x+1,y);
}
if(i==5){
data = requestData.substring(0, x);
requestData = requestData.substring(x+1,y);
}
if(i==6){
intent = requestData;
LogManager.logDebug("Intent: "+intent);
}
}
FingerprintImage fingerprintimage = new FingerprintImage(format,resolution,data);
fingerprint.image = fingerprintimage;
fingerprint.position = position;
responseMsg = verify.verify(key, criteria, fingerprint, intent);
this.errorMsg = responseMsg[0];
this.response = responseMsg[1];
LogManager.logDebug("Back in bio verify - array element1"+this.errorMsg);
LogManager.logDebug("Back in bio verify - array element2"+this.response);
outMsg = UsbMessageFactory.createUbusMessage();
outMsg.setMsgType("XML");
outMsg.setMsgSubType("FIXML");
LogManager.logDebug("Bio: executeOutboundRequest():: errorMsg=" + errorMsg);
if (errorMsg.toString().trim().length() > 0)
{
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: Inside FAILURE");
outMsg.setBackEndTranStatus("FAILURE");
outMsg.setErrMsgFlg(1);
outMsg.setPayload(new Object[] { new CIFatalException(errorMsg.toString()) });
}
else
{
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: Inside SUCCESS");
outMsg.setBackEndTranStatus("SUCCESS");
outMsg.setErrMsgFlg(0);
resBodyXML = this.response.toString();
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: outputXMLMsg XML:" + outputXMLMsg);
outMsg.setPayload(new Object[] { outputXMLMsg });
}
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: outMsg:" + outMsg);
LogManager.logDebug("Bio_Verify: executeOutboundRequest():: END");
return outMsg;
}
Can you follow the steps , this will help to you
There are 6 steps are below added ( I think you will get idea how to archive your problem )
1.Right click inside package and you can see CLASS then it will pop up this attached window
2. Insight Main method you can crate some object like I have created and pass parameter what you want (You just understand what method you have to call )
You have to write main function into Bio_Verify class.
main function is boot function.
So if you write main function, you can execute this class.
ex)
public class BioVerify extends AbstractOutboundServiceProvider {
public static void main(String[] args) {
// TODO: Write a code....
}
}
write the main function below to the code and create object for BIO_verify class and it's function
I'm working with the Bitfinex API and the version of the API is 1.
But I have a problem that can not be solved.
When I use '/v1/order/new', the server sends to the message "Key symbol was not present."
I can not find which point is the problem.
The parameter settings are as belows.
Please advise.
========== ========== ========== ==========
/**
Create Header, Param
*/
JSONObject json = new JSONObject();
json.put("request", targetURL);
json.put("nonce", Long.toString(getNonce()));
String payload = json.toString();
String payload_base64 = Base64.getEncoder().encodeToString(payload.getBytes());
String payload_sha384hmac = hmacDigest(payload_base64, apiKeySecret, ALGORITHM_HMACSHA384);
HttpTask http = new HttpTask(URL, Method.POST);
http.addHeader("X-BFX-APIKEY", apiKey);
http.addHeader("X-BFX-PAYLOAD", payload_base64);
http.addHeader("X-BFX-SIGNATURE", payload_sha384hmac);
http.setContentType("x-www-urlencoded");
http.setAcceptType("application/xml");
http.addParam("symbol", "btcusd");
http.addParam("amount", "0.01");
http.addParam("price", "0.01");
http.addParam("side", "buy");
http.addParam("type", "exchange market");
http.addParam("is_hidden", "false");
http.addParam("is_postonly", "true");
http.addParam("use_all_available", "0");
http.addParam("exchange", "bitfinex");
http.addParam("ocoorder", "false");
http.addParam("buy_price_oco", "0");
/**
Parsing Param
*/
StringBuilder sb = new StringBuilder();
Set<String> key = m_params.keySet();
int totalCount = key.size();
if (totalCount > 0) {
int index = 0;
for (Iterator<String> iterator = key.iterator(); iterator.hasNext();) {
String keyValue = (String) iterator.next();
String valueValue = (String) m_params.get(keyValue);
sb.append(String.format("%s=%s", keyValue, valueValue));
if (index < totalCount - 1) {
sb.append("&");
}
index++;
}
query = sb.toString();
}
/**
send Param
*/
if (!query.isEmpty()) {
DataOutputStream wr;
try {
wr = new DataOutputStream(m_connection.getOutputStream());
wr.writeBytes(query);
wr.flush();
wr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
You need to put all params in payload object.
Here is my example on JAVASCRIPT:
auth_v1_request(path, params){
return new Promise((resolve, reject) => {
// console.log(this.account);
const apiKey = this.account.api_key;
const apiSecret = this.account.api_secret;
const apiPath = '/' + path;
const nonce = (Date.now() * 1000).toString();
const completeURL = `${ CONFIG.BITFINEX.API_URL }${apiPath}`;
params.nonce = nonce;
params.request = apiPath;
const payload = new Buffer(JSON.stringify(params))
.toString('base64');
const signature = crypto
.createHmac('sha384', apiSecret)
.update(payload)
.digest('hex');
const options = {
url: completeURL,
headers: {
'X-BFX-APIKEY': apiKey,
'X-BFX-PAYLOAD': payload,
'X-BFX-SIGNATURE': signature
},
body: JSON.stringify(params),
json: true
};
request.post(options, (error, response, res_body) => {
console.log(error);
console.log(res_body);
if(error) {
reject(error);
}
else {
let parsed;
try {
parsed = res_body;
if(parsed.message){
reject(parsed);
}
else {
resolve(parsed);
}
}
catch(err) {
reject(err);
}
}
})
});
}
I want to get google contacts in my Blackberry Application. Is there any public libraries availabile for blackberry to do this?
I try to use Oauth-SignPost. But the libraies used in it not supported by blackberry.Then I try the following code
public static String requestToken(){
String url = C.REQUEST_URL;
String header = oauth_header(url, HttpProtocolConstants.HTTP_METHOD_GET);
String requestTokenUrl = concatURL(url, header);
HttpConnection httpConn = null;
InputStream input = null;
try{
HttpConnectionFactory factory = new HttpConnectionFactory( requestTokenUrl,
HttpConnectionFactory.TRANSPORT_WIFI |
HttpConnectionFactory.TRANSPORT_WAP2 |
HttpConnectionFactory.TRANSPORT_BIS |
HttpConnectionFactory.TRANSPORT_BES |
HttpConnectionFactory.TRANSPORT_DIRECT_TCP);
httpConn = factory.getNextConnection();
httpConn.setRequestMethod(HttpProtocolConstants.HTTP_METHOD_GET);
httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
input = httpConn.openDataInputStream();
int resp = httpConn.getResponseCode();
if (resp == HttpConnection.HTTP_OK) {
StringBuffer buffer = new StringBuffer();
int ch;
while ( (ch = input.read()) != -1){
buffer.append( (char) ch);
}
String content = buffer.toString();
System.out.println("Response"+content);
}
return "";
} catch (IOException e) {
return "exception";
} catch (NoMoreTransportsException nc) {
return "noConnection";
} finally {
try {
httpConn.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The oauth_header() which create the appending parameters
public static String oauth_header(String url, String method) {
String nonce = nonce();
long timestamp = timestamp();
Hashtable pairs = new Hashtable();
pairs.put(C.OAUTH_CONSUMER_KEY, C.CONSUMER_KEY);
pairs.put(C.OAUTH_NONCE, nonce);
pairs.put(C.OAUTH_SIGNATURE_METHOD, C.SIGNATURE_METHOD);
pairs.put(C.OAUTH_TIMESTAMP, Long.toString(timestamp));
pairs.put(C.OAUTH_SCOPE,C.SCOPE);
pairs.put(C.OAUTH_VERSION, "1.0");
String sig = signature(method, url, pairs);
StringBuffer header_sb = new StringBuffer();
header_sb.append(C.OAUTH_CONSUMER_KEY).append("=").append(C.CONSUMER_KEY).append(",");
header_sb.append(C.OAUTH_NONCE).append("=").append(nonce).append(",");
header_sb.append(C.OAUTH_SIGNATURE).append("=").append(URLUTF8Encoder.encode(sig)).append(",");
header_sb.append(C.OAUTH_SIGNATURE_METHOD).append("=").append(C.SIGNATURE_METHOD).append(",");
header_sb.append(C.OAUTH_TIMESTAMP).append("=").append(Long.toString(timestamp)).append(",");
header_sb.append(C.OAUTH_SCOPE).append("=").append(C.SCOPE);
header_sb.append(C.OAUTH_VERSION).append("=").append("1.0");
return header_sb.toString();
}
Signature() and concatUrl() here
private static String signature(String method, String requestURL, Hashtable pairs) {
StringBuffer sb = new StringBuffer();
String[] keys = new String[pairs.size()];
Enumeration e = pairs.keys();
int i = 0;
while(e.hasMoreElements()) {
String k = (String)e.nextElement();
keys[i++] = k + "=" + URLUTF8Encoder.encode((String)pairs.get(k));
}
Arrays.sort(keys, new Comparator() {
public int compare(Object arg0, Object arg1) {
return ((String)arg0).compareTo((String)arg1);
}
});
for(i = 0; i < keys.length; i++) {
sb.append(keys[i]).append('&');
}
sb.deleteCharAt(sb.length()-1);
String msg = method.toUpperCase() +"&" + URLUTF8Encoder.encode(requestURL) + "&" + URLUTF8Encoder.encode(sb.toString());
System.out.println(msg);
StringBuffer key = new StringBuffer();
if(C.CONSUMER_SECRET != null) key.append(URLUTF8Encoder.encode(C.CONSUMER_SECRET));
key.append('&');
/* if(Const.tokenSecret != null){
key.append(URLUTF8Encoder.encode(Const.tokenSecret));
}*/
try {
return hmacsha1(key.toString(), msg);
} catch (Exception ex) {
return null;
}
}
private static String hmacsha1(String key, String message)
throws CryptoTokenException, CryptoUnsupportedOperationException, IOException {
HMACKey k = new HMACKey(key.getBytes());
HMAC hmac = new HMAC(k, new SHA1Digest());
hmac.update(message.getBytes());
byte[] mac = hmac.getMAC();
return Base64OutputStream.encodeAsString(mac, 0, mac.length, false, false);
}
public static String concatURL(String url, String header){
String newurl=url;
header = header.replace(',', '&');
newurl = newurl+"?"+header;
return newurl;
}
Then I get the signature_invalid Message. please Help me to find out the error.
I'm trying to make a Facebook Chat on Android with the Smack library. I've read the Chat API from Facebook, but I cannot understand how I have to authenticate with Facebook using this library.
Can anyone point me how to accomplish this?
Update: According to the no.good.at.coding answer, I have this code adapted to the Asmack library. All works fine except I receive as response to the login: not-authorized. Here is the code I use:
public class SASLXFacebookPlatformMechanism extends SASLMechanism
{
private static final String NAME = "X-FACEBOOK-PLATFORM";
private String apiKey = "";
private String applicationSecret = "";
private String sessionKey = "";
/**
* Constructor.
*/
public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication)
{
super(saslAuthentication);
}
#Override
protected void authenticate() throws IOException, XMPPException
{
getSASLAuthentication().send(new AuthMechanism(NAME, ""));
}
#Override
public void authenticate(String apiKeyAndSessionKey, String host,
String applicationSecret) throws IOException, XMPPException
{
if (apiKeyAndSessionKey == null || applicationSecret == null)
{
throw new IllegalArgumentException("Invalid parameters");
}
String[] keyArray = apiKeyAndSessionKey.split("\\|", 2);
if (keyArray.length < 2)
{
throw new IllegalArgumentException(
"API key or session key is not present");
}
this.apiKey = keyArray[0];
Log.d("API_KEY", apiKey);
this.applicationSecret = applicationSecret;
Log.d("SECRET_KEY", applicationSecret);
this.sessionKey = keyArray[1];
Log.d("SESSION_KEY", sessionKey);
this.authenticationId = sessionKey;
this.password = applicationSecret;
this.hostname = host;
String[] mechanisms = { "DIGEST-MD5" };
Map<String, String> props = new HashMap<String, String>();
this.sc =
Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,
this);
authenticate();
}
#Override
protected String getName()
{
return NAME;
}
#Override
public void challengeReceived(String challenge) throws IOException
{
byte[] response = null;
if (challenge != null)
{
String decodedChallenge = new String(Base64.decode(challenge));
Log.d("DECODED", decodedChallenge);
Map<String, String> parameters = getQueryMap(decodedChallenge);
String version = "1.0";
String nonce = parameters.get("nonce");
String method = parameters.get("method");
long callId = new GregorianCalendar().getTimeInMillis() / 1000L;
String sig =
"api_key=" + apiKey + "call_id=" + callId + "method="
+ method + "nonce=" + nonce + "session_key="
+ sessionKey + "v=" + version + applicationSecret;
try
{
sig = md5(sig);
sig = sig.toUpperCase();
} catch (NoSuchAlgorithmException e)
{
throw new IllegalStateException(e);
}
String composedResponse =
"api_key=" + URLEncoder.encode(apiKey, "utf-8")
+ "&call_id=" + callId + "&method="
+ URLEncoder.encode(method, "utf-8") + "&nonce="
+ URLEncoder.encode(nonce, "utf-8")
+ "&session_key="
+ URLEncoder.encode(sessionKey, "utf-8") + "&v="
+ URLEncoder.encode(version, "utf-8") + "&sig="
+ URLEncoder.encode(sig, "utf-8");
Log.d("COMPOSED", composedResponse);
response = composedResponse.getBytes("utf-8");
}
String authenticationText = "";
if (response != null)
{
authenticationText =
Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
}
// Send the authentication to the server
getSASLAuthentication().send(new Response(authenticationText));
}
private Map<String, String> getQueryMap(String query)
{
Map<String, String> map = new HashMap<String, String>();
String[] params = query.split("\\&");
for (String param : params)
{
String[] fields = param.split("=", 2);
map.put(fields[0], (fields.length > 1 ? fields[1] : null));
}
return map;
}
private String md5(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(text.getBytes("utf-8"), 0, text.length());
return convertToHex(md.digest());
}
private String convertToHex(byte[] data)
{
StringBuilder buf = new StringBuilder();
int len = data.length;
for (int i = 0; i < len; i++)
{
int halfByte = (data[i] >>> 4) & 0xF;
int twoHalfs = 0;
do
{
if (0 <= halfByte && halfByte <= 9)
{
buf.append((char) ('0' + halfByte));
}
else
{
buf.append((char) ('a' + halfByte - 10));
}
halfByte = data[i] & 0xF;
} while (twoHalfs++ < 1);
}
return buf.toString();
}
}
And this, is the communication with the server with the sent and received messages:
PM SENT (1132418216): <stream:stream to="chat.facebook.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">
PM RCV (1132418216): <?xml version="1.0"?><stream:stream id="C62D0F43" from="chat.facebook.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xml:lang="en"><stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>X-FACEBOOK-PLATFORM</mechanism><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features>
PM SENT (1132418216): <auth mechanism="X-FACEBOOK-PLATFORM" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></auth>
PM RCV (1132418216): <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">dmVyc2lvbj0xJm1ldGhvZD1hdXRoLnhtcHBfbG9naW4mbm9uY2U9NzFGNkQ3Rjc5QkIyREJCQ0YxQTkwMzA0QTg3OTlBMzM=</challenge>
PM SENT (1132418216): <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">YXBpX2tleT0zMWYzYjg1ZjBjODYwNjQ3NThiZTZhOTQyNjVjZmNjMCZjYWxsX2lkPTEzMDA0NTYxMzUmbWV0aG9kPWF1dGgueG1wcF9sb2dpbiZub25jZT03MUY2RDdGNzlCQjJEQkJDRjFBOTAzMDRBODc5OUEzMyZzZXNzaW9uX2tleT0yNjUzMTg4ODNkYWJhOGRlOTRiYTk4ZDYtMTAwMDAwNTAyNjc2Nzc4JnY9MS4wJnNpZz04RkRDRjRGRTgzMENGOEQ3QjgwNjdERUQyOEE2RERFQw==</response>
PM RCV (1132418216): <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
As read in the developers Facebook forum, it is needed to disable the "Disable Deprecated Auth Methods" setting from the Facebook settings page of your app. But, even doing that, I can't login. And the session key is the second part of the OAuth token in the form AAA|BBB|CCC, I mean, BBB.
Finally, thanks to the no.good.at.coding code and the suggestion of harism, I've been able to connect to the Facebook chat. This code is the Mechanism for the Asmack library (the Smack port for Android). For the Smack library is necessary to use the no.good.at.coding mechanism.
SASLXFacebookPlatformMechanism.java:
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
import org.apache.harmony.javax.security.sasl.Sasl;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.Base64;
public class SASLXFacebookPlatformMechanism extends SASLMechanism
{
private static final String NAME = "X-FACEBOOK-PLATFORM";
private String apiKey = "";
private String applicationSecret = "";
private String sessionKey = "";
/**
* Constructor.
*/
public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication)
{
super(saslAuthentication);
}
#Override
protected void authenticate() throws IOException, XMPPException
{
getSASLAuthentication().send(new AuthMechanism(NAME, ""));
}
#Override
public void authenticate(String apiKeyAndSessionKey, String host,
String applicationSecret) throws IOException, XMPPException
{
if (apiKeyAndSessionKey == null || applicationSecret == null)
{
throw new IllegalArgumentException("Invalid parameters");
}
String[] keyArray = apiKeyAndSessionKey.split("\\|", 2);
if (keyArray.length < 2)
{
throw new IllegalArgumentException(
"API key or session key is not present");
}
this.apiKey = keyArray[0];
this.applicationSecret = applicationSecret;
this.sessionKey = keyArray[1];
this.authenticationId = sessionKey;
this.password = applicationSecret;
this.hostname = host;
String[] mechanisms = { "DIGEST-MD5" };
Map<String, String> props = new HashMap<String, String>();
this.sc =
Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,
this);
authenticate();
}
#Override
public void authenticate(String username, String host, CallbackHandler cbh)
throws IOException, XMPPException
{
String[] mechanisms = { "DIGEST-MD5" };
Map<String, String> props = new HashMap<String, String>();
this.sc =
Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,
cbh);
authenticate();
}
#Override
protected String getName()
{
return NAME;
}
#Override
public void challengeReceived(String challenge) throws IOException
{
byte[] response = null;
if (challenge != null)
{
String decodedChallenge = new String(Base64.decode(challenge));
Map<String, String> parameters = getQueryMap(decodedChallenge);
String version = "1.0";
String nonce = parameters.get("nonce");
String method = parameters.get("method");
long callId = new GregorianCalendar().getTimeInMillis();
String sig =
"api_key=" + apiKey + "call_id=" + callId + "method="
+ method + "nonce=" + nonce + "session_key="
+ sessionKey + "v=" + version + applicationSecret;
try
{
sig = md5(sig);
} catch (NoSuchAlgorithmException e)
{
throw new IllegalStateException(e);
}
String composedResponse =
"api_key=" + URLEncoder.encode(apiKey, "utf-8")
+ "&call_id=" + callId + "&method="
+ URLEncoder.encode(method, "utf-8") + "&nonce="
+ URLEncoder.encode(nonce, "utf-8")
+ "&session_key="
+ URLEncoder.encode(sessionKey, "utf-8") + "&v="
+ URLEncoder.encode(version, "utf-8") + "&sig="
+ URLEncoder.encode(sig, "utf-8");
response = composedResponse.getBytes("utf-8");
}
String authenticationText = "";
if (response != null)
{
authenticationText =
Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
}
// Send the authentication to the server
getSASLAuthentication().send(new Response(authenticationText));
}
private Map<String, String> getQueryMap(String query)
{
Map<String, String> map = new HashMap<String, String>();
String[] params = query.split("\\&");
for (String param : params)
{
String[] fields = param.split("=", 2);
map.put(fields[0], (fields.length > 1 ? fields[1] : null));
}
return map;
}
private String md5(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(text.getBytes("utf-8"), 0, text.length());
return convertToHex(md.digest());
}
private String convertToHex(byte[] data)
{
StringBuilder buf = new StringBuilder();
int len = data.length;
for (int i = 0; i < len; i++)
{
int halfByte = (data[i] >>> 4) & 0xF;
int twoHalfs = 0;
do
{
if (0 <= halfByte && halfByte <= 9)
{
buf.append((char) ('0' + halfByte));
}
else
{
buf.append((char) ('a' + halfByte - 10));
}
halfByte = data[i] & 0xF;
} while (twoHalfs++ < 1);
}
return buf.toString();
}
}
To use it:
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
config.setSASLAuthenticationEnabled(true);
XMPPConnection xmpp = new XMPPConnection(config);
try
{
SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM", SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
xmpp.connect();
xmpp.login(apiKey + "|" + sessionKey, sessionSecret, "Application");
} catch (XMPPException e)
{
xmpp.disconnect();
e.printStackTrace();
}
apiKey is the API key given in the application settings page in Facebook. sessionKey is the second part of the access token. If the token is in this form, AAA|BBB|CCC, the BBB is the session key. sessionSecret is obtained using the old REST API with the method auth.promoteSession. To use it, it's needed to make a Http get to this url:
https://api.facebook.com/method/auth.promoteSession?access_token=yourAccessToken
Despite of the Facebook Chat documentation says that it's needed to use your application secret key, only when I used the key that returned that REST method I was able to make it works. To make that method works, you have to disable the Disable Deprecated Auth Methods option in the Advance tab in your application settings.
I'd used this about 6 months ago with Smack (not asmack) so I'm not sure how it'll hold up now but here goes, hope it helps!
I found an implementation of Facebook's X-FACEBOOK-PLATFORM authentication mechanism on the Ignite Realtime Smack forum where someone got it from the fbgc project. You'll find the a ZIP with the SASLXFacebookPlatformMechanism.java source in the answer I linked to. You can use it as follows:
public void login() throws XMPPException
{
SASLAuthentication.registerSASLMechanism(SASLXFacebookPlatformMechanism.NAME,
SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism(SASLXFacebookPlatformMechanism.NAME, 0);
ConnectionConfiguration connConfig = new ConnectionConfiguration(host, port);
XMPPConnection connection = new XMPPConnection(connConfig);
connection.connect();
log.info("XMPP client connected");
connection.login(Utils.FB_APP_ID + "|" + this.user.sessionId, Utils.FB_APP_SECRET, "app_name");
log.info("XMPP client logged in");
}
I was doing this on the server without an SDK. I don't remember the details (and the Facebook documentation isn't very good) but from what I can tell from my code, after getting the user to authorize the app, I get a callback request from Facebook with a code parameter. I open a URLConnection to https://graph.facebook.com/oauth/access_token?client_id=<app_id>&redirect_uri=http://myserver/context/path/&client_secret=<app_secret>&code=<code>. The response should be the access token where the session id is the part after the | - something of the form XXX|<sessionId>.
Here's code I've been using successfully for authentication. Maybe this helps even though this is not related to Smack in any way. You can get sessionKey from access token received from FB, and for getting sessionSecret I've been using oldish REST API;
http://developers.facebook.com/docs/reference/rest/auth.promoteSession/
private final void processChallenge(XmlPullParser parser, Writer writer,
String sessionKey, String sessionSecret) throws IOException,
NoSuchAlgorithmException, XmlPullParserException {
parser.require(XmlPullParser.START_TAG, null, "challenge");
String challenge = new String(Base64.decode(parser.nextText(),
Base64.DEFAULT));
String params[] = challenge.split("&");
HashMap<String, String> paramMap = new HashMap<String, String>();
for (int i = 0; i < params.length; ++i) {
String p[] = params[i].split("=");
p[0] = URLDecoder.decode(p[0]);
p[1] = URLDecoder.decode(p[1]);
paramMap.put(p[0], p[1]);
}
String api_key = "YOUR_API_KEY";
String call_id = "" + System.currentTimeMillis();
String method = paramMap.get("method");
String nonce = paramMap.get("nonce");
String v = "1.0";
StringBuffer sigBuffer = new StringBuffer();
sigBuffer.append("api_key=" + api_key);
sigBuffer.append("call_id=" + call_id);
sigBuffer.append("method=" + method);
sigBuffer.append("nonce=" + nonce);
sigBuffer.append("session_key=" + sessionKey);
sigBuffer.append("v=" + v);
sigBuffer.append(sessionSecret);
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(sigBuffer.toString().getBytes());
byte[] digest = md.digest();
StringBuffer sig = new StringBuffer();
for (int i = 0; i < digest.length; ++i) {
sig.append(Integer.toHexString(0xFF & digest[i]));
}
StringBuffer response = new StringBuffer();
response.append("api_key=" + URLEncoder.encode(api_key));
response.append("&call_id=" + URLEncoder.encode(call_id));
response.append("&method=" + URLEncoder.encode(method));
response.append("&nonce=" + URLEncoder.encode(nonce));
response.append("&session_key=" + URLEncoder.encode(sessionKey));
response.append("&v=" + URLEncoder.encode(v));
response.append("&sig=" + URLEncoder.encode(sig.toString()));
StringBuilder out = new StringBuilder();
out.append("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>");
out.append(Base64.encodeToString(response.toString().getBytes(),
Base64.NO_WRAP));
out.append("</response>");
writer.write(out.toString());
writer.flush();
}
I'm sorry to make new answer but I had to include the new code #YShinkarev sorry for being late
By modifying #Adrian answer to make challengeReceived we can use APIKey and accessToken all I modified was the composedResponse
#Override
public void challengeReceived(String challenge) throws IOException {
byte[] response = null;
if (challenge != null) {
String decodedChallenge = new String(Base64.decode(challenge));
Map<String, String> parameters = getQueryMap(decodedChallenge);
String version = "1.0";
String nonce = parameters.get("nonce");
String method = parameters.get("method");
long callId = new GregorianCalendar().getTimeInMillis();
String composedResponse = "api_key="
+ URLEncoder.encode(apiKey, "utf-8") + "&call_id=" + callId
+ "&method=" + URLEncoder.encode(method, "utf-8")
+ "&nonce=" + URLEncoder.encode(nonce, "utf-8")
+ "&access_token="
+ URLEncoder.encode(access_token, "utf-8") + "&v="
+ URLEncoder.encode(version, "utf-8");
response = composedResponse.getBytes("utf-8");
}
String authenticationText = "";
if (response != null) {
authenticationText = Base64.encodeBytes(response,
Base64.DONT_BREAK_LINES);
}
// Send the authentication to the server
getSASLAuthentication().send(new Response(authenticationText));
}
What do you want to do?
If you just want to login on FB chat, you connect to FB just like any other XMPP server.
I would look at and use "Authenticating with Username/Password" from Chat API, wich is supported by Smack. Unless I would like to write an FaceBook-application. Then I would try to login in with "Authenticating with Facebook Platform".
So, just use Smack to connect to FB chat as you would do with your ordinary Jabber client.
For the username, use your Facebook username. (see http://www.facebook.com/username/ )
For the domain, use: chat.facebook.com
For the password, use your Facebook password
Turn off SSL and TSL
Set connect port to: 5222 (which is the default for XMPP)
Set connect server to chat.facebook.com