[Pki-devel] [PATCH] 691 Added Python wrapper for pki pkcs12-import.

Endi Sukma Dewata edewata at redhat.com
Thu Feb 25 11:42:15 UTC 2016


A wrapper has been added for the pki pkcs12-import command to
allow implementing a workaround in Python to address JSS import
limitations.

https://fedorahosted.org/pki/ticket/1742

Note: The build fails due to weird pylint errors. The Python code itself 
seems to be working just fine.

-- 
Endi S. Dewata
-------------- next part --------------
From 015245f18af8b536363f5ee277bd09e6730c6efa Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata at redhat.com>
Date: Wed, 24 Feb 2016 22:22:10 +0100
Subject: [PATCH] Added Python wrapper for pki pkcs12-import.

A wrapper has been added for the pki pkcs12-import command to
allow implementing a workaround in Python to address JSS import
limitations.

https://fedorahosted.org/pki/ticket/1742
---
 base/common/python/CMakeLists.txt                  |   2 +-
 base/common/python/pki/{cli.py => cli/__init__.py} |   0
 base/common/python/pki/cli/pkcs12.py               | 124 +++++++++
 base/java-tools/bin/pki                            | 299 ++++++++++++++-------
 specs/pki-core.spec                                |   4 +
 5 files changed, 328 insertions(+), 101 deletions(-)
 rename base/common/python/pki/{cli.py => cli/__init__.py} (100%)
 create mode 100644 base/common/python/pki/cli/pkcs12.py

diff --git a/base/common/python/CMakeLists.txt b/base/common/python/CMakeLists.txt
index 7c2fad86919a328ab4f507b610ffa26c087da49b..0fa7638ec9fa6f45ec48720828e86b857fee1744 100644
--- a/base/common/python/CMakeLists.txt
+++ b/base/common/python/CMakeLists.txt
@@ -35,7 +35,7 @@ add_custom_target(dogtag_python_client_man_docs ALL
 
 install(
     DIRECTORY
-        pki
+        pki/
     DESTINATION
         ${PYTHON_SITE_PACKAGES}
 )
diff --git a/base/common/python/pki/cli.py b/base/common/python/pki/cli/__init__.py
similarity index 100%
rename from base/common/python/pki/cli.py
rename to base/common/python/pki/cli/__init__.py
diff --git a/base/common/python/pki/cli/pkcs12.py b/base/common/python/pki/cli/pkcs12.py
new file mode 100644
index 0000000000000000000000000000000000000000..f6afb99418a0bec810e5c186f0d1c0b53b6ba78f
--- /dev/null
+++ b/base/common/python/pki/cli/pkcs12.py
@@ -0,0 +1,124 @@
+# Authors:
+#     Endi S. Dewata <edewata at 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) 2016 Red Hat, Inc.
+# All rights reserved.
+#
+
+from __future__ import absolute_import
+from __future__ import print_function
+import getopt
+import sys
+
+import pki.cli
+
+
+class PKCS12CLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(PKCS12CLI, self).__init__(
+            'pkcs12', 'PKCS #12 utilities')
+
+        self.add_module(PKCS12ImportCLI())
+
+
+class PKCS12ImportCLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(PKCS12ImportCLI, self).__init__(
+            'import', 'Import PKCS #12 file into NSS database')
+
+    def print_help(self):
+        print('Usage: pki pkcs-import [OPTIONS]')
+        print()
+        print('      --pkcs12                    PKCS #12 file containing certificates and keys.')
+        print('      --pkcs12-password           Password for the PKCS #12 file.')
+        print('      --pkcs12-password-file      File containing the PKCS #12 password.')
+        print('      --no-trust-flags            Do not include trust flags')
+        print('  -v, --verbose                   Run in verbose mode.')
+        print('      --debug                     Run in debug mode.')
+        print('      --help                      Show help message.')
+        print()
+
+    def execute(self, args):
+
+        try:
+            opts, _ = getopt.gnu_getopt(args, 'v', [
+                'pkcs12=', 'pkcs12-password=', 'pkcs12-password-file=',
+                'no-trust-flags', 'verbose', 'debug', 'help'])
+
+        except getopt.GetoptError as e:
+            print('ERROR: ' + str(e))
+            self.print_help()
+            sys.exit(1)
+
+        pkcs12_file = None
+        pkcs12_password = None
+        password_file = None
+        no_trust_flags = False
+
+        for o, a in opts:
+            if o == '--pkcs12':
+                pkcs12_file = a
+
+            elif o == '--pkcs12-password':
+                pkcs12_password = a
+
+            elif o == '--pkcs12-password-file':
+                password_file = a
+
+            elif o == '--no-trust-flags':
+                no_trust_flags = True
+
+            elif o in ('-v', '--verbose'):
+                self.set_verbose(True)
+
+            elif o == '--help':
+                self.print_help()
+                sys.exit()
+
+            else:
+                print('ERROR: unknown option ' + o)
+                self.print_help()
+                sys.exit(1)
+
+        if not pkcs12_file:
+            print('ERROR: Missing PKCS #12 file')
+            self.print_help()
+            sys.exit(1)
+
+        if not pkcs12_password:
+            print('ERROR: Missing PKCS #12 password')
+            self.print_help()
+            sys.exit(1)
+
+        main_cli = self.parent.parent
+
+        cmd = ['pkcs12-import']
+
+        if pkcs12_file:
+            cmd.extend(['--pkcs12', pkcs12_file])
+
+        if pkcs12_password:
+            cmd.extend(['--pkcs12-password', pkcs12_password])
+
+        if password_file:
+            cmd.extend(['--pkcs12-password-file', password_file])
+
+        if no_trust_flags:
+            cmd.extend(['--no-trust-flags'])
+
+        main_cli.execute_java(cmd)
diff --git a/base/java-tools/bin/pki b/base/java-tools/bin/pki
index ce322a2ec7b853e6beacc28c26bfe39e0875571a..d3c2d0013d76a85ff56b0c5a2a12cc29849ab269 100644
--- a/base/java-tools/bin/pki
+++ b/base/java-tools/bin/pki
@@ -20,113 +20,212 @@
 #
 
 from __future__ import absolute_import
+from __future__ import print_function
 import shlex
 import subprocess
 import sys
 
-
-def run_java_cli(args):
-
-    # read RESTEasy library path
-    value = subprocess.check_output(
-        '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $RESTEASY_LIB',
-        shell=True)
-    resteasy_lib = value.decode(sys.getfilesystemencoding()).strip()
-
-    # read logging configuration path
-    value = subprocess.check_output(
-        '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $LOGGING_CONFIG',
-        shell=True)
-    logging_config = value.decode(sys.getfilesystemencoding()).strip()
-
-    # construct classpath
-    classpath = [
-        '/usr/share/java/commons-cli.jar',
-        '/usr/share/java/commons-codec.jar',
-        '/usr/share/java/commons-httpclient.jar',
-        '/usr/share/java/commons-io.jar',
-        '/usr/share/java/commons-lang.jar',
-        '/usr/share/java/commons-logging.jar',
-        '/usr/share/java/httpcomponents/httpclient.jar',
-        '/usr/share/java/httpcomponents/httpcore.jar',
-        '/usr/share/java/jackson/jackson-core-asl.jar',
-        '/usr/share/java/jackson/jackson-jaxrs.jar',
-        '/usr/share/java/jackson/jackson-mapper-asl.jar',
-        '/usr/share/java/jackson/jackson-mrbean.jar',
-        '/usr/share/java/jackson/jackson-smile.jar',
-        '/usr/share/java/jackson/jackson-xc.jar',
-        '/usr/share/java/jaxb-api.jar',
-        '/usr/share/java/ldapjdk.jar',
-        '/usr/share/java/servlet.jar',
-        resteasy_lib + '/jaxrs-api.jar',
-        resteasy_lib + '/resteasy-atom-provider.jar',
-        resteasy_lib + '/resteasy-client.jar',
-        resteasy_lib + '/resteasy-jaxb-provider.jar',
-        resteasy_lib + '/resteasy-jaxrs.jar',
-        resteasy_lib + '/resteasy-jaxrs-jandex.jar',
-        resteasy_lib + '/resteasy-jackson-provider.jar',
-        '/usr/share/java/pki/pki-nsutil.jar',
-        '/usr/share/java/pki/pki-cmsutil.jar',
-        '/usr/share/java/pki/pki-certsrv.jar',
-        '/usr/share/java/pki/pki-tools.jar',
-        '/usr/lib64/java/jss4.jar',
-        '/usr/lib/java/jss4.jar'
-    ]
-
-    command = [
-        'java',
-        '-cp',
-        ':'.join(classpath),
-        '-Djava.util.logging.config.file=' + logging_config,
-        'com.netscape.cmstools.cli.MainCLI'
-    ]
-
-    command.extend(args)
-
-    rv = subprocess.call(command)
-    exit(rv)
-
-
-# pylint: disable=W0613
-def run_python_cli(args):
-
-    raise Exception('Not implemented')
-
-
-def main(argv):
-
-    # read global options
-    value = subprocess.check_output(
-        '. /etc/pki/pki.conf && echo $PKI_CLI_OPTIONS',
-        shell=True)
-    value = value.decode(sys.getfilesystemencoding()).strip()
-    args = shlex.split(value)
-    args.extend(argv[1:])
-
-    client_type = 'java'
-
-    new_args = []
-
-    # read --client-type parameter and remove it from the argument list
-    i = 0
-    while i < len(args):
-        if args[i] == '--client-type':
-            client_type = args[i + 1]
+import pki.cli
+import pki.cli.pkcs12
+
+
+PYTHON_COMMANDS = ['pkcs12-import']
+
+
+class PKICLI(pki.cli.CLI):
+
+    def __init__(self):
+        super(PKICLI, self).__init__(
+            'pki', 'PKI command-line interface')
+
+        self.database = None
+        self.password = None
+        self.password_file = None
+        self.token = None
+
+        self.add_module(pki.cli.pkcs12.PKCS12CLI())
+
+    def get_full_module_name(self, module_name):
+        return module_name
+
+    def print_help(self):
+        print('Usage: pki [OPTIONS]')
+        print()
+        print('      --client-type <type>     PKI client type (default: java)')
+        print('   -d <path>                   Client security database location ' +
+              '(default: ~/.dogtag/nssdb)')
+        print('   -c <password>               Client security database password ' +
+              '(mutually exclusive to the -C option)')
+        print('   -C <path>                   Client-side password file ' +
+              '(mutually exclusive to the -c option)')
+        print('      --token <name>           Security token name')
+        print()
+        print('  -v, --verbose                Run in verbose mode.')
+        print('      --debug                  Show debug messages.')
+        print('      --help                   Show help message.')
+        print()
+
+        super(PKICLI, self).print_help()
+
+    def execute_java(self, args):
+
+        # read RESTEasy library path
+        value = subprocess.check_output(
+            '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $RESTEASY_LIB',
+            shell=True)
+        resteasy_lib = value.decode(sys.getfilesystemencoding()).strip()
+
+        # read logging configuration path
+        value = subprocess.check_output(
+            '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $LOGGING_CONFIG',
+            shell=True)
+        logging_config = value.decode(sys.getfilesystemencoding()).strip()
+
+        # construct classpath
+        classpath = [
+            '/usr/share/java/commons-cli.jar',
+            '/usr/share/java/commons-codec.jar',
+            '/usr/share/java/commons-httpclient.jar',
+            '/usr/share/java/commons-io.jar',
+            '/usr/share/java/commons-lang.jar',
+            '/usr/share/java/commons-logging.jar',
+            '/usr/share/java/httpcomponents/httpclient.jar',
+            '/usr/share/java/httpcomponents/httpcore.jar',
+            '/usr/share/java/jackson/jackson-core-asl.jar',
+            '/usr/share/java/jackson/jackson-jaxrs.jar',
+            '/usr/share/java/jackson/jackson-mapper-asl.jar',
+            '/usr/share/java/jackson/jackson-mrbean.jar',
+            '/usr/share/java/jackson/jackson-smile.jar',
+            '/usr/share/java/jackson/jackson-xc.jar',
+            '/usr/share/java/jaxb-api.jar',
+            '/usr/share/java/ldapjdk.jar',
+            '/usr/share/java/servlet.jar',
+            resteasy_lib + '/jaxrs-api.jar',
+            resteasy_lib + '/resteasy-atom-provider.jar',
+            resteasy_lib + '/resteasy-client.jar',
+            resteasy_lib + '/resteasy-jaxb-provider.jar',
+            resteasy_lib + '/resteasy-jaxrs.jar',
+            resteasy_lib + '/resteasy-jaxrs-jandex.jar',
+            resteasy_lib + '/resteasy-jackson-provider.jar',
+            '/usr/share/java/pki/pki-nsutil.jar',
+            '/usr/share/java/pki/pki-cmsutil.jar',
+            '/usr/share/java/pki/pki-certsrv.jar',
+            '/usr/share/java/pki/pki-tools.jar',
+            '/usr/lib64/java/jss4.jar',
+            '/usr/lib/java/jss4.jar'
+        ]
+
+        cmd = [
+            'java',
+            '-cp',
+            ':'.join(classpath),
+            '-Djava.util.logging.config.file=' + logging_config,
+            'com.netscape.cmstools.cli.MainCLI'
+        ]
+
+        # restore options for Java commands
+
+        if self.database:
+            cmd.extend(['-d', self.database])
+
+        if self.password:
+            cmd.extend(['-c', self.password])
+
+        if self.password_file:
+            cmd.extend(['-C', self.password_file])
+
+        if self.token and self.token != 'internal':
+            cmd.extend(['--token', self.token])
+
+        cmd.extend(args)
+
+        rv = subprocess.call(cmd)
+        exit(rv)
+
+    def execute(self, argv):
+
+        # append global options
+        value = subprocess.check_output(
+            '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $PKI_CLI_OPTIONS',
+            shell=True)
+        value = value.decode(sys.getfilesystemencoding()).strip()
+        args = shlex.split(value)
+        args.extend(argv[1:])
+
+        client_type = 'java'
+        command = None
+
+        new_args = []
+
+        # read pki options before the command
+        # remove options for Python module
+
+        i = 0
+        while i < len(args):
+            # if arg is a command, stop
+            if args[i][0] != '-':
+                command = args[i]
+                break
+
+            # get database path
+            if args[i] == '-d':
+                self.database = args[i + 1]
+                i = i + 2
+
+            # get database password
+            elif args[i] == '-c':
+                self.password = args[i + 1]
+                i = i + 2
+
+            # get database password file path
+            elif args[i] == '-C':
+                self.password_file = args[i + 1]
+                i = i + 2
+
+            # get token name
+            elif args[i] == '--token':
+                self.token = args[i + 1]
+                i = i + 2
+
+            # check verbose option
+            elif args[i] == '-v' or args[i] == '--verbose':
+                self.set_verbose(True)
+                i = i + 1
+
+            # check debug option
+            elif args[i] == '--debug':
+                self.set_verbose(True)
+                self.set_debug(True)
+                i = i + 1
+
+            # get client type
+            elif args[i] == '--client-type':
+                client_type = args[i + 1]
+                i = i + 2
+
+            else:  # otherwise, save the arg for the next module
+                new_args.append(args[i])
+                i = i + 1
+
+        # save the rest of the args
+        while i < len(args):
+            new_args.append(args[i])
             i = i + 1
 
+        if self.verbose:
+            print('Command: %s' % ' '.join(args))
+
+        if client_type == 'python' or command in PYTHON_COMMANDS:
+            (module, module_args) = self.parse_args(new_args)
+            module.execute(module_args)
+
+        elif client_type == 'java':
+            self.execute_java(new_args)
+
         else:
-            new_args.append(args[i])
+            raise Exception('Unsupported client type: ' + client_type)
 
-        i = i + 1
-
-    if client_type == 'java':
-        run_java_cli(new_args)
-
-    elif client_type == 'python':
-        run_python_cli(new_args)
-
-    else:
-        raise Exception('Unsupported client type: ' + client_type)
 
 if __name__ == '__main__':
-    main(sys.argv)
+    cli = PKICLI()
+    cli.execute(sys.argv)
diff --git a/specs/pki-core.spec b/specs/pki-core.spec
index 4da0788ba06d055c1e06abd59db8b17f7e56edb9..bd1e116913c92bf3e57f56d019daff29d9468b08 100644
--- a/specs/pki-core.spec
+++ b/specs/pki-core.spec
@@ -871,6 +871,10 @@ systemctl daemon-reload
 %{python_sitelib}/pki/*.py
 %{python_sitelib}/pki/*.pyc
 %{python_sitelib}/pki/*.pyo
+%dir %{python_sitelib}/pki/cli
+%{python_sitelib}/pki/cli/*.py
+%{python_sitelib}/pki/cli/*.pyc
+%{python_sitelib}/pki/cli/*.pyo
 %dir %{_localstatedir}/log/pki
 %{_sbindir}/pki-upgrade
 %{_mandir}/man8/pki-upgrade.8.gz
-- 
2.4.3



More information about the Pki-devel mailing list