[icloud - SOAP] SOAP, digest and Login

Basic Tutorials concerning: GUI, Views, Activites, XML, Layouts, Intents, ...

[icloud - SOAP] SOAP, digest and Login

Postby Tobias » Fri Feb 19, 2010 4:48 pm

[icloud - SOAP] SOAP, digest and Login


What you learn: You will learn how to call a server using SOAP (A String body and nost just value-pairs), DefaultHTTPClient and how to set credentials (username, password) for authentication with digest.

Why? What's next? This is my first tutorial in a series of tutorials where we will be learning using SOAP, parsing XML, XPATH and uploading/downloading files in the cloud (icloud.com). Login and making the first SOAP call is the basics we need for the future tutorials. Where we will be taking care of the result, parse it and navigate through it using XPATH.

Difficulty: 2 of 5

Requires: A free or premium account at icloud.com

Description: Okay, so in this initial tutorial I won't make anything fancy, just two functions. For the more advanced tutorials I will provide packages and .class-files if you like.

Now to the fun part, coding!

The first function that we will look into is the one preparing the SOAP-call calling the function callServer and then "taking care" of the result.
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public void login() {
  2.                 String soapAction = "login";
  3.                 String soapBody = "";
  4.                 byte[] loginDoc = callServer(soapAction, soapBody);
  5.                
  6.                 // Parse the loginDoc-XML...
  7.         }
Parsed in 0.032 seconds, using GeSHi 1.0.8.4


The callServer function that we will look at soon will generate the SOAP-Envelope and surrounding <login></login> tag in the SOAP-body, that's all that is needed for the login call, that's why the soapBody variable in this example is empty.

This is what the request body will look like:
Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
  2. <SOAP-ENV:Body>
  3. <login/>
  4. </SOAP-ENV:Body>
  5. </SOAP-ENV:Envelope>
Parsed in 0.001 seconds, using GeSHi 1.0.8.4


Now to the heart of this tutorial, the callServer function.
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public byte[] callServer(String soapAction, String body) {
  2.                 byte[] result = null;
  3.                 DefaultHttpClient httpclient = new DefaultHttpClient();
  4.                
  5.                 HttpProtocolParams.setUseExpectContinue(httpclient.getParams(), false); // Comment: 1
  6.                
  7.  
  8.             httpclient.getCredentialsProvider().setCredentials(
  9.                     new AuthScope("os.icloud.com", 80, null, "Digest"),
  10.                     new UsernamePasswordCredentials(username, password)); // Comment: 2, 3
  11.            
  12.             HttpPost httppost = new HttpPost("http://os.icloud.com/v1/"); // Comment: 3
  13.             httppost.setHeader("soapaction", soapAction);
  14.             httppost.setHeader("Content-Type", "text/xml; charset=utf-8");
  15.  
  16.                 final StringBuffer soap = new StringBuffer(); // Comment: 4
  17.                 soap.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SOAP-ENV:Body>");
  18.                         soap.append("<");
  19.                 soap.append(soapAction);
  20.                 soap.append(">");
  21.                 soap.append(body);
  22.                 soap.append("</");
  23.                 soap.append(soapAction);
  24.                 soap.append("></SOAP-ENV:Body></SOAP-ENV:Envelope>");
  25.                        
  26.                 try {
  27.                         HttpEntity entity = new StringEntity(soap.toString()); // Comment: 5
  28.                         httppost.setEntity(entity);
  29.                         HttpResponse response = httpclient.execute(httppost);
  30.                         HttpEntity r_entity = response.getEntity();
  31.  
  32.                 if( r_entity != null ) {
  33.                     result = new byte[(int) r_entity.getContentLength()];
  34.                 if(r_entity.isStreaming()) {
  35.                         DataInputStream is = new DataInputStream(r_entity.getContent()); // Comment: 6
  36.                         is.readFully(result);
  37.                 }
  38.                 }
  39.                 } catch(Exception E) {
  40.                         // Do something, I won't discuss error handling in this tutorial
  41.                 }
  42.                
  43.                 httpclient.getConnectionManager().shutdown();
  44.                 return result;
  45.         }
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


Comment: 1
In this case with the os.icloud.com server we have to set this one to false, since this feature isn't supported by the server. This is one of the KEY points in this tutorial. Default value is true, and might be supported by other systems.

Comment: 2
These rows you probably recognize from other tutorials, nothing special just making sure you provide you're username and password, from the private variables (You'll see them in the full class code below) in this example or from a UI form. (Recommended is to use a login form for public applications because you don't want others to use your account).

Comment: 3
This is the URL and Realm to the icloud servers where you can reach their API, change this only if you don't want to access icloud.

Comment: 4
Use the StringBuffer to build your SOAP-envelope, this is the best way of building your envelope when building for performance, using the DOM and building a real XML-document is just a waste in this case.

Comment: 5
This is another KEY point of this tutorial. I have seen many asking how to POST a body that looks the way you want, and not only value-pairs, well this is one way. There are other nice classes aswell, like the FileEntity that you can use for uploading files.

Comment: 6
The DataInputStream is a really nice universal InputStream when working with this kind of tasks (files and xml), you can read it all, and the readFully function won't release it's control untill all data is read, so you don't need to worry about reading only the half response. Simple and powerfull in this case.

Now the callServer function only returns the XML-doc in a byte-array, and the login-function does nothing to it, don't worry to much, that's what we will look into the next tutorial. That I will post shortly.
Rumours are about that we will see a public API for icloud.com shortly :) Which means hopefully in the future I can refer to a API where you'll find all methods for accessing the filesystem and all social functions.

Now here is the full thing, see you soon!
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package com.xcerion.android.tutorials;
  2.  
  3. import java.io.DataInputStream;
  4.  
  5. import org.apache.http.HttpEntity;
  6. import org.apache.http.HttpResponse;
  7. import org.apache.http.auth.AuthScope;
  8. import org.apache.http.auth.UsernamePasswordCredentials;
  9. import org.apache.http.client.methods.HttpPost;
  10. import org.apache.http.entity.StringEntity;
  11. import org.apache.http.impl.client.DefaultHttpClient;
  12. import org.apache.http.params.HttpProtocolParams;
  13.  
  14. public class BaxideTiny {
  15.         // TODO: You need to edit these two lines (In the future we will make a login form and not use static data)
  16.         private String username = ""; // Edit to Your username at icloud.com
  17.         private String password = ""; // Edit to Your password associated with your icloud.com account
  18.        
  19.         public void login() {
  20.                 String soapAction = "login";
  21.                 String soapBody = "";
  22.                 byte[] loginDoc = callServer(soapAction, soapBody);
  23.                
  24.                 // Parse the loginDoc-XML...
  25.         }
  26.        
  27.         public byte[] callServer(String soapAction, String body) {
  28.                 byte[] result = null;
  29.                 DefaultHttpClient httpclient = new DefaultHttpClient();
  30.                
  31.                 HttpProtocolParams.setUseExpectContinue(httpclient.getParams(), false);
  32.                
  33.  
  34.             httpclient.getCredentialsProvider().setCredentials(
  35.                     new AuthScope("os.icloud.com", 80, null, "Digest"),
  36.                     new UsernamePasswordCredentials(username, password));
  37.            
  38.             HttpPost httppost = new HttpPost("http://os.icloud.com/v1/");
  39.             httppost.setHeader("soapaction", soapAction);
  40.             httppost.setHeader("Content-Type", "text/xml; charset=utf-8");
  41.            
  42.             System.out.println("executing request" + httppost.getRequestLine());
  43.  
  44.                 final StringBuffer soap = new StringBuffer();
  45.                 soap.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SOAP-ENV:Body>");
  46.                         soap.append("<");
  47.                 soap.append(soapAction);
  48.                 soap.append(">");
  49.                 soap.append(body);
  50.                 soap.append("</");
  51.                 soap.append(soapAction);
  52.                 soap.append("></SOAP-ENV:Body></SOAP-ENV:Envelope>");
  53.                        
  54.                 try {
  55.                         HttpEntity entity = new StringEntity(soap.toString());
  56.                         httppost.setEntity(entity);
  57.                         HttpResponse response = httpclient.execute(httppost);
  58.                         HttpEntity r_entity = response.getEntity();
  59.  
  60.                 if( r_entity != null ) {
  61.                     result = new byte[(int) r_entity.getContentLength()];
  62.                 if(r_entity.isStreaming()) {
  63.                         DataInputStream is = new DataInputStream(r_entity.getContent());
  64.                         is.readFully(result);
  65.                 }
  66.                 }
  67.                 } catch(Exception E) {
  68.                        
  69.                 }
  70.                
  71.                 httpclient.getConnectionManager().shutdown();
  72.                 return result;
  73.         }
  74. }
Parsed in 0.047 seconds, using GeSHi 1.0.8.4


Best regards,
Tobias
Tobias
Junior Developer
Junior Developer
 
Posts: 10
Joined: Mon Nov 23, 2009 11:29 pm

Top

Re: [icloud - SOAP] SOAP, digest and Login

Postby dbhasin » Wed Jul 07, 2010 8:20 am

I'm using URLConnection to connect to the main server. The server implements digest authentication. If I connect to the server with java library, the connection is successful. But if I use the same code for android, the connection is rejected for the reason - username and password do not match.

Here is the code for my Java project:
Code: Select all
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;

public class Connect {

   static StringBuilder sb;

   public static void main(String args[]) {
      String strURL = "http://hostserver/";
      final String username = "username";
      final String password = "password";

      Authenticator.setDefault(new Authenticator() {
           protected PasswordAuthentication getPasswordAuthentication() {
               PasswordAuthentication pa = new PasswordAuthentication (username, password.toCharArray());
               System.out.println(pa.getUserName() + ":" + new String(pa.getPassword()));
               return pa;
            }
           });
      BufferedReader in = null;
      StringBuffer sb = new StringBuffer();

      try {
         URL url = new URL(strURL);
         URLConnection connection = url.openConnection();
         in = new BufferedReader(new InputStreamReader(connection
               .getInputStream()));

         String line;

         while ((line = in.readLine()) != null) {
            sb.append(line);
         }
      } catch (java.net.ProtocolException e) {
         sb.append("User Or Password is wrong!");
         e.printStackTrace();
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         try {
            if (in != null) {
               in.close();
            }
         } catch (Exception e) {
            System.out.println("Exception");
         }
      }

      System.out.println("The Data is: " + sb.toString());

   }
}



The above code works fine and I'm able to connect to my host server which is implementing digest authentication. I'm unable to use the same code for Android to connect. Here is my android code:


Code: Select all
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class Connect extends Activity {
   static StringBuilder sb;

    @Override
   public void onCreate(Bundle savedInstanceState) {
       
        super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
         
         String strURL = "http://hostserver/";
      final String username = "username";
      final String password = "password";
      Authenticator.setDefault(new Authenticator() {
           protected PasswordAuthentication getPasswordAuthentication() {
               PasswordAuthentication pa = new PasswordAuthentication (username, password.toCharArray());
//               System.out.println(pa.getUserName() + ":" + new String(pa.getPassword()));
               return pa;
            }
           });
      BufferedReader in = null;
      StringBuffer sb = new StringBuffer();

      try {
         URL url = new URL(strURL);
         URLConnection connection = url.openConnection();
         in = new BufferedReader(new InputStreamReader(connection
               .getInputStream()));

         String line;

         while ((line = in.readLine()) != null) {
            sb.append(line);
         }
      } catch (java.net.ProtocolException e) {
         sb.append("User Or Password is wrong!");
         e.printStackTrace();
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         try {
            if (in != null) {
               in.close();
            }
         } catch (Exception e) {
            System.out.println("Exception");
         }
      }

      Log.d("DATA", sb.toString());

   }       
    }



If the same code works for Java, it should also work for Android.

The code loops in the Authenticator as it finds username and password not matching in the Android code for some reason which in fact are correct. The code runs perfect for Java project.
dbhasin
Freshman
Freshman
 
Posts: 3
Joined: Wed Jul 07, 2010 8:14 am

Re: [icloud - SOAP] SOAP, digest and Login

Postby Sivan » Thu Jul 22, 2010 12:17 pm

Any ScreenShots ??
Sivan
Junior Developer
Junior Developer
 
Posts: 14
Joined: Mon Jul 05, 2010 10:02 am
Location: Bangalore , India

Re: [icloud - SOAP] SOAP, digest and Login

Postby Tobias » Fri Jul 23, 2010 2:57 am

Screenshots for the tutorial or "dbhasin"'s problem?

Regards
Tobias
Tobias
Junior Developer
Junior Developer
 
Posts: 10
Joined: Mon Nov 23, 2009 11:29 pm

Re: [icloud - SOAP] SOAP, digest and Login

Postby Tobias » Fri Jul 23, 2010 3:01 am

dbhasin: Are you sure that classe's you use are the same versions in Android and in your Java Project? I Know that the apache implementations are older ones which miss some nice features that have been added "lately".

Have you debugged your http-traffic? Maybe the answear can be found in the http-request?

Regards
Tobias
Tobias
Junior Developer
Junior Developer
 
Posts: 10
Joined: Mon Nov 23, 2009 11:29 pm

Top

Return to Novice Tutorials

Who is online

Users browsing this forum: No registered users and 9 guests