1
votes

My Android app must access to Gmail by IMAP with OAuth2, without the user's password. I have implemented the example: https://java.net/projects/javamail/pages/OAuth2 adding a Provider as required (The SASL XOAUTH2 provider will be added to the Java security configuration when SASL support is first used)

this is my code:

  1. get access token

    public void getAndUseAuthTokenBlocking() throws JSONException 
    {           
       String token = "";
       try 
       {
            // Retrieve a token for the given account and scope. It will always return either
            // a non-empty String or throw an exception.
    
        String scope = "oauth2:https://mail.google.com/"; 
        Log.i("Access TOKEN account",accountName);
    
        token = GoogleAuthUtil.getToken(activity.getApplicationContext(), accountName, scope);
    
        // Do work with token.
        URL url = new URL("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token="+ token);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        int serverCode = con.getResponseCode();
    
        if (serverCode == 200)
        {
            access_token = token;
            return;
        //bad token, invalidate and get a new one
        } 
        else if (serverCode == 401)
        {
          // invalidate the token that we found is bad so that GoogleAuthUtil won't
          // return it next time (it may have cached it)
          GoogleAuthUtil.invalidateToken(activity.getApplicationContext(), token);
          // consider retrying getAndUseTokenBlocking() once more
          Log.w("Access TOKEN","INVALIDATO");   
          getAndUseAuthTokenBlocking();
        }
        else 
        {
            Log.e("SERVER CODE","Server returned the following error code: " + serverCode);
            return;
        }
    
        return;
     } 
     catch (GooglePlayServicesAvailabilityException playEx) 
     {
     Dialog alert = GooglePlayServicesUtil.getErrorDialog(
         playEx.getConnectionStatusCode(),
         activity,1);
     } 
     catch (UserRecoverableAuthException userAuthEx) 
     {
      // Start the user recoverable action using the intent returned by
      // getIntent()
      activity.startActivityForResult(
              userAuthEx.getIntent(),
              1);
      return;
     } 
     catch (IOException ioEx) 
     {
      // network or server error, the call is expected to succeed if you try again later.
      // Don't attempt to call again immediately - the request is likely to
      // fail, you'll hit quotas or back-off.
    
       Log.e("IOException", "transient error encountered: " + ioEx.getMessage());
      return;
     } 
     catch (GoogleAuthException authEx) 
     {
      // Failure. The call is not expected to ever succeed so it should not be
      // retried.
       Log.e("GoogleAuthException", "Unrecoverable authentication exception: " + authEx.getMessage(), authEx);
      return;
     }
    } 
    
  2. creation of provider (OAuthFactory e OAuthClient classes were taken from https://code.google.com/p/google-mail-oauth2-tools/source/browse/trunk/java/#java%2Fcom%2Fgoogle%2Fcode%2Fsamples%2Foauth2 )

    public static final class OAuthProvider extends Provider {
    private static final long serialVersionUID = 1L;
    
    public OAuthProvider() {
        super("Google OAuth2 Provider", 1.0,
              "Provides the XOAUTH2 SASL Mechanism");
        String className = OAuthFactory.class.getName();
        put("SaslClientFactory.XOAUTH2", className);
      }
    }
    
  3. IMAP connection

    protected String doInBackground(String... params)
    {
    Log.i("account",accountName);
    
    try {
        getAndUseAuthTokenBlocking();
    } catch (JSONException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    
    Log.i("access token",access_token);       
    
    initialize();
    
    Properties props = new Properties();
    props.put("mail.imap.ssl.enable", "true"); // required for Gmail
    props.put("mail.imap.sasl.enable", "true");
    props.put("mail.imap.sasl.mechanisms", "XOAUTH2");
    props.put("mail.imap.auth.login.disable", "true");
    props.put("mail.imap.auth.plain.disable", "true");
    Session session = Session.getInstance(props);
    
    session.setDebug(true);
    
    Store store;
    
    try {
        store = session.getStore("imaps");
         store.connect("imap.gmail.com", accountName, access_token);        
    } catch (NoSuchProviderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (MessagingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    return null;
    }
    

But this code gives the [AUTHENTICATIONFAILED] Invalid credentials (Failure) error

08-21 16:14:43.100: I/System.out(7346): DEBUG: setDebug: JavaMail version 1.5.2
08-21 16:14:43.100: I/System.out(7346): DEBUG: getProvider() returning javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle,1.5.2]
08-21 16:14:43.100: W/dalvikvm(7346): method Lcom/sun/mail/imap/IMAPStore;.getSession incorrectly overrides package-private method with same name in Ljavax/mail/Service;
08-21 16:14:43.104: I/System.out(7346): DEBUG IMAPS: mail.imap.fetchsize: 16384
08-21 16:14:43.104: I/System.out(7346): DEBUG IMAPS: mail.imap.ignorebodystructuresize: false
08-21 16:14:43.104: I/System.out(7346): DEBUG IMAPS: mail.imap.statuscachetimeout: 1000
08-21 16:14:43.104: I/System.out(7346): DEBUG IMAPS: mail.imap.appendbuffersize: -1
08-21 16:14:43.104: I/System.out(7346): DEBUG IMAPS: mail.imap.minidletime: 10
08-21 16:14:43.108: I/System.out(7346): DEBUG IMAPS: trying to connect to host "imap.gmail.com", port 993, isSSL true
08-21 16:14:48.408: I/System.out(7346): * OK Gimap ready for requests from 82.57.18.250 z47mb29911677eep
08-21 16:14:48.408: I/System.out(7346): A0 CAPABILITY
08-21 16:14:48.468: I/System.out(7346): * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN
08-21 16:14:48.468: I/System.out(7346): A0 OK Thats all she wrote! z47mb29911677eep
08-21 16:14:48.468: I/System.out(7346): DEBUG IMAPS: AUTH: XOAUTH
08-21 16:14:48.468: I/System.out(7346): DEBUG IMAPS: AUTH: XOAUTH2
08-21 16:14:48.468: I/System.out(7346): DEBUG IMAPS: AUTH: PLAIN
08-21 16:14:48.468: I/System.out(7346): DEBUG IMAPS: AUTH: PLAIN-CLIENTTOKEN
08-21 16:14:48.472: I/System.out(7346): DEBUG IMAPS: protocolConnect login, host=imap.gmail.com, [email protected], password=<non-null>
08-21 16:14:48.472: I/System.out(7346): DEBUG IMAPS: AUTHENTICATE PLAIN command trace suppressed
08-21 16:14:49.488: I/System.out(7346): DEBUG IMAPS: AUTHENTICATE PLAIN command result: A1 NO [AUTHENTICATIONFAILED] Invalid credentials (Failure)
08-21 16:14:49.488: W/System.err(7346): javax.mail.AuthenticationFailedException: [AUTHENTICATIONFAILED] Invalid credentials (Failure)
08-21 16:14:49.492: W/System.err(7346):     at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:715)
08-21 16:14:49.492: W/System.err(7346):     at javax.mail.Service.connect(Service.java:364)
08-21 16:14:49.492: W/System.err(7346):     at javax.mail.Service.connect(Service.java:245)
08-21 16:14:49.492: W/System.err(7346):     at com.example.tickets.Reader2.doInBackground(Reader2.java:113)
08-21 16:14:49.492: W/System.err(7346):     at com.example.tickets.Reader2.doInBackground(Reader2.java:1)
08-21 16:14:49.492: W/System.err(7346):     at android.os.AsyncTask$2.call(AsyncTask.java:287)
08-21 16:14:49.492: W/System.err(7346):     at java.util.concurrent.FutureTask.run(FutureTask.java:234)
08-21 16:14:49.492: W/System.err(7346):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
08-21 16:14:49.492: W/System.err(7346):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
08-21 16:14:49.500: W/System.err(7346):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
08-21 16:14:49.500: W/System.err(7346):     at java.lang.Thread.run(Thread.java:841)

I don't understand if the problem is the IMAP connection or the access token; for take the access token I also tried oauth.py but the result is the same.

Thanks for your reply.

1
Your log says you're issuing an AUTHENTICATE PLAIN command and the server is issing a a NO response with an AUTHENTICATIONFAILED response code. So you want to use Oauth2, but you actually are using Plain. - arnt
In according of the javamail docs, I have used props.put("mail.imap.auth.plain.disable", true"); mail.imap.auth.plain.disable boolean If true, prevents use of the AUTHENTICATE PLAIN command. Default is false. - blackat
You're setting a bunch of properties for the "imap" protocol, but you're using the "imaps" protocol. Change the getStore call to use "imap". Also, you don't need all the Google OAuth code if you're using the latest JavaMail version, which has OAuth support built in. - Bill Shannon
thank you Bill for your response,the problem was the name of protocol in the getStore method. But now I've some problem with SASL authentication : 08-21 21:46:39.102: I/System.out(2234): DEBUG IMAPS: Can't load SASL authenticator, THROW: 08-21 21:46:39.102: I/System.out(2234): java.lang.ClassNotFoundException: com.sun.mail.imap.protocol.IMAPSaslAuthenticator I've tried to use mannaz.at/codebase/imap-ssl-mail-android but I've always sasl authentication problem. What do you mean with "you don't need all the Google OAuth code"? I've use javamail 1.5.2 release.Tnx - blackat
If anyone has solution for this, please post here. - Priyanka Singh

1 Answers

2
votes

enter image description here

you may need to follow the picture ,put your gmail account setting