Index: salesforce/README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/salesforce/README.txt,v
retrieving revision 1.4.6.9
diff -u -p -r1.4.6.9 README.txt
--- salesforce/README.txt 17 May 2010 20:14:25 -0000 1.4.6.9
+++ salesforce/README.txt 19 May 2010 13:38:39 -0000
@@ -27,6 +27,16 @@ You will need to know your login data an
http://php.net/soap
+RECOMMENDED:
+
+1) Download and install your organization's generated Enterprise WSDL file.
+ (see WORKING WITH WSDL FILES)
+
+2) AES encryption
+ http://drupal.org/project/aes
+ (see SOME NOTES ABOUT SECURITY).
+
+
INSTALLATION:
1) Download, uncompress and situate the module as per usual.
@@ -85,6 +95,19 @@ QUICKSTART:
mapping for and manually create a Salesforce object for it.
+SOME NOTES ABOUT SECURITY:
+By default all SalesForce credentials are stored in the variables table,
+unencrypted. If this is a problem for you, this module supports encryption via
+aes module http://drupal.org/project/aes. You will need to create a directory
+outside your webroot (you can use the same one you used for your WSDL) wherein
+your encryption key will be stored. Your credentials will thus forth be
+encrypted as securely as AES allows. PLEASE NOTE: your data is still only as
+secure as your network. It may be possible for a savvy attacker to access your
+data at any of various points between your Drupal site and SalesForce.com. As
+this always, you should educate yourself about the risks involved before storing
+and transferring sensitive data across the internet.
+
+
WORKING WITH WSDL FILES
If you do not upload a WSDL file, Salesforce module will use a default .wsdl
Index: salesforce/salesforce_api/salesforce_api.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/salesforce/salesforce_api/salesforce_api.admin.inc,v
retrieving revision 1.2.2.27
diff -u -p -r1.2.2.27 salesforce_api.admin.inc
--- salesforce/salesforce_api/salesforce_api.admin.inc 17 May 2010 20:14:25 -0000 1.2.2.27
+++ salesforce/salesforce_api/salesforce_api.admin.inc 19 May 2010 13:38:39 -0000
@@ -10,7 +10,7 @@
/**
* The settings form at admin/settings/salesforce.
*/
-function salesforce_api_settings_form() {
+function salesforce_api_settings_form($form_state) {
$form = array();
// Use the username field to collapse the API settings fieldset.
@@ -25,26 +25,61 @@ function salesforce_api_settings_form()
'#weight' => -10,
);
$form['api']['salesforce_api_username'] = array(
- '#type' => 'textfield',
+ '#type' => 'password',
'#title' => t('Username'),
'#description' => t('Should be in the form of an e-mail address.'),
- '#default_value' => variable_get('salesforce_api_username', ''),
- '#required' => TRUE,
+ '#default_value' => $form_state['values']['salesforce_api_username'],
+ '#required' => !variable_get('salesforce_api_username', FALSE),
);
$form['api']['salesforce_api_password'] = array(
'#type' => 'password',
'#title' => t('Password'),
'#description' => t('Enter the password used when logging into Salesforce.'),
- '#default_value' => variable_get('salesforce_api_password', ''),
+ '#default_value' => $form_state['values']['salesforce_api_password'],
+ '#required' => !variable_get('salesforce_api_password', FALSE),
);
$form['api']['salesforce_api_token'] = array(
- '#type' => 'textfield',
+ '#type' => 'password',
'#title' => t('Security token'),
- '#description' => t('Set your security token by logging into Salesforce and navigating to Setup > My Personal Information > Reset My Security Token.'),
- '#required' => TRUE,
- '#default_value' => variable_get('salesforce_api_token', ''),
- );
-
+ '#description' => t('Set your security token by logging into Salesforce and
+ navigating to Setup > My Personal Information > Reset My Security Token.'),
+ '#default_value' => $form_state['values']['salesforce_api_token'],
+ '#required' => !variable_get('salesforce_api_token', FALSE),
+ );
+
+ if (!empty($username)) {
+ $form['api']['#description'] =
+ t('Salesforce.com connection is working properly.
Edit the following
+ fields only if you wish to change your login credentials.');
+ $form['api']['salesforce_api_reset_credentials'] = array(
+ '#type' => 'checkbox',
+ '#title' => 'Clear SalesForce API credentials',
+ '#description' => 'Erase current API login settings. Clearing SalesForce
+ API credentials will prevent your website from connecting to Salesforce.com',
+ );
+ }
+ $form['api']['encryption'] = array(
+ '#type' => 'item',
+ '#title' => 'Encryption',
+ '#value' => t('It is highly recommended that you use encryption to protect your SalesForce.com credentials. Encryption is supported via AES module.'),
+ 'status' => array('#type' => 'item', '#title' => FALSE),
+ );
+ if (salesforce_api_encryption_available(array('display_all' => TRUE))) {
+ $form['api']['encryption']['status']['#value'] =
+ 'Encryption is available and configured properly.';
+ $form['api']['encryption']['salesforce_api_encrypt'] = array(
+ '#type' => 'checkbox',
+ '#title' => 'Encrypt SalesForce credentials (HIGHLY RECOMMENDED)',
+ '#description' => 'Note: enabling this setting will not encrypt existing credentials.',
+ '#default_value' => TRUE,
+ );
+ }
+ else {
+ $form['api']['encryption']['status']['#value'] =
+ 'AES is not installed - encryption is not
+ available.';
+ }
+
$form['log'] = array(
'#type' => 'fieldset',
'#title' => t('Log settings'),
@@ -102,11 +137,11 @@ function salesforce_api_settings_form()
$wsdl_dir = variable_get('salesforce_api_dir_wsdl', FALSE);
$form['wsdl'] = array(
'#type' => 'fieldset',
- '#title' => 'WSDL directory',
- '#description' => 'Your organization\'s WSDL file can expose potentially sensitive information. It is highly recommended that your WSDL file be stored outside your webroot. Please enter either a path relative to your webroot (e.g. ../wsdl) or a fully qualified path (e.g. /home/username/wsdl) in which to store your WSDL.',
+ '#title' => t('WSDL directory'),
+ '#description' => t('Your organization\'s WSDL file can expose potentially sensitive information. It is highly recommended that your WSDL file be stored outside your webroot. Please enter either a path relative to your webroot (e.g. ../wsdl) or a fully qualified path (e.g. /home/username/wsdl) in which to store your WSDL.'),
'salesforce_api_dir_wsdl' => array(
'#type' => 'textfield',
- '#title' => 'WSDL Directory',
+ '#title' => t('WSDL Directory'),
'#default_value' => $wsdl_dir,
),
'#collapsible' => TRUE,
@@ -121,21 +156,56 @@ function salesforce_api_settings_form()
}
/**
- * Settings form validate handler to verify new salesforce credentials before saving them.
+ * Settings form validate handler to verify new salesforce credentials before
+ * saving them.
*/
function salesforce_api_settings_form_validate($form, &$form_state) {
$values = $form_state['values'];
- if (!salesforce_api_connect($values['salesforce_api_username'], $values['salesforce_api_password'], $values['salesforce_api_token'], TRUE)) {
- // If not, prevent the user from overwriting the current configuration.
- form_set_error('salesforce_api_username', t('Unable to connect to Salesforce. Please check your credentials.'));
+
+ if (isset($values['salesforce_api_dir_wsdl'])
+ && !file_exists($values['salesforce_api_dir_wsdl'])) {
+ form_set_error('salesforce_api_dir_wsdl', 'The specified WSDL directory does not exist. Please make sure the directory exists, check your input, and try again.');
}
- else {
- drupal_set_message(t('Salesforce connection established.'));
+
+ // If we are clearing values, no need to continue validation.
+ if ($values['salesforce_api_reset_credentials']) {
+ return;
}
- if (isset($form_state['values']['salesforce_api_dir_wsdl'])
- && !file_exists($form_state['values']['salesforce_api_dir_wsdl'])) {
- form_set_error('salesforce_api_dir_wsdl', 'The specified directory does not exist. Please make sure the directory exists, check your input, and try again.');
+ foreach (array('salesforce_api_username', 'salesforce_api_password', 'salesforce_api_token') as $value) {
+ if (empty($values[$value])) {
+ $errors[$value] = ucwords(str_replace('salesforce_api_', ' ', $value)) . ' is required';
+ }
+ }
+
+ if (count($errors) == 3) {
+ // If all 3 fields are empty, the user has not tried to change credentials.
+ // Unset the form values in order to preserve existing credentials.
+ unset($form_state['values']['salesforce_api_username'],
+ $form_state['salesforce_api_password'],
+ $form_state['values']['salesforce_api_token']);
+ return;
+ }
+ elseif (!empty($errors)) {
+ drupal_set_message(t('Unable to reset SalesForce API credentials.'), 'error');
+ foreach ($errors as $field => $error) {
+ form_set_error($field, $error);
+ }
+ // If we got errors already no need to continue with validation.
+ return;
+ }
+
+ // If we are setting or resetting values, test the connection.
+ $connection = salesforce_api_connect($values['salesforce_api_username'],
+ $values['salesforce_api_password'], $values['salesforce_api_token'], TRUE);
+ if (is_object($connection)) {
+ drupal_set_message(t('Connection established. SalesForce credentials updated.'));
+ } else {
+ drupal_set_message(
+ t('Resetting SalesForce API credentials failed.', 'error'));
+ form_set_error('salesforce_api_username', t('Unable to connect to Salesforce. Please check your credentials.'));
+ form_set_error('salesforce_api_password');
+ form_set_error('salesforce_api_token');
}
}
@@ -143,21 +213,36 @@ function salesforce_api_settings_form_va
* Settings form submit handler so that password doesn't get deleted.
*/
function salesforce_api_settings_form_submit($form, &$form_state) {
- // If the user hit "Save Configuration" and the required field
- // salesforce_api_password is blank, try to get it from variables
- if ($form_state['values']['submit'] == $form_state['values']['op'] and empty($form_state['values']['salesforce_api_password'])) {
- $pass = variable_get('salesforce_api_password', FALSE);
- if (isset($pass)) {
- $form_state['values']['salesforce_api_password'] = $pass;
- }
- }
- if (variable_get('salesforce_api_dir_wsdl', FALSE) !=
- $form_state['values']['salesforce_api_dir_wsdl']) {
+ $values = $form_state['values'];
+
+ if (variable_get('salesforce_api_dir_wsdl', FALSE)
+ != $values['salesforce_api_dir_wsdl']) {
drupal_set_message('Please make sure the WSDL directory is writeable, and upload a valid SalesForce .xml or .wsdl file.');
$form_state['redirect'] = array(
SALESFORCE_PATH_UPDATE_WSDL,
'destination=' . SALESFORCE_PATH_ADMIN);
}
+
+ if ($values['salesforce_api_reset_credentials']) {
+ unset($form_state['values']['salesforce_api_reset_credentials']);
+ foreach (array('username', 'password', 'token', 'encrypt') as $value) {
+ variable_del('salesforce_api_' . $value);
+ unset($form_state['values']['salesforce_api_' . $value]);
+ }
+ drupal_set_message('SalesForce credentials reset.');
+ // If credentials were reset, we don't need to continue to encryption.
+ return;
+ }
+
+ if ($values['salesforce_api_encrypt']
+ && !empty($values['salesforce_api_username'])) {
+ $form_state['values']['salesforce_api_username'] =
+ salesforce_api_encrypt($values['salesforce_api_username']);
+ $form_state['values']['salesforce_api_password'] =
+ salesforce_api_encrypt($values['salesforce_api_password']);
+ $form_state['values']['salesforce_api_token'] =
+ salesforce_api_encrypt($values['salesforce_api_token']);
+ }
}
/**
Index: salesforce/salesforce_api/salesforce_api.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/salesforce/salesforce_api/salesforce_api.install,v
retrieving revision 1.2.2.12
diff -u -p -r1.2.2.12 salesforce_api.install
--- salesforce/salesforce_api/salesforce_api.install 23 Feb 2010 20:54:11 -0000 1.2.2.12
+++ salesforce/salesforce_api/salesforce_api.install 19 May 2010 13:38:39 -0000
@@ -150,6 +150,14 @@ function salesforce_api_requirements($ph
$description = t('Unable to connect to Salesforce using current credentials.', array('!url' => url(SALESFORCE_PATH_ADMIN)));
$severity = REQUIREMENT_ERROR;
}
+ elseif (!salesforce_api_encryption_available(array('check_config' => FALSE))) {
+ $description = t('Encryption is unavailable. Using encryption is highly recommended in order to better secure your data.');
+ $severity = REQUIREMENT_ERROR;
+ }
+ elseif (!salesforce_api_encryption_available(array('check_config' => TRUE))) {
+ $description = t('SalesForce encryption is enabled but not configured securely.');
+ $severity = REQUIREMENT_WARNING;
+ }
else {
$description = '';
$severity = REQUIREMENT_OK;
Index: salesforce/salesforce_api/salesforce_api.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/salesforce/salesforce_api/salesforce_api.module,v
retrieving revision 1.2.2.39
diff -u -p -r1.2.2.39 salesforce_api.module
--- salesforce/salesforce_api/salesforce_api.module 17 May 2010 20:14:25 -0000 1.2.2.39
+++ salesforce/salesforce_api/salesforce_api.module 19 May 2010 13:38:39 -0000
@@ -194,13 +195,25 @@ function salesforce_api_connect($usernam
return $sf;
}
- // Boolean, whether we are connecting with the default website user or not.
- $default_site_user = $username == variable_get('salesforce_api_username', FALSE);
+ // Load up the sitewide API credentials if none were provided.
+ $encrypted = variable_get('salesforce_api_encrypt', FALSE);
+ $default_username = $encrypted
+ ? salesforce_api_decrypt(variable_get('salesforce_api_username', ''))
+ : variable_get('salesforce_api_username', '');
+ $username = $username ? $username : $default_username;
+ $password = $password
+ ? $password
+ : ($encrypted
+ ? salesforce_api_decrypt(variable_get('salesforce_api_password', ''))
+ : variable_get('salesforce_api_password', ''));
+ $token = $token
+ ? $token
+ : ($encrypted
+ ? salesforce_api_decrypt(variable_get('salesforce_api_token', ''))
+ : variable_get('salesforce_api_token', ''));
- // Load up the sitewide API credentials if no others were provided:
- $username = $username ? $username : variable_get('salesforce_api_username', '');
- $password = $password ? $password : variable_get('salesforce_api_password', '');
- $token = $token ? $token : variable_get('salesforce_api_token', '');
+ // Boolean, whether we are connecting with the default website user or not.
+ $default_site_user = $username == $default_username;
// Include the file that defines the class.
require_once(drupal_get_path('module', 'salesforce_api') .'/salesforce.class.inc');
@@ -864,6 +877,68 @@ function salesforce_api_cron() {
return;
}
+/**
+ * Wrappers for encryption lib. Right now only AES encryption is supported.
+ * If/when other methods are supported, this abstraction layer will make the
+ * transition easier.
+ */
+function salesforce_api_decrypt($value) {
+ return aes_decrypt($value);
+}
+function salesforce_api_encrypt($value) {
+ return aes_encrypt($value);
+}
+function salesforce_api_encryption_available($options = array()) {
+ $defaults = array(
+ 'check_config' => TRUE,
+ 'display_errors' => FALSE,
+ 'display_warnings' => FALSE,
+ 'display_all' => FALSE,
+ 'fail_threshold' => 'warnings',
+ );
+ $options = array_merge($defaults, $options);
+ extract($options);
+ $errors = array();
+ $warnings = array();
+
+ if (!module_exists('aes')) {
+ $errors[] = 'AES Encryption module is not installed.';
+ }
+ elseif ($check_config) {
+ if (!variable_get('aes_key_path', FALSE)
+ || variable_get('aes_key_storage_method', FALSE) != 'File') {
+ $warnings[] = 'AES Encryption is installed but not configured securely.
+ Please go configure AES Encryption to use
+ file storage to enable encryption for SalesForce credentials.';
+ }
+ }
+
+ if ($display_errors || $display_all) {
+ foreach ($errors as $msg) {
+ drupal_set_message(t($msg), 'error');
+ }
+ }
+
+ if ($display_warnings || $display_all) {
+ foreach ($warnings as $msg) {
+ drupal_set_message(t($msg), 'warning');
+ }
+ }
+
+ switch ($fail_threshold) {
+ case 'errors': {
+ if (empty($errors)) {
+ return TRUE;
+ }
+ }
+ case 'warnings': {
+ if (empty($errors) && empty($warnings)) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
/**
* Wrapper for SOAP SforceBaseClient::describeSObject