Add a method to authenticate via OAuth for Google accounts.
--- a/AndroidManifest.xml Sun Sep 23 03:22:37 2012 +0200
+++ b/AndroidManifest.xml Mon Sep 24 20:56:26 2012 +0200
@@ -3,8 +3,8 @@
package="com.beem.project.beem" android:versionCode="12"
android:versionName="0.1.7" android:installLocation="auto">
- <uses-sdk android:minSdkVersion="5" android:targetSdkVersion="7" />
- <uses-feature name="android.hardware.touchscreen" required="false" />
+ <uses-sdk android:minSdkVersion="5" android:targetSdkVersion="7" />
+ <uses-feature name="android.hardware.touchscreen" required="false" />
<permission android:permissionGroup="android.permission-group.NETWORK"
android:label="BeemService" android:description="@string/BeemServiceDescription"
@@ -13,6 +13,8 @@
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
+ <uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<uses-permission android:name="com.beem.project.beem.BEEM_SERVICE"/>
<supports-screens android:largeScreens="true"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/service/auth/AccountAuthenticator.java Mon Sep 24 20:56:26 2012 +0200
@@ -0,0 +1,145 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2012 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
+package com.beem.project.beem.service.auth;
+
+import java.io.IOException;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.Context;
+import android.util.Log;
+
+import org.apache.harmony.javax.security.auth.callback.Callback;
+import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
+import org.apache.harmony.javax.security.auth.callback.NameCallback;
+import org.apache.harmony.javax.security.auth.callback.PasswordCallback;
+import org.apache.harmony.javax.security.auth.callback.UnsupportedCallbackException;
+import org.apache.harmony.javax.security.sasl.RealmCallback;
+import org.jivesoftware.smack.util.StringUtils;
+
+/**
+ * The AccountAuthenticator use an Android Account to authenticate.
+ */
+public class AccountAuthenticator implements CallbackHandler {
+ private static final String GOOGLE_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/googletalk";
+ private static final String TAG = AccountAuthenticator.class.getSimpleName();
+
+ private AccountManager accountMgr;
+ private Account account;
+
+ /**
+ * Create an AccountAuthenticator.
+ *
+ * @param context the Android context
+ * @param account the account to use
+ *
+ */
+ public AccountAuthenticator(final Context context, final Account account) {
+ accountMgr = AccountManager.get(context);
+ this.account = account;
+ }
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ String tmpJid = account.name;
+ String service = StringUtils.parseServer(tmpJid);
+
+ for (int i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof NameCallback) {
+ String authenticationId = StringUtils.parseName(tmpJid);
+ if (useFullJid(account)) {
+ authenticationId = tmpJid;
+ }
+ NameCallback ncb = (NameCallback) callbacks[i];
+ ncb.setName(authenticationId);
+ } else if (callbacks[i] instanceof PasswordCallback) {
+ PasswordCallback pcb = (PasswordCallback) callbacks[i];
+ // skip if password is asked for PKCS11 (SSL keystore)
+ String prompt = pcb.getPrompt();
+ if (prompt != null && prompt.startsWith("PKCS11 Password:"))
+ continue;
+ String password;
+ if (useToken(account))
+ password = getToken();
+ else
+ password = accountMgr.getPassword(account);
+ if (password == null)
+ password = "";
+ pcb.setPassword(password.toCharArray());
+ } else if (callbacks[i] instanceof RealmCallback) {
+ RealmCallback rcb = (RealmCallback) callbacks[i];
+ rcb.setText(service);
+ } else {
+ throw new UnsupportedCallbackException(callbacks[i]);
+ }
+ }
+ }
+
+ /**
+ * Test if the accout use the full jid to authenticate.
+ *
+ * @param accountt the account to test
+ *
+ * @return true if the account use full jid false otherwise
+ */
+ private boolean useFullJid(Account accountt) {
+ String type = accountt.type;
+ return "com.google".equals(type);
+ }
+
+ /**
+ * Test if the account use authentication token.
+ *
+ * @param accountt the account to test
+ *
+ * @return true if the account use token false otherwise
+ */
+ private boolean useToken(Account accountt) {
+ String type = accountt.type;
+ return "com.google".equals(type);
+ }
+
+ /**
+ * Get a authentication token from the Account.
+ *
+ * @return the token or en empty string if an error occurs
+ */
+ private String getToken() {
+ try {
+ return accountMgr.blockingGetAuthToken(account, GOOGLE_TOKEN_TYPE, true);
+ } catch (OperationCanceledException e) {
+ Log.v(TAG, "Token request canceled", e);
+ } catch (AuthenticatorException e) {
+ Log.d(TAG, "Unable to get token", e);
+ } catch (IOException e) {
+ Log.d(TAG, "Unable to get token", e);
+ }
+ return "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/smack/sasl/SASLGoogleOAuth2Mechanism.java Mon Sep 24 20:56:26 2012 +0200
@@ -0,0 +1,141 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2012 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
+package com.beem.project.beem.smack.sasl;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import de.measite.smack.Sasl;
+
+import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
+import org.apache.harmony.javax.security.sasl.SaslException;
+import org.jivesoftware.smack.SASLAuthentication;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.sasl.SASLMechanism;
+import org.jivesoftware.smack.util.Base64;
+
+/**
+ * An implementation of the SASL OAuth2 mechanism made by Google.
+ * The extension is described here :
+ * https://developers.google.com/talk/jep_extensions/oauth
+ */
+public class SASLGoogleOAuth2Mechanism extends SASLMechanism {
+
+ /**
+ * The name of the Google Oauth mechanism.
+ */
+ public static final String MECHANISM_NAME = "X-OAUTH2";
+
+ /**
+ * Create a SASLGoogleOAuth2Mechanism.
+ *
+ * @param saslAuthentication the smack SASLAuthentication.
+ *
+ */
+ public SASLGoogleOAuth2Mechanism(final SASLAuthentication saslAuthentication) {
+ super(saslAuthentication);
+ }
+
+ @Override
+ public void authenticate(String username, String host, String password) throws IOException, XMPPException {
+ //Since we were not provided with a CallbackHandler, we will use our own with the given
+ //information
+
+ //Set the authenticationID as the username, since they must be the same in this case.
+ this.authenticationId = username;
+ this.password = password;
+ this.hostname = host;
+
+ String[] mechanisms = {"PLAIN" };
+ Map<String, String> props = new HashMap<String, String>();
+ sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
+ authenticate();
+ }
+
+ @Override
+ public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
+ String[] mechanisms = {"PLAIN" };
+ Map<String, String> props = new HashMap<String, String>();
+ sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, cbh);
+ authenticate();
+ }
+
+ @Override
+ protected void authenticate() throws IOException, XMPPException {
+ String authenticationText = null;
+ try {
+ if (sc.hasInitialResponse()) {
+ byte[] response = sc.evaluateChallenge(new byte[0]);
+ authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
+ }
+ } catch (SaslException e) {
+ throw new XMPPException("SASL authentication failed", e);
+ }
+
+ // Send the authentication to the server
+ getSASLAuthentication().send(new GoogleOAuthMechanism(authenticationText));
+ }
+
+ @Override
+ protected String getName() {
+ return MECHANISM_NAME;
+ }
+
+ /**
+ * Initiating SASL authentication by select a mechanism.
+ */
+ public static class GoogleOAuthMechanism extends Packet {
+ private final String authenticationText;
+
+ /**
+ * Create a GoogleOAuthMechanism.
+ *
+ * @param authenticationText the authentification token
+ *
+ */
+ public GoogleOAuthMechanism(final String authenticationText) {
+ this.authenticationText = authenticationText;
+ }
+
+ @Override
+ public String toXML() {
+ StringBuilder stanza = new StringBuilder();
+ stanza.append("<auth mechanism=\"").append(MECHANISM_NAME);
+ stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
+ + "auth:service=\"oauth2\" "
+ + "xmlns:auth=\"http://www.google.com/talk/protocol/auth\">");
+ if (authenticationText != null
+ && authenticationText.trim().length() > 0) {
+ stanza.append(authenticationText);
+ }
+ stanza.append("</auth>");
+ return stanza.toString();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/smack/sasl/package-info.java Mon Sep 24 20:56:26 2012 +0200
@@ -0,0 +1,31 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2012 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
+
+/**
+ * This package contains implementations of different SASL mechanism.
+ */
+package com.beem.project.beem.smack.sasl;