Ksoap 3.0.0 not work with basic authentication - java

I try to use KSOAP2 with Basic Authentication. I´m download ksoap2-android-assembly-3.0.0-jar-with-dependencies.jar, ksoap2-extras-3.0.0.jar, ksoap2-extra-ntlm-3.0.0.jar. I Tried to use the code below:
ArrayList<HeaderProperty> headerProperty = new ArrayList<HeaderProperty>();
headerProperty.add(new HeaderProperty("Authorization", "Basic " +
org.kobjects.base64.Base64.encode("user:password".getBytes())));
it's generate the error:
java.io.IOException: HTTP request failed, HTTP status: 401
ERROR:java.io.IOException:HTTP request failed, HTTP status: 401
I Tried to use the code below too:
HttpTransportBasicAuth androidHttpTpAut = new HttpTransportBasicAuth(URL, "user", "password");
androidHttpTpAut.getServiceConnection().connect();
again not work, generate the error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/ksoap2/transport/HttpTransport
at java.lang.ClassLoader.defineClass1(Native Method)
Anybody do this work fine ?

After many test, I found that the code below need to change:
ArrayList headerProperty = new ArrayList();
headerProperty.add(new HeaderProperty("Authorization", "Basic " +
org.kobjects.base64.Base64.encode("user:password".getBytes())));
androidHttpTransport.call(SOAP_ACTION, envelope);
Change above androidHttpTransport.call() to below polymorphic method:
androidHttpTransport.call(SOAP_ACTION, envelope, headerProperty);
It´s necessary put the parameter headerProperty in method androidHttpTransport.call.
And, I use only ksoap2-android-assembly-3.0.0-jar-with-dependencies.jar in project.
Thanks

You can try the following code. It worked in my case, hope it will help you too.
Create a class called HttpTransportBasicAuth
import org.ksoap2.transport.*;
import org.ksoap2.transport.HttpTransportSE;
import java.io.*;
public class HttpTransportBasicAuth extends HttpTransportSE {
private String username;
private String password;
public HttpTransportBasicAuth(String url, String username, String password) {
super(url);
this.username = username;
this.password = password;
}
public ServiceConnection getServiceConnection() throws IOException {
ServiceConnectionSE midpConnection = new ServiceConnectionSE(url);
addBasicAuthentication(midpConnection);
return midpConnection;
}
protected void addBasicAuthentication(ServiceConnection midpConnection) throws IOException {
if (username != null && password != null) {
StringBuffer buf = new StringBuffer(username);
buf.append(':').append(password);
byte[] raw = buf.toString().getBytes();
buf.setLength(0);
buf.append("Basic ");
org.kobjects.base64.Base64.encode(raw, 0, raw.length, buf);
midpConnection.setRequestProperty("Authorization", buf.toString());
}
}
}
And then, change the following in your proxy class (refer the proxy class below)
protected org.ksoap2.transport.Transport createTransport()
{
return new HttpTransportBasicAuth(url,username,password);
}
Proxy class
import java.util.List;
import org.ksoap2.HeaderProperty;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.AttributeContainer;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
public class Z_WS_SCAN_REPLENISHMENT
{
interface IWcfMethod
{
ExtendedSoapSerializationEnvelope CreateSoapEnvelope() throws java.lang.Exception;
Object ProcessResult(ExtendedSoapSerializationEnvelope envelope,SoapObject result) throws java.lang.Exception;
}
String url="http://example.com/z_ws_scan_replenishment/200/z_ws_scan_replenishment/z_ws_scan_replenishment";
String username = "username";
String password = "password";
int timeOut=60000;
public List< HeaderProperty> httpHeaders;
IServiceEvents callback;
public Z_WS_SCAN_REPLENISHMENT(){}
public Z_WS_SCAN_REPLENISHMENT (IServiceEvents callback)
{
this.callback = callback;
}
public Z_WS_SCAN_REPLENISHMENT(IServiceEvents callback,String url)
{
this.callback = callback;
this.url = url;
}
public Z_WS_SCAN_REPLENISHMENT(IServiceEvents callback,String url,int timeOut)
{
this.callback = callback;
this.url = url;
this.timeOut=timeOut;
}
protected org.ksoap2.transport.Transport createTransport()
{
return new HttpTransportBasicAuth(url,username,password);
}
protected ExtendedSoapSerializationEnvelope createEnvelope()
{
return new ExtendedSoapSerializationEnvelope();
}
protected void sendRequest(String methodName,ExtendedSoapSerializationEnvelope envelope,org.ksoap2.transport.Transport transport) throws java.lang.Exception
{
transport.call(methodName, envelope,httpHeaders);
}
Object getResult(Class destObj,SoapObject source,String resultName,ExtendedSoapSerializationEnvelope __envelope) throws java.lang.Exception
{
if (source.hasProperty(resultName))
{
Object j=source.getProperty(resultName);
if(j==null)
{
return null;
}
Object instance=__envelope.get((AttributeContainer)j,destObj);
return instance;
}
else if( source.getName().equals(resultName)) {
Object instance=__envelope.get(source,destObj);
return instance;
}
return null;
}
public Bapireturn1 ZScanReplenishment(final String ILgnum,final String IPernr,final String IScannedId,final String IScannedLgpl ) throws java.lang.Exception
{
return (Bapireturn1)execute(new IWcfMethod()
{
#Override
public ExtendedSoapSerializationEnvelope CreateSoapEnvelope(){
ExtendedSoapSerializationEnvelope __envelope = createEnvelope();
SoapObject __soapReq = new SoapObject("urn:sap-com:document:sap:soap:functions:mc-style", "ZScanReplenishment");
__envelope.setOutputSoapObject(__soapReq);
PropertyInfo __info=null;
__info = new PropertyInfo();
__info.namespace="";
__info.name="ILgnum";
__info.type=PropertyInfo.STRING_CLASS;
__info.setValue(ILgnum);
__soapReq.addProperty(__info);
__info = new PropertyInfo();
__info.namespace="";
__info.name="IPernr";
__info.type=PropertyInfo.STRING_CLASS;
__info.setValue(IPernr);
__soapReq.addProperty(__info);
__info = new PropertyInfo();
__info.namespace="";
__info.name="IScannedId";
__info.type=PropertyInfo.STRING_CLASS;
__info.setValue(IScannedId);
__soapReq.addProperty(__info);
__info = new PropertyInfo();
__info.namespace="";
__info.name="IScannedLgpl";
__info.type=PropertyInfo.STRING_CLASS;
__info.setValue(IScannedLgpl);
__soapReq.addProperty(__info);
return __envelope;
}
#Override
public Object ProcessResult(ExtendedSoapSerializationEnvelope __envelope,SoapObject __result)throws java.lang.Exception {
return (Bapireturn1)getResult(Bapireturn1.class,__result,"EReturn",__envelope);
}
},"");
}
protected Object execute(IWcfMethod wcfMethod,String methodName) throws java.lang.Exception
{
org.ksoap2.transport.Transport __httpTransport=createTransport();
ExtendedSoapSerializationEnvelope __envelope=wcfMethod.CreateSoapEnvelope();
sendRequest(methodName, __envelope, __httpTransport);
Object __retObj = __envelope.bodyIn;
if (__retObj instanceof SoapFault){
SoapFault __fault = (SoapFault)__retObj;
throw convertToException(__fault,__envelope);
}else{
SoapObject __result=(SoapObject)__retObj;
return wcfMethod.ProcessResult(__envelope,__result);
}
}
java.lang.Exception convertToException(SoapFault fault,ExtendedSoapSerializationEnvelope envelope)
{
return new java.lang.Exception(fault.faultstring);
}
}
These changes did the magic for me. Hope it will work for you as well.

Related

Android - Error when storing parsed xml data to sql

I am getting a java.lang.NullPointerException error when storing xml data parsed from a URL on my localhost (http://10.0.0.22/cardealers.xml) to sql. Here is the xml am parsing:
<Providers>
<CarDealer name="BEFORWARD" id="1">
<CarMake name="Toyota" id="20">
<CarModel name="Belta" id="21"/>
<CarModel name="RunX" id="22"/>
<CarModel name="Corolla" id="23"/>
</CarMake>
<CarMake name="Nissan" id="30">
<CarModel name="Murano" id="31"/>
<CarModel name="Pathfinder" id="32"/>
<CarModel name="Navara" id="33"/>
</CarMake>
</CarDealer>
</Providers>
In my xml handler class, I passed my xml like so:
public class SAXXMLHandler extends DefaultHandler {
private List<CarMake> carMaker;
private String tempVal;
// to maintain context
private CarMake carmake;
public SAXXMLHandler() {
carMaker = new ArrayList<CarMake>();
}
public List<CarMake> getCarMake() {
return carMaker;
}
// Event Handlers
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// reset
tempVal = "";
if (qName.equalsIgnoreCase("CarMake")) {
// create a new instance of CarMake
carmake = new CarMake();
carmake.setName(attributes.getValue("name"));
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
tempVal = new String(ch, start, length);
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (qName.equalsIgnoreCase("CarMake")) {
// add it to the list
carMaker.add(carmake);
} else if (qName.equalsIgnoreCase("CarModel")) {
carmake.setCarModel(tempVal);
}
}
}
Then using AsyncTask in Sell.java
public class Sell extends Activity implements
View.OnClickListener, AdapterView.OnItemClickListener {
static final String URL = "http://10.0.0.22/cardealers.xml";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sell);
//new GetXMLTask().execute();
new GetXMLTask(this).execute();
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
}
#Override
public void onClick(View view) {
GetXMLTask task = new GetXMLTask(this);
task.execute(new String[]{URL});
}
//private inner class extending AsyncTask
private class GetXMLTask extends AsyncTask<String, Void, List<Service>> {
private Activity context;
public GetXMLTask(Activity context) {
this.context = context;
}
/* uses HttpURLConnection to make Http request from Android to download
the XML file */
private String getXmlFromUrl(String urlString) {
StringBuffer output = new StringBuffer("");
try {
InputStream stream = null;
URL url = new URL(urlString);
URLConnection connection = url.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setRequestMethod("GET");
httpConnection.connect();
if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
stream = httpConnection.getInputStream();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(stream));
String s = "";
while ((s = buffer.readLine()) != null)
output.append(s);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return output.toString();
}
#Override
protected List<CarMake> doInBackground(String... urls) {
List<CarMake> carMaker = null;
String xml = null;
for (String url : urls) {
xml = getXmlFromUrl(url);
InputStream stream = new ByteArrayInputStream(xml.getBytes());
carMaker = SAXXMLParser.parse(stream);
}
// stream.close();
return carMaker;
}
#Override
protected void onPostExecute(List<CarMake> carMaker) {
if (carMaker==null){
Toast.makeText(Sell.this, "carMaker is empty..", Toast.LENGTH_LONG).show();
} else {
E_VodaDB myE_Voda = new E_VodaDB(this.context);
myE_Voda.InsertData(carMaker);
}
}
}
}
As can be seen, my doInBackground() returns a result, carMaker. Then in my OnPostExecute(), I am passing the carMaker arraylist to my databases class to insert in db.
// Adding new service
public void InsertData(List<CarMake> carMaker) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(CARMAKE_NAME, carMaker.get(0).getCarMake()); // CarMake Names
// Inserting Row
db.insert(TABLE_CARDEALER, null, values);
db.close(); // Closing database connection
}
}
I get the following error when I run the app in Android Studio:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)' on a null object reference
Pointing to my Sell.java in my onPostExecute(). It seems the carMaker arraylist returned from doInBackground() is empty or it is in a different data type that cannot be directly stored into db. How would I go about fixing this error? Please note am a newbie to android
on doInBackground() you create arraylist but forget to initialize. try this.
#Override
protected List<CarMake> doInBackground(String... urls) {
List<CarMake> carMaker = new ArrayList<CarMake>();
String xml = null;
for (String url : urls) {
xml = getXmlFromUrl(url);
InputStream stream = new ByteArrayInputStream(xml.getBytes());
carMaker = SAXXMLParser.parse(stream);
}
// stream.close();
return carMaker;
}
you pass the null instance of current class context in this:
#Override
protected void onPostExecute(List<CarMake> carMaker) {
//E_DB myE_db = new E_DB(null);// replace this to
E_DB myE_db = new E_DB(this);
myE_db.InsertData(carMaker);
}
}
Happy coding!!

How to get a byte[] from a SoapObject

I have a web service that returns an ArrayList of object Home... this is my class Home:
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
public class Home implements Serializable {
public void setPercorso(String percorso) {
this.percorso = percorso;
}
public String getPercorso() {
return percorso;
}
public void setNomignolo(String nomignolo) {
this.nomignolo = nomignolo;
}
public void setNome(String nome) {
this.nome = nome;
}
public void setUtente(String utente) {
this.utente = utente;
}
public void setFamiglia(String famiglia) {
this.famiglia = famiglia;
}
public void setFoto(byte[] foto) {
this.foto = foto;
}
public String getNomignolo() {
return nomignolo;
}
public String getNome() {
return nome;
}
public String getUtente() {
return utente;
}
public String getFamiglia() {
return famiglia;
}
public byte[] getFoto() {
return foto;
}
public Home(String nomignolo, String nome, String utente, String famiglia, byte[] foto, String percorso) {
this.nomignolo = nomignolo;
this.nome = nome;
this.utente = utente;
this.famiglia = famiglia;
this.foto = foto;
this.percorso = percorso;
}
public Home() {
}
private String nomignolo;
private String nome;
private String utente;
private String famiglia;
private byte[] foto;
private String percorso;
public ArrayList<Home> caricaH() throws SQLException, ClassNotFoundException, MyException, FileNotFoundException {
ArrayList<Home> list = new ArrayList<Home>();
list= HomeDAO.caricaHome(this);
return list;
}
}
In the Android part i receive data in this way:
// other code bla bla bla...
public static ArrayList<Home> invokeHomeWS(String userName, String webMethName) {
boolean homeStatus = false;
ArrayList<Home> list = new ArrayList<Home>();
SoapObject request = new SoapObject(NAMESPACE, webMethName);
PropertyInfo unamePI = new PropertyInfo();
// Set Username
unamePI.setName("username");
// Set Value
unamePI.setValue(userName);
// Set dataType
unamePI.setType(String.class);
// Add the property to request object
request.addProperty(unamePI);
// Create envelope
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
// Set output SOAP object
envelope.setOutputSoapObject(request);
// Create HTTP call object
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try {
// Invoke web service
androidHttpTransport.call(SOAP_ACTION + webMethName, envelope);
// Get the response
java.util.Vector<SoapObject> rs = (java.util.Vector<SoapObject>) envelope.getResponse();
for(SoapObject cs : rs){
Home item = new Home();
item.setNomignolo(cs.getPropertyAsString("nomignolo"));
item.setUtente(cs.getPropertyAsString("utente"));
item.setNome(cs.getPropertyAsString("nome"));
item.setPercorso(cs.getPropertyAsString("percorso"));
item.setFoto((byte[])cs.getProperty("foto"));
item.setFamiglia(cs.getPropertyAsString("famiglia"));
list.add(item);
}
} catch (Exception e) {
//Assign Error Status true in static variable 'errored'
HomeActivity.errored = true;
e.printStackTrace();
}
return list;
}
everything works except
item.setFoto((byte[])cs.getProperty("foto"));...
it generates an error:
W/System.err﹕ java.lang.ClassCastException:
org.ksoap2.serialization.SoapPrimitive cannot be cast to byte[].
So my question is: how i can obtain the byte array from the SoapObject?
if it is return String, you can convert it to byte[] as below. try this out.
byte[] b = string.getBytes();
Just try this
byte[] bitmapdata = blob.toByteArray();
and if bitmap data is the byte array then getting bitmap goes like this
Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapdata , 0, bitmapdata .length);
Hope this help.

Server Authentication Module forwarding in Glassfish

I found this guide for developing your own Server Authentication Module (SAM) for Glassfish: http://docs.oracle.com/cd/E18930_01/html/821-2418/gizel.html
It seems pretty straightforward to verify some credentials (in HTTP Auth headers for instance), but my question is this:
Can I develop my SAM in such a way that I can forward the user to a specific page if he's not logged in?
Here's the example from the guide:
package tip.sam;
import java.io.IOException;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.MessagePolicy;
import javax.security.auth.message.callback.CallerPrincipalCallback;
import javax.security.auth.message.callback.GroupPrincipalCallback;
import javax.security.auth.message.callback.PasswordValidationCallback;
import javax.security.auth.message.module.ServerAuthModule;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.util.Base64;
public class MySam implements ServerAuthModule {
protected static final Class[]
supportedMessageTypes = new Class[]{
HttpServletRequest.class,
HttpServletResponse.class
};
private MessagePolicy requestPolicy;
private MessagePolicy responsePolicy;
private CallbackHandler handler;
private Map options;
private String realmName = null;
private String defaultGroup[] = null;
private static final String REALM_PROPERTY_NAME =
"realm.name";
private static final String GROUP_PROPERTY_NAME =
"group.name";
private static final String BASIC = "Basic";
static final String AUTHORIZATION_HEADER =
"authorization";
static final String AUTHENTICATION_HEADER =
"WWW-Authenticate";
public void initialize(MessagePolicy reqPolicy,
MessagePolicy resPolicy,
CallbackHandler cBH, Map opts)
throws AuthException {
requestPolicy = reqPolicy;
responsePolicy = resPolicy;
handler = cBH;
options = opts;
if (options != null) {
realmName = (String)
options.get(REALM_PROPERTY_NAME);
if (options.containsKey(GROUP_PROPERTY_NAME)) {
defaultGroup = new String[]{(String)
options.get(GROUP_PROPERTY_NAME)};
}
}
}
public Class[] getSupportedMessageTypes() {
return supportedMessageTypes;
}
public AuthStatus validateRequest(
MessageInfo msgInfo, Subject client,
Subject server) throws AuthException {
try {
String username =
processAuthorizationToken(msgInfo, client);
if (username ==
null && requestPolicy.isMandatory()) {
return sendAuthenticateChallenge(msgInfo);
}
setAuthenticationResult(
username, client, msgInfo);
return AuthStatus.SUCCESS;
} catch (Exception e) {
AuthException ae = new AuthException();
ae.initCause(e);
throw ae;
}
}
private String processAuthorizationToken(
MessageInfo msgInfo, Subject s)
throws AuthException {
HttpServletRequest request =
(HttpServletRequest)
msgInfo.getRequestMessage();
String token =
request.getHeader(AUTHORIZATION_HEADER);
if (token != null && token.startsWith(BASIC + " ")) {
token = token.substring(6).trim();
// Decode and parse the authorization token
String decoded =
new String(Base64.decode(token.getBytes()));
int colon = decoded.indexOf(':');
if (colon <= 0 || colon == decoded.length() - 1) {
return (null);
}
String username = decoded.substring(0, colon);
// use the callback to ask the container to
// validate the password
PasswordValidationCallback pVC =
new PasswordValidationCallback(s, username,
decoded.substring(colon + 1).toCharArray());
try {
handler.handle(new Callback[]{pVC});
pVC.clearPassword();
} catch (Exception e) {
AuthException ae = new AuthException();
ae.initCause(e);
throw ae;
}
if (pVC.getResult()) {
return username;
}
}
return null;
}
private AuthStatus sendAuthenticateChallenge(
MessageInfo msgInfo) {
String realm = realmName;
// if the realm property is set use it,
// otherwise use the name of the server
// as the realm name.
if (realm == null) {
HttpServletRequest request =
(HttpServletRequest)
msgInfo.getRequestMessage();
realm = request.getServerName();
}
HttpServletResponse response =
(HttpServletResponse)
msgInfo.getResponseMessage();
String header = BASIC + " realm=\"" + realm + "\"";
response.setHeader(AUTHENTICATION_HEADER, header);
response.setStatus(
HttpServletResponse.SC_UNAUTHORIZED);
return AuthStatus.SEND_CONTINUE;
// MAYBE SOMETHING HERE?
}
public AuthStatus secureResponse(
MessageInfo msgInfo, Subject service)
throws AuthException {
return AuthStatus.SEND_SUCCESS;
}
public void cleanSubject(MessageInfo msgInfo,
Subject subject)
throws AuthException {
if (subject != null) {
subject.getPrincipals().clear();
}
}
private static final String AUTH_TYPE_INFO_KEY =
"javax.servlet.http.authType";
// distinguish the caller principal
// and assign default groups
private void setAuthenticationResult(String name,
Subject s, MessageInfo m)
throws IOException,
UnsupportedCallbackException {
handler.handle(new Callback[]{
new CallerPrincipalCallback(s, name)
});
if (name != null) {
// add the default group if the property is set
if (defaultGroup != null) {
handler.handle(new Callback[]{
new GroupPrincipalCallback(s, defaultGroup)
});
}
m.getMap().put(AUTH_TYPE_INFO_KEY, ""MySAM");
}
}
}
Yes, you can do that in the validateRequest method.
Here is a simple example:
public AuthStatus validateRequest(MessageInfo messageInfo,
Subject clientSubject,
Subject serviceSubject) throws AuthException {
// clientSubject.getPrincipals() returns the principals
// check this set to know if the user is not logged in
// if the user is not logged in do the following
HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage();
response.sendRedirect("login.html");
}
It might be better to do it inside of a custom LoginModule (if you already know what that is), but I guess this depends on your requirements.
See also:
LoginModule Bridge Profile (JASPIC) in glassfish
Implementing container authentication in Java EE with JASPIC
JAAS for human beings

gson.toJson(obj) local class

Why does gson.toJson(obj) return null when I do this?
public class LoginServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
Gson gson = new Gson();
if (user != null) {
resp.setContentType("application/json");
resp.getWriter().println(gson.toJson(user));
} else {
class Url {
private String url;
Url(String url) {
this.url=url;
}
}
Url obj = new Url(userService.createLoginURL(req.getRequestURI()));
resp.setContentType("application/json");
resp.getWriter().println(gson.toJson(obj));
}
}
}
When I define the Url class outside the LoginServlet class it works and returns a json string of the url object?
class Url {
private String url;
Url(String url) {
this.url=url;
}
}
public class LoginServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
Gson gson = new Gson();
if (user != null) {
resp.setContentType("application/json");
resp.getWriter().println(gson.toJson(user));
} else {
Url obj = new Url(userService.createLoginURL(req.getRequestURI()));
resp.setContentType("application/json");
resp.getWriter().println(gson.toJson(obj));
}
}
}
I guess I'm still not sure what the actual problem you're having is...I can't get Gson to give me a null.
import com.google.gson.Gson;
public class GsonUrlParse {
public static void main( String[] args ) {
Url url = new Url( "foo" );
System.out.println( new Gson().toJson( url ) );
Url nurl = new Url( null );
System.out.println( new Gson().toJson( nurl ) );
}
}
class Url {
String url;
public Url( String url ) {
this.url = url;
}
}
Output:
{"url":"foo"}
{}

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