Gmail OAuth - proof of concept

This commit is contained in:
M66B
2019-12-20 12:20:50 +01:00
parent 916a966ce4
commit f496a0fa6c
9 changed files with 161 additions and 3 deletions

View File

@@ -73,6 +73,21 @@ import com.microsoft.identity.client.IPublicClientApplication;
import com.microsoft.identity.client.PublicClientApplication;
import com.microsoft.identity.client.exception.MsalException;
import net.openid.appauth.AppAuthConfiguration;
import net.openid.appauth.AuthorizationException;
import net.openid.appauth.AuthorizationRequest;
import net.openid.appauth.AuthorizationResponse;
import net.openid.appauth.AuthorizationService;
import net.openid.appauth.AuthorizationServiceConfiguration;
import net.openid.appauth.ClientAuthentication;
import net.openid.appauth.ClientSecretPost;
import net.openid.appauth.ResponseTypeValues;
import net.openid.appauth.TokenResponse;
import net.openid.appauth.browser.BrowserBlacklist;
import net.openid.appauth.browser.Browsers;
import net.openid.appauth.browser.VersionRange;
import net.openid.appauth.browser.VersionedBrowserMatcher;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.json.JSONArray;
@@ -131,8 +146,10 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
static final int REQUEST_CHOOSE_ACCOUNT = 5;
static final int REQUEST_DONE = 6;
static final int REQUEST_IMPORT_CERTIFICATE = 7;
static final int REQUEST_OAUTH = 8;
static final String ACTION_QUICK_GMAIL = BuildConfig.APPLICATION_ID + ".ACTION_QUICK_GMAIL";
static final String ACTION_QUICK_OAUTH = BuildConfig.APPLICATION_ID + ".ACTION_QUICK_OAUTH";
static final String ACTION_QUICK_OUTLOOK = BuildConfig.APPLICATION_ID + ".ACTION_QUICK_OUTLOOK";
static final String ACTION_QUICK_SETUP = BuildConfig.APPLICATION_ID + ".ACTION_QUICK_SETUP";
static final String ACTION_VIEW_ACCOUNTS = BuildConfig.APPLICATION_ID + ".ACTION_VIEW_ACCOUNTS";
@@ -310,6 +327,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
IntentFilter iff = new IntentFilter();
iff.addAction(ACTION_QUICK_GMAIL);
iff.addAction(ACTION_QUICK_OAUTH);
iff.addAction(ACTION_QUICK_OUTLOOK);
iff.addAction(ACTION_QUICK_SETUP);
iff.addAction(ACTION_VIEW_ACCOUNTS);
@@ -383,6 +401,10 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
if (resultCode == RESULT_OK && data != null)
handleImportCertificate(data);
break;
case REQUEST_OAUTH:
if (resultCode == RESULT_OK && data != null)
onHandleOAuth(data);
break;
}
} catch (Throwable ex) {
Log.e(ex);
@@ -1138,6 +1160,78 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
fragmentTransaction.commit();
}
private void onOAuth(Intent intent) {
String name = intent.getStringExtra("name");
for (EmailProvider provider : EmailProvider.loadProfiles(this))
if (provider.name.equals(name) && provider.oauth != null) {
AppAuthConfiguration appAuthConfig = new AppAuthConfiguration.Builder()
.setBrowserMatcher(new BrowserBlacklist(
new VersionedBrowserMatcher(
Browsers.SBrowser.PACKAGE_NAME,
Browsers.SBrowser.SIGNATURE_SET,
true,
VersionRange.atMost("5.3")
)))
.build();
AuthorizationService authService = new AuthorizationService(this, appAuthConfig);
AuthorizationRequest authRequest =
new AuthorizationRequest.Builder(
new AuthorizationServiceConfiguration(
Uri.parse(provider.oauth.authorizationEndpoint),
Uri.parse(provider.oauth.tokenEndpoint)),
provider.oauth.clientId,
ResponseTypeValues.CODE,
Uri.parse(provider.oauth.redirectUri))
.setScopes(provider.oauth.scopes)
.setState(name)
.build();
Intent authIntent = authService.getAuthorizationRequestIntent(authRequest);
startActivityForResult(authIntent, REQUEST_OAUTH);
return;
}
Log.unexpectedError(getSupportFragmentManager(),
new IllegalArgumentException("Unknown provider=" + name));
}
private void onHandleOAuth(Intent data) {
AuthorizationResponse auth = AuthorizationResponse.fromIntent(data);
if (auth == null) {
AuthorizationException ex = AuthorizationException.fromIntent(data);
Log.unexpectedError(getSupportFragmentManager(), ex);
return;
}
for (EmailProvider provider : EmailProvider.loadProfiles(this))
if (provider.name.equals(auth.state)) {
AuthorizationService authService = new AuthorizationService(this);
ClientAuthentication clientAuth = new ClientSecretPost(provider.oauth.clientSecret);
authService.performTokenRequest(
auth.createTokenExchangeRequest(),
clientAuth,
new AuthorizationService.TokenResponseCallback() {
@Override
public void onTokenRequestCompleted(TokenResponse access, AuthorizationException ex) {
if (access == null) {
Log.unexpectedError(getSupportFragmentManager(), ex);
return;
}
// access.accessToken
}
});
return;
}
Log.unexpectedError(getSupportFragmentManager(),
new IllegalArgumentException("Unknown state=" + auth.state));
}
private void onOutlook(Intent intent) {
PublicClientApplication.createMultipleAccountPublicClientApplication(
this,
@@ -1484,6 +1578,8 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
String action = intent.getAction();
if (ACTION_QUICK_GMAIL.equals(action))
onGmail(intent);
else if (ACTION_QUICK_OAUTH.equals(action))
onOAuth(intent);
else if (ACTION_QUICK_OUTLOOK.equals(action))
onOutlook(intent);
else if (ACTION_QUICK_SETUP.equals(action))

View File

@@ -67,6 +67,7 @@ public class EmailProvider {
public String link;
public Server imap = new Server();
public Server smtp = new Server();
public OAuth oauth;
public UserType user = UserType.EMAIL;
public StringBuilder documentation; // html
@@ -129,6 +130,14 @@ public class EmailProvider {
provider.smtp.host = xml.getAttributeValue(null, "host");
provider.smtp.port = xml.getAttributeIntValue(null, "port", 0);
provider.smtp.starttls = xml.getAttributeBooleanValue(null, "starttls", false);
} else if ("oauth".equals(name)) {
provider.oauth = new OAuth();
provider.oauth.clientId = xml.getAttributeValue(null, "clientId");
provider.oauth.clientSecret = xml.getAttributeValue(null, "clientSecret");
provider.oauth.scopes = xml.getAttributeValue(null, "scopes").split(",");
provider.oauth.authorizationEndpoint = xml.getAttributeValue(null, "authorizationEndpoint");
provider.oauth.tokenEndpoint = xml.getAttributeValue(null, "tokenEndpoint");
provider.oauth.redirectUri = xml.getAttributeValue(null, "redirectUri");
} else
throw new IllegalAccessException(name);
} else if (eventType == XmlPullParser.END_TAG) {
@@ -650,4 +659,13 @@ public class EmailProvider {
return host + ":" + port;
}
}
public static class OAuth {
String clientId;
String clientSecret;
String[] scopes;
String authorizationEndpoint;
String tokenEndpoint;
String redirectUri;
}
}

View File

@@ -167,9 +167,16 @@ public class FragmentSetup extends FragmentBase {
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(getContext(), getViewLifecycleOwner(), btnQuick);
popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_gmail, 1, R.string.title_setup_gmail);
//popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_outlook, 2, R.string.title_setup_outlook);
popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_activesync, 3, R.string.title_setup_activesync);
popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_other, 4, R.string.title_setup_other);
// Android 5 Lollipop does not support app links
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_gmail_oauth, 2, R.string.title_setup_gmail_oauth);
if (BuildConfig.DEBUG)
popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_outlook, 3, R.string.title_setup_outlook);
popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_activesync, 4, R.string.title_setup_activesync);
popupMenu.getMenu().add(Menu.NONE, R.string.title_setup_other, 5, R.string.title_setup_other);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
@@ -182,6 +189,9 @@ public class FragmentSetup extends FragmentBase {
else
ToastEx.makeText(getContext(), R.string.title_setup_gmail_support, Toast.LENGTH_LONG).show();
return true;
case R.string.title_setup_gmail_oauth:
lbm.sendBroadcast(new Intent(ActivitySetup.ACTION_QUICK_OAUTH).putExtra("name", "Gmail"));
return true;
case R.string.title_setup_outlook:
lbm.sendBroadcast(new Intent(ActivitySetup.ACTION_QUICK_OUTLOOK));
return true;