Search code examples
javaandroidgmailimap

Access gmail using imap with accountmanager token


I'm trying to implement a IMAP gmail client using the token received from the Android's AccountManager instead of using username and password.

Google provides this example of IMAP with oauth2 http://code.google.com/p/google-mail-oauth2-tools/source/browse/#svn%2Ftrunk%2Fjava%2Fcom%2Fgoogle%2Fcode%2Fsamples%2Foauth2 http://code.google.com/p/google-mail-oauth2-tools/wiki/JavaSampleCode

public static IMAPStore connectToImap(String host,
                                    int port,
                                    String userEmail,
                                    String oauthToken,
                                    boolean debug) throws Exception {
Properties props = new Properties();
props.put("mail.imaps.sasl.enable", "true");
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
Session session = Session.getInstance(props);
session.setDebug(debug);

final URLName unusedUrlName = null;
IMAPSSLStore store = new IMAPSSLStore(session, unusedUrlName);
final String emptyPassword = "";
store.connect(host, port, userEmail, emptyPassword);
return store;

}

public static void main(String args[]) throws Exception {
if (args.length != 2) {
  System.err.println(
      "Usage: OAuth2Authenticator <email> <oauthToken>");
  return;
}
String email = args[0];
String oauthToken = args[1];

initialize();

IMAPStore imapStore = connectToImap("imap.gmail.com",
                                    993,
                                    email,
                                    oauthToken,
                                    true);
System.out.println("Successfully authenticated to IMAP.\n");

}

But, when I run the code above, I get an exception of "Empty username or password". Could someone tell me how to access gmail using imap with xoauth2? Thanks.

Update 2013/02/20, below comes debug log

 02-19 17:27:20.098  1905: 1905 I/System.out : setDebug: JavaMail version 1.4.1    
 02-19 17:27:20.098  1905: 1905 I/System.out : mail.imap.fetchsize: 16384    
 02-19 17:27:20.106  1905: 1905 I/System.out : enable SASL    
 02-19 17:27:20.106  1905: 1905 I/System.out : SASL mechanisms allowed: XOAUTH2    
 02-19 17:27:21.340  1905: 1905 I/System.out : * OK Gimap ready for requests from 36.224.98.49 z8if14713202igb.53
 02-19 17:27:21.348  1905: 1905 I/System.out : A0 CAPABILITY
 02-19 17:27:21.598  1905: 1905 I/System.out : * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2
 02-19 17:27:21.598  1905: 1905 I/System.out : A0 OK Thats all she wrote! z8if14713202igb.53
 02-19 17:27:21.614  1905: 1905 I/System.out : IMAP DEBUG: AUTH: XOAUTH    
 02-19 17:27:21.614  1905: 1905 I/System.out : IMAP DEBUG: AUTH: XOAUTH2    
 02-19 17:27:21.614  1905: 1905 I/System.out : DEBUG: protocolConnect login, host=imap.gmail.com, [email protected], password=<non-null>    
 02-19 17:27:21.622  1905: 1905 I/System.out : IMAP SASL DEBUG: Mechanisms: XOAUTH2    
 02-19 17:27:21.817  1905: 1905 I/System.out : IMAP SASL DEBUG: Failed to create SASL client: myjavax.security.sasl.SaslException: Cannot instantiate class com.research.oauth.OAuth2SaslClientFactory [Caused by java.lang.InstantiationException: can't instantiate class com.research.oauth.OAuth2SaslClientFactory]
  02-19 17:27:21.817  1905: 1905 I/System.out : A1 LOGIN [email protected] ""
 02-19 17:27:22.036  1905: 1905 I/System.out : A1 NO Empty username or password. z8if14713202igb.53
 02-19 17:27:22.044  1905: 1905 D/test       : javax.mail.AuthenticationFailedException: Empty username or password. z8if14713202igb.53

I use yor mail.jar and my app Failed to create SASL client: myjavax.security.sasl.SaslException: Cannot instantiate class com.research.oauth.OAuth2SaslClientFactory, then app use Empty password to login gmail. Please help me to figure out the problem, Thank you!


Solution

  • Did you remeber to change your package name in OAuth2Provider? I forgot it when I was doing tests with that code.

    public static final class OAuth2Provider extends Provider {
    private static final long serialVersionUID = 1L;
    
    public OAuth2Provider() {
      super("Google OAuth2 Provider", 1.0,
            "Provides the XOAUTH2 SASL Mechanism");
      put("SaslClientFactory.XOAUTH2",
          "com.example.testjavamail.OAuth2SaslClientFactory");
    }
    

    }

    As I said in another answer, I only tested the connection, but it's working for me.

    UPDATE

    Here's the code I used, it's basically the example code, what really changed the porting of SASL support in Java Mail.

    public class OAuth2Authenticator {
    private static final Logger logger = Logger
            .getLogger(OAuth2Authenticator.class.getName());
    private static Session mSession;
    
    public static final class OAuth2Provider extends Provider {
        private static final long serialVersionUID = 1L;
    
        public OAuth2Provider() {
            super("Google OAuth2 Provider", 1.0,
                    "Provides the XOAUTH2 SASL Mechanism");
            put("SaslClientFactory.XOAUTH2",
                    "com.example.testjavamail.OAuth2SaslClientFactory");
        }
    }
    
    public static void initialize() {
        Security.addProvider(new OAuth2Provider());
    }
    
    public static IMAPStore connectToImap(String host, int port,
            String userEmail, String oauthToken, boolean debug)
            throws Exception {
        Properties props = new Properties();
        props.put("mail.imaps.sasl.enable", "true");
        props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
        props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
        Session session = Session.getInstance(props);
        session.setDebug(debug);
    
        final URLName unusedUrlName = null;
        IMAPSSLStore store = new IMAPSSLStore(session, unusedUrlName);
        final String emptyPassword = "";
        store.connect(host, port, userEmail, emptyPassword);
        return store;
    }
    
    public static SMTPTransport connectToSmtp(String host, int port,
            String userEmail, String oauthToken, boolean debug)
            throws Exception {
        Properties props = new Properties();
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.starttls.required", "true");
        props.put("mail.smtp.sasl.enable", "true");
        props.put("mail.smtp.sasl.mechanisms", "XOAUTH2");
        props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
        mSession = Session.getInstance(props);
        mSession.setDebug(debug);
    
        final URLName unusedUrlName = null;
        SMTPTransport transport = new SMTPTransport(mSession, unusedUrlName);
        // If the password is non-null, SMTP tries to do AUTH LOGIN.
        final String emptyPassword = null;
        transport.connect(host, port, userEmail, emptyPassword);
    
        return transport;
    }
    
    public synchronized void testImap(String user, String oauthToken) {
        try {
    
            initialize();
    
    
            IMAPStore imapStore = connectToImap("imap.gmail.com", 993, user,
                    oauthToken, true);
    
        } catch (Exception e) {
            Log.d("test", e.toString());
        }
    
    }
    
    public class ByteArrayDataSource implements DataSource {
        private byte[] data;
        private String type;
    
        public ByteArrayDataSource(byte[] data, String type) {
            super();
            this.data = data;
            this.type = type;
        }
    
        public ByteArrayDataSource(byte[] data) {
            super();
            this.data = data;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public String getContentType() {
            if (type == null)
                return "application/octet-stream";
            else
                return type;
        }
    
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(data);
        }
    
        public String getName() {
            return "ByteArrayDataSource";
        }
    
        public OutputStream getOutputStream() throws IOException {
            throw new IOException("Not Supported");
        }
    }
    

    }

    And here's the debug from Java Mail. Btw, post your debug log, it should help in undertanding what's going wrong

    02-06 10:18:11.805: I/System.out(7434): DEBUG: setDebug: JavaMail version 1.4.1
    02-06 10:18:11.905: I/System.out(7434): DEBUG: mail.imap.fetchsize: 16384
    02-06 10:18:12.025: I/System.out(7434): DEBUG: enable SASL
    02-06 10:18:12.040: I/System.out(7434): DEBUG: SASL mechanisms allowed: XOAUTH2
    02-06 10:18:12.600: I/System.out(7434): * OK Gimap ready for requests from 2.233.xxx.xxx  2if1471965eej.3
    02-06 10:18:12.605: I/System.out(7434): A0 CAPABILITY
    02-06 10:18:12.635: I/System.out(7434): * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2
    02-06 10:18:12.635: I/System.out(7434): A0 OK Thats all she wrote! 2if1471965eej.3
    02-06 10:18:12.645: I/System.out(7434): IMAP DEBUG: AUTH: XOAUTH
    02-06 10:18:12.645: I/System.out(7434): IMAP DEBUG: AUTH: XOAUTH2
    02-06 10:18:12.645: I/System.out(7434): DEBUG: protocolConnect login, host=imap.gmail.com, [email protected], password=<non-null>
    02-06 10:18:12.650: I/System.out(7434): IMAP SASL DEBUG: Mechanisms: XOAUTH2
    02-06 10:18:12.695: I/System.out(7434): IMAP SASL DEBUG: SASL client XOAUTH2
    02-06 10:18:12.695: I/System.out(7434): A1 AUTHENTICATE XOAUTH2
    02-06 10:18:12.720: I/System.out(7434): + 
    02-06 10:18:12.720: I/System.out(7434): IMAP SASL DEBUG: challenge:  :
    02-06 10:18:12.730: I/System.out(7434): IMAP SASL DEBUG: callback length: 1
    02-06 10:18:12.730: I/System.out(7434): IMAP SASL DEBUG: callback 0: myjavax.security.auth.callback.NameCallback@41760f78
    02-06 10:18:12.730: I/System.out(7434): IMAP SASL DEBUG: response: [email protected]=Bearer ya29.... :
    02-06 10:18:12.735: I/System.out(7434): dXNlcj1hbGVhbGVtYXp6b3R0aUBnbWFpbC5jb20BYXV0aD1CZWFyZXIgeWEyOS5BSEVTNlpRYklPeU8xU09sR01WSEo3X2tqVzlVdzNYY1RvODBtQ0hyWFVacjRsYlhIdwEB
    02-06 10:18:12.870: I/System.out(7434): * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE
    02-06 10:18:12.870: I/System.out(7434): A1 OK [email protected] My NAME authenticated (Success)
    02-06 10:18:12.870: I/System.out(7434): A2 CAPABILITY
    02-06 10:18:13.160: I/System.out(7434): * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE
    02-06 10:18:13.160: I/System.out(7434): A2 OK Success