This is an automated email from the ASF dual-hosted git repository.
maximebeauchemin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new f3065a7 [database] Improve form and API validation for invalid URI
(#8240)
f3065a7 is described below
commit f3065a763f34d00dc5da6b5c5fc1c13d3f6095d0
Author: Daniel Vaz Gaspar <[email protected]>
AuthorDate: Mon Sep 23 16:28:08 2019 +0100
[database] Improve form and API validation for invalid URI (#8240)
* [database] Improve form and API validation for invalid URI
* [database] Added missing EOL
* [database] lint
---
superset/views/database/__init__.py | 29 +++++++++++++++++++++++++++--
superset/views/database/api.py | 3 ++-
superset/views/database/views.py | 13 ++++++++++++-
3 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/superset/views/database/__init__.py
b/superset/views/database/__init__.py
index 9b7c8cf..4673644 100644
--- a/superset/views/database/__init__.py
+++ b/superset/views/database/__init__.py
@@ -16,10 +16,14 @@
# under the License.
# pylint: disable=C,R,W
import inspect
+from typing import Type
from flask import Markup
from flask_babel import lazy_gettext as _
+from marshmallow import ValidationError
from sqlalchemy import MetaData
+from sqlalchemy.engine.url import make_url
+from sqlalchemy.exc import ArgumentError
from superset import security_manager
from superset.exceptions import SupersetException
@@ -27,6 +31,24 @@ from superset.utils import core as utils
from superset.views.base import SupersetFilter
+def sqlalchemy_uri_validator(
+ uri: str, exception: Type[ValidationError] = ValidationError
+) -> None:
+ """
+ Check if a user has submitted a valid SQLAlchemy URI
+ """
+ try:
+ make_url(uri.strip())
+ except ArgumentError:
+ raise exception(
+ _(
+ "Invalid connnection string, a valid string follows: "
+ " 'DRIVER://USER:PASSWORD@DB-HOST/DATABASE-NAME'"
+ "
<p>Example:'postgresql://user:password@your-postgres-db/database'</p>"
+ )
+ )
+
+
class DatabaseFilter(SupersetFilter):
def apply(self, query, func): # noqa
if security_manager.all_database_access():
@@ -189,7 +211,7 @@ class DatabaseMixin: # noqa
"backend": _("Backend"),
}
- def pre_add(self, db):
+ def _pre_add_update(self, db):
self.check_extra(db)
db.set_sqlalchemy_uri(db.sqlalchemy_uri)
security_manager.add_permission_view_menu("database_access", db.perm)
@@ -199,8 +221,11 @@ class DatabaseMixin: # noqa
"schema_access", security_manager.get_schema_perm(db, schema)
)
+ def pre_add(self, db):
+ self._pre_add_update(db)
+
def pre_update(self, db):
- self.pre_add(db)
+ self._pre_add_update(db)
def pre_delete(self, obj):
if obj.tables:
diff --git a/superset/views/database/api.py b/superset/views/database/api.py
index 352086e..fbfbc5b 100644
--- a/superset/views/database/api.py
+++ b/superset/views/database/api.py
@@ -19,7 +19,7 @@ from flask_appbuilder.models.sqla.interface import
SQLAInterface
from superset import appbuilder
import superset.models.core as models
-from . import DatabaseFilter, DatabaseMixin
+from . import DatabaseFilter, DatabaseMixin, sqlalchemy_uri_validator
class DatabaseRestApi(DatabaseMixin, ModelRestApi):
@@ -53,6 +53,7 @@ class DatabaseRestApi(DatabaseMixin, ModelRestApi):
]
# Removes the local limit for the page size
max_page_size = -1
+ validators_columns = {"sqlalchemy_uri": sqlalchemy_uri_validator}
appbuilder.add_api(DatabaseRestApi)
diff --git a/superset/views/database/views.py b/superset/views/database/views.py
index 19fe490..0c616d1 100644
--- a/superset/views/database/views.py
+++ b/superset/views/database/views.py
@@ -19,18 +19,21 @@ import os
from flask import flash, redirect
from flask_appbuilder import SimpleFormView
+from flask_appbuilder.forms import DynamicForm
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
from sqlalchemy.exc import IntegrityError
from werkzeug.utils import secure_filename
+from wtforms.fields import StringField
+from wtforms.validators import ValidationError
from superset import app, appbuilder, security_manager
from superset.connectors.sqla.models import SqlaTable
import superset.models.core as models
from superset.utils import core as utils
from superset.views.base import DeleteMixin, SupersetModelView, YamlExportMixin
-from . import DatabaseMixin
+from . import DatabaseMixin, sqlalchemy_uri_validator
from .forms import CsvToDatabaseForm
@@ -38,6 +41,13 @@ config = app.config
stats_logger = config.get("STATS_LOGGER")
+def sqlalchemy_uri_form_validator(form: DynamicForm, field: StringField) ->
None:
+ """
+ Check if user has submitted a valid SQLAlchemy URI
+ """
+ sqlalchemy_uri_validator(field.data, exception=ValidationError)
+
+
class DatabaseView(
DatabaseMixin, SupersetModelView, DeleteMixin, YamlExportMixin
): # noqa
@@ -45,6 +55,7 @@ class DatabaseView(
add_template = "superset/models/database/add.html"
edit_template = "superset/models/database/edit.html"
+ validators_columns = {"sqlalchemy_uri": [sqlalchemy_uri_form_validator]}
def _delete(self, pk):
DeleteMixin._delete(self, pk)