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

Commit 55135ff9 authored by daquexian's avatar daquexian
Browse files

Support oauth 2.0 for outlook

parent 70a2100f
Loading
Loading
Loading
Loading
+4 −11
Original line number Diff line number Diff line
@@ -2,17 +2,10 @@ package com.fsck.k9.mail.oauth;

import com.fsck.k9.mail.AuthenticationFailedException;

public interface SpecificOAuth2TokenProvider {
    OAuth2TokenProvider.Tokens exchangeCode(String username, String code) throws AuthenticationFailedException;
public abstract class SpecificOAuth2TokenProvider {
    public abstract OAuth2TokenProvider.Tokens exchangeCode(String username, String code) throws AuthenticationFailedException;

    /**
     * refresh access token with refresh token
     * @param username username (usually email address)
     * @param refreshToken refresh token got before
     * @return new access token
     * @throws AuthenticationFailedException throws it when error occurs
     */
    String refreshToken(String username, String refreshToken) throws AuthenticationFailedException;
    public abstract String refreshToken(String username, String refreshToken) throws AuthenticationFailedException;

    void showAuthDialog();
    public abstract void showAuthDialog();
}
+1 −1
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit;
 * It's not used for the time being because we have {@link GmailOAuth2TokenStore} that handle all Gmail account
 */
// TODO: 2017/8/19 maybe we can use it when google account is in Android account system (don't know whether it need effort)
public class AndroidAccountOAuth2TokenStore implements SpecificOAuth2TokenProvider {
public class AndroidAccountOAuth2TokenStore extends SpecificOAuth2TokenProvider {
    private static final String GMAIL_AUTH_TOKEN_TYPE = "oauth2:https://mail.google.com/";
    private static final String GOOGLE_ACCOUNT_TYPE = "com.google";

+76 −0
Original line number Diff line number Diff line
package com.fsck.k9.account;

import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.oauth.OAuth2TokenProvider;
import com.fsck.k9.mail.oauth.SpecificOAuth2TokenProvider;
import com.google.gson.annotations.SerializedName;

import java.io.IOException;

import retrofit2.Call;
import retrofit2.Response;

/**
 *
 */
public abstract class AndroidSpecificOAuth2TokenProvider extends SpecificOAuth2TokenProvider {
    protected XOauth2PromptRequestHandler promptRequestHandler;

    protected abstract Call<ExchangeResponse> getExchangeCodeCall(String code);
    protected abstract Call<RefreshResponse> getRefreshTokenCall(String code);

    void setPromptRequestHandler(XOauth2PromptRequestHandler promptRequestHandler) {
        this.promptRequestHandler = promptRequestHandler;
    }

    public OAuth2TokenProvider.Tokens exchangeCode(String username, String code) throws AuthenticationFailedException {
        Call<ExchangeResponse> call = getExchangeCodeCall(code);
        ExchangeResponse exchangeResponse;
        Response<ExchangeResponse> response;
        try {
            response = call.execute();
            exchangeResponse = response.body();
        } catch (Exception e) {
            throw new AuthenticationFailedException(e.getMessage());
        }
        if (exchangeResponse == null || exchangeResponse.accessToken.isEmpty()) return null;

        return new OAuth2TokenProvider.Tokens(exchangeResponse.accessToken, exchangeResponse.refreshToken);
    }

    public String refreshToken(String username, String refreshToken) throws AuthenticationFailedException {
        Call<RefreshResponse> call = getRefreshTokenCall(refreshToken);
        RefreshResponse response;
        try {
            response = call.execute().body();
        } catch (IOException e) {
            throw new AuthenticationFailedException(e.getMessage());
        }
        if (response == null) {
            throw new AuthenticationFailedException("Error when getting refresh token");
        }
        return response.accessToken;
    }

    protected static class ExchangeResponse {
        @SerializedName("access_token")
        String accessToken;
        @SerializedName("id_token")
        String idToken;
        @SerializedName("refresh_token")
        String refreshToken;
        @SerializedName("expires_in")
        int expiresIn;
        @SerializedName("token_type")
        String tokenType;
    }

    protected static class RefreshResponse {
        @SerializedName("access_token")
        String accessToken;
        @SerializedName("expires_in")
        int expiresIn;
        @SerializedName("token_type")
        String tokenType;
    }
}
+7 −62
Original line number Diff line number Diff line
package com.fsck.k9.account;


import java.io.IOException;

import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.oauth.OAuth2TokenProvider;
import com.fsck.k9.mail.oauth.SpecificOAuth2TokenProvider;
import com.google.gson.annotations.SerializedName;
import retrofit2.Call;
import retrofit2.GsonConverterFactory;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;


public class GmailOAuth2TokenStore implements SpecificOAuth2TokenProvider {
    private XOauth2PromptRequestHandler promptRequestHandler;
public class GmailOAuth2TokenStore extends AndroidSpecificOAuth2TokenProvider {
    private static final String GOOGLE_API_BASE_URL = "https://www.googleapis.com/";
    private static final String CLIENT_ID = "486728022013-39d7vq9t06r004r7ec9m2eti0p1ihs12.apps.googleusercontent.com";
    private static final String REDIRECT_URI = "com.fsck.k9.debug:/oauth2redirect";
@@ -37,44 +29,19 @@ public class GmailOAuth2TokenStore implements SpecificOAuth2TokenProvider {
        service = retrofit.create(GoogleAPIService.class);
    }

    public void setPromptRequestHandler(XOauth2PromptRequestHandler promptRequestHandler) {
        this.promptRequestHandler = promptRequestHandler;
    }

    @Override
    public String refreshToken(String username, String refreshToken) throws AuthenticationFailedException {
        Call<RefreshResponse> call = service.refreshToken(CLIENT_ID, refreshToken, "refresh_token");
        RefreshResponse response;
        try {
            response = call.execute().body();
        } catch (IOException e) {
            throw new AuthenticationFailedException(e.getMessage());
        }
        if (response == null) {
            throw new AuthenticationFailedException("Error when getting refresh token");
        }
        return response.accessToken;
    }

    @Override
    public void showAuthDialog() {
        promptRequestHandler.handleGmailRedirectUrl(AUTHORIZATION_URL);
    }

    @Override
    public OAuth2TokenProvider.Tokens exchangeCode(String username, String code) throws AuthenticationFailedException {
        Call<ExchangeResponse> call = service.exchangeCode(code, CLIENT_ID, "authorization_code", REDIRECT_URI);
        ExchangeResponse exchangeResponse;
        Response<ExchangeResponse> response;
        try {
            response = call.execute();
            exchangeResponse = response.body();
        } catch (Exception e) {
            throw new AuthenticationFailedException(e.getMessage());
    protected Call<RefreshResponse> getRefreshTokenCall(String refreshToken) {
        return service.refreshToken(CLIENT_ID, refreshToken, "refresh_token");
    }
        if (exchangeResponse == null || exchangeResponse.accessToken.isEmpty()) return null;

        return new OAuth2TokenProvider.Tokens(exchangeResponse.accessToken, exchangeResponse.refreshToken);
    @Override
    protected Call<ExchangeResponse> getExchangeCodeCall(String code) {
        return service.exchangeCode(code, CLIENT_ID, "authorization_code", REDIRECT_URI);
    }

    private interface GoogleAPIService {
@@ -87,26 +54,4 @@ public class GmailOAuth2TokenStore implements SpecificOAuth2TokenProvider {
        Call<ExchangeResponse> exchangeCode(@Field("code") String code, @Field("client_id") String clientId,
                                            @Field("grant_type") String grantType, @Field("redirect_uri") String redirectUri);
    }

    private static class ExchangeResponse {
        @SerializedName("access_token")
        String accessToken;
        @SerializedName("id_token")
        String idToken;
        @SerializedName("refresh_token")
        String refreshToken;
        @SerializedName("expires_in")
        int expiresIn;
        @SerializedName("token_type")
        String tokenType;
    }

    private static class RefreshResponse {
        @SerializedName("access_token")
        String accessToken;
        @SerializedName("expires_in")
        int expiresIn;
        @SerializedName("token_type")
        String tokenType;
    }
}
+22 −0
Original line number Diff line number Diff line
package com.fsck.k9.account;

import android.net.Uri;

import com.fsck.k9.activity.setup.AccountSetupPresenter;

public class GmailWebViewClient extends OAuth2WebViewClient {
    public GmailWebViewClient(AccountSetupPresenter presenter) {
        super(presenter);
    }

    @Override
    protected boolean arrivedAtRedirectUri(Uri uri) {
        return "com.fsck.k9.debug".equals(uri.getScheme());
    }

    @Override
    protected boolean getOutOfDomain(Uri uri) {
        return !uri.getHost().contains("google"); // TODO: 8/18/17 how to improve it?
    }

}
Loading