Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7774ebc7 authored by Philip Whitehouse's avatar Philip Whitehouse
Browse files

Back-end changes for Google XOAUTH2

parent 03426485
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -16,6 +16,13 @@ public enum AuthType {
    CRAM_MD5,
    EXTERNAL,

    /**
     * XOAUTH2 is an OAuth2.0 protocol designed/used by GMail.
     *
     * https://developers.google.com/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism
     */
    XOAUTH2,

    /*
     * The following are obsolete authentication settings that were used with
     * SMTP. They are no longer presented to the user as options, but they may
+8 −0
Original line number Diff line number Diff line
package com.fsck.k9.mail;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;

import com.fsck.k9.mail.filter.Base64;
@@ -7,6 +8,7 @@ import com.fsck.k9.mail.filter.Hex;

public class Authentication {
    private static final String US_ASCII = "US-ASCII";
    private static final String XOAUTH_FORMAT = "user=%1s\001auth=Bearer %2s\001\001";

    /**
     * Computes the response for CRAM-MD5 authentication mechanism given the user credentials and
@@ -82,4 +84,10 @@ public class Authentication {
            throw new MessagingException("Something went wrong during CRAM-MD5 computation", e);
        }
    }

    public static String computeXoauth(String username, String authToken) throws UnsupportedEncodingException {
        return new String(
                Base64.encodeBase64(String.format(XOAUTH_FORMAT, username, authToken).getBytes()),
                US_ASCII);
    }
}
+5 −2
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ package com.fsck.k9.mail;

import android.content.Context;

import com.fsck.k9.mail.oauth.OAuth2TokenProvider;
import com.fsck.k9.mail.ssl.DefaultTrustedSocketFactory;
import com.fsck.k9.mail.store.StoreConfig;
import com.fsck.k9.mail.ServerSettings.Type;
@@ -19,10 +20,12 @@ public abstract class Transport {
    // RFC 1047
    protected static final int SOCKET_READ_TIMEOUT = 300000;

    public synchronized static Transport getInstance(Context context, StoreConfig storeConfig) throws MessagingException {
    public synchronized static Transport getInstance(Context context, StoreConfig storeConfig,
             OAuth2TokenProvider oauth2TokenProvider) throws MessagingException {
        String uri = storeConfig.getTransportUri();
        if (uri.startsWith("smtp")) {
            return new SmtpTransport(storeConfig, new DefaultTrustedSocketFactory(context));
            return new SmtpTransport(storeConfig, new DefaultTrustedSocketFactory(context),
                    oauth2TokenProvider);
        } else if (uri.startsWith("webdav")) {
            return new WebDavTransport(storeConfig);
        } else {
+11 −0
Original line number Diff line number Diff line
package com.fsck.k9.mail.oauth;

public class AuthorizationException extends Exception {
    public AuthorizationException(String detailMessage, Throwable throwable) {
        super(detailMessage, throwable);
    }

    public AuthorizationException(String detailMessage) {
        super(detailMessage);
    }
}
+61 −0
Original line number Diff line number Diff line
package com.fsck.k9.mail.oauth;

import android.app.Activity;

import com.fsck.k9.mail.AuthenticationFailedException;

import java.util.List;

public interface OAuth2TokenProvider {

    /**
     * A default timeout value to use when fetching tokens.
     */
    public static final int OAUTH2_TIMEOUT = 30000;

    /**
     * @return Accounts suitable for OAuth 2.0 token provision.
     */
    List<String> getAccounts();

    /**
     * Provides an asynchronous response to an
     * {@link OAuth2TokenProvider#authorizeAPI(String, Activity, OAuth2TokenProviderAuthCallback)} request
     */
    interface OAuth2TokenProviderAuthCallback {

        void success();

        void failure(AuthorizationException e);
    }

    /**
     * Request API authorization. This is a foreground action that may produce a dialog to interact with.
     * @param username Username
     * @param activity The responsible activity
     * @param callback A callback to process the asynchronous response
     */
    void authorizeAPI(String username, Activity activity,
                        OAuth2TokenProviderAuthCallback callback);

    /**
     * Fetch a token. No guarantees are provided for validity.
     * @param username Username
     * @return Token string
     * @throws AuthenticationFailedException
     */
    String getToken(String username, long timeoutMillis) throws AuthenticationFailedException;

    /**
     * Invalidate the token for this username.
     * Note that the token should always be invalidated on credential failure.
     * However invalidating a token every single time is not recommended.
     *
     * Invalidating a token and then failure with a new token
     * should be treated as a permanent failure.
     *
     * @param username
     */
    void invalidateToken(String username);

}
Loading