Category Archives: java

Embedding OSGi into an Android application part 1

OSGi is a modular service platform written in Java. Individual components (called bundles) may provide services, and can be deployed or removed without restarting the whole OSGi framework. Knopflerfish is a complete open source implementation of the OSGi R4 v4.2 specifications maintained by Makewave.

Knopflerfish logo

The great thing about Android is that it can seamlessly integrate existing Java code and libraries. Even though it uses a VM, Dalvik, that utilizes a bytecode format that is not compatible with the original Java bytecode specification, existing jars and classes can be converted into Dalvik bytecode easily and thus used by Android applications. Since the OSGi framework itself and the bundles are just plain jars (with some extra manifest headers), they are also supposed to just work in Android. Indeed, in most cases they do, however, there are a few catches.

Note: this is the first part of a series of posts about how to embed OSGi into an Android application.

Continue reading

Implementing SMTP or IMAP XOAUTH authentication in Java

XOAUTH is a SASL authentication mechanism that can be used with the IMAP AUTHENTICATE and SMTP AUTH commands. It is based on OAuth, and uses the same OAuth parameters to authenticate against an SMTP or IMAP server. It is backed by Google, and you can use XOAUTH with Gmail SMTP or IMAP to authenticate without an username and its corresponding password.

You need to go through the usual “OAuth dance” to acquire an access token and its corresponding secret. Once you have that, you can generate the OAuth signature the usual OAuth way, with the following parameters:

  1. The HTTP method is GET,
  2. The URL has the following form: https://mail.google.com/mail/b/[user email address]/[protocol]/, where protocol is either “smtp” or “imap” (without quotes) and
  3. All the usual OAuth parameters except “oauth_signature”.

The actual XOAUTH string will be constructed from the HTTP method, the URL as defined above and the OAuth parameters, the three parts concatenated with space characters, and then base64-encoded. You can find examples for it at Google’s reference page.

We can build the XOAUTH string in a straightforward way with signpost and our Android OAuth helper class (if you’d like to use it in plain Java, just remove the Log lines). Since many people have asked for the source code of the class, here it goes the whole stuff as used in SMSForwarder.


package com.nilvec.oauth;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.SortedSet;
import java.util.Map.Entry;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.util.Log;

import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthProvider;
import oauth.signpost.commonshttp.HttpRequestAdapter;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;
import oauth.signpost.exception.OAuthNotAuthorizedException;
import oauth.signpost.http.HttpParameters;
import oauth.signpost.signature.HmacSha1MessageSigner;
import oauth.signpost.signature.OAuthMessageSigner;

public class OAuthHelper {

    private static final String TAG = "OAuthHelper";

    private OAuthConsumer mConsumer;
    private OAuthProvider mProvider;

    private String mCallbackUrl;

    public OAuthHelper(String consumerKey, String consumerSecret,
            String scope, String callbackUrl, String appname)
    throws UnsupportedEncodingException {
        String reqUrl;
        if (appname == null)
            reqUrl = OAuth.addQueryParameters(
                    "https://www.google.com/accounts/OAuthGetRequestToken",
                    "scope", scope);
        else
            reqUrl = OAuth.addQueryParameters(
                    "https://www.google.com/accounts/OAuthGetRequestToken",
                    "scope", scope, "xoauth_displayname", appname);

        mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);

        mProvider = new CommonsHttpOAuthProvider(reqUrl,
                "https://www.google.com/accounts/OAuthGetAccessToken",
                "https://www.google.com/accounts/OAuthAuthorizeToken?hd=default");
        mProvider.setOAuth10a(true);

        mCallbackUrl = (callbackUrl == null ? OAuth.OUT_OF_BAND : callbackUrl);
    }

    public String getRequestToken()
    throws OAuthMessageSignerException, OAuthNotAuthorizedException,
    OAuthExpectationFailedException, OAuthCommunicationException {
        String authUrl =
                mProvider.retrieveRequestToken(mConsumer, mCallbackUrl);
        return authUrl;
    }

    public String[] getAccessToken(String verifier)
    throws OAuthMessageSignerException, OAuthNotAuthorizedException,
    OAuthExpectationFailedException, OAuthCommunicationException {
        mProvider.retrieveAccessToken(mConsumer, verifier);
        return new String[] {
                mConsumer.getToken(), mConsumer.getTokenSecret()
        };
    }

    public String[] getToken() {
        return new String[] {
                mConsumer.getToken(), mConsumer.getTokenSecret()
        };
    }

    public void setToken(String token, String secret) {
        mConsumer.setTokenWithSecret(token, secret);
    }

    public String getUrlContent(String url)
    throws OAuthMessageSignerException, OAuthExpectationFailedException,
    OAuthCommunicationException, IOException {
        HttpGet request = new HttpGet(url);

        // sign the request
        mConsumer.sign(request);

        // send the request
        HttpClient httpClient = new DefaultHttpClient();
        HttpResponse response = httpClient.execute(request);

        // get content
        BufferedReader in = new BufferedReader(
                new InputStreamReader(response.getEntity().getContent()));
        StringBuffer sb = new StringBuffer("");
        String line = "";
        String NL = System.getProperty("line.separator");
        while ((line = in.readLine()) != null)
            sb.append(line + NL);
        in.close();

        return sb.toString();
    }

    public String buildXOAuth(String email) {
        String url =
            String.format("https://mail.google.com/mail/b/%s/smtp/", email);
        HttpRequestAdapter request = new HttpRequestAdapter(new HttpGet(url));

        // Sign the request, the consumer will add any missing parameters
        try {
            mConsumer.sign(request);
        } catch (OAuthMessageSignerException e) {
            Log.e(TAG, "failed to sign xoauth http request " + e);
            return null;
        } catch (OAuthExpectationFailedException e) {
            Log.e(TAG, "failed to sign xoauth http request " + e);
            return null;
        } catch (OAuthCommunicationException e) {
            Log.e(TAG, "failed to sign xoauth http request " + e);
            return null;
        }
        HttpParameters params = mConsumer.getRequestParameters();

        // Since signpost doesn't put the signature into params,
        // we've got to create it again.
        OAuthMessageSigner signer = new HmacSha1MessageSigner();
        signer.setConsumerSecret(mConsumer.getConsumerSecret());
        signer.setTokenSecret(mConsumer.getTokenSecret());
        String signature;
        try {
            signature = signer.sign(request, params);
        } catch (OAuthMessageSignerException e) {
            Log.e(TAG, "invalid oauth request or parameters " + e);
            return null;
        }
        params.put(OAuth.OAUTH_SIGNATURE, OAuth.percentEncode(signature));

        StringBuilder sb = new StringBuilder();
        sb.append("GET ");
        sb.append(url);
        sb.append(" ");
        int i = 0;
        for (Entry<String, SortedSet<String>> entry : params.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue().first();

            int size = entry.getValue().size();
            if (size != 1)
                Log.d(TAG, "warning: " + key + " has " + size + " values");

            if (i++ != 0)
                sb.append(",");
            sb.append(key);
            sb.append("=\"");
            sb.append(value);
            sb.append("\"");
        }
        Log.d(TAG, "xoauth encoding " + sb);

        Base64 base64 = new Base64();
        try {
            byte[] buf = base64.encode(sb.toString().getBytes("utf-8"));
            return new String(buf, "utf-8");
        } catch (UnsupportedEncodingException e) {
            Log.e(TAG, "invalid string " + sb);
        }

        return null;
    }

}

Don’t forget to provide feedback if you find this class or article useful. Happy hacking!

Implementing client-side OAuth on Android

OAuth is becoming the de-facto protocol to allow access to your data and services without sharing user password. Effectively all the big names such as Twitter, Google, Yahoo or LinkedIn have already implemented it. There are quite a few libraries and code samples in all the popular programming languages out there to implement OAuth in your desktop, mobile or web application as well.

There are guides for Android too, however most of them are not up to date, accurate or just difficult to comprehend if you are in a hurry. Here we provide a few easy to follow steps with some explanation how it can be done in a straightforward way.

First, a short summary how OAuth works. It is based on cryptography, where

  1. a token and a corresponding secret is acquired by a consumer (a desktop or web application) from a provider (a server in the cloud),
  2. this token is authorized by the user as valid and allowed to access their data and then
  3. the token is upgraded, and this can then be used from then on until it is revoked by same user who authorized it.

The token acquired in the first step is called a request token, this is where you usually specify which service you would like to get access to; it is called scope. The second step is called authorization, after which control can be passed back to the consumer application via a callback. The final token that is received in the third step is called access token. This can be used for a long period of time, it won’t expire (but, as mentioned, the user can revoke it any time). It is basically a short string, with a corresponding secret string, and once the application acquired it, it can be used to sign HTTP requests, thus authenticating it for the provider. All three steps have a corresponding URL at the provider, to where an HTTP request is sent to get the token or manipulate it.

If you need further details, there’s a good article with API reference at code.google.com, and another very detailed overview with figures here.

We will use the excellent signpost Java library to implement OAuth access to Gmail. Just download at least the signpost-core and signpost-commonshttp4 jars, copy them to the lib/ folder inside your Android project, right click on the project, and under Properties/Java Build Path you can add them to the build path:

Adding the signpost jars to the build path

We will implement OAuth support via a helper class called OAuthHelper. The two single most important classes provided by signpost are OAuthConsumer and OAuthProvider; before diving into actual communications, we set these up first:


	private OAuthConsumer mConsumer;
	private OAuthProvider mProvider;

	private String mCallbackUrl;

	public OAuthHelper(String consumerKey, String consumerSecret,
			String scope, String callbackUrl)
	throws UnsupportedEncodingException {
		mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
		mProvider = new CommonsHttpOAuthProvider(
				"https://www.google.com/accounts/OAuthGetRequestToken?scope="
				+ URLEncoder.encode(scope, "utf-8"),
				"https://www.google.com/accounts/OAuthGetAccessToken",
				"https://www.google.com/accounts/OAuthAuthorizeToken?hd=default");
		mProvider.setOAuth10a(true);
		mCallbackUrl = (callbackUrl == null ? OAuth.OUT_OF_BAND : callbackUrl);
	}

The consumerKey and consumerSecret strings depend on your consumer application, you can use anonymous for both. Later you might want to register your application at the provider (Google in this case), which will issue a key and secret for your app. To access an user’s Gmail inbox the scope is “https://mail.google.com/”, the URLs for OAuth are in the constructor of the helper class.

The callbackUrl variable can be used to pass an URL to the provider which will be called once your token is authorized. On Android you can register a special URL scheme to your application, thus the browser will fire up an activity of your app once authorization has been done. E.g. if you would like MyActivity to be called put the following into your app manifest:


<activity android:name="MyActivity">
	<intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="my-activity"/>
	</intent-filter>
</activity>

and pass “my-activity://mywebsite.com/” as the callback URL. This also has the side effect of identifying your application as mywebsite.com at the provider (at least at Google). Your application will get back a verifier code via the callback as a query parameter to the URL, where the query key is “verifier”. You will need this later.

As a next step, retrieve the request token:


	public String getRequestToken()
	throws OAuthMessageSignerException, OAuthNotAuthorizedException,
	OAuthExpectationFailedException, OAuthCommunicationException {
		String authUrl = mProvider.retrieveRequestToken(mConsumer, mCallbackUrl);
		return authUrl;
	}

Once you got back the authentication URL from this method, just start up the browser with it:


try {
	String uri = helper.getRequestToken();
	startActivity(new Intent("android.intent.action.VIEW", Uri.parse(uri)));
} catch (...) {
}

In your OnResume() method in MyActivity you can catch the callback and retrieve the verifier, and upgrade your token with it:


		String[] token = getVerifier();
		if (token != null)
			String accessToken[] = getAccessToken(token[1]);

...

	private String[] getVerifier() {
		// extract the token if it exists
		Uri uri = this.getIntent().getData();
		if (uri == null) {
			return null;
		}

		String token = uri.getQueryParameter("oauth_token");
		String verifier = uri.getQueryParameter("oauth_verifier");
		return new String[] { token, verifier };
	}

In our helper class:


	public String[] getAccessToken(String verifier)
	throws OAuthMessageSignerException, OAuthNotAuthorizedException,
	OAuthExpectationFailedException, OAuthCommunicationException {
		mProvider.retrieveAccessToken(mConsumer, verifier);
		return new String[] {
				mConsumer.getToken(), mConsumer.getTokenSecret()
		};
	}

And that’s it. Just make sure you save the access token and its secret. You can now use signpost to sign your HTTP queries e.g.


	OAuthConsumer consumer = new CommonsHttpOAuthConsumer(accessToken[0], accessToken[1]);

	HttpGet request = new HttpGet(url);

       // sign the request
       consumer.sign(request);

       // send the request
       HttpClient httpClient = new DefaultHttpClient();
       HttpResponse response = httpClient.execute(request);

Happy hacking!

Update: fixed some typos in code snippets.

Email sending example

As promised, here’s a simple example on how to use the SMTP library. If the username and the password are replaced with actually existing user credentials then this code snippet can send mails via Gmail.
Continue reading

Sending email without user interaction in Android

To send emails from an Activity in Android the easiest way is to fire up the built-in mail application with an Intent, and let it take care of the low-level details about how to assemble the message, negotiate a secure connection with the mail server and send it using the proper protocol (as suggested here).  However, there may be cases where this is not applicable, like when the mail should be sent in the background (from a Service, for instance) with no user intervention.  For some users it may not sound like the best idea to just send out mails on their behalf without explicit permission, but there are legitimate use cases where “silent” emailing is necessary.  What SMSForwarder does (automatic forwarding of incoming SMS to a mailbox) is one such case.  If anyone is concerned about privacy — it is easy to set up an additional email account and use it for archiving SMS.  SMSForwarder does not use the primary Gmail account used by Google apps in Android, the SMTP user and server should be set up directly in the application.

So the question is how to send mails with no user interaction in Android.  Since SMTP is not a difficult protocol, it could be tempting to come up with a bunch of simple SMTP client classes and send outgoing emails directly to the mail server of the recipient (technically speaking, to the MX of the domain the user has an email address in).  However, there are a few catches.  Any reasonable mail server can store emails for temporary network errors, and this is quite difficult to do correctly and efficiently, especially on a mobile device.  MX records also have priorities, and in theory they should be used in increasing priority order when sending emails to a domain.  There are lots of picky SMTP servers out there, so a simplistic approach may not always be adequate.  And, as always, we should not reinvent the wheel.

If one wants to handle SMTP or IMAP in Java the obvious choice of library is javax.mail that was released as open source by Sun some time ago.  This is a great package, with outstanding support for SMTP including ESMTP commands like AUTH and STARTTLS — these are required by virtually every mail server if anyone wants to use them as a relay (that is, sending mail through them to an external mail server).  It supports MIME too, so one can use it as a full-featured email library — as a matter of fact, javax.mail is *the* library to do emailing in Java.  The only drawback is its binding to javax.activation, which in turn needs a handful of AWT classes.  Most Android developers are now getting why it is not so straightforward to use javax.mail on Android: since Android implements its own widgets in order to stay away from the somewhat bloated and bulky AWT, either these AWT classes would be needed to be brought to Android, or the dependency on AWT should be eliminated.  Some people claim they have done it, but only a couple of jars can be found with no source code, and most developers are having difficulties even just making them work.

The Jakarta Commons Net project also produces an extensive networking library with SMTP support which basically has no external dependencies like javax.mail.  Unfortunately, it also has its own catch: it only supports basic SMTP commands and semantics, no ESMTP, thus making it a no-go for any serious mail client (good luck relaying a mail via an average mail server without AUTH or STARTTLS).  Nevertheless, this library seemed to be an ideal candidate to extend it with the necessary ESMTP features and make SMSForwarder be able to send mails.

What we did is we implemented the EHLO, AUTH and STARTTLS commands in the commons net library, reusing some code snippets from javax.mail.  The currently supported authentication mechanisms are ‘plain’ and ‘login’, but we are also planning to add support for digest-md5 authentication.  The patched library is tested with Gmail and a few other mail servers too.

You can find the patch that can be applied on top of the latest stable Jakarta Commons Net library (version 2.0) here.  For base64 encoding/decoding the Commons Codec library is used.  A conveniently packaged, patched library (with source code) can be downloaded here.

Feel free to comment, give us feedback, or just drop us a line where and how you are using this library.