diff options
author | Endi Sukma Dewata <edewata@redhat.com> | 2013-02-21 19:47:35 -0500 |
---|---|---|
committer | Endi Sukma Dewata <edewata@redhat.com> | 2013-03-07 17:51:32 -0500 |
commit | c87a65024177ed67cd4ec0f7d533d973f8e1f971 (patch) | |
tree | dcceb0a14d514c62773ee07a1fcb09e787dae6e4 /base | |
parent | b18a44db98f19c4d9b9d8d586d2bd1772a5d9f41 (diff) | |
download | pki-c87a65024177ed67cd4ec0f7d533d973f8e1f971.tar.gz pki-c87a65024177ed67cd4ec0f7d533d973f8e1f971.tar.xz pki-c87a65024177ed67cd4ec0f7d533d973f8e1f971.zip |
Added security domain info validation.
The installer script has been modified to validate security domain
info in both interactive and silent installation.
A basic Python API has been added to access the REST interface.
Ticket #473
Diffstat (limited to 'base')
-rw-r--r-- | base/common/CMakeLists.txt | 8 | ||||
-rw-r--r-- | base/common/python/pki/__init__.py | 0 | ||||
-rw-r--r-- | base/common/python/pki/account.py | 31 | ||||
-rw-r--r-- | base/common/python/pki/client.py | 53 | ||||
-rw-r--r-- | base/common/python/pki/system.py | 38 | ||||
-rw-r--r-- | base/deploy/CMakeLists.txt | 16 | ||||
-rwxr-xr-x | base/deploy/src/pkispawn | 73 | ||||
-rw-r--r-- | base/deploy/src/scriptlets/pkilogging.py | 40 | ||||
-rw-r--r-- | base/deploy/src/scriptlets/pkiparser.py | 23 |
9 files changed, 224 insertions, 58 deletions
diff --git a/base/common/CMakeLists.txt b/base/common/CMakeLists.txt index 73877c82c..e48133986 100644 --- a/base/common/CMakeLists.txt +++ b/base/common/CMakeLists.txt @@ -1,5 +1,13 @@ project(common NONE) +# install Python libraries +install( + DIRECTORY + python/ + DESTINATION + ${PYTHON_SITE_PACKAGES} +) + # install systemd scripts install( FILES diff --git a/base/common/python/pki/__init__.py b/base/common/python/pki/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/base/common/python/pki/__init__.py diff --git a/base/common/python/pki/account.py b/base/common/python/pki/account.py new file mode 100644 index 000000000..84f2d0ef0 --- /dev/null +++ b/base/common/python/pki/account.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +# Authors: +# Endi S. Dewata <edewata@redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2013 Red Hat, Inc. +# All rights reserved. +# + +class AccountClient: + + def __init__(self, connection): + self.connection = connection + + def login(self): + self.connection.get('account/login') + + def logout(self): + self.connection.get('account/logout') diff --git a/base/common/python/pki/client.py b/base/common/python/pki/client.py new file mode 100644 index 000000000..7635fe879 --- /dev/null +++ b/base/common/python/pki/client.py @@ -0,0 +1,53 @@ +#!/usr/bin/python +# Authors: +# Endi S. Dewata <edewata@redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2013 Red Hat, Inc. +# All rights reserved. +# + +import requests + +class PKIConnection: + + def __init__(self, + protocol='http', + hostname='localhost', + port=80, + subsystem='ca'): + + self.protocol = protocol + self.hostname = hostname + self.port = port + self.subsystem = subsystem + + self.serverURI = self.protocol + '://' +\ + self.hostname + ':' + self.port + '/' + \ + self.subsystem + + self.session = requests.Session() + self.session.headers.update({'Accept': 'application/json'}) + + def authenticate(self, username=None, password=None): + if username is not None and password is not None: + self.session.auth = (username, password) + + def get(self, path): + r = self.session.get( + self.serverURI + '/rest/' + path, + verify=False) + r.raise_for_status() + return r
\ No newline at end of file diff --git a/base/common/python/pki/system.py b/base/common/python/pki/system.py new file mode 100644 index 000000000..61ffbb9ff --- /dev/null +++ b/base/common/python/pki/system.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +# Authors: +# Endi S. Dewata <edewata@redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2013 Red Hat, Inc. +# All rights reserved. +# + +class SecurityDomainInfo: + + def __init__(self): + pass + +class SecurityDomainClient: + + def __init__(self, connection): + self.connection = connection + + def getSecurityDomainInfo(self): + r = self.connection.get('securityDomain/domainInfo') + + info = SecurityDomainInfo() + info.name = r.json['DomainInfo']['@id'] + + return info diff --git a/base/deploy/CMakeLists.txt b/base/deploy/CMakeLists.txt index 94abccdbc..ff9d64545 100644 --- a/base/deploy/CMakeLists.txt +++ b/base/deploy/CMakeLists.txt @@ -105,15 +105,6 @@ install( ${SYSCONF_INSTALL_DIR}/pki/ ) -find_package(PythonInterp REQUIRED) -execute_process( - COMMAND - ${PYTHON_EXECUTABLE} -c - "from distutils.sysconfig import get_python_lib; print get_python_lib()" - OUTPUT_VARIABLE - PYTHON_SITE_PACKAGES - OUTPUT_STRIP_TRAILING_WHITESPACE -) install( FILES src/scriptlets/configuration.jy @@ -147,13 +138,6 @@ install( "execute_process( COMMAND ${CMAKE_COMMAND} -E touch - \"\$ENV{DESTDIR}${PYTHON_SITE_PACKAGES}/pki/__init__.py\")" -) -install( - CODE - "execute_process( - COMMAND - ${CMAKE_COMMAND} -E touch \"\$ENV{DESTDIR}${PYTHON_SITE_PACKAGES}/pki/deployment/__init__.py\")" ) diff --git a/base/deploy/src/pkispawn b/base/deploy/src/pkispawn index bca496e1d..65bbaa4a8 100755 --- a/base/deploy/src/pkispawn +++ b/base/deploy/src/pkispawn @@ -30,10 +30,12 @@ try: import ldap import logging import os + import requests import socket import struct import subprocess import time + import urllib2 from time import strftime as date from pki.deployment import pkiconfig as config from pki.deployment.pkiparser import PKIConfigParser @@ -225,15 +227,33 @@ def main(argv): print print "Security Domain:" - parser.read_text('Name', config.pki_subsystem, 'pki_security_domain_name') - if config.pki_subsystem != "CA": - parser.read_text('Hostname', config.pki_subsystem, 'pki_security_domain_hostname') - parser.read_text('Secure HTTP port', config.pki_subsystem, 'pki_security_domain_https_port') - parser.read_text('Username', config.pki_subsystem, 'pki_security_domain_user') - parser.read_password( - 'Password', config.pki_subsystem, 'pki_security_domain_password', - verifyMessage='Verify password') + if config.pki_subsystem == "CA": + parser.read_text('Name', config.pki_subsystem, 'pki_security_domain_name') + + else: + while True: + parser.read_text('Hostname', config.pki_subsystem, 'pki_security_domain_hostname') + parser.read_text('Secure HTTP port', config.pki_subsystem, 'pki_security_domain_https_port') + + try: + parser.sd_connect() + info = parser.sd_get_info() + parser.print_text('Name: ' + info.name) + parser.set_property(config.pki_subsystem, 'pki_security_domain_name', info.name) + break + except requests.exceptions.ConnectionError as e: + parser.print_text('ERROR: ' + str(e)) + + while True: + parser.read_text('Username', config.pki_subsystem, 'pki_security_domain_user') + parser.read_password('Password', config.pki_subsystem, 'pki_security_domain_password') + + try: + parser.sd_authenticate() + break + except requests.exceptions.HTTPError as e: + parser.print_text('ERROR: ' + str(e)) print @@ -321,23 +341,40 @@ def main(argv): config.pki_log.debug(pkilogging.format(config.pki_master_dict), extra=config.PKI_INDENTATION_LEVEL_0) - if not interactive: + if not interactive and\ + not config.str2bool(config.pki_master_dict['pki_skip_configuration']): try: - if not config.str2bool(config.pki_master_dict['pki_skip_configuration']): - parser.ds_connect() - parser.ds_bind() + parser.ds_connect() + parser.ds_bind() - if parser.ds_base_dn_exists() and\ - not config.str2bool(config.pki_master_dict['pki_ds_remove_data']): - print 'ERROR: Base DN already exists.' - sys.exit(1) + if parser.ds_base_dn_exists() and\ + not config.str2bool(config.pki_master_dict['pki_ds_remove_data']): + print 'ERROR: Base DN already exists.' + sys.exit(1) - parser.ds_close() + parser.ds_close() except ldap.LDAPError as e: - print 'ERROR: ' + e.message['desc'] + print 'ERROR: Unable to access directory server: ' + e.message['desc'] sys.exit(1) + if config.pki_subsystem != "CA" or\ + config.str2bool(config.pki_master_dict['pki_clone']) or\ + config.str2bool(config.pki_master_dict['pki_subordinate']): + try: + parser.sd_connect() + info = parser.sd_get_info() + parser.set_property(config.pki_subsystem, 'pki_security_domain_name', info.name) + parser.sd_authenticate() + + except requests.exceptions.ConnectionError as e: + print('ERROR: Unable to access security domain: ' + str(e)) + sys.exit(1) + + except requests.exceptions.HTTPError as e: + print('ERROR: Unable to access security domain: ' + str(e)) + sys.exit(1) + print "Installing " + config.pki_subsystem + " into " + config.pki_master_dict['pki_instance_path'] + "." # Process the various "scriptlets" to create the specified PKI subsystem. diff --git a/base/deploy/src/scriptlets/pkilogging.py b/base/deploy/src/scriptlets/pkilogging.py index 3c146a12c..319616145 100644 --- a/base/deploy/src/scriptlets/pkilogging.py +++ b/base/deploy/src/scriptlets/pkilogging.py @@ -43,42 +43,34 @@ def format(dict): return pp.pformat(new_dict) # PKI Deployment Logging Functions -def enable_pki_logger(log_dir, log_name, log_level, console_log_level, logger): +def enable_pki_logger(log_dir, log_name, log_level, console_log_level, name): if not os.path.isdir(log_dir): try: os.makedirs(log_dir) except OSError: return OSError - # Establish 'file' logger using 'basicConfig()' - logging.LoggerAdapter(logging.getLogger(''), {'indent' : ''}) - logging.basicConfig(level=log_level, - format='%(asctime)s %(name)-12s ' +\ - '%(levelname)-8s ' +\ - '%(indent)s%(message)s', - datefmt='%Y-%m-%d %H:%M:%S', - filename=log_dir + "/" + log_name, - filemode='w') + # Configure logger + logger = logging.getLogger(name) + logger.setLevel(log_level) - # Establish 'console' logger + # Configure console handler console = logging.StreamHandler() - logging.LoggerAdapter(console, {'indent' : ''}) console.setLevel(console_log_level) console_format = logging.Formatter('%(name)-12s: ' +\ '%(levelname)-8s ' +\ '%(indent)s%(message)s') console.setFormatter(console_format) - logging.getLogger('').addHandler(console) + logger.addHandler(console) - # Establish 'file' logger -# file = logging.FileHandler(log_dir + "/" + log_name, 'w') -# logging.LoggerAdapter(file, {'indent' : ''}) -# file.setLevel(log_level) -# file_format = logging.Formatter('%(asctime)s %(name)-12s: ' +\ -# '%(levelname)-8s ' +\ -# '%(indent)s%(message)s', -# '%Y-%m-%d %H:%M:%S') -# file.setFormatter(file_format) -# logging.getLogger('').addHandler(file) + # Configure file handler + file = logging.FileHandler(log_dir + "/" + log_name, 'w') + file.setLevel(log_level) + file_format = logging.Formatter('%(asctime)s %(name)-12s: ' +\ + '%(levelname)-8s ' +\ + '%(indent)s%(message)s', + '%Y-%m-%d %H:%M:%S') + file.setFormatter(file_format) + logger.addHandler(file) - return logging.getLogger(logger) + return logger diff --git a/base/deploy/src/scriptlets/pkiparser.py b/base/deploy/src/scriptlets/pkiparser.py index eee56ca3e..32a3da154 100644 --- a/base/deploy/src/scriptlets/pkiparser.py +++ b/base/deploy/src/scriptlets/pkiparser.py @@ -38,6 +38,9 @@ import pkilogging import pkiconfig as config import pkimessages as log +import pki.account +import pki.client +import pki.system class PKIConfigParser: @@ -391,6 +394,26 @@ class PKIConfigParser: def ds_close(self): self.ds_connection.unbind_s() + def sd_connect(self): + self.sd_connection = pki.client.PKIConnection( + protocol='https', + hostname=config.pki_master_dict['pki_security_domain_hostname'], + port=config.pki_master_dict['pki_security_domain_https_port'], + subsystem='ca') + + def sd_get_info(self): + sd = pki.system.SecurityDomainClient(self.sd_connection) + return sd.getSecurityDomainInfo() + + def sd_authenticate(self): + self.sd_connection.authenticate( + config.pki_master_dict['pki_security_domain_user'], + config.pki_master_dict['pki_security_domain_password']) + + account = pki.account.AccountClient(self.sd_connection) + account.login() + account.logout() + def compose_pki_master_dictionary(self): "Create a single master PKI dictionary from the sectional dictionaries" try: |