aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/impl
diff options
context:
space:
mode:
authorDanny van Heumen <danny@dannyvanheumen.nl>2015-06-07 23:07:00 +0200
committerDanny van Heumen <danny@dannyvanheumen.nl>2015-07-20 22:29:45 +0200
commitdcbeba9b6a262ce0ab99b96e673a7ef1ec8b5acd (patch)
tree74f38c0477f8a9b6f1c35b5e3c634d464c9263c4 /src/net/java/sip/communicator/impl
parent7d311ba178defc059ad22ee9371051915346b365 (diff)
downloadjitsi-dcbeba9b6a262ce0ab99b96e673a7ef1ec8b5acd.zip
jitsi-dcbeba9b6a262ce0ab99b96e673a7ef1ec8b5acd.tar.gz
jitsi-dcbeba9b6a262ce0ab99b96e673a7ef1ec8b5acd.tar.bz2
Working prototype OAuth 2 authentication for Google Contacts plugin.
Diffstat (limited to 'src/net/java/sip/communicator/impl')
-rw-r--r--src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java184
-rw-r--r--src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java7
-rw-r--r--src/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf3
3 files changed, 177 insertions, 17 deletions
diff --git a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java
index 2722a86..46849aa 100644
--- a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java
+++ b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java
@@ -6,17 +6,25 @@
*/
package net.java.sip.communicator.impl.googlecontacts;
+import java.io.*;
+import java.util.concurrent.atomic.*;
+
import net.java.sip.communicator.service.googlecontacts.*;
import net.java.sip.communicator.util.*;
-import com.google.gdata.client.*;
+import com.google.api.client.auth.oauth2.*;
+import com.google.api.client.http.*;
+import com.google.api.client.http.javanet.*;
+import com.google.api.client.json.jackson2.*;
import com.google.gdata.client.contacts.*;
+import com.google.gdata.data.contacts.*;
import com.google.gdata.util.*;
/**
* Google Contacts credentials to connect to the service.
*
* @author Sebastien Vincent
+ * @author Danny van Heumen
*/
public class GoogleContactsConnectionImpl
implements GoogleContactsConnection
@@ -28,6 +36,39 @@ public class GoogleContactsConnectionImpl
Logger.getLogger(GoogleContactsConnectionImpl.class);
/**
+ * Google OAuth 2 token server.
+ */
+ private static final GenericUrl GOOGLE_OAUTH2_TOKEN_SERVER =
+ new GenericUrl("https://accounts.google.com/o/oauth2/token");
+
+ /**
+ * Client ID for OAuth 2 based authentication.
+ */
+ private static final String GOOGLE_API_CLIENT_ID = null;
+
+ /**
+ * Client secret for OAuth 2 based authentication.
+ */
+ private static final String GOOGLE_API_CLIENT_SECRET = null;
+
+ // FIXME Actually use scopes!
+ private static final String[] GOOGLE_API_OAUTH2_SCOPES = new String[]
+ { "profile", "email", "https://www.google.com/m8/feeds" };
+
+ // FIXME Actually use the redirect URL!
+ private static final String GOOGLE_API_OAUTH2_REDIRECT_URI =
+ "urn:ietf:wg:oauth:2.0:oob";
+
+ // FIXME (Danny) Temporary stored refresh token during development...
+ private static final String TEMP_REFRESH_TOKEN =
+ "1/mjFeVE86qVmm-O2B6SSLweW6hBcj4qxuYSb0fGvJvH0";
+
+ /**
+ * The credential store to pass around.
+ */
+ private final AtomicReference<Credential> credential = new AtomicReference<Credential>(null);
+
+ /**
* Login.
*/
private String login = null;
@@ -121,26 +162,127 @@ public class GoogleContactsConnectionImpl
*
* @return connection status
*/
- public ConnectionStatus connect()
+ public synchronized ConnectionStatus connect()
+ {
+ createCredential(GOOGLE_OAUTH2_TOKEN_SERVER);
+ googleService.setOAuth2Credentials(this.credential.get());
+ return ConnectionStatus.SUCCESS;
+ }
+
+ /**
+ * Query for contacts using provided ContactQuery.
+ *
+ * Executes query. In case of failure, refresh OAuth2 token and retry query.
+ * If query fails again, throws FailedContactQueryException.
+ *
+ * @param query the contact query
+ * @return Returns the contact feed with matching contacts.
+ * @throws IOException
+ * @throws ServiceException
+ * @throws FailedContactQueryException Throws in case of failed query.
+ * @throws FailedTokenRefreshException Throws in case refreshing OAuth2
+ * token fails.
+ */
+ public synchronized ContactFeed query(final ContactQuery query)
+ throws IOException,
+ ServiceException,
+ FailedContactQueryException,
+ FailedTokenRefreshException
{
try
{
- googleService.setUserCredentials(login, password);
+ return this.googleService.query(query, ContactFeed.class);
}
- catch(AuthenticationException e)
+ catch (Exception e)
{
- logger.info("Google contacts connection failure: " + e);
- if(e instanceof GoogleService.InvalidCredentialsException)
+ // FIXME if possible narrow down the exceptions on which to
+ // refresh token
+ logger.info("Failed to execute query. Going to refresh token"
+ + " and try again.", e);
+ refreshToken();
+ }
+ try
+ {
+ return this.googleService.query(query, ContactFeed.class);
+ }
+ catch (Exception e)
+ {
+ throw new FailedContactQueryException(e);
+ }
+ }
+
+ /**
+ * Refresh OAuth2 authentication token.
+ *
+ * @throws IOException
+ */
+ private void refreshToken() throws IOException, FailedTokenRefreshException
+ {
+ final Credential credential = this.credential.get();
+ if (!credential.refreshToken())
+ {
+ logger.warn("Refresh of OAuth2 authentication token failed.");
+ throw new FailedTokenRefreshException();
+ }
+ }
+
+ /**
+ * Create credential instance suitable for use in Google Contacts API.
+ * @param tokenServer the token server URL
+ * @return Returns a Credential instance.
+ */
+ private void createCredential(final GenericUrl tokenServerURL)
+ {
+ final Credential.Builder builder =
+ new Credential.Builder(
+ BearerToken.authorizationHeaderAccessMethod());
+ builder.setTokenServerUrl(tokenServerURL);
+ builder.setTransport(new NetHttpTransport());
+ builder.setJsonFactory(new JacksonFactory());
+ builder.setClientAuthentication(new HttpExecuteInterceptor()
+ {
+
+ @Override
+ public void intercept(HttpRequest request) throws IOException
{
- return ConnectionStatus.ERROR_INVALID_CREDENTIALS;
+ final RefreshTokenRequest content =
+ (RefreshTokenRequest) ((UrlEncodedContent) request
+ .getContent()).getData();
+ content.put("client_id", GOOGLE_API_CLIENT_ID);
+ content.put("client_secret", GOOGLE_API_CLIENT_SECRET);
+ logger.warn("Refresh token request: " + content.toString());
}
- else
+ });
+ builder.addRefreshListener(new CredentialRefreshListener()
+ {
+ final AtomicReference<Credential> store =
+ GoogleContactsConnectionImpl.this.credential;
+
+ @Override
+ public void onTokenResponse(Credential credential,
+ TokenResponse tokenResponse) throws IOException
{
- return ConnectionStatus.ERROR_UNKNOWN;
+ logger.debug("Successful token refresh response: "
+ + tokenResponse.toPrettyString());
+ store.set(credential);
}
- }
- return ConnectionStatus.SUCCESS;
+ @Override
+ public void onTokenErrorResponse(Credential credential,
+ TokenErrorResponse tokenErrorResponse) throws IOException
+ {
+ logger.debug("Failed token refresh response: "
+ + tokenErrorResponse.toPrettyString());
+ logger.error("Failed to refresh OAuth2 token: "
+ + tokenErrorResponse.getError() + ": "
+ + tokenErrorResponse.getErrorDescription());
+ }
+ });
+ final Credential credential = builder.build();
+ credential.setAccessToken("ya29.iwG37LYEgB4FCwfPLq8vV6Q-CX1vQ5sJrb_2AGydhLAiUT4wmz4iW4FlVkZE57s1B6NgA3BJAspLIw");
+ credential.setRefreshToken(TEMP_REFRESH_TOKEN);
+ credential.setExpiresInSeconds(3600L);
+ this.credential.set(credential);
}
/**
@@ -182,4 +324,24 @@ public class GoogleContactsConnectionImpl
{
return prefix;
}
+
+ public static class FailedContactQueryException
+ extends Exception
+ {
+
+ private FailedContactQueryException(Throwable cause)
+ {
+ super("Failed to query Google Contacts API.", cause);
+ }
+ }
+
+ public static class FailedTokenRefreshException
+ extends Exception
+ {
+
+ private FailedTokenRefreshException()
+ {
+ super("Failed to refresh OAuth2 token.");
+ }
+ }
}
diff --git a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java
index c81814a..206f4aa 100644
--- a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java
@@ -269,14 +269,11 @@ public class GoogleContactsServiceImpl
try
{
- contactFeed = cnxImpl.getGoogleService().query(
- query, ContactFeed.class);
+ contactFeed = cnxImpl.query(query);
}
catch(Exception e)
{
- logger.info(
- "Problem occurred during Google Contacts retrievment",
- e);
+ logger.warn("Problem occurred during Google Contacts query", e);
return ret;
}
diff --git a/src/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf b/src/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf
index 6fbb11f..99337a8 100644
--- a/src/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf
+++ b/src/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf
@@ -24,4 +24,5 @@ Import-Package: org.osgi.framework,
javax.swing.event,
javax.swing.table,
javax.swing.tree,
- javax.swing.text
+ javax.swing.text,
+ javax.net.ssl