Skip to content

Commit

Permalink
Merge pull request #17 from dataiku/bug/sc-106495-cleartext-password
Browse files Browse the repository at this point in the history
[sc-106495] cleartext password
  • Loading branch information
alexbourret authored Sep 25, 2023
2 parents c0559bb + e3c6a81 commit 661a93a
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 49 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [Version 0.2.1](https://github.com/dataiku/dss-plugin-tableau-hyper/releases/tag/v0.2.1) - Feature release - 2023-06-21

- Feature: add secure personal preset

## [Version 0.1.6](https://github.com/dataiku/dss-plugin-tableau-hyper/releases/tag/v0.1.6) - Feature release - 2022-11-14

- Feature: add a project selector
Expand Down
51 changes: 51 additions & 0 deletions parameter-sets/tableau-personal-connection/parameter-set.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"meta" : {
"label": "Tableau Server Personal Preset",
"description": "Tableau Server Personal Preset",
"icon": "icon-tableau"
},
"defaultDefinableInline": false,
"defaultDefinableAtProjectLevel": false,

"pluginParams": [],

"params": [
{
"name": "server_url",
"label":"URL",
"type": "STRING",
"mandatory": true,
"description": "URL of your Tableau server without subpaths. \nFor local Tableau servers, an example would be: https://www.MY_SERVER.com. For Tableau Online, \nan example would be: https://10ax.online.tableau.com/."
},
{
"name": "site_id",
"label":"Site ID",
"type": "STRING",
"description":"The site_id is the subpath of your full site URL."
},
{
"name": "ignore_ssl",
"label" : "Ignore SSL",
"type": "BOOLEAN",
"mandatory": false,
"description": "(not recommended)",
"defaultValue": false
},
{
"name": "ssl_cert_path",
"label": "SSL certificate",
"type": "STRING",
"description": "(optional) Full path to your tableau SSL certificate",
"mandatory": false,
"visibilityCondition": "model.ignore_ssl == false"
},
{
"name": "tableau_personal_basic",
"type": "CREDENTIAL_REQUEST",
"label": "Tableau basic login",
"credentialRequestSettings": {
"type": "BASIC"
}
}
]
}
2 changes: 1 addition & 1 deletion plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "tableau-hyper-export",
"version": "0.2.0",
"version": "0.2.1",
"meta": {
"label": "Tableau Hyper format",
"description": "Export datasets to Tableau .hyper format.",
Expand Down
43 changes: 35 additions & 8 deletions python-exporters/tableau-hyper_upload/exporter.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,67 @@
"label":"Tableau Server",
"type": "SEPARATOR"
},
{
"name": "auth_type",
"label": "Authentication type",
"type": "SELECT",
"selectChoices": [
{
"value": "basic-preset",
"label": "Personal preset"
},
{
"value": "legacy-preset",
"label": "Preset (legacy)"
},
{
"value": "legacy-login",
"label": "User name / password (legacy)"
}
]
},
{
"name": "usePreset",
"label" : "Use preset",
"type": "BOOLEAN",
"mandatory": false,
"description":"Get the Tableau Server connection parameters from a shared configuration in DSS"
"description":"Get the Tableau Server connection parameters from a shared configuration in DSS. Legacy: we just keep it to let existing flow working.",
"visibilityCondition": false
},
{
"name": "tableau_server_personal_connection",
"label": "Tableau Server Personal Preset",
"type": "PRESET",
"parameterSetId": "tableau-personal-connection",
"visibilityCondition": "model.auth_type == 'basic-preset'"
},
{
"name": "tableau_server_connection",
"label": "Tableau Server Preset",
"type": "PRESET",
"parameterSetId": "tableau-server-connection",
"visibilityCondition": "model.usePreset == true"
"visibilityCondition": "model.auth_type == 'legacy-preset' || (model.auth_type == null && model.usePreset == true)"
},
{
"name": "server_url",
"label":"URL",
"type": "STRING",
"mandatory": false,
"visibilityCondition": "model.usePreset == false || model.tableau_server_connection.mode == 'NONE'"
"visibilityCondition": "model.auth_type == 'legacy-login' || (model.auth_type == null && model.usePreset == false && model.server_url != null)"
},
{
"name": "username",
"label":"Username",
"type": "STRING",
"mandatory": false,
"visibilityCondition": "model.usePreset == false || model.tableau_server_connection.mode == 'NONE'"
"visibilityCondition": "model.auth_type == 'legacy-login' || (model.auth_type == null && model.usePreset == false && model.server_url != null)"
},
{
"name": "password",
"label":"Password",
"type": "PASSWORD",
"mandatory": false,
"visibilityCondition": "model.usePreset == false || model.tableau_server_connection.mode == 'NONE'"
"visibilityCondition": "model.auth_type == 'legacy-login' || (model.auth_type == null && model.usePreset == false && model.server_url != null)"
},
{
"name": "ignore_ssl",
Expand All @@ -59,15 +86,15 @@
"mandatory": false,
"description": "Ignore SSL",
"defaultValue": false,
"visibilityCondition": "model.usePreset == false || model.tableau_server_connection.mode == 'NONE'"
"visibilityCondition": "model.auth_type == 'legacy-login' || (model.auth_type == null && model.server_url != null)"
},
{
"name": "ssl_cert_path",
"label": "SSL certificate",
"type": "STRING",
"description": "(optional) Full path to your tableau SSL certificate",
"mandatory": false,
"visibilityCondition": "(model.usePreset == false || model.tableau_server_connection.mode == 'NONE') && model.ignore_ssl == false"
"visibilityCondition": "(model.auth_type == 'legacy-login' || (model.auth_type == null && model.server_url != null)) && model.ignore_ssl == false"
},
{
"label":"Destination",
Expand Down Expand Up @@ -111,7 +138,7 @@
"type": "STRING",
"description": "The site_id is the subpath of your full site URL. (See the README.md for details)",
"mandatory": false,
"visibilityCondition": "model.usePreset == false || model.tableau_server_connection.mode == 'NONE'"
"visibilityCondition": "model.auth_type == 'legacy-login' || model.auth_type == null"
}
]
}
40 changes: 3 additions & 37 deletions python-exporters/tableau-hyper_upload/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
from cache_utils import get_cache_location_from_user_config
from dataiku.exporter import Exporter
from tableau_table_writer import TableauTableWriter
from tableau_server_utils import get_project_from_name
from tableau_server_utils import get_full_list_of_projects
from tableau_server_utils import get_project_from_name, get_full_list_of_projects, get_tableau_server_connection
import tempfile
from custom_exceptions import InvalidPluginParameter

Expand Down Expand Up @@ -60,46 +59,13 @@ def __init__(self, config, plugin_config):
self.output_file = None
self.tmp_output_dir = None

# Extract preset configuration from general configuration
preset_config = config.pop('tableau_server_connection')

# Sanitize the two configurations
logger.info("Processing user interface input parameters...")
remove_empty_keys(preset_config)
remove_empty_keys(config)

# Preset configuration will overwrite the manual configuration
config = {**config, **preset_config}
self.config = config # final config

# Retrieve credentials parameters
username = config.get('username', None)
check_null_values(username, 'username')
password = config.get('password', None)
check_null_values(password, 'password')
server_name = config.get('server_url', None)
check_null_values(server_name, 'server_url')
# The site name is optional in Tableau Server, default value should not be None but empty String
site_name = config.get('site_id', '')

server_name, username, password, site_name, self.ignore_ssl = get_tableau_server_connection(config)

logger.info("Detected following user input configuration:\n"
" username: {},\n"
" server_url: {},\n"
" site_name: {}".format(username, server_name, site_name))

# Handle ssl certificates
self.ssl_cert_path = config.get('ssl_cert_path', None)
self.ignore_ssl = config.get('ignore_ssl', False)

if not self.ignore_ssl:
if self.ssl_cert_path:
if not os.path.isfile(self.ssl_cert_path):
raise ValueError('SSL certificate file %s does not exist' % self.ssl_cert_path)
else:
# default variables handled by python requests to validate cert (used by underlying tableauserverclient)
os.environ['REQUESTS_CA_BUNDLE'] = self.ssl_cert_path
os.environ['CURL_CA_BUNDLE'] = self.ssl_cert_path

# Retrieve Tableau Hyper and Server/Online locations and table configurations
self.output_file_name = config.get('output_table', 'my_dss_table')
self.project_id = None
Expand Down
40 changes: 37 additions & 3 deletions python-lib/tableau_server_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def get_project_full_path(project, all_projects):
return root + " / " + project.get("name")


def get_tableau_server_connection(config):
def get_legacy_tableau_server_connection(config):
server_url = username = password = site_id = None
use_preset = config.get('usePreset', False)
if use_preset:
Expand All @@ -111,12 +111,46 @@ def get_tableau_server_connection(config):
ssl_cert_path = configuration.get('ssl_cert_path', None)
ignore_ssl = configuration.get('ignore_ssl', False)

setup_ssl(ignore_ssl, ssl_cert_path)

return server_url, username, password, site_id, ignore_ssl


def get_tableau_server_connection(config):
server_url = username = password = site_id = None
auth_type = config.get("auth_type", None)

if auth_type == "legacy-login":
configuration = config
elif auth_type == "legacy-preset":
configuration = config.get('tableau_server_connection', {})
elif auth_type == "basic-preset":
configuration = config.get('tableau_server_personal_connection', {})
tableau_personal_basic = configuration.get("tableau_personal_basic", {})
username = tableau_personal_basic.get("user")
password = tableau_personal_basic.get("password")
else: # the auth_type selector was never used, so old conf file, use legacy mode
server_url, username, password, site_id, ignore_ssl = get_legacy_tableau_server_connection(config)
return server_url, username, password, site_id, ignore_ssl

server_url = configuration.get('server_url', None)
username = configuration.get('username', username)
password = configuration.get('password', password)
site_id = configuration.get('site_id', '')

ssl_cert_path = configuration.get('ssl_cert_path', None)
ignore_ssl = configuration.get('ignore_ssl', False)

setup_ssl(ignore_ssl, ssl_cert_path)

return server_url, username, password, site_id, ignore_ssl


def setup_ssl(ignore_ssl, ssl_cert_path):
if not ignore_ssl and ssl_cert_path:
if not os.path.isfile(ssl_cert_path):
raise ValueError('SSL certificate file {} does not exist'.format(ssl_cert_path))
else:
# default variables handled by python requests to validate cert (used by underlying tableauserverclient)
os.environ['REQUESTS_CA_BUNDLE'] = ssl_cert_path
os.environ['CURL_CA_BUNDLE'] = ssl_cert_path

return server_url, username, password, site_id, ignore_ssl

0 comments on commit 661a93a

Please sign in to comment.