def cert_audit(appliances=[],
               credentials=[],
               timeout=120,
               no_check_hostname=False,
               domains=[],
               out_file="tmp/cert-audit.xlsx",
               delay=0.5,
               date_time_format="%A, %B %d, %Y, %X",
               localtime=False,
               days_only=False,
               web=False):
    """Perform an audit of all CryptoCertificate objects which are
up and enabled for the specified appliances and domains.

Output:

A table and an excel spreadsheet.

Parameters:

* `-a, --appliances`: The hostname(s), ip address(es), environment name(s)
or alias(es) of the appliances you would like to affect. For details
on configuring environments please see the comments in
`environments.conf` located in `$MAST_HOME/etc/default`. For details
on configuring aliases, please see the comments in `hosts.conf` located in
`$MAST_HOME/etc/default`. To pass multiple arguments to this parameter,
use multiple entries of the form `[-a appliance1 [-a appliance2...]]`
* `-c, --credentials`: The credentials to use for authenticating to the
appliances. Should be either one set to use for all appliances
or one set for each appliance. Credentials should be in the form
`username:password`. To pass multiple credentials to this parameter, use
multiple entries of the form `[-c credential1 [-c credential2...]]`.
When referencing multiple appliances with multiple credentials,
there must be a one-to-one correspondence of credentials to appliances:
`[-a appliance1 [-a appliance2...]] [-c credential1 [-c credential2...]]`
If you would prefer to not use plain-text passwords,
you can use the output of `$ mast-system xor <username:password>`.
* `-t, --timeout`: The timeout in seconds to wait for a response from
an appliance for any single request. __NOTE__ Program execution may
halt if a timeout is reached.
* `-n, --no-check-hostname`: If specified SSL verification will be turned
off when sending commands to the appliances.
* `-d, --domains`: The domains to audit, to audit all domains, provide
`all-domains`, to specify multiple domains use multiple entries of the
form `[-d domain1 [-d domain2...]]`.
* `-o, --out-file`: The excel spreadsheet to output, use either relative
or absolute path. The file should end in `.xlsx`
* `-D, --delay`: The amount of time in seconds to wait between auditing
each certificate. If you are experiencing intermitten `AuthenticationFailure`s,
it is a good idea to increase this parameter.
* `--date-time-format`: The format for date-timestamps. Refer to
[this document](https://docs.python.org/2/library/time.html#time.strftime)
for information on using this parameter
* `-l, --localtime`: If specified, the date-timestamps will be output in
local time instead of UTC.
* `--days-only`: If specified, only the number of days (floored) will be
reported in the `time-since-expiration` and `time-until-expiration` columns.
* `-w, --web`: __For Internel Use Only, will be removed in future versions.
DO NOT USE.__"""
    logger = make_logger("cert-audit")
    if out_file is None:
        logger.error("Must specify out file")
        if not web:
            print "Must specify out_file"
        sys.exit(2)
    if not os.path.exists(os.path.dirname(out_file)):
        os.makedirs(os.path.dirname(out_file))
    check_hostname = not no_check_hostname
    env = datapower.Environment(
        appliances,
        credentials,
        timeout,
        check_hostname=check_hostname)

    header_row = [
        "appliance",
        "domain",
        "certificate-object",
        "filename",
        "serial-number",
        "subject",
        "signature_algorithm",
        "not_before",
        "not_after",
        "issuer",
        "is-expired",
        "time-since-expiration",
        "time-until-expiration"]
    rows = [header_row]
    for appliance in env.appliances:
        logger.info("Checking appliance {}".format(appliance.hostname))
        if not web:
            print appliance.hostname
        _domains = domains
        if "all-domains" in domains:
            _domains = appliance.domains
        for domain in _domains:
            logger.info("In domain {}".format(domain))
            if not web:
                print "\t", domain
            config = appliance.get_config("CryptoCertificate", domain=domain)
            certs = [x for x in config.xml.findall(datapower.CONFIG_XPATH)]

            # Filter out disabled objects because the results won't change,
            # but we will perform less network traffic
            certs = filter(
                lambda x: x.find("mAdminState").text == "enabled",
                certs)

            for cert in certs:
                logger.info("Exporting cert {}".format(cert))
                filename = cert.find("Filename").text
                name = cert.get("name")
                _filename = name
                if not web:
                    print "\t\t", name
                row = [appliance.hostname, domain, name, filename]

                appliance.CryptoExport(
                    domain=domain,
                    ObjectType="cert",
                    ObjectName=name,
                    OutputFilename=_filename)
                logger.info("Finished exporting cert {}".format(cert))
                try:
                    logger.info(
                        "Retrieving file {}".format(
                            "temporary:///{}".format(_filename)))
                    cert = appliance.getfile(
                        domain,
                        "temporary:///{}".format(_filename))
                    logger.info(
                        "Finished retrieving file {}".format(
                            "temporary:///{}".format(_filename)))
                    logger.info(
                        "Attempting to delete file {}".format(
                            "temporary:///{}".format(_filename)))
                    appliance.DeleteFile(
                        domain=domain,
                        File="temporary:///{}".format(_filename))
                    logger.info(
                        "Finished deleting file {}".format(
                            "temporary:///{}".format(_filename)))
                except:
                    logger.exception("An unhandled exception has occurred")
                    rows.append(row)
                    if not web:
                        print "SKIPPING CERT"
                    continue
                cert = etree.fromstring(cert)
                _contents = insert_newlines(cert.find("certificate").text)
                certificate = \
                    "-----BEGIN CERTIFICATE-----\n" +\
                    _contents +\
                    "\n-----END CERTIFICATE-----\n"
                _cert = OpenSSL.crypto.load_certificate(
                    OpenSSL.crypto.FILETYPE_PEM,
                    certificate)
                subject = "'{}'".format(
                    ";".join(
                        ["=".join(x)
                         for x in _cert.get_subject().get_components()]))
                issuer = "'{}'".format(
                    ";".join(
                        ["=".join(x)
                         for x in _cert.get_issuer().get_components()]))
                serial_number = _cert.get_serial_number()
                try:
                    signature_algorithm = _cert.get_signature_algorithm()
                except AttributeError:
                    signature_algorithm = ""
                local_tz = tz.tzlocal()
                utc_tz = tz.tzutc()
                notBefore_utc = parser.parse(_cert.get_notBefore())
                notBefore_local = notBefore_utc.astimezone(local_tz)

                notAfter_utc = parser.parse(_cert.get_notAfter())
                notAfter_local = notAfter_utc.astimezone(local_tz)
                if localtime:
                    notAfter = notAfter_local.strftime(date_time_format)
                    notBefore = notBefore_local.strftime(date_time_format)
                else:
                    notAfter = notAfter_utc.strftime(date_time_format)
                    notBefore = notBefore_utc.strftime(date_time_format)

                if _cert.has_expired():
                    time_since_expiration = datetime.utcnow().replace(tzinfo=utc_tz) - notAfter_utc
                    if days_only:
                        time_since_expiration = time_since_expiration.days
                    else:
                        time_since_expiration = str(time_since_expiration)
                    time_until_expiration = 0
                else:
                    time_until_expiration = notAfter_utc - datetime.utcnow().replace(tzinfo=utc_tz)
                    if days_only:
                        time_until_expiration = time_until_expiration.days
                    else:
                        time_until_expiration = str(time_until_expiration)
                    time_since_expiration = 0
                row.extend(
                    [serial_number,
                     subject,
                     signature_algorithm,
                     notBefore,
                     notAfter,
                     issuer,
                     str(_cert.has_expired()),
                     time_since_expiration,
                     time_until_expiration])
                rows.append(row)
                sleep(delay)

    wb = openpyxl.Workbook()
    ws = wb.active
    for row in rows:
        ws.append(row)
    wb.save(out_file)
    if not web:
        print "\n\nCertificate Report (available at {}):".format(os.path.abspath(out_file))
        print_table(rows)
        print
    else:
        return (html_table(rows,
                           table_class="width-100",
                           header_row_class="results_table_header_row",
                           header_cell_class="results_table_header_column",
                           body_row_class="result_table_row",
                           body_cell_class="result_table_cell"),
                util.render_history(env))
def cert_file_audit(appliances=[],
                    credentials=[],
                    timeout=120,
                    no_check_hostname=False,
                    out_file=os.path.join("tmp", "cert-file-audit.xlsx"),
                    web=False):
    """Perform an audit of all files which reside in `cert:`, `pubcert:`
and `sharedcert:` on the specified appliances.

Output:

A table and an excel spreadsheet.

Parameters:

* `-a, --appliances`: The hostname(s), ip address(es), environment name(s)
or alias(es) of the appliances you would like to affect. For details
on configuring environments please see the comments in
`environments.conf` located in `$MAST_HOME/etc/default`. For details
on configuring aliases, please see the comments in `hosts.conf` located in
`$MAST_HOME/etc/default`. To pass multiple arguments to this parameter,
use multiple entries of the form `[-a appliance1 [-a appliance2...]]`
* `-c, --credentials`: The credentials to use for authenticating to the
appliances. Should be either one set to use for all appliances
or one set for each appliance. Credentials should be in the form
`username:password`. To pass multiple credentials to this parameter, use
multiple entries of the form `[-c credential1 [-c credential2...]]`.
When referencing multiple appliances with multiple credentials,
there must be a one-to-one correspondence of credentials to appliances:
`[-a appliance1 [-a appliance2...]] [-c credential1 [-c credential2...]]`
If you would prefer to not use plain-text passwords,
you can use the output of `$ mast-system xor <username:password>`.
* `-t, --timeout`: The timeout in seconds to wait for a response from
an appliance for any single request. __NOTE__ Program execution may
halt if a timeout is reached.
* `-n, --no-check-hostname`: If specified SSL verification will be turned
off when sending commands to the appliances.
* `-o, --out-file`: The excel spreadsheet to output, use either relative
or absolute path. The file should end in `.xlsx`
* `-w, --web`: __For Internel Use Only, will be removed in future versions.
DO NOT USE.__"""
    logger = make_logger("cert-file-audit")
    if out_file is None:
        logger.error("Must specify out file")
        if not web:
            print "Must specify out_file"
        sys.exit(2)
    if not os.path.exists(os.path.dirname(out_file)):
        os.makedirs(os.path.dirname(out_file))
    locations = ["cert:", "pubcert:", "sharedcert:"]
    check_hostname = not no_check_hostname
    env = datapower.Environment(appliances,
                                credentials,
                                timeout,
                                check_hostname=check_hostname)

    header_row = ["appliance",
                  "domain",
                  "directory",
                  "filename",
                  "size",
                  "modified"]
    rows = [header_row]

    for appliance in env.appliances:
        if not web:
            print appliance.hostname
        domain = "default"

        for location in locations:
            if not web:
                print "\t{}".format(location)
            filestore = appliance.get_filestore(domain=domain,
                                                location=location)
            _location = filestore.xml.find(datapower.FILESTORE_XPATH)
            if _location is None:
                continue
            if _location.findall("./file") is not None:
                for _file in _location.findall("./file"):
                    dir_name = _location.get("name")
                    filename = _file.get("name")
                    if not web:
                        print "\t\t{}".format(filename)
                    size = _file.find("size").text
                    modified = _file.find("modified").text
                    rows.append([appliance.hostname,
                                 domain,
                                 dir_name,
                                 filename,
                                 size,
                                 modified])
            for directory in _location.findall(".//directory"):
                dir_name = directory.get("name")
                if not web:
                    print "\t\t{}".format(dir_name)
                for _file in directory.findall(".//file"):
                    filename = _file.get("name")
                    if not web:
                        print "\t\t\t{}".format(filename)
                    size = _file.find("size").text
                    modified = _file.find("modified").text

                    rows.append([appliance.hostname,
                                 domain,
                                 dir_name,
                                 filename,
                                 size,
                                 modified])
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "CertFileAudit"
    for row in rows:
        ws.append(row)
    wb.save(out_file)
    if not web:
        print_table(rows)
    else:
        return (html_table(rows,
                           table_class="width-100",
                           header_row_class="results_table_header_row",
                           header_cell_class="results_table_header_column",
                           body_row_class="result_table_row",
                           body_cell_class="result_table_cell"),
               util.render_history(env))