Calling Apache http client library underload in webservice - java

I have an issue with my Apache Http Client code. It's a simple hello world method, and another method which calls hello world using the Apache http client code.
I deploy it to webservice and for the first 100 or so in a loop it responds with 20ms fast times. After that is slowly starts going up in response time, if I run it for 3000 requests the response time becomes 150ms, 10000 450ms, etc.. Also the response time never goes back down after long period of in-activity, it only increases.
I have linked this to the method createHttpClient, the b.build method takes longer and longer to build the client for some reason. Is there any way to fix this, or is there a better http API for high long conditions.
My code (not finalized just more of a proof of concept phase right now):
public final class HttpClientTools
{
private static Logger LOG = LoggerFactory.getLogger(HttpClientTools.class);
private HttpClientTools() {}
private static SSLContextBuilder ___builder = null;
private static SSLContext sslContext = null;
private static SSLConnectionSocketFactory __sslsf = null;
private static Registry<ConnectionSocketFactory> socketFactoryRegistry = null;
private static SSLConnectionSocketFactory sslsf = null;
private static final AllowAllHostnameVerifier allowAllHostnameVerifier = new org.apache.http.conn.ssl.AllowAllHostnameVerifier();
private static void init() throws Exception
{
___builder = SSLContexts.custom();
___builder.loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; }
#Override
public boolean isTrusted(java.security.cert.X509Certificate[] chain,String authType) throws CertificateException { return true; }
});
sslContext = ___builder.build();
__sslsf = new SSLConnectionSocketFactory( sslContext, new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"},null,new X509HostnameVerifier()
{
#Override public void verify(String host, SSLSocket ssl) throws IOException { }
public void verify(String host, X509Certificate cert) throws SSLException { }
#Override public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { }
#Override public boolean verify(String s, SSLSession sslSession) { return true; }
#Override public void verify(String arg0,java.security.cert.X509Certificate arg1) throws SSLException { }
});
socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("http", PlainConnectionSocketFactory.INSTANCE).register("https", __sslsf).build();
sslsf = new SSLConnectionSocketFactory(___builder.build());
}
private static HttpClient createHttpClient(HttpClientToolsJsonInput input) throws Exception
{
HttpClientToolsInput temp = new HttpClientToolsInput();
temp.setConnectionRequestTimeout(input.getConnectionRequestTimeout());
temp.setConnectionTimeout(input.getConnectionTimeout());
temp.setSocketTimeout(input.getSocketTimeout());
temp.setUsername(input.getUsername());
temp.setPassword(input.getPassword());
temp.setUseDetailedResponseHandler(input.isUseDetailedResponseHandler());
return HttpClientTools.createHttpClient(temp);
}
private static HttpClient createHttpClient(HttpClientToolsInput input) throws Exception
{
HttpClient rtn = null;
long startms = System.currentTimeMillis();
if (___builder == null)
{
init();
}
HttpClientBuilder b = HttpClientBuilder.create();
b.setSslcontext( sslContext);
HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager(socketFactoryRegistry);
b.setConnectionManager(cm);
RequestConfig defaultRequestConfig = RequestConfig.custom().setSocketTimeout(
input.getSocketTimeout()).setConnectTimeout(
input.getConnectionTimeout()).setConnectionRequestTimeout(
input.getConnectionRequestTimeout()).build();
b.setDefaultRequestConfig(defaultRequestConfig);
if (StringTools.doesStringHaveData(input.getUsername()) && StringTools.doesStringHaveData(input.getPassword()) )
{
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(input.getUsername(), input.getPassword()));
b.setDefaultCredentialsProvider(credsProvider);
}
long ms1=System.currentTimeMillis();
rtn = b.build(); // takes increasing time when deployed on tomee
System.out.println("HttpClientTools m12 took "+(System.currentTimeMillis()-ms1)+" ms");
long endms = System.currentTimeMillis();
System.out.println("HttpClientTools getCloseableHttpClient() took "+(endms-startms)+" ms");
return rtn;
}
public static String sendHttpPostRequest(HttpClientToolsInput input) throws Exception
{
HttpClient httpclient = null;
HttpPost _http = null;
InputStream entityIS = null;
String responseBody = null;
HttpResponse clhttpr = null;
try
{
for (String url : input.getUrls())
{
httpclient = HttpClientTools.createHttpClient(input);
_http = new HttpPost(url);
RequestConfig defaultRequestConfig = RequestConfig.custom().setSocketTimeout(input.getSocketTimeout()).setConnectTimeout(input.getConnectionTimeout()).setConnectionRequestTimeout(input.getConnectionRequestTimeout()).build();
_http.setConfig(defaultRequestConfig);
StringEntity strent = new StringEntity(input.getMessage());
strent.setContentType("text/xml; charset=utf-8");
_http.setEntity(strent);
ResponseHandler<String> response = null;
if (input.isUseDetailedResponseHandler())
{
response = new DetailedExceptionReasonResponseHandler();
}
else
{
response = new BasicResponseHandler();
}
boolean https = false;
if (url.toLowerCase(Locale.US).startsWith("https"))
{
https = true;
}
AuthCache authCache = new BasicAuthCache();
BasicScheme basicAuth = new BasicScheme();
HttpHost host = new HttpHost(url);
if (StringTools.doesStringHaveData(input.getUsername()) && StringTools.doesStringHaveData(input.getPassword()))
{
authCache.put(host, basicAuth);
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(input.getUsername(), input.getPassword()));
HttpClientContext _context = HttpClientContext.create();
_context.setAuthCache(authCache);
_context.setCredentialsProvider(credentialsProvider);
clhttpr = httpclient.execute(_http, _context);
}
else
{
clhttpr = httpclient.execute(_http);
}
entityIS = clhttpr.getEntity().getContent();
responseBody = Convert.inputStreamToString(entityIS);
try { EntityUtils.consume(_http.getEntity()); } catch(Exception e) {}
try { clhttpr.getEntity().getContent().close(); } catch(Exception e) {}
try { entityIS.close(); } catch(Exception e) {}
}
return responseBody;
}
catch (Exception e)
{
try { EntityUtils.consume(_http.getEntity()); } catch(Exception e1) {}
try { clhttpr.getEntity().getContent().close(); } catch(Exception e2) {}
try { entityIS.close(); } catch(Exception e3) {}
e.printStackTrace();
throw e;
}
}
public static void main(String[] args) throws Exception
{
HttpClientToolsInput input = new HttpClientToolsInput();
input.setConnectionRequestTimeout(9000);
input.setConnectionTimeout(9000);
input.setSocketTimeout(9000);
String msg2="<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsdl=\"http://myservice.org/wsdl\"><soapenv:Header/><soapenv:Body><wsdl:callHello/></soapenv:Body></soapenv:Envelope>";
input.setMessage(msg2);
input.setUseDetailedResponseHandler(false);
input.addUrl("http://127.0.0.1:8282/simple-webservice/MyService?wsdl");
String response = "";
long ms=0;
for (int i=0; i<999;i++)
{
ms = System.currentTimeMillis();
response = HttpClientTools.sendHttpPostRequest(input);
System.out.println("response["+i+"][ms="+(System.currentTimeMillis()-ms)+"]="+response);
}
}
}

Related

java - unit testing for REST request

I have the method:
public HTTPResult get(String url) throws Exception{
try {
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return new HTTPResult(response.getBody(), response.getStatusCode().value());
}
catch (ResourceAccessException e) {
String responseBody = e.getCause().getMessage();
JSONObject obj = new JSONObject(responseBody);
return new HTTPResult(obj.getString("responseBody"), Integer.parseInt(obj.getString("statusCode")));
}
}
I want to do unit testing for it and i am not sure how to proceed:
public class MockHttpServerTest {
private static final int PORT = 51234;
private static final String baseUrl = "http://localhost:" + PORT;
private MockHttpServer server;
private SimpleHttpResponseProvider responseProvider;
private HttpClient client;
#Before
public void setUp() throws Exception {
responseProvider = new SimpleHttpResponseProvider();
server = new MockHttpServer(PORT, responseProvider);
server.start();
client = new DefaultHttpClient();
}
I am getting RED for MockHttpServer & SimpleHttpResponseProvider which should be part of org.apache.wink.client.*; which i am importing. so why do i have red ones? is there some simple way to unit test it?
HTTPResult return me response code and message.

Read rcon command response

I want to send rcon command to server using java, to do this I'm using the following library https://github.com/Kronos666/rkon-core
When i run command like this
Rcon rcon = new Rcon("127.0.0.1", 27015, "mypassword".getBytes());
// Example: On a minecraft server this will list the connected players
String result = rcon.command("list");
// Display the result in the console
System.out.println(result);
My server show response in console Gc connection established from... and so on
but in java app i have the empty result, it's not null, it's just empty
String result = rcon.command("list");
How can i take response from server using rcon protocol?
Try this:
try {
Rcon rcon = new Rcon("127.0.0.1", 27015, "mypassword".getBytes());
String result = rcon.command("list");
System.out.println(result);
} catch (AuthenticationException e) {
String result = "Authentication failed";
}
Finally I write my own implementation:
public final class RconClient implements AutoCloseable {
private static final int MAX_SIZE = 4096;
private final Socket socket;
private final RconData data;
private static final Logger LOG = LoggerFactory.getLogger(RconClient.class);
#SuppressWarnings("ConstructorShouldNotThrowExceptions")
public RconClient(final String host,
final int port,
final byte[] password) throws IOException {
this.socket = new Socket(host, port);
final RconData requst = request(new RconData(RconData.AUTH, password));
if (requst.getId() == -1) {
LOG.error("Wrong password or ip to connect to rcon");
throw new LoginException(host, port);
}
this.data = read();
}
public String command(String command) throws IOException {
command = "get5_status";
final RconData response = request(new RconData(command.getBytes()));
return new String(response.getPayload(), Charset.forName("UTF-8"));
}
public RconData request(RconData packet) throws IOException {
try {
write(packet);
return read();
} catch (final SocketException exception) {
socket.close();
throw exception;
}
}
private void write(RconData packet) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(packet.getPayload().length + 14);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.putInt(packet.getPayload().length + 10);
buffer.putInt(packet.getId());
buffer.putInt(packet.getType());
buffer.put(packet.getPayload());
buffer.put((byte)0);
buffer.put((byte)0);
socket.getOutputStream().write(buffer.array());
socket.getOutputStream().flush();
}
private RconData read() throws IOException {
byte[] packet = new byte[MAX_SIZE];
int packetSize = this.socket.getInputStream().read(packet);
ByteBuffer buffer = ByteBuffer.wrap(packet, 0, packetSize);
buffer.order(ByteOrder.LITTLE_ENDIAN);
if (buffer.remaining() < 4) {
throw new WrongPacketException();
}
int size = buffer.getInt();
if (buffer.remaining() < size) {
throw new WrongPacketException();
}
int id = buffer.getInt();
int type = buffer.getInt();
byte[] payload = new byte[size - 10];
buffer.get(payload);
buffer.get(new byte[2]);
return new RconData(id, type, payload);
}
#Override
public void close() throws IOException {
this.socket.close();
}
}
Where RconData it's simple POJO with byte[] password property,

java.io.IOException: HTTP request failed, HTTP status: 500 (ksoap2)

I'm using KSOAP2, when sending request to the server and got java.io.IOException: HTTP request failed, HTTP status: 500 in the line httpTransport.call(SOAP_ACTION, envelope) , but server works, I have checked it using SoapUI. What can be the problem?
public class SOAPClient
{
private static final int TIMEOUT_SOCKET = 180000;
public static SoapObject get(Context context, String methodName, ArrayList<Pair<String, ?>> args) throws Exception
{
final String URL = PrefHelper.getSOAPUrl(context);
final String NAMESPACE = PrefHelper.getSOAPNamespace(context);
final String SOAP_ACTION = methodName; //NAMESPACE + "#" + "mapx" + ":" + methodName;
SoapObjectEve request = new SoapObjectEve(NAMESPACE, methodName);
if (args != null) {
for (Pair<String, ?> arg : args) {
if (arg.first != null) {
request.addProperty(arg.first, arg.second);
}
}
}
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
new MarshalBase64().register(envelope);
envelope.setOutputSoapObject(request);
envelope.implicitTypes = true;
HttpTransportSE httpTransport = new HttpTransportSE(URL, TIMEOUT_SOCKET);
httpTransport.setXmlVersionTag("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
try
{
httpTransport.call(SOAP_ACTION, envelope);
AppLog.e(httpTransport.requestDump+"requestDump");
}
catch (ConnectTimeoutException e) {
AppLog.e(e.getMessage());
throw new Exception(context.getString(R.string.node_unavailable));
}
catch (SocketTimeoutException e) {
AppLog.e(e.getMessage());
throw new Exception(context.getString(R.string.timeout));
}
catch (Exception e) {
e.printStackTrace();
AppLog.e(e.getMessage());
AppLog.e(httpTransport.requestDump+"requestDump");
throw new Exception(context.getString(R.string.warning_error_get_data) + e.getMessage() == null ? "" : " " + e.getMessage());
}
AppLog.i(httpTransport.requestDump+"requestDump");
SoapObject soapObj = null;
try {
soapObj = (SoapObject) envelope.getResponse();
}
catch (Exception e) {
String response = ((SoapPrimitive) envelope.getResponse()).toString();
boolean res = Boolean.valueOf(response);
soapObj = new SoapObject();
soapObj.addProperty("response", res);
soapObj.addProperty("msg", "");
soapObj.addProperty("data", null);
}
AppLog.e(httpTransport.responseDump+"responseDump");
return soapObj;
}
}
Make sure your NAMESPACE, METHODNAME, WSDL and SOAP_ACTION are correct.
Try this code,
private static final String NAMESPACE = "http://www.kltro.com";
private static final String METHODNAME = "getUser";
private static final String WSDL = "http://ap.kashkan.org:55555/tro/ws/kltro";
private static final String SOAP_ACTION = NAMESPACE + "#kltro:" + METHODNAME ;
private static String TAG = "soap";
public static String callWebservice() {
String responseDump = "";
try {
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
SoapObject request = new SoapObject(NAMESPACE, METHODNAME);
request.addProperty("login", login);
request.addProperty("pass", password);
request.addProperty("androidID", androidID);
request.addProperty("ver", version);
envelope.bodyOut = request;
HttpTransportSE transport = new HttpTransportSE(WSDL);
transport.debug = true;
try {
transport.call(SOAP_ACTION, envelope);
String requestDump = transport.requestDump;
responseDump = transport.responseDump;
Log.e(TAG, requestDump);
Log.e(TAG, responseDump);
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return responseDump;
}
Also make sure you have internet permission in the manifest,
<uses-permission android:name="android.permission.INTERNET" />

Java Restful Webservices giving error

//Back end
#Path("/travelgood")
public class TravelgoodResource {
#POST
#Path("/{bookingNo}/{name}/{number}/{expMonth}/{expYear}")
public boolean bookingFlight(#PathParam("bookingNo") String bookingNo, #PathParam("name") String name, #PathParam("number") String number, #PathParam("expMonth") String expMonth, #PathParam("expYear") String expYear) {
ws.tg.BookType booking = new ws.tg.BookType();
booking.setBookingnumber(Integer.parseInt(bookingNo));
CreditCardInfoType cci = new CreditCardInfoType();
cci.setName(name);
cci.setNumber(number);
CreditCardInfoType.ExpirationDate ed = new CreditCardInfoType.ExpirationDate();
ed.setYear(Integer.parseInt(expYear));
ed.setMonth(Integer.parseInt(expMonth));
cci.setExpirationDate(ed);
booking.setCreditcardinformation(cci);
boolean myBooking = false;
try {
myBooking = bookFlight(booking);
} catch (BookFault ex) {
Logger.getLogger(TravelgoodResource.class.getName()).log(Level.SEVERE, null, ex);
}
return myBooking;
}
private static boolean bookFlight(ws.tg.BookType input2) throws BookFault {
ws.tg.Lameduck2Service service = new ws.tg.Lameduck2Service();
ws.tg.Lameduck2PortType port = service.getLameduck2PortTypeBindingPort();
return port.bookFlight(input2);
}
}
//TEST CLASS (Client)
public class TravelGoodRESTTest {
Client client = Client.create();
#Test
public void TestbookFlight() {
WebResource r = client.resource("htttp://localhost:8080/tg/webresources/travelgood/1/Donovan%20Jasper/50408818/6/9");
System.out.println("testBookFlight: "+r.post(String.class));
}
}
When running a Unit test it gives me the following error:
Caused an ERROR: POST htttp://localhost/8080/tg/webresources/travelgood/1/Donovan%20Jasper/50408818/6/9 returned a response status of 500 internal server error

Problems with connecting to Facebook XMMP MD5-DIGEST

I have tried all the things to connect Facebook with XMPP but i have faced only
one error all the time which is :
SASL authentication failed using mechanism DIGEST-MD5 I am implementing following method to perform this task :
public class MySASLDigestMD5Mechanism extends SASLMechanism {
public MySASLDigestMD5Mechanism(SASLAuthentication saslAuthentication) {
super(saslAuthentication);
}
protected void authenticate() throws IOException, XMPPException {
String[] mechanisms = { getName() };
Map<String, String> props = new HashMap<String, String>();
sc = Sasl.createSaslClient(mechanisms, null, "xmpp", hostname, props, this);
super.authenticate();
}
public void authenticate(String username, String host, String password) throws IOException, XMPPException {
this.authenticationId = username;
this.password = password;
this.hostname = host;
String[] mechanisms = { getName() };
Map<String,String> props = new HashMap<String,String>();
sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);
super.authenticate();
}
public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
String[] mechanisms = { getName() };
Map<String,String> props = new HashMap<String,String>();
sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, (org.apache.harmony.javax.security.auth.callback.CallbackHandler) cbh);
super.authenticate();
}
protected String getName() {
return "DIGEST-MD5";
}
/*public void challengeReceived1(String challenge) throws IOException {
// Build the challenge response stanza encoding the response text
StringBuilder stanza = new StringBuilder();
byte response[];
if (challenge != null) {
response = sc.evaluateChallenge(Base64.decode(challenge));
} else {
response = sc.evaluateChallenge(null);
}
String authenticationText="";
if (response != null) { // fix from 3.1.1
authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
if (authenticationText.equals("")) {
authenticationText = "=";
}
}
stanza.append("<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
stanza.append(authenticationText);
stanza.append("</response>");
// Send the authentication to the server
getSASLAuthentication().send(stanza.toString());
}*/
public void challengeReceived(String challenge)
throws IOException {
byte response[];
if (challenge != null) {
response = sc.evaluateChallenge(Base64.decode(challenge));
} else {
response = sc.evaluateChallenge(new byte[0]);
}
Packet responseStanza;
if (response == null) {
responseStanza = new Response();
} else {
responseStanza = new Response(Base64.encodeBytes(response, Base64.DONT_BREAK_LINES));
}
getSASLAuthentication().send(responseStanza);
}
}
And Connection Function is :
try{
SASLAuthentication.registerSASLMechanism("DIGEST-MD5",MySASLDigestMD5Mechanism. class);
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com",5222);
config.setSASLAuthenticationEnabled(true);
config.setRosterLoadedAtLogin (true);
connection = new XMPPConnection(config);
connection.connect();
Log.d("Connect...", "Afetr Connect");
connection.login("username#chat.facebook.com", "password");
Log.d("done","XMPP client logged in");
}
catch(XMPPException ex)
{
Log.d("not done","in catchhhhhhhhh");
System.out.println(ex.getMessage ());
connection.disconnect();
}
}
but "After connect" it gone to the ctach and give me error like :
SASL authentication failed using mechanism DIGEST-MD5
I searched all blog and find same thing but i dont know what am i doing wrong here..
If is there any other way or solution to connect Facebook XMPP then please Help me
ASAP
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 solved this problem. I find solution that http://community.igniterealtime.org/thread/41080
Jerry Magill wrote this...
import java.io.IOException;
import java.util.HashMap;
import javax.security.auth.callback.CallbackHandler;
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.packet.Packet;
import org.jivesoftware.smack.util.Base64;
public class MySASLDigestMD5Mechanism extends SASLMechanism
{
public MySASLDigestMD5Mechanism(SASLAuthentication saslAuthentication)
{
super(saslAuthentication);
}
protected void authenticate()
throws IOException, XMPPException
{
String mechanisms[] = {
getName()
};
java.util.Map props = new HashMap();
sc = Sasl.createSaslClient(mechanisms, null, "xmpp", hostname, props, this);
super.authenticate();
}
public void authenticate(String username, String host, String password)
throws IOException, XMPPException
{
authenticationId = username;
this.password = password;
hostname = host;
String mechanisms[] = {
getName()
};
java.util.Map props = new HashMap();
sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);
super.authenticate();
}
public void authenticate(String username, String host, CallbackHandler cbh)
throws IOException, XMPPException
{
String mechanisms[] = {
getName()
};
java.util.Map props = new HashMap();
sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh);
super.authenticate();
}
protected String getName()
{
return "DIGEST-MD5";
}
public void challengeReceived(String challenge)
throws IOException
{
//StringBuilder stanza = new StringBuilder();
byte response[];
if(challenge != null)
response = sc.evaluateChallenge(Base64.decode(challenge));
else
//response = sc.evaluateChallenge(null);
response = sc.evaluateChallenge(new byte[0]);
//String authenticationText = "";
Packet responseStanza;
//if(response != null)
//{
//authenticationText = Base64.encodeBytes(response, 8);
//if(authenticationText.equals(""))
//authenticationText = "=";
if (response == null){
responseStanza = new Response();
} else {
responseStanza = new Response(Base64.encodeBytes(response,Base64.DONT_BREAK_LINES));
}
//}
//stanza.append("<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
//stanza.append(authenticationText);
//stanza.append("</response>");
//getSASLAuthentication().send(stanza.toString());
getSASLAuthentication().send(responseStanza);
}
}
It is then called thus from the JabberSmackAPI:
public void login(String userName, String password) throws XMPPException
{
SASLAuthentication.registerSASLMechanism("DIGEST-MD5",MySASLDigestMD5Mechanism. class);
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com",5222);
config.setSASLAuthenticationEnabled(true);
config.setRosterLoadedAtLogin (true);
connection = new XMPPConnection(config);
connection.connect();
connection.login(userName, password);
}

Categories