X-FACEBOOK-PLATFORM authentication error - xmpp

I'm trying to connect to Facebook chat api via SMACK using the code below but I always receive X-FACEBOOK-PLATFORM failed: not-authorized. I have a valid token with xmpp permission but I think I'm missing something... it's working with user/pass, but not with accessToken.
Thanks for your help guys, this thing is driving me crazy.
public class FacebookChatSample {
public static void main( )
{
String accessToken = //internet example "AAACjg0Eh1N8BAFuhUFZAN0EteV6pjZAsZAI46i8oV3iVmyLdaKiwaBcM5DPFjbEZAq9LZAZAA0qXsvaXkKB7SqnhubzlUAK7tmr3UYLaeQgaXSJ6EZCKn2G";
String consumerKey = //internet example "179784128779487";
long targetFacebookId = 550121201669650L;
String toID = "1002221765";
String message = "HELLOOOOO FROM MY JAVA PROGRAM!!";
XMPPConnection connection = createXMPPConnection();
try
{
connection.connect();
connection.login( consumerKey, accessToken );
String to = String.format( "-%d#chat.facebook.com", Long.valueOf( targetFacebookId ) );
Chat chat = connection.getChatManager().createChat( to, null );
chat.sendMessage( message );
}
catch( XMPPException e )
{
e.printStackTrace();
}
finally
{
connection.disconnect();
}
}
private static synchronized XMPPConnection createXMPPConnection()
{
SASLAuthentication.registerSASLMechanism(
SASLXFacebookPlatformMechanism.NAME,
SASLXFacebookPlatformMechanism.class );
SASLAuthentication.supportSASLMechanism(
SASLXFacebookPlatformMechanism.NAME, 0 );
ConnectionConfiguration configuration = new ConnectionConfiguration(
"chat.facebook.com", 5222 );
configuration.setSASLAuthenticationEnabled( true );
return new XMPPConnection( configuration );
}
public static class SASLXFacebookPlatformMechanism extends SASLMechanism
{
public static final String NAME = "X-FACEBOOK-PLATFORM";
public SASLXFacebookPlatformMechanism(
SASLAuthentication saslAuthentication )
{
super( saslAuthentication );
}
private String apiKey = "";
private String accessToken = "";
#Override
protected void authenticate() throws IOException, XMPPException
{
AuthMechanism stanza = new AuthMechanism( getName(), null );
getSASLAuthentication().send( stanza );
}
#SuppressWarnings( "hiding" )
#Override
public void authenticate( String apiKey, String host, String accessToken )
throws IOException, XMPPException
{
if( apiKey == null || accessToken == null )
{
throw new IllegalStateException( "Invalid parameters!" );
}
this.apiKey = apiKey;
this.accessToken = accessToken;
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 decodedResponse = new String(
org.jivesoftware.smack.util.Base64.decode( challenge ) );
Map<String, String> parameters = getQueryMap( decodedResponse );
String version = "1.0";
String nonce = parameters.get( "nonce" );
String method = parameters.get( "method" );
Long callId = Long.valueOf( System.currentTimeMillis() );
String composedResponse = String
.format(
"method=%s&nonce=%s&access_token=%s&api_key=%s&call_id=%s&v=%s",
URLEncoder.encode( method, "UTF-8" ),
URLEncoder.encode( nonce, "UTF-8" ),
URLEncoder.encode( this.accessToken, "UTF-8" ),
URLEncoder.encode( this.apiKey, "UTF-8" ),
callId, URLEncoder.encode( version, "UTF-8" ) );
response = composedResponse.getBytes();
}
String authenticationText = "";
if( response != null )
{
authenticationText = org.jivesoftware.smack.util.Base64
.encodeBytes(
response,
org.jivesoftware.smack.util.Base64.DONT_BREAK_LINES );
}
Response stanza = new Response( authenticationText );
getSASLAuthentication().send( stanza );
}
private Map<String, String> getQueryMap( String query )
{
String[] params = query.split( "&" );
Map<String, String> map = new HashMap<String, String>();
for( String param : params )
{
String name = param.split( "=" )[0];
String value = param.split( "=" )[1];
map.put( name, value );
}
return map;
}
}
}

My God, I have been struggling with this forever as well. I just figured it out! Once I got it, it seemed so easy, but the confusing thing is the problem that seems to come from XMPP is actually a problem with Facebook. I think your problem (my problem was) that Facebook requires you to request application specific login permissions that have nothing to do with the XMPP protocol. If you look at the Chat API specifications, it says you need to request xmpp_login extended permission for your application if you're using X-FACEBOOK-PLATFORM. You have to do this through the session object in the Facebook SDK you used to get your session_token.
Here is the code I used:
session.requestNewReadPermissions(new NewPermissionsRequest(getActivity(), Arrays.asList("xmpp_login")));
As soon as I did that it worked like a charm. Last caveat is that you need to make sure the popup dialog asking the user to grant your app this extended permission comes up and gets the required permission BEFORE you moved on and try to xmpp.login. Otherwise you'll have the same problem as your app will request permission but not actually get permission.
I hope this works for you.

Related

How to pass user context object to the response callback of async Jetty HTTP client?

When sending notifications to single recipients over Google Firebase Cloud Messaging, sometimes a response comes back (200 + error:MissingRegistration, 200 + error:InvalidRegistration, 200 + error:NotRegistered), which requires deleting the token of that recipient (because she for example reinstalled the Android app and the token has changed).
My question is:
How to pass that string (the FCM token) back to the response callback of the non-blocking Jetty HTTP client?
Currently my workaround is to add a custom HTTP header to my request:
X-token: APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...
and then I retrieve it in the response callback. But this is a hack, because FCM does not specify such a header and also I need to pass more custom data (the internal user id in my app) back.
Here is my current source code with the custom HTTP header, how to change it please?
private static final String FCM_URL = "https://fcm.googleapis.com/fcm/send";
private static final String FCM_KEY = "key=REPLACE_BY_YOUR_KEY";
private static final String FCM_RESULTS = "results";
private static final String FCM_ERROR = "error";
private static final String FCM_NOT_REGISTERED = "NotRegistered";
private static final String FCM_MISSING_REGISTRATION = "MissingRegistration";
private static final String FCM_INVALID_REGISTRATION = "InvalidRegistration";
private static final String FCM_X_TOKEN = "X-token";
private static final String TOKEN = "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...";
private static final Map<String, Object> REQUEST = new HashMap<>();
private static final Map<String, Object> NOTIFICATION = new HashMap<>();
private static final Map<String, Object> DATA = new HashMap<>();
static {
REQUEST.put("to", TOKEN);
REQUEST.put("notification", NOTIFICATION);
REQUEST.put("data", DATA);
NOTIFICATION.put("body", "great match!");
NOTIFICATION.put("title", "Portugal vs. Denmark");
NOTIFICATION.put("icon", "myicon");
DATA.put("Nick", "Mario");
DATA.put("Room", "PortugalVSDenmark");
}
private static final SslContextFactory sFactory = new SslContextFactory();
private static final HttpClient sHttpClient = new HttpClient(sFactory);
private static final BufferingResponseListener sFcmListener = new BufferingResponseListener() {
#Override
public void onComplete(Result result) {
if (!result.isSucceeded()) {
System.err.println(result.getFailure());
return;
}
String body = getContentAsString(StandardCharsets.UTF_8);
try {
Map<String, Object> resp = (Map<String, Object>) JSON.parse(body);
Object[] results = (Object[]) resp.get(FCM_RESULTS);
Map map = (Map) results[0];
String error = (String) map.get(FCM_ERROR);
System.out.printf("error: %s\n", error);
if (FCM_NOT_REGISTERED.equals(error) ||
FCM_MISSING_REGISTRATION.equals(error) ||
FCM_INVALID_REGISTRATION.equals(error)) {
String token = result.getRequest().getHeaders().get(FCM_X_TOKEN);
System.out.printf("TODO delete invalid FCM token from the database: %s\n", token);
}
} catch (Exception ex) {
System.err.println(ex);
}
}
};
public static void main(String[] args) throws Exception {
sHttpClient.start();
sHttpClient.POST(FCM_URL)
.header(HttpHeader.AUTHORIZATION, FCM_KEY)
.header(HttpHeader.CONTENT_TYPE, "application/json")
.header(FCM_X_TOKEN, TOKEN) // Workaround, how to improve?
.content(new StringContentProvider(JSON.toString(REQUEST)))
.send(sFcmListener);
}
You want to set the token as a request attribute and the retrieve it back:
httpClient.POST(url)
.attribute(key, token)
...
.send(new BufferingResponseListener() {
#Override
public void onComplete(Result result) {
Object token = result.getRequest().getAttribute(key);
...
}
});

How do I implement facebook chat using aSmack XMPP library in Android (2014)? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I searched many places to find ways to integrate facebook chat into Android/Smack but none of them worked completely. Could someone provide a working example that works with the latest version of the API?
Authenticating using X-FACEBOOK-PLATFORM SASLAuthentication. Verified working on 14 Jan 2014 with Android 4.2.2.
The jabber ID is not username#chat.facebook.com. It is resolved to a numeric id that you can check against the roster.
ChatActivity.java
public void connectToFb() throws XMPPException {
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM",SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
config.setSASLAuthenticationEnabled(true);
config.setSecurityMode(SecurityMode.required);
config.setSendPresence(false);
XMPPConnection xmpp = new XMPPConnection(config);
try {
xmpp.connect();
xmpp.login(Session.getActiveSession().getApplicationId(), Session.getActiveSession().getAccessToken(), "Application");
//send a chat message
ChatManager chatmanager = xmpp.getChatManager();
Chat newChat = chatmanager.createChat("<jabber-id-here>#chat.facebook.com", new MessageListener() {
#Override
public void processMessage(Chat chat, Message msg) {
Log.d("test", "message sent = "+ msg);
}
});
newChat.sendMessage("Cowdy!");
//get roster
Roster roster = xmpp.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
System.out.println("Connected!");
System.out.println("\n\n" + entries.size() + " buddy(ies):");
for (RosterEntry entry : entries) {
Log.i("test", entry.getName());
Log.i("test", entry.getUser());
}
} catch (XMPPException e) {
xmpp.disconnect();
e.printStackTrace();
}
}
SASLXFacebookPlatformMechanism.java
public class SASLXFacebookPlatformMechanism extends SASLMechanism {
public static final String NAME = "X-FACEBOOK-PLATFORM";
private String apiKey = "";
private String accessToken = "";
/**
* Constructor.
*/
public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication) {
super(saslAuthentication);
}
#Override
protected void authenticate() throws IOException, XMPPException {
// Send the authentication to the server
getSASLAuthentication().send(new AuthMechanism(getName(), ""));
}
#Override
public void authenticate(String apiKey, String host, String accessToken) throws IOException, XMPPException {
this.apiKey = apiKey;
this.accessToken = accessToken;
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));
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 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(accessToken, "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));
}
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;
}
}
Authentication flow using SASL/Plain (when username and password are supplied)
Refer to Android Facebook chat example project

Testing Intuit IPP

I would like to create some unit tests for inserting data to QuickBooks Online. I am having a problem with the authentication step:
public DataServices Authenticate(IntuitServicesType intuitDataServicesType)
{
DataServices dataServices = null;
string accessToken = HttpContext.Current.Session["accessToken"].ToString();
string accessTokenSecret = HttpContext.Current.Session["accessTokenSecret"].ToString();
string companyID = HttpContext.Current.Session["realm"].ToString();
// now auth to IA
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(accessToken, accessTokenSecret, ConfigurationManager.AppSettings["consumerKey"].ToString(), ConfigurationManager.AppSettings["consumerSecret"].ToString());
ServiceContext context = new ServiceContext(oauthValidator, accessToken, companyID, intuitDataServicesType);
dataServices = new DataServices(context);
if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
HttpContext.Current.Session["DataServices"] = dataServices;
}
return dataServices;
}
In my unit test project, which has no user interface, how can I obtain an access token and an access token secret? I cannot log into Intuit from that area.
[TestMethod()]
public void AuthorizeWithHeadersTest()
{
string accessToken = ConfigurationManager.AppSettings["AccessTokenQBD"];
string accessTokenSecret = ConfigurationManager.AppSettings["AccessTokenSecretQBD"];
string consumerKey = ConfigurationManager.AppSettings["ConsumerKeyQBD"];
string consumerKeySecret = ConfigurationManager.AppSettings["ConsumerSecretQBD"];
string requestUri = "https://appcenter.intuit.com/Developer/Create";
WebRequest webRequest = WebRequest.Create(requestUri);
webRequest.Headers.Add("ContentType", "text/xml");
OAuthRequestValidator target = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerKeySecret);
target.Authorize(webRequest, string.Empty);
Assert.IsTrue(webRequest.Headers.Count > 0);
}
I'm sharing a sample standalone java code snippet. You can try the same in .net
From appcenter, you can create an app to get consumer key, consumer secret and app token.
Using apiexplorer and the above consumer key, consumer secret, you can get access tokens.
AppCenter - https://appcenter.intuit.com/
Apiexplorer - https://developer.intuit.com/apiexplorer?apiname=V2QBO
You can set all the 5 values in the standalone program(setupQBO method). It will work fine.
import java.util.ArrayList;
import java.util.List;
import com.intuit.ds.qb.PartyType;
import com.intuit.ds.qb.QBCustomer;
import com.intuit.ds.qb.QBCustomerService;
import com.intuit.ds.qb.QBInvalidContextException;
import com.intuit.ds.qb.QBObjectFactory;
import com.intuit.ds.qb.QBServiceFactory;
import com.intuit.platform.client.PlatformSessionContext;
import com.intuit.platform.client.PlatformServiceType;
import com.intuit.platform.client.security.OAuthCredentials;
import org.slf4j.Logger;
// QBO API Docs - https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/v2/0400_quickbooks_online/Customer
// JavaDocs - http://developer-static.intuit.com/SDKDocs/QBV2Doc/ipp-java-devkit-2.0.10-SNAPSHOT-javadoc/
public class CodegenStubCustomerall {
static String accesstoken = "";
static String accessstokensecret = "";
static String appToken = "";
static String oauth_consumer_key = "";
static String oauth_consumer_secret = "";
static String realmID = "";
static String dataSource = "";
final PlatformSessionContext context;
public CodegenStubCustomerall(PlatformSessionContext context) {
this.context = context;
}
public void testAdd(){
try {
QBCustomer entityPojo = QBObjectFactory.getQBObject(context, QBCustomer.class);
entityPojo.setName("TestQBCustomer12345");
entityPojo.setTypeOf(PartyType.PERSON);
QBCustomerService service = QBServiceFactory.getService(context, QBCustomerService.class);
QBCustomer qbQBCustomer = service.addCustomer(context, entityPojo);
} catch (QBInvalidContextException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public List<QBCustomer> testGetAll() {
final List<QBCustomer> entityList = new ArrayList<QBCustomer>();
try {
QBCustomerService service = QBServiceFactory.getService(context, QBCustomerService.class);
List<QBCustomer> qbCustomerList = service.findAll(context, 1,100);
for (QBCustomer each : qbCustomerList) {
entityList.add(each);
}
} catch (QBInvalidContextException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return entityList;
}
public static void main(String args[]) {
PlatformSessionContext context = getPlatformContext("QBO");
CodegenStubCustomerall testObj = new CodegenStubCustomerall(context);
testObj.testGetAll();
}
public static PlatformSessionContext getPlatformContext(String dataSource) {
PlatformServiceType serviceType = null;
if (dataSource.equalsIgnoreCase("QBO")) {
serviceType = PlatformServiceType.QBO;
setupQBO();
}
final OAuthCredentials oauthcredentials = new OAuthCredentials(
oauth_consumer_key, oauth_consumer_secret, accesstoken,
accessstokensecret);
final PlatformSessionContext context = new PlatformSessionContext(
oauthcredentials, appToken, serviceType, realmID);
return context;
}
private static void setupQBO() {
System.out.println("QBO token setup");
accesstoken = "replace your tokens";
accessstokensecret = "replace your tokens";
appToken = "replace your tokens";
oauth_consumer_key = "replace your tokens";
oauth_consumer_secret = "replace your tokens";
realmID = "7123456720";
dataSource = "QBO";
}
}
For sample .net code, you can refer this link.
https://developer.intuit.com/docs/0025_quickbooksapi/0055_devkits/0100_ipp_.net_devkit/0299_synchronous_calls/0001_data_service_apis
Thanks

X-FACEBOOK-PLATFORM authentication with SMACK Java library using OAuth 2.0

First post here so please be gentle.
I'm building a facebook chat client, using Smack library.
I'm using X-FACEBOOK-PLATFORM method in order not to save any passwords. I had it working properly using oauth 1.0, and want to change it to 2.0, cause of the october 1st deadline ;p. From what I understand the only thing I'd have to do in order to migrate to 2.0 is removing "sig" and "session_key" parameters and adding an "access_token" parameter, but I'm getting an "SASL authentication X-FACEBOOK-PLATFORM failed: not-authorized:".
I'm using this custom SASLMechanism class:
package smackresearching;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import 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 {
public static final String NAME = "X-FACEBOOK-PLATFORM";
private String apiKey = "";
private String accessToken = "";
/**
* Constructor.
*/
public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication) {
super(saslAuthentication);
}
#Override
protected void authenticate() throws IOException, XMPPException {
// Send the authentication to the server
getSASLAuthentication().send(new AuthMechanism(getName(), ""));
}
#Override
public void authenticate(String apiKey, String host, String accessToken) throws IOException, XMPPException {
this.apiKey = apiKey;
this.accessToken = accessToken;
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));
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 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(accessToken, "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));
}
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;
}
}
And this is the Main code:
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
config.setSASLAuthenticationEnabled(true);
// config.setDebuggerEnabled(true);
XMPPConnection connection = new XMPPConnection(config);
try {
//ESTA LINEA HACE QUE NO DE TIMEOUT
SmackConfiguration.setPacketReplyTimeout(15000);
XMPPConnection.DEBUG_ENABLED = true;
SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM", SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
connection.connect();
String apiKey = "3290282390339";
String accessToken = "ADSJGFGFKDKSJKSJD0-43DKJSDJKSDKJSD094JJSDKJSDKJDSNDSKJEWEWNSDLkljdkjs";
connection.login(apiKey, accessToken);
...
Thanks in advance for any advice.
There is a missing ampersand for the access_token parameter in the composedResponse string. Is this a typo?
Could you post the authenticationText you are sending?

SASL Authentication failed while integrating facebook chat using Smack

I am trying to integrate facebook chat using smack API.But i get an error telling authentication failed using digest md5...
Here s the code for authentication:
SASLAuthentication.registerSASLMechanism("DIGEST-MD5", SASLDigestMD5Mechanism.class);
SASLAuthentication.supportSASLMechanism("DIGEST-MD5", 0);
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com",5222);
connection = new XMPPConnection(config);
config.setSASLAuthenticationEnabled(true);
connection.connect();
connection.login(userName, password);
below is the error i get wen i run it:
Exception in thread "main" SASL authentication failed using mechanism DIGEST-MD5:
at org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:325)
at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:395)
at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:349)
at JabberSmackAPIFacebook.login(JabberSmackAPIFacebook.java:31)
at JabberSmackAPIFacebook.main(JabberSmackAPIFacebook.java:77)
I can successfully connect to gtalk but am having no success vit fb...
can sumone tel me wat s the problem
For me the solution was to not include the host part in the username when calling login() without DNS SRV and not agains the Google Talk services. This is also described in the ignite forums.
E.g.
connection.login("user#jabber.org", "password", "resource");
becomes
connection.login("user", "password", "resource");
There is a huge thread at Ignite that deals with this issue. You may want to take a look at it as there are several solutions for Java and Android given that seem to work.
I have succesfully connected using DIGEST-MD5 to facebook, the code you have posted looks good.
But still we need to check the contents of your SASLDigestMD5Mechanism class
I have used the class provided in here with success
http://community.igniterealtime.org/message/200878#200878
Also you have to notice that in the DIGEST-MD5 mechanism you have to login with your facebook username and not with the email address. By default the facebook accounts don't have a username, you have to create one fisrt, you can check that in here:
http://www.facebook.com/username/
MainActivity.java
public class MainActivity extends Activity {
XMPPConnection xmpp;
ArrayList<HashMap<String, String>> friends_list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Session.openActiveSession(this, true, new StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
if ( session.isOpened()){
new testLoginTask().execute();
}
}
});
}
private class testLoginTask extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
testLogin();
return null;
}
}
private void testLogin(){
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
config.setSASLAuthenticationEnabled(true);
config.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
config.setDebuggerEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
config.setTruststoreType("AndroidCAStore");
config.setTruststorePassword(null);
config.setTruststorePath(null);
} else {
config.setTruststoreType("BKS");
String path = System.getProperty("javax.net.ssl.trustStore");
if (path == null)
path = System.getProperty("java.home") + File.separator + "etc"
+ File.separator + "security" + File.separator
+ "cacerts.bks";
config.setTruststorePath(path);
}
xmpp = new XMPPConnection(config);
SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM",SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
try {
xmpp.connect();
Log.i("XMPPClient","Connected to " + xmpp.getHost());
} catch (XMPPException e1) {
Log.i("XMPPClient","Unable to " + xmpp.getHost());
e1.printStackTrace();
}
try {
String apiKey = Session.getActiveSession().getApplicationId();
String sessionKey = Session.getActiveSession().getAccessToken();
String sessionSecret = "replace with your app secret key";
xmpp.login(apiKey + "|" + sessionKey, sessionSecret , "Application");
Log.i("XMPPClient"," its logined ");
Log.i("Connected",""+xmpp.isConnected());
if ( xmpp.isConnected()){
Presence presence = new Presence(Presence.Type.available);
xmpp.sendPacket(presence);
}
} catch (XMPPException e) {
e.printStackTrace();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
SASLXFacebookPlatformMechanism.java
public class SASLXFacebookPlatformMechanism extends SASLMechanism{
private static final String NAME = "X-FACEBOOK-PLATFORM";
private String apiKey = "";
private String accessToken = "";
/**
* Constructor.
*/
public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication) {
super(saslAuthentication);
}
#Override
protected void authenticate() throws IOException, XMPPException {
getSASLAuthentication().send(new AuthMechanism(NAME, ""));
}
#Override
public void authenticate(String apiKey, String host, String accessToken) throws IOException, XMPPException {
if (apiKey == null || accessToken == null) {
throw new IllegalArgumentException("Invalid parameters");
}
this.apiKey = apiKey;
this.accessToken = accessToken;
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 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(accessToken, "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));
}
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;
}
}