Encrypting the passwords out of connection strings

This commit is contained in:
Maxime Beauchemin 2015-11-21 12:35:49 -08:00
parent d8c79cd26e
commit 85227912b3
4 changed files with 55 additions and 4 deletions

View File

@ -0,0 +1,28 @@
"""Add encrypted password field
Revision ID: 289ce07647b
Revises: 2929af7925ed
Create Date: 2015-11-21 11:18:00.650587
"""
# revision identifiers, used by Alembic.
revision = '289ce07647b'
down_revision = '2929af7925ed'
from alembic import op
import sqlalchemy as sa
from sqlalchemy_utils.types.encrypted import EncryptedType
def upgrade():
op.add_column(
'dbs',
sa.Column(
'password',
EncryptedType(sa.String(1024)),
nullable=True))
def downgrade():
op.drop_column('dbs', 'password')

View File

@ -6,13 +6,14 @@ from flask.ext.appbuilder.models.mixins import AuditMixin
from pandas import read_sql_query
from pydruid import client
from pydruid.utils.filters import Dimension, Filter
import sqlalchemy as sqla
from sqlalchemy import (
Column, Integer, String, ForeignKey, Text, Boolean, DateTime)
from sqlalchemy import Table
from sqlalchemy import create_engine, MetaData, desc, select, and_
Column, Integer, String, ForeignKey, Text, Boolean, DateTime,
Table, create_engine, MetaData, desc, select, and_)
from sqlalchemy.orm import relationship
from sqlalchemy.sql import table, literal_column, text
from sqlalchemy.sql.elements import ColumnClause
from sqlalchemy_utils import EncryptedType
from copy import deepcopy, copy
from collections import namedtuple
@ -187,12 +188,16 @@ class Database(Model, AuditMixinNullable):
id = Column(Integer, primary_key=True)
database_name = Column(String(250), unique=True)
sqlalchemy_uri = Column(String(1024))
password = Column(EncryptedType(String(1024), config.get('SECRET_KEY')))
def __repr__(self):
return self.database_name
def get_sqla_engine(self):
return create_engine(self.sqlalchemy_uri)
return create_engine(self.sqlalchemy_uri_decrypted)
def safe_sqlalchemy_uri(self):
return self.sqlalchemy_uri
def get_table(self, table_name):
meta = MetaData()
@ -201,6 +206,12 @@ class Database(Model, AuditMixinNullable):
autoload=True,
autoload_with=self.get_sqla_engine())
@property
def sqlalchemy_uri_decrypted(self):
conn = sqla.engine.url.make_url(self.sqlalchemy_uri)
conn.password = self.password
return str(conn)
class SqlaTable(Model, Queryable, AuditMixinNullable):
type = "table"

View File

@ -10,6 +10,7 @@ from flask.ext.appbuilder.models.sqla.interface import SQLAInterface
from flask.ext.appbuilder.security.decorators import has_access
from pydruid.client import doublesum
from sqlalchemy import create_engine
import sqlalchemy as sqla
from wtforms.validators import ValidationError
from panoramix import appbuilder, db, models, viz, utils, app, sm, ascii_art
@ -105,6 +106,7 @@ class DatabaseView(PanoramixModelView, DeleteMixin):
datamodel = SQLAInterface(models.Database)
list_columns = ['database_name', 'created_by', 'created_on']
add_columns = ['database_name', 'sqlalchemy_uri']
search_exclude_columns = ('password',)
edit_columns = add_columns
add_template = "panoramix/models/database/add.html"
edit_template = "panoramix/models/database/edit.html"
@ -114,6 +116,14 @@ class DatabaseView(PanoramixModelView, DeleteMixin):
"to structure your URI here: "
"http://docs.sqlalchemy.org/en/rel_1_0/core/engines.html")
}
def pre_add(self, db):
conn = sqla.engine.url.make_url(db.sqlalchemy_uri)
db.password = conn.password
conn.password = "X" * 10 if conn.password else None
db.sqlalchemy_uri = str(conn) # hides the password
def pre_update(self, db):
self.pre_add(db)
appbuilder.add_view(
DatabaseView,

View File

@ -18,6 +18,7 @@ setup(
scripts=['panoramix/bin/panoramix'],
install_requires=[
'alembic>=0.7.7, <0.8.0',
'cryptography>=1.1.1, <2.0.0',
'flask>=0.10.1, <1.0.0',
'flask-appbuilder>=1.4.5, <2.0.0',
'flask-login==0.2.11',
@ -33,6 +34,7 @@ setup(
'python-dateutil>=2.4.2, <3.0.0',
'requests>=2.7.0, <3.0.0',
'sqlparse>=0.1.16, <0.2.0',
'sqlalchemy-utils>=0.31.3, <0.32.0',
'sqlalchemy==1.0.8',
'flask-sqlalchemy==2.0',
],