Skip to content

Commit

Permalink
Added support for SSL connection & username auth.
Browse files Browse the repository at this point in the history
  • Loading branch information
matriv committed Jun 26, 2017
1 parent a9ece9d commit cae226d
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Changes for crash
Unreleased
==========

- Added support for SSL connection to CrateDB.

- Added new parameter ``username`` used to authenticate the user in CrateDB.

- Improved queries for ``sysinfo`` command

- Fix: Single word statements (such as ``BEGIN;``) that return ``OK`` crashed
Expand Down
62 changes: 56 additions & 6 deletions src/crate/crash/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ def _conf_or_default(key, value):
dest='autocapitalize',
default=False,
help='use -a to enable experimental auto-capitalization of SQL keywords')

parser.add_argument('-U', '--username', type=str,
help='the username in the database')
parser.add_argument('--history', type=str,
help='the history file to use', default=HISTORY_PATH)
parser.add_argument('--config', type=str,
Expand All @@ -158,6 +159,8 @@ def _conf_or_default(key, value):
help='path to client certificate')
parser.add_argument('--key-file', type=str,
help='path to the key file for the client certificate')
parser.add_argument('--ca-cert-file', type=str,
help='path to the CA certificate file')
parser.add_argument('--format', type=str,
default=_conf_or_default('format', 'tabular'),
choices=output_formats,
Expand Down Expand Up @@ -186,7 +189,12 @@ def __init__(self,
error_trace=False,
is_tty=True,
autocomplete=True,
autocapitalize=True):
autocapitalize=True,
verify_ssl=True,
cert_file=None,
key_file=None,
ca_cert_file=None,
username=None):
self.error_trace = error_trace
self.connection = connection or connect(error_trace=error_trace)
self.cursor = self.connection.cursor()
Expand All @@ -207,6 +215,11 @@ def __init__(self,
self.logger = ColorPrinter(is_tty)
self._autocomplete = autocomplete
self._autocapitalize = autocapitalize
self.username = username
self.verify_ssl = verify_ssl
self.cert_file = cert_file
self.key_file = key_file
self.ca_cert_file = ca_cert_file

def get_num_columns(self):
return 80
Expand Down Expand Up @@ -275,7 +288,9 @@ def is_conn_avaliable(self):

def _connect(self, server):
""" connect to the given server, e.g.: \connect localhost:4200 """
self.connection = connect(servers=server, error_trace=self.error_trace)
self.connection = connect(servers=server, error_trace=self.error_trace, verify_ssl_cert=self.verify_ssl,
cert_file=self.cert_file, key_file=self.key_file, ca_cert=self.ca_cert_file,
username=self.username)
self.cursor = self.connection.cursor()
results = []
failed = 0
Expand All @@ -295,7 +310,7 @@ def _connect(self, server):
else:
self.logger.info('CONNECT OK')
SysInfoCommand.CLUSTER_INFO['information_schema_query'] = \
get_information_schema_query(self.connection.lowest_server_version)
get_information_schema_query(self.connection.lowest_server_version)
# check for failing node and cluster checks
built_in_commands['check'](self, startup=True)

Expand Down Expand Up @@ -442,13 +457,20 @@ def main():
conn = connect(crate_hosts,
verify_ssl_cert=args.verify_ssl,
cert_file=args.cert_file,
key_file=args.key_file)
key_file=args.key_file,
ca_cert=args.ca_cert_file,
username=args.username)
cmd = CrateCmd(connection=conn,
error_trace=error_trace,
output_writer=output_writer,
is_tty=is_tty,
autocomplete=args.autocomplete,
autocapitalize=args.autocapitalize)
autocapitalize=args.autocapitalize,
verify_ssl=args.verify_ssl,
cert_file=args.cert_file,
key_file=args.key_file,
ca_cert_file=args.ca_cert_file,
username=args.username)
if error_trace:
# log CONNECT command only in verbose mode
cmd._connect(crate_hosts)
Expand All @@ -472,6 +494,34 @@ def main():
cmd.exit()
sys.exit(cmd.exit_code)

def test_main():
is_tty = sys.stdout.isatty()
output_writer = OutputWriter(PrintWrapper(), is_tty)
parser = get_parser(output_writer.formats)
args = parse_args(parser)
output_writer.output_format = args.format

if args.version:
sys.exit(0)
error_trace = args.verbose > 0
crate_hosts = [host_and_port(h) for h in args.hosts]
conn = connect(crate_hosts,
verify_ssl_cert=args.verify_ssl,
cert_file=args.cert_file,
key_file=args.key_file,
ca_cert=args.ca_cert_file,
username=args.username)
return CrateCmd(connection=conn,
error_trace=error_trace,
output_writer=output_writer,
is_tty=is_tty,
autocomplete=args.autocomplete,
autocapitalize=args.autocapitalize,
verify_ssl=args.verify_ssl,
cert_file=args.cert_file,
key_file=args.key_file,
ca_cert_file=args.ca_cert_file,
username=args.username)

if __name__ == '__main__':
main()
34 changes: 33 additions & 1 deletion src/crate/crash/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import sys
import os
import re
import ssl
from unittest import TestCase
from six import PY2, StringIO
import tempfile
from io import TextIOWrapper
from mock import patch, Mock
from crate.client.exceptions import ProgrammingError

from .command import CrateCmd, main, get_stdin, noargs_command, Result, \
from .command import CrateCmd, main, test_main, get_stdin, noargs_command, Result, \
host_and_port, get_information_schema_query, stmt_type
from .outputs import _val_len as val_len, OutputWriter
from .printer import ColorPrinter
Expand Down Expand Up @@ -516,6 +517,37 @@ def my_cmd(self, *args):
self.assertEqual(None, text)
self.assertEqual('Command does not take any arguments.\n', output.getvalue())

def test_username_param(self):
sys.argv = ["testcrash",
"--hosts", self.crate_host,
"--username", "testUser"
]
CrateCmd = test_main()
self.assertEqual(CrateCmd.username, "testUser")
self.assertEqual(CrateCmd.connection.client.username, "testUser")

def test_ssl_params(self):
sys.argv = ["testcrash",
"--hosts", self.crate_host,
"--verify-ssl", "false",
"--cert-file", "cert_file",
"--key-file", "key_file",
"--ca-cert-file", "ca_cert_file"
]
CrateCmd = test_main()
self.assertEqual(CrateCmd.verify_ssl, False)
self.assertEqual(CrateCmd.connection.client._pool_kw['cert_reqs'], ssl.CERT_NONE)

self.assertEqual(CrateCmd.cert_file, 'cert_file')
self.assertEqual(CrateCmd.connection.client._pool_kw['cert_file'], 'cert_file')

self.assertEqual(CrateCmd.key_file, 'key_file')
self.assertEqual(CrateCmd.connection.client._pool_kw['key_file'], 'key_file')

self.assertEqual(CrateCmd.ca_cert_file, 'ca_cert_file')
self.assertEqual(CrateCmd.connection.client._pool_kw['ca_certs'], 'ca_cert_file')


class TestGetInformationSchemaQuery(TestCase):

def test_low_version(self):
Expand Down
2 changes: 1 addition & 1 deletion versions.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ argparse = 1.1
codecov = 1.6.3
collective.recipe.omelette = 0.16
coverage = 4.0.3
crate = 0.19.2
crate = 0.20.0
docutils = 0.12
gp.recipe.tox = 0.4
hexagonit.recipe.download = 1.7.1
Expand Down

0 comments on commit cae226d

Please sign in to comment.