#!/usr/bin/python
#
# Authors:
#   Rob Crittenden <rcritten@redhat.com>
#
# Copyright (C) 2011  Red Hat
# see file 'COPYING' for use and warranty information
#
# 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, either version 3 of the License, or
# (at your option) any later version.
#
# 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, see <http://www.gnu.org/licenses/>.

"""
Generate a custom certificate used in the service unit tests. The certificate
will be created in tests/test_xmlrpc/service.crt
"""
import sys
import os
import tempfile
import shutil
import nss.nss as nss
from ipalib import api, x509, backend, errors
from ipaserver.plugins import rabase
from ipapython import ipautil

CERTPATH = 'tests/test_xmlrpc/service.crt'

def run_certutil(reqdir, args, stdin=None):
    """
    Run an NSS certutil command
    """
    new_args = ["/usr/bin/certutil", "-d", reqdir]
    new_args = new_args + args
    return ipautil.run(new_args, stdin)

def generateCSR(reqdir, pwname, subject):
    """
    Create a CSR for the given subject.
    """
    run_certutil(reqdir, ["-R", "-s", subject,
                       "-o", '%s/req' % reqdir,
                       "-z", "/etc/group",
                       "-f", pwname,
                       "-a",
                       ])
    fp = open('%s/req' % reqdir, "r")
    data = fp.read()
    fp.close()
    return data

class client(backend.Executioner):
    """
    A simple-minded IPA client that can execute remote commands.
    """

    def run(self, method, *args, **options):
        self.create_context()
        result = self.execute(method, *args, **options)
        return result


def makecert(reqdir):
    """
    Generate a service certificate that can be used during unit testing.
    """
    cfg = dict(
        context='cli',
        in_server=False,
        debug=False,
        verbose=0,
    )

    api.bootstrap(**cfg)
    api.register(client)
    api.finalize()

    ra = rabase.rabase()
    if not os.path.exists(ra.sec_dir) and api.env.xmlrpc_uri == 'http://localhost:8888/ipa/xml':
        sys.exit('The in-tree self-signed CA is not configured, see tests/test_xmlrpc/test_cert.py')

    pwname = reqdir + "/pwd"

    # Create an empty password file
    fp = open(pwname, "w")
    fp.write("\n")
    fp.close()

    # Generate NSS cert database to store the private key for our CSR
    run_certutil(reqdir, ["-N", "-f", pwname])

    cert = None
    subject = 'CN=%s,O=%s' % (api.env.host, api.env.realm)
    princ = 'unittest/%s@%s' % (api.env.host, api.env.realm)
    csr = unicode(generateCSR(reqdir, pwname, subject))

    try:
        res = api.Backend.client.run('cert_request', csr, principal=princ,
            add=True)
        cert = x509.make_pem(res['result']['certificate'])
        fd = open(CERTPATH, 'w')
        fd.write(cert)
        fd.close()
    except errors.NotFound:
        return "certificate request failed"
    except errors.CommandError:
        return "You need to set enable_ra=True in ~/.ipa/default.conf"

    nss.nss_init_nodb()
    c = x509.load_certificate(cert, x509.PEM)
    print c

    return 0

reqdir = None

if os.path.exists(CERTPATH):
    print "Test certificate %s exists, skipping." % CERTPATH
    sys.exit(0)
try:
    reqdir = tempfile.mkdtemp(prefix = "tmp-")
    sys.exit(makecert(reqdir))
finally:
    shutil.rmtree(reqdir)
