Add configuration for oauth providers

There is now an xml file that holds parameters for oauth
providers, and entries in providers.xml can specify that
they can use oauth.

Change-Id: Ibce5b207f83ce9c773f8f713be9e73bb068070ed
This commit is contained in:
Martin Hibdon 2013-12-03 14:08:34 -08:00
parent 34662f11b2
commit e62688f0d6
3 changed files with 168 additions and 1 deletions

View File

@ -192,6 +192,22 @@ public class VendorPolicyLoader {
return result;
}
public static class OAuthProvider implements Serializable {
private static final long serialVersionUID = 8511656164616538990L;
public String id;
public String label;
public String authEndpoint;
public String tokenEndpoint;
public String refreshEndpoint;
public String responseType;
public String redirectUri;
public String scope;
public String clientId;
public String clientSecret;
public String state;
}
public static class Provider implements Serializable {
private static final long serialVersionUID = 8511656164616538989L;
@ -207,6 +223,7 @@ public class VendorPolicyLoader {
public String outgoingUri;
public String outgoingUsername;
public String note;
public String oauth;
/**
* Expands templates in all of the provider fields that support them. Currently,

61
res/xml/oauth.xml Normal file
View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
This file contains configuration information for OAuth providers this app
is registered with.
==== FORMAT OF ENTRIES ====
This file is used to specify parameters to be used when attempting
to authenticate using OAuth.
Here is an example entry:
<provider id="google"
label="Google"
auth_endpoint="https://accounts.google.com/o/oauth2/auth"
token_endpoint="https://accounts.google.com/o/oauth2/token"
refresh_endpoint="https://accounts.google.com/o/oauth2/token"
response_type="code"
redirect_uri="http://localhost"
scope="https://mail.google.com"
state="state"
client_id=[REDACTED]
client_secret=[REDACTED]>
</provider>
id: An identifier that is unique within this file. It can be referenced from providers.xml
if a email provider is known to allow OAuth authentication.
label: The text that will be displayed to the user when selecting a provider to access
for OAuth authentication.
The rest of these values are determined when registering your app with a provider.
auth_endpoint: The uri to access when making the authentication request.
token_endpoint: The uri to access when getting the initial access and refresh tokens.
refresh_endpoint: The uri to access when refreshing the access token.
response_type: Value sent as "response_type" when making the authentication request.
redirect_uri: Value sent as "redirect_uri" when making the authentication request.
scope: Value(s) sent as "scope" when making the authentication request.
state: Value sent as "state" when making the authentication request.
client_id: Value sent as "client_id" when making the authentication request, and when
getting and refreshing the access token.
client_secret: Value sent as "client_secret" when getting and refreshing the access token.
-->
<oauth>
</oauth>

View File

@ -20,6 +20,7 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.net.Uri;
import android.text.Editable;
import android.text.TextUtils;
import android.widget.EditText;
@ -29,6 +30,7 @@ import com.android.email.SecurityPolicy;
import com.android.email.provider.AccountBackupRestore;
import com.android.emailcommon.Logging;
import com.android.emailcommon.VendorPolicyLoader;
import com.android.emailcommon.VendorPolicyLoader.OAuthProvider;
import com.android.emailcommon.VendorPolicyLoader.Provider;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
@ -112,7 +114,89 @@ public class AccountSettingsUtils {
return cv;
}
/**
/**
* Create the request to get the authorization code.
*
* @param context
* @param provider The OAuth provider to register with
* @param emailAddress Email address to send as a hint to the oauth service.
* @return
*/
public static Uri createOAuthRegistrationRequest(final Context context,
final OAuthProvider provider, final String emailAddress) {
final Uri.Builder b = Uri.parse(provider.authEndpoint).buildUpon();
b.appendQueryParameter("response_type", provider.responseType);
b.appendQueryParameter("client_id", provider.clientId);
b.appendQueryParameter("redirect_uri", provider.redirectUri);
b.appendQueryParameter("scope", provider.scope);
b.appendQueryParameter("state", provider.state);
b.appendQueryParameter("login_hint", emailAddress);
return b.build();
}
/**
* Search for a single resource containing known oauth provider definitions.
*
* @param context
* @param id String Id of the oauth provider.
* @return The OAuthProvider if found, null if not.
*/
public static OAuthProvider findOAuthProvider(final Context context, final String id) {
return findOAuthProvider(context, id, R.xml.oauth);
}
/**
* Search for a single resource containing known oauth provider definitions.
*
* @param context
* @param id String Id of the oauth provider.
* @param resourceId ResourceId of the xml file to search.
* @return The OAuthProvider if found, null if not.
*/
public static OAuthProvider findOAuthProvider(final Context context, final String id,
final int resourceId) {
// TODO: Consider adding a way to cache this file during new account setup, so that we
// don't need to keep loading the file over and over.
// TODO: need a mechanism to get a list of all supported OAuth providers so that we can
// offer the user a choice of who to authenticate with.
try {
final XmlResourceParser xml = context.getResources().getXml(resourceId);
int xmlEventType;
OAuthProvider provider = null;
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
if (xmlEventType == XmlResourceParser.START_TAG
&& "provider".equals(xml.getName())) {
String providerId = getXmlAttribute(context, xml, "id");
try {
if (TextUtils.equals(id, providerId)) {
provider = new OAuthProvider();
provider.id = id;
provider.label = getXmlAttribute(context, xml, "label");
provider.authEndpoint = getXmlAttribute(context, xml, "auth_endpoint");
provider.tokenEndpoint = getXmlAttribute(context, xml, "token_endpoint");
provider.refreshEndpoint = getXmlAttribute(context, xml,
"refresh_endpoint");
provider.responseType = getXmlAttribute(context, xml, "response_type");
provider.redirectUri = getXmlAttribute(context, xml, "redirect_uri");
provider.scope = getXmlAttribute(context, xml, "scope");
provider.state = getXmlAttribute(context, xml, "state");
provider.clientId = getXmlAttribute(context, xml, "client_id");
provider.clientSecret = getXmlAttribute(context, xml, "client_secret");
return provider;
}
} catch (IllegalArgumentException e) {
LogUtils.w(Logging.LOG_TAG, "providers line: " + xml.getLineNumber() +
"; Domain contains multiple globals");
}
}
}
} catch (Exception e) {
LogUtils.e(Logging.LOG_TAG, "Error while trying to load provider settings.", e);
}
return null;
}
/**
* Search the list of known Email providers looking for one that matches the user's email
* domain. We check for vendor supplied values first, then we look in providers_product.xml,
* and finally by the entries in platform providers.xml. This provides a nominal override
@ -158,6 +242,11 @@ public class AccountSettingsUtils {
provider.label = getXmlAttribute(context, xml, "label");
provider.domain = domain.toLowerCase();
provider.note = getXmlAttribute(context, xml, "note");
// TODO: Maybe this should actually do a lookup of the OAuth provider
// here, and keep a pointer to it rather than a textual key.
// To do this probably requires caching oauth.xml, otherwise the lookup
// is expensive and likely to happen repeatedly.
provider.oauth = getXmlAttribute(context, xml, "oauth");
}
} catch (IllegalArgumentException e) {
LogUtils.w(Logging.LOG_TAG, "providers line: " + xml.getLineNumber() +