Package org.rssowl.core.connection

Source Code of org.rssowl.core.connection.PlatformCredentialsProvider$Credentials

/*   **********************************************************************  **
**   Copyright notice                                                       **
**                                                                          **
**   (c) 2005-2009 RSSOwl Development Team                                  **
**   http://www.rssowl.org/                                                 **
**                                                                          **
**   All rights reserved                                                    **
**                                                                          **
**   This program and the accompanying materials are made available under   **
**   the terms of the Eclipse Public License v1.0 which accompanies this    **
**   distribution, and is available at:                                     **
**   http://www.rssowl.org/legal/epl-v10.html                               **
**                                                                          **
**   A copy is found in the file epl-v10.html and important notices to the  **
**   license from the team is found in the textfile LICENSE.txt distributed **
**   in this package.                                                       **
**                                                                          **
**   This copyright notice MUST APPEAR in all copies of the file!           **
**                                                                          **
**   Contributors:                                                          **
**     RSSOwl Development Team - initial API and implementation             **
**                                                                          **
**  **********************************************************************  */

package org.rssowl.core.connection;

import org.eclipse.core.net.proxy.IProxyData;
import org.eclipse.core.net.proxy.IProxyService;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.equinox.internal.security.storage.friends.InternalExchangeUtils;
import org.eclipse.equinox.security.storage.EncodingUtils;
import org.eclipse.equinox.security.storage.ISecurePreferences;
import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
import org.eclipse.equinox.security.storage.StorageException;
import org.eclipse.equinox.security.storage.provider.IProviderHints;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.Activator;
import org.rssowl.core.internal.InternalOwl;
import org.rssowl.core.internal.persist.pref.DefaultPreferences;
import org.rssowl.core.persist.pref.IPreferenceScope;
import org.rssowl.core.util.Pair;
import org.rssowl.core.util.StringUtils;
import org.rssowl.core.util.URIUtils;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

/**
* The default implementation of the ICredentialsProvider retrieves
* authentication Credentials from the Equinox Security Storage.
*
* @author bpasero
*/
@SuppressWarnings("restriction")
public class PlatformCredentialsProvider implements ICredentialsProvider {

  /* Node for feed related security preferences */
  private static final String SECURE_FEED_NODE = "rssowl/feeds"; //$NON-NLS-1$

  /* File with credentials stored */
  private static final String SECURE_STORAGE_FILE = ".credentials"; //$NON-NLS-1$

  /* ID of the Win32 dependent password provider (win32) */
  private static final String WIN_PW_PROVIDER_ID = "org.eclipse.equinox.security.WindowsPasswordProvider"; //$NON-NLS-1$

  /* ID of the RSSOwl password provider (Dialog asking for Master Password) */
  private static final String RSSOWL_PW_PROVIDER_ID = "org.rssowl.ui.RSSOwlPasswordProvider"; //$NON-NLS-1$

  /* ID of the MacOS dependent password provider */
  private static final String MACOS_PW_PROVIDER_ID = "org.eclipse.equinox.security.OSXKeystoreIntegration"; //$NON-NLS-1$

  /* Unique Key to store Usernames */
  private static final String USERNAME = "org.rssowl.core.connection.auth.Username"; //$NON-NLS-1$

  /* Unique Key to store Passwords */
  private static final String PASSWORD = "org.rssowl.core.connection.auth.Password"; //$NON-NLS-1$

  /* Unique Key to store Domains */
  private static final String DOMAIN = "org.rssowl.core.connection.auth.Domain"; //$NON-NLS-1$

  /* Separator between Domain and Username */
  private static final String DOMAIN_SEPARATOR = "\\"; //$NON-NLS-1$

  /* System Property to enable NTLM Proxy support */
  private static final String ENABLE_NTLM_PROXY = "enableNtlmProxy"; //$NON-NLS-1$

  /* Flag for NTLM Proxy Support controlled through System Property */
  private static final boolean NTLM_PROXY_ENABLED = (System.getProperty(ENABLE_NTLM_PROXY) != null);

  /* Default Realm being used to store credentials */
  private static final String REALM = ""; //$NON-NLS-1$

  /* A cache of non-protected Links (in the form Link + Realm) */
  private final Set<String> fUnprotectedLinksCache = Collections.synchronizedSet(new HashSet<String>());

  /* The In-Memory credentials store if the user chooses to not store passwords permanently */
  private final Map<String, ICredentials> fInMemoryStore = Collections.synchronizedMap(new HashMap<String, ICredentials>());

  /* Simple POJO Implementation of ICredentials */
  private static class Credentials implements ICredentials {
    private String fUsername;
    private String fPassword;
    private String fDomain;

    Credentials(String username, String password, String domain) {
      fUsername = username;
      fPassword = password;
      fDomain = domain;
    }

    public String getUsername() {
      return fUsername;
    }

    public String getPassword() {
      return fPassword;
    }

    public String getDomain() {
      return fDomain;
    }
  }

  /*
   * @see
   * org.rssowl.core.connection.ICredentialsProvider#getPersistedAuthCredentials
   * (java.net.URI, java.lang.String)
   */
  public ICredentials getPersistedAuthCredentials(URI link, String realm) throws CredentialsException {
    return internalGetAuthCredentials(link, realm, true);
  }

  /*
   * @see
   * org.rssowl.core.connection.ICredentialsProvider#getAuthCredentials(java
   * .net.URI, java.lang.String)
   */
  public synchronized ICredentials getAuthCredentials(URI link, String realm) throws CredentialsException {
    return internalGetAuthCredentials(link, realm, false);
  }

  private synchronized ICredentials internalGetAuthCredentials(URI link, String realm, boolean persistedOnly) throws CredentialsException {

    /* Check Cache first */
    if (isUnprotected(link, realm))
      return null;

    /* Check In-Memory Store */
    if (!persistedOnly) {
      ICredentials inMemoryCredentials = fInMemoryStore.get(toCacheKey(link, realm));
      if (inMemoryCredentials != null)
        return inMemoryCredentials;
    }

    /* Retrieve Credentials */
    ICredentials authorizationInfo = getAuthorizationInfo(link, realm);

    /* Credentials Provided */
    if (authorizationInfo != null)
      return authorizationInfo;

    /* Cache as unprotected (but check memory store as necessary) */
    if (!persistedOnly || !fInMemoryStore.containsKey(toCacheKey(link, realm)))
      addUnprotected(link, realm);

    /* Credentials not provided */
    return null;
  }

  private ISecurePreferences getSecurePreferences() {
    if (!InternalOwl.IS_ECLIPSE) {
      IPreferenceScope prefs = Owl.getPreferenceService().getGlobalScope();
      boolean useOSPasswordProvider = prefs.getBoolean(DefaultPreferences.USE_OS_PASSWORD);

      /* Disable OS Password if Master Password shall be used */
      if (prefs.getBoolean(DefaultPreferences.USE_MASTER_PASSWORD))
        useOSPasswordProvider = false;

      /* Try storing credentials in profile folder */
      try {
        Activator activator = Activator.getDefault();

        /* Check if Bundle is Stopped */
        if (activator == null)
          return null;

        IPath stateLocation = activator.getStateLocation();
        stateLocation = stateLocation.append(SECURE_STORAGE_FILE);
        URL location = stateLocation.toFile().toURL();
        Map<String, String> options = null;

        /* Use OS dependent password provider if available */
        if (useOSPasswordProvider) {
          if (Platform.OS_WIN32.equals(Platform.getOS())) {
            options = new HashMap<String, String>();
            options.put(IProviderHints.REQUIRED_MODULE_ID, WIN_PW_PROVIDER_ID);
          } else if (Platform.OS_MACOSX.equals(Platform.getOS())) {
            options = new HashMap<String, String>();
            options.put(IProviderHints.REQUIRED_MODULE_ID, MACOS_PW_PROVIDER_ID);
          }
        }

        /* Use RSSOwl password provider */
        else {
          options = new HashMap<String, String>();
          options.put(IProviderHints.REQUIRED_MODULE_ID, RSSOWL_PW_PROVIDER_ID);
        }

        return SecurePreferencesFactory.open(location, options);
      } catch (MalformedURLException e) {
        Activator.safeLogError(e.getMessage(), e);
      } catch (IllegalStateException e1) {
        Activator.safeLogError(e1.getMessage(), e1);
      } catch (IOException e2) {
        Activator.safeLogError(e2.getMessage(), e2);
      }
    }

    /* Fallback to default location */
    return SecurePreferencesFactory.getDefault();
  }

  private ICredentials getAuthorizationInfo(URI link, String realm) throws CredentialsException {
    ISecurePreferences securePreferences = getSecurePreferences();

    /* Check if Bundle is Stopped */
    if (securePreferences == null)
      return null;

    /* Return from Equinox Security Storage */
    if (securePreferences.nodeExists(SECURE_FEED_NODE)) { // Global Feed Node
      ISecurePreferences allFeedsPreferences = securePreferences.node(SECURE_FEED_NODE);
      if (allFeedsPreferences.nodeExists(EncodingUtils.encodeSlashes(link.toString()))) { // Feed Node
        ISecurePreferences feedPreferences = allFeedsPreferences.node(EncodingUtils.encodeSlashes(link.toString()));
        if (feedPreferences.nodeExists(EncodingUtils.encodeSlashes(realm != null ? realm : REALM))) { // Realm Node
          ISecurePreferences realmPreferences = feedPreferences.node(EncodingUtils.encodeSlashes(realm != null ? realm : REALM));

          try {
            String username = realmPreferences.get(USERNAME, null);
            String password = realmPreferences.get(PASSWORD, null);
            String domain = realmPreferences.get(DOMAIN, null);

            if (username != null && password != null)
              return new Credentials(username, password, domain);
          } catch (StorageException e) {
            throw new CredentialsException(Activator.getDefault().createErrorStatus(e.getMessage(), e));
          }
        }
      }
    }

    return null;
  }

  /*
   * @see
   * org.rssowl.core.connection.auth.ICredentialsProvider#getProxyCredentials
   * (java.net.URI)
   */
  public IProxyCredentials getProxyCredentials(URI link) {
    Activator activator = Activator.getDefault();

    /* Check if Bundle is Stopped */
    if (activator == null)
      return null;

    IProxyService proxyService = activator.getProxyService();

    /* Check if Proxy is enabled */
    if (!proxyService.isProxiesEnabled())
      return null;

    String host = URIUtils.safeGetHost(link);
    boolean isSSL = URIUtils.HTTPS_SCHEME.equals(link.getScheme());

    /* Retrieve Proxy Data */
    final IProxyData proxyData = proxyService.getProxyDataForHost(host, isSSL ? IProxyData.HTTPS_PROXY_TYPE : IProxyData.HTTP_PROXY_TYPE);
    if (proxyData != null) {

      /* Look for Domain as part of Username to support NTLM Proxy */
      final String proxyHost = proxyData.getHost();
      final int proxyPort = proxyData.getPort();
      final Pair<String /* Username */, String /* Domain */> proxyUserAndDomain = splitUserAndDomain(proxyData.getUserId());
      final String proxyPassword = proxyData.getPassword();

      /* Return as IProxyCredentials Object */
      return new IProxyCredentials() {
        public String getHost() {
          return proxyHost;
        }

        public int getPort() {
          return proxyPort;
        }

        public String getUsername() {
          return proxyUserAndDomain.getFirst();
        }

        public String getPassword() {
          return proxyPassword;
        }

        public String getDomain() {
          return proxyUserAndDomain.getSecond();
        }
      };
    }

    /* Feed does not require Proxy or Credentials not supplied */
    return null;
  }

  private Pair<String /* Username */, String /* Domain */> splitUserAndDomain(String username) {
    if (NTLM_PROXY_ENABLED && StringUtils.isSet(username) && username.contains(DOMAIN_SEPARATOR)) {
      String user = null;
      String domain = null;

      StringTokenizer tokenizer = new StringTokenizer(username, DOMAIN_SEPARATOR);
      while (tokenizer.hasMoreTokens()) {
        String token = tokenizer.nextToken();
        if (StringUtils.isSet(token)) {
          if (domain == null)
            domain = token;
          else if (user == null)
            user = token;
        }
      }

      if (StringUtils.isSet(user) && StringUtils.isSet(domain))
        return Pair.create(user, domain);
    }

    return Pair.create(username, null);
  }

  /*
   * @see
   * org.rssowl.core.connection.ICredentialsProvider#setAuthCredentials(org.
   * rssowl.core.connection.ICredentials, java.net.URI, java.lang.String)
   */
  public void setAuthCredentials(ICredentials credentials, URI link, String realm) throws CredentialsException {
    internalSetAuthCredentials(credentials, link, realm, true);
  }

  /*
   * @see
   * org.rssowl.core.connection.ICredentialsProvider#setInMemoryAuthCredentials
   * (org.rssowl.core.connection.ICredentials, java.net.URI, java.lang.String)
   */
  public void setInMemoryAuthCredentials(ICredentials credentials, URI link, String realm) throws CredentialsException {
    internalSetAuthCredentials(credentials, link, realm, false);
  }

  private void internalSetAuthCredentials(ICredentials credentials, URI link, String realm, boolean persist) throws CredentialsException {

    /* Store Credentials in In-Memory Store */
    if (!persist) {
      fInMemoryStore.put(toCacheKey(link, realm), credentials);
    }

    /* Store Credentials in secure Storage */
    else {
      ISecurePreferences securePreferences = getSecurePreferences();

      /* Check if Bundle is Stopped */
      if (securePreferences == null)
        return;

      /* Store in Equinox Security Storage */
      ISecurePreferences allFeedsPreferences = securePreferences.node(SECURE_FEED_NODE);
      ISecurePreferences feedPreferences = allFeedsPreferences.node(EncodingUtils.encodeSlashes(link.toString()));
      ISecurePreferences realmPreference = feedPreferences.node(EncodingUtils.encodeSlashes(realm != null ? realm : REALM));

      IPreferenceScope globalScope = Owl.getPreferenceService().getGlobalScope();

      /* OS Password is only supported on Windows and Mac */
      boolean useOSPassword = globalScope.getBoolean(DefaultPreferences.USE_OS_PASSWORD);
      if (!Platform.OS_WIN32.equals(Platform.getOS()) && !Platform.OS_MACOSX.equals(Platform.getOS()))
        useOSPassword = false;

      boolean encryptPW = useOSPassword || globalScope.getBoolean(DefaultPreferences.USE_MASTER_PASSWORD);
      try {
        if (credentials.getUsername() != null)
          realmPreference.put(USERNAME, credentials.getUsername(), encryptPW);

        if (credentials.getPassword() != null)
          realmPreference.put(PASSWORD, credentials.getPassword(), encryptPW);

        if (credentials.getDomain() != null)
          realmPreference.put(DOMAIN, credentials.getDomain(), encryptPW);

        realmPreference.flush(); // Flush to disk early
      } catch (StorageException e) {
        throw new CredentialsException(Activator.getDefault().createErrorStatus(e.getMessage(), e));
      } catch (IOException e) {
        throw new CredentialsException(Activator.getDefault().createErrorStatus(e.getMessage(), e));
      }
    }

    /* Uncache */
    removeUnprotected(link, realm);
  }

  /*
   * @see
   * org.rssowl.core.connection.auth.ICredentialsProvider#setProxyCredentials
   * (org.rssowl.core.connection.auth.IProxyCredentials, java.net.URI)
   */
  public void setProxyCredentials(IProxyCredentials credentials, URI link) {
    IProxyService proxyService = Activator.getDefault().getProxyService();
    proxyService.setProxiesEnabled(true);
    boolean isSSL = URIUtils.HTTPS_SCHEME.equals(link.getScheme());

    /* Retrieve Proxy Data */
    final IProxyData proxyData = proxyService.getProxyData(isSSL ? IProxyData.HTTPS_PROXY_TYPE : IProxyData.HTTP_PROXY_TYPE);
    if (proxyData != null) { //TODO What if Data is NULL?
      proxyData.setHost(credentials.getHost());
      proxyData.setPort(credentials.getPort());
      proxyData.setUserid(credentials.getUsername());
      proxyData.setPassword(credentials.getPassword());
    }
  }

  /*
   * @see
   * org.rssowl.core.connection.ICredentialsProvider#deleteAuthCredentials(java
   * .net.URI, java.lang.String)
   */
  public synchronized void deleteAuthCredentials(URI link, String realm) throws CredentialsException {

    /* Delete from In-Memory Store if present */
    fInMemoryStore.remove(toCacheKey(link, realm));

    /* Delete from Cache */
    removeUnprotected(link, realm);

    /* Check if Bundle is Stopped */
    ISecurePreferences securePreferences = getSecurePreferences();
    if (securePreferences == null)
      return;

    /* Remove from Equinox Security Storage */
    if (securePreferences.nodeExists(SECURE_FEED_NODE)) { // Global Feed Node
      ISecurePreferences allFeedsPreferences = securePreferences.node(SECURE_FEED_NODE);
      if (allFeedsPreferences.nodeExists(EncodingUtils.encodeSlashes(link.toString()))) { // Feed Node
        ISecurePreferences feedPreferences = allFeedsPreferences.node(EncodingUtils.encodeSlashes(link.toString()));
        if (feedPreferences.nodeExists(EncodingUtils.encodeSlashes(realm != null ? realm : REALM))) { // Realm Node
          ISecurePreferences realmPreferences = feedPreferences.node(EncodingUtils.encodeSlashes(realm != null ? realm : REALM));
          realmPreferences.clear();
          realmPreferences.removeNode();
          try {
            feedPreferences.flush();
          } catch (IOException e) {
            throw new CredentialsException(Activator.getDefault().createErrorStatus(e.getMessage(), e));
          }
        }
      }
    }
  }

  /*
   * @see
   * org.rssowl.core.connection.auth.ICredentialsProvider#deleteProxyCredentials
   * (java.net.URI)
   */
  public void deleteProxyCredentials(URI link) {
    IProxyService proxyService = Activator.getDefault().getProxyService();
    proxyService.setProxiesEnabled(false);
    //TODO System Properties are still set?
  }

  /**
   * An internal method only available for the
   * {@link PlatformCredentialsProvider} to clear all secure preferences nodes.
   * This method is called e.g. when the master password is to be changed or
   * disabled.
   */
  public void clear() {

    /* Clear In-Memory Store */
    fInMemoryStore.clear();

    /* Clear unprotected links cache */
    fUnprotectedLinksCache.clear();

    /* Clear cached info */
    InternalExchangeUtils.passwordProvidersReset();

    /* Remove all Nodes */
    ISecurePreferences secureRoot = getSecurePreferences();

    /* Check if Bundle is Stopped */
    if (secureRoot == null)
      return;

    String[] childrenNames = secureRoot.childrenNames();
    for (String child : childrenNames) {
      secureRoot.node(child).removeNode();
    }

    /* Flush to Disk */
    try {
      secureRoot.flush();
    } catch (IOException e) {
      Activator.getDefault().logError(e.getMessage(), e);
    }
  }

  private boolean isUnprotected(URI link, String realm) {
    return fUnprotectedLinksCache.contains(toCacheKey(link, realm));
  }

  private void addUnprotected(URI link, String realm) {
    fUnprotectedLinksCache.add(toCacheKey(link, realm));
  }

  private void removeUnprotected(URI link, String realm) {
    fUnprotectedLinksCache.remove(toCacheKey(link, realm));
  }

  private String toCacheKey(URI link, String realm) {
    if (realm == null)
      realm = REALM;

    return link.toString() + realm;
  }
}
TOP

Related Classes of org.rssowl.core.connection.PlatformCredentialsProvider$Credentials

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.