aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/java')
-rw-r--r--src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsActivator.java45
-rw-r--r--src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java2
-rw-r--r--src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java2
-rw-r--r--src/net/java/sip/communicator/impl/googlecontacts/OAuth2TokenStore.java193
-rw-r--r--src/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf8
5 files changed, 194 insertions, 56 deletions
diff --git a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsActivator.java b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsActivator.java
index 7c33c7d..75c6f14 100644
--- a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsActivator.java
+++ b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsActivator.java
@@ -13,6 +13,7 @@ import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.service.googlecontacts.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
import org.jitsi.service.configuration.*;
@@ -37,7 +38,7 @@ public class GoogleContactsActivator implements BundleActivator
* The OSGi <tt>ServiceRegistration</tt> of
* <tt>GoogleContactsServiceImpl</tt>.
*/
- private ServiceRegistration serviceRegistration = null;
+ private ServiceRegistration<?> serviceRegistration = null;
/**
* BundleContext from the OSGI bus.
@@ -67,8 +68,8 @@ public class GoogleContactsActivator implements BundleActivator
/**
* List of contact source service registrations.
*/
- private static Map<GoogleContactsSourceService, ServiceRegistration> cssList
- = new HashMap<GoogleContactsSourceService, ServiceRegistration>();
+ private static Map<GoogleContactsSourceService, ServiceRegistration<?>> cssList
+ = new HashMap<GoogleContactsSourceService, ServiceRegistration<?>>();
/**
* The registered PhoneNumberI18nService.
@@ -86,12 +87,9 @@ public class GoogleContactsActivator implements BundleActivator
{
if(configService == null)
{
- ServiceReference confReference
- = bundleContext.getServiceReference(
- ConfigurationService.class.getName());
- configService
- = (ConfigurationService) bundleContext.getService(
- confReference);
+ configService =
+ ServiceUtils.getService(bundleContext,
+ ConfigurationService.class);
}
return configService;
}
@@ -120,12 +118,9 @@ public class GoogleContactsActivator implements BundleActivator
{
if(credentialsService == null)
{
- ServiceReference confReference
- = bundleContext.getServiceReference(
- CredentialsStorageService.class.getName());
- credentialsService
- = (CredentialsStorageService) bundleContext.getService(
- confReference);
+ credentialsService =
+ ServiceUtils.getService(bundleContext,
+ CredentialsStorageService.class);
}
return credentialsService;
}
@@ -142,12 +137,8 @@ public class GoogleContactsActivator implements BundleActivator
{
if(resourceService == null)
{
- ServiceReference confReference
- = bundleContext.getServiceReference(
- ResourceManagementService.class.getName());
- resourceService
- = (ResourceManagementService) bundleContext.getService(
- confReference);
+ resourceService =
+ ResourceManagementServiceUtils.getService(bundleContext);
}
return resourceService;
}
@@ -207,7 +198,7 @@ public class GoogleContactsActivator implements BundleActivator
*/
private void serviceChanged(ServiceEvent event)
{
- ServiceReference serviceRef = event.getServiceReference();
+ ServiceReference<?> serviceRef = event.getServiceReference();
// if the event is caused by a bundle being stopped, we don't want to
// know
@@ -303,7 +294,7 @@ public class GoogleContactsActivator implements BundleActivator
}
/* remove contact source services */
- for(Map.Entry<GoogleContactsSourceService, ServiceRegistration> entry :
+ for(Map.Entry<GoogleContactsSourceService, ServiceRegistration<?>> entry :
cssList.entrySet())
{
if (entry.getValue() != null)
@@ -338,7 +329,7 @@ public class GoogleContactsActivator implements BundleActivator
{
GoogleContactsSourceService css = new GoogleContactsSourceService(
login, password);
- ServiceRegistration cssServiceRegistration = null;
+ ServiceRegistration<?> cssServiceRegistration = null;
css.setGoogleTalk(googleTalk);
@@ -380,7 +371,7 @@ public class GoogleContactsActivator implements BundleActivator
boolean googleTalk)
{
GoogleContactsSourceService css = new GoogleContactsSourceService(cnx);
- ServiceRegistration cssServiceRegistration = null;
+ ServiceRegistration<?> cssServiceRegistration = null;
css.setGoogleTalk(googleTalk);
@@ -418,7 +409,7 @@ public class GoogleContactsActivator implements BundleActivator
{
GoogleContactsSourceService found = null;
- for(Map.Entry<GoogleContactsSourceService, ServiceRegistration> entry :
+ for(Map.Entry<GoogleContactsSourceService, ServiceRegistration<?>> entry :
cssList.entrySet())
{
String cssName = entry.getKey().getLogin();
@@ -459,7 +450,7 @@ public class GoogleContactsActivator implements BundleActivator
return;
}
- for(Map.Entry<GoogleContactsSourceService, ServiceRegistration> entry :
+ for(Map.Entry<GoogleContactsSourceService, ServiceRegistration<?>> entry :
cssList.entrySet())
{
String cssName = entry.getKey().getLogin();
diff --git a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java
index 503b413..52d03da 100644
--- a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java
+++ b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsConnectionImpl.java
@@ -135,7 +135,7 @@ public class GoogleContactsConnectionImpl
{
try
{
- googleService.setOAuth2Credentials(this.store.get());
+ googleService.setOAuth2Credentials(this.store.get(this.login));
return ConnectionStatus.SUCCESS;
}
catch (FailedAcquireCredentialException e)
diff --git a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java
index 206f4aa..adcd198 100644
--- a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsServiceImpl.java
@@ -68,7 +68,7 @@ public class GoogleContactsServiceImpl
/**
* Path where to store the account settings
*/
- private final static String CONFIGURATION_PATH =
+ final static String CONFIGURATION_PATH =
"net.java.sip.communicator.impl.googlecontacts";
/**
diff --git a/src/net/java/sip/communicator/impl/googlecontacts/OAuth2TokenStore.java b/src/net/java/sip/communicator/impl/googlecontacts/OAuth2TokenStore.java
index cd04b39..3dfaaea 100644
--- a/src/net/java/sip/communicator/impl/googlecontacts/OAuth2TokenStore.java
+++ b/src/net/java/sip/communicator/impl/googlecontacts/OAuth2TokenStore.java
@@ -19,16 +19,27 @@ import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
+import java.util.*;
import java.util.concurrent.atomic.*;
import javax.swing.*;
import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.util.*;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.*;
+import org.apache.http.client.entity.*;
+import org.apache.http.client.methods.*;
+import org.apache.http.impl.client.*;
+import org.apache.http.message.*;
+
import com.google.api.client.auth.oauth2.*;
import com.google.api.client.http.*;
+import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.javanet.*;
+import com.google.api.client.json.*;
import com.google.api.client.json.jackson2.*;
/**
@@ -42,7 +53,37 @@ public class OAuth2TokenStore
/**
* Logger.
*/
- private static final Logger LOGGER = Logger.getLogger(OAuth2TokenStore.class);
+ private static final Logger LOGGER = Logger
+ .getLogger(OAuth2TokenStore.class);
+
+ /**
+ * Symbol for refresh token in token server response.
+ */
+ private static final String REFRESH_TOKEN_SYMBOL = "refresh_token";
+
+ /**
+ * Symbol for access token in token server response.
+ */
+ private static final String ACCESS_TOKEN_SYMBOL = "access_token";
+
+ /**
+ * Symbol for expiration time in token server response.
+ */
+ private static final String EXPIRES_IN_SYMBOL = "expires_in";
+
+ /**
+ * Interesting token server response fields.
+ */
+ private static final Set<String> TOKEN_RESPONSE_FIELDS;
+
+ static
+ {
+ final HashSet<String> set = new HashSet<String>();
+ set.add(REFRESH_TOKEN_SYMBOL);
+ set.add(ACCESS_TOKEN_SYMBOL);
+ set.add(EXPIRES_IN_SYMBOL);
+ TOKEN_RESPONSE_FIELDS = Collections.unmodifiableSet(set);
+ }
/**
* Google OAuth 2 token server.
@@ -73,13 +114,17 @@ public class OAuth2TokenStore
"urn:ietf:wg:oauth:2.0:oob";
/**
+ * Grant type for communication with token server.
+ */
+ private static final String GOOGLE_API_GRANT_TYPE = "authorization_code";
+
+ /**
* Approval URL.
*/
private static final String APPROVAL_URL = String.format(
- "https://accounts.google.com/o/oauth2/auth?scope=%s&redirect_uri=%s&response_type=code&client_id=%s",
- GOOGLE_API_OAUTH2_SCOPES,
- GOOGLE_API_OAUTH2_REDIRECT_URI,
- GOOGLE_API_CLIENT_ID);
+ "https://accounts.google.com/o/oauth2/auth?scope=%s&redirect_uri=%s"
+ + "&response_type=code&client_id=%s", GOOGLE_API_OAUTH2_SCOPES,
+ GOOGLE_API_OAUTH2_REDIRECT_URI, GOOGLE_API_CLIENT_ID);
/**
* The credential store.
@@ -96,17 +141,19 @@ public class OAuth2TokenStore
* exist, acquire one preferrably from the password store. Optionally,
* involve the user if a credential is not yet stored.
*
+ * @param identity The identity of the API token.
* @return Returns the credential.
* @throws FailedAcquireCredentialException
* @throws MalformedURLException In case requesting authn token failed.
*/
- public Credential get() throws FailedAcquireCredentialException
+ public Credential get(final String identity)
+ throws FailedAcquireCredentialException
{
if (this.store.get() == null)
{
try
{
- acquireCredential(this.store);
+ acquireCredential(this.store, identity);
}
catch (Exception e)
{
@@ -122,23 +169,67 @@ public class OAuth2TokenStore
*
* @param store credential store to update upon refreshing and other
* operations
+ * @param identity the identity to which the refresh token belongs
* @return Acquires and returns the credential instance.
- * @throws MalformedURLException In case of bad redirect URL.
* @throws URISyntaxException In case of bad redirect URI.
+ * @throws IOException
+ * @throws ClientProtocolException
*/
private static void acquireCredential(
- final AtomicReference<Credential> store)
- throws MalformedURLException,
- URISyntaxException
+ final AtomicReference<Credential> store, final String identity)
+ throws URISyntaxException, ClientProtocolException, IOException
{
- LOGGER.info("No credentials available yet. Requesting user to "
- + "approve access to Contacts API using URL: " + APPROVAL_URL);
- final OAuthApprovalDialog dialog = new OAuthApprovalDialog();
- dialog.setVisible(true);
- final String approvalCode = dialog.getApprovalCode();
- LOGGER.debug("Approval code from user: " + approvalCode);
- final TokenData data = requestAuthenticationToken(approvalCode);
- store.set(createCredential(store, data));
+ final TokenData token;
+ String refreshToken = restoreRefreshToken(identity);
+ if (refreshToken == null)
+ {
+ LOGGER.info("No credentials available yet. Requesting user to "
+ + "approve access to Contacts API for identity " + identity
+ + " using URL: " + APPROVAL_URL);
+ final OAuthApprovalDialog dialog =
+ new OAuthApprovalDialog(identity);
+ dialog.setVisible(true);
+ final String approvalCode = dialog.getApprovalCode();
+ LOGGER.debug("Approval code from user: " + approvalCode);
+ token = requestAuthenticationToken(approvalCode);
+ saveRefreshToken(token, identity);
+ }
+ else
+ {
+ token = new TokenData("TOKEN_NOT_AVAILABLE", refreshToken, 0);
+ }
+ store.set(createCredential(store, token));
+ }
+
+ /**
+ * Restore refresh token from encrypted credentials store.
+ *
+ * @param identity The identity corresponding to the refresh token.
+ * @return Returns the refresh token.
+ */
+ private static String restoreRefreshToken(final String identity)
+ {
+ final CredentialsStorageService credentials =
+ GoogleContactsActivator.getCredentialsService();
+ return credentials
+ .loadPassword(GoogleContactsServiceImpl.CONFIGURATION_PATH + "."
+ + identity);
+ }
+
+ /**
+ * Save refresh token for provided identity.
+ *
+ * @param token The refresh token.
+ * @param identity The identity.
+ * @throws IOException An IOException in case of errors.
+ */
+ private static void saveRefreshToken(final TokenData token,
+ final String identity) throws IOException
+ {
+ final CredentialsStorageService credentials =
+ GoogleContactsActivator.getCredentialsService();
+ credentials.storePassword(GoogleContactsServiceImpl.CONFIGURATION_PATH
+ + "." + identity, token.refreshToken);
}
/**
@@ -174,7 +265,8 @@ public class OAuth2TokenStore
* @throws URISyntaxException In case of bad OAuth 2 redirect URI.
*/
private static Credential createCredential(
- final AtomicReference<Credential> store, final TokenData data) throws URISyntaxException
+ final AtomicReference<Credential> store, final TokenData data)
+ throws URISyntaxException
{
final Credential.Builder builder =
new Credential.Builder(
@@ -198,7 +290,7 @@ public class OAuth2TokenStore
content.put("client_id", GOOGLE_API_CLIENT_ID);
content.put("client_secret", GOOGLE_API_CLIENT_SECRET);
LOGGER.info("Inserting client authentication data into "
- + " refresh token request.");
+ + "refresh token request.");
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Request: " + content.toString());
@@ -249,11 +341,57 @@ public class OAuth2TokenStore
*
* @param approvalCode the approval code
* @return Returns the acquired token data from OAuth 2 token server.
+ * @throws IOException
+ * @throws ClientProtocolException
*/
- private static TokenData requestAuthenticationToken(final String approvalCode)
+ private static TokenData requestAuthenticationToken(
+ final String approvalCode) throws ClientProtocolException, IOException
{
- // FIXME actually acquire credential
- return new TokenData("", "", 3600L);
+ final HttpClient client = new DefaultHttpClient();
+ final HttpPost post = new HttpPost(GOOGLE_OAUTH2_TOKEN_SERVER.toURI());
+ final UrlEncodedFormEntity entity =
+ new UrlEncodedFormEntity(Arrays.asList(new BasicNameValuePair(
+ "code", approvalCode), new BasicNameValuePair("client_id",
+ GOOGLE_API_CLIENT_ID), new BasicNameValuePair("client_secret",
+ GOOGLE_API_CLIENT_SECRET), new BasicNameValuePair(
+ "redirect_uri", GOOGLE_API_OAUTH2_REDIRECT_URI),
+ new BasicNameValuePair("grant_type", GOOGLE_API_GRANT_TYPE)));
+ post.setEntity(entity);
+ final HttpResponse httpResponse = client.execute(post);
+ final JsonParser parser =
+ JacksonFactory.getDefaultInstance().createJsonParser(
+ httpResponse.getEntity().getContent());
+ try
+ {
+ // Token response components initialized with defaults in case
+ // fields are missing in the token server response.
+ String accessToken = "";
+ String refreshToken = "";
+ long expiresIn = 3600;
+ // Parse token server response.
+ String found;
+ while (parser.nextToken() != JsonToken.END_OBJECT)
+ {
+ found = parser.skipToKey(TOKEN_RESPONSE_FIELDS);
+ if (REFRESH_TOKEN_SYMBOL.equals(found))
+ {
+ refreshToken = parser.getText();
+ }
+ else if (ACCESS_TOKEN_SYMBOL.equals(found))
+ {
+ accessToken = parser.getText();
+ }
+ else if (EXPIRES_IN_SYMBOL.equals(found))
+ {
+ expiresIn = parser.getLongValue();
+ }
+ }
+ return new TokenData(accessToken, refreshToken, expiresIn);
+ }
+ finally
+ {
+ parser.close();
+ }
}
/**
@@ -270,10 +408,13 @@ public class OAuth2TokenStore
private final SIPCommTextField code = new SIPCommTextField("");
- public OAuthApprovalDialog()
+ public OAuthApprovalDialog(final String identity)
{
this.setModal(true);
- this.label = new SIPCommLinkButton("Click here to approve.");
+ this.label =
+ new SIPCommLinkButton(
+ "Click here to approve. Make sure you log in as "
+ + identity);
this.label.addActionListener(new ActionListener()
{
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 99337a8..4fd9387 100644
--- a/src/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf
+++ b/src/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf
@@ -25,4 +25,10 @@ Import-Package: org.osgi.framework,
javax.swing.table,
javax.swing.tree,
javax.swing.text,
- javax.net.ssl
+ javax.net.ssl,
+ org.apache.http,
+ org.apache.http.client,
+ org.apache.http.client.entity,
+ org.apache.http.client.methods,
+ org.apache.http.impl.client,
+ org.apache.http.message