#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# This file is part of cepces.
#
# cepces 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.
#
# cepces 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 cepces.  If not, see <http://www.gnu.org/licenses/>.
#
# pylint: disable=broad-except,invalid-name

"""
This is a submission helper for user certificates.

It requires that you have a valid kerberos ticket in your credential cache (check with `klist`).
This is normally automatically created during login with a domain account by SSSD.
You can manually acquire a kerberos ticket via `kinit username@DOMAIN.TLD`.
"""

import sys
import argparse
from cepces.user import UserEnrollment, ApprovalPendingException


def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

def list_templates(templates):
        print("\n".join(templates))

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="cepces submission helper for user certs")
    parser.add_argument("action",
        choices=["list-templates", "request", "poll"])
    parser.add_argument("--server",
        help="Hostname of the issuing certification authority")
    parser.add_argument("--auth",
        help="Authentication mechanism used for connecting to the service",
        choices=["Anonymous", "Kerberos",
                 "UsernamePassword", "Certificate"],
        default="Kerberos")
    parser.add_argument("--keytab",
        help="Use the specified keytab")
    parser.add_argument("--principals",
        help="A list of principals to try when requesting a ticket")
    parser.add_argument("--openssl-seclevel",
        help="The openssl security level")
    parser.add_argument("--profile", "-T",
        help="The template name for the request")
    parser.add_argument("--keyfile", "-k",
        help="The private key file for the signing request, will be generated/created if does not exist")
    parser.add_argument("--certfile", "-f",
        help="The certificate file to write on successful request")
    parser.add_argument("--keysize", "-s",
        help="The key size of the key to generate", default="4096")
    parser.add_argument("--passphrase", "-p",
        help="The passphrase to decrypt the existing key file or to encrypt the generated key")
    parser.add_argument("--request-id", "-i",
        help="The request ID to poll for")
    parser.add_argument("--reference", "-r",
        help="The request reference to poll for")
    args = parser.parse_args()

    g_overrides = {}
    if args.server is not None:
        g_overrides["server"] = args.server
        g_overrides["auth"] = args.auth
        endpoint = "https://%s/ADPolicyProvider_CEP_%s/service.svc/CEP" % \
                        (args.server, args.auth)
        g_overrides["endpoint"] = endpoint
    if args.openssl_seclevel is not None:
        g_overrides["openssl_seclevel"] = args.openssl_seclevel

    k_overrides = {
        # this script is intended to use as normal user with
        # existing ccache created during login, e.g. /tmp/krb5cc_1000
        # so we disable the ccache creation feature and
        # pass empty principals to use the default one
        "ccache": "False",
        "principals": "",
    }
    if args.keytab is not None:
        k_overrides["keytab"] = args.keytab
    if args.principals is not None:
        k_overrides["principals"] = args.principals

    try:
        user_enrollment = UserEnrollment(g_overrides, k_overrides)

        if args.action == "list-templates":
            list_templates(user_enrollment.service.templates)

        elif args.action == "request":
            if args.keyfile is None or args.certfile is None or args.profile is None:
                raise Exception("--keyfile, --certfile, --profile is required")
            user_enrollment.request(args.keyfile, args.certfile, args.profile, args.keysize, args.passphrase)

        elif args.action == "poll":
            if args.certfile is None or args.request_id is None or args.reference is None:
                raise Exception("--certfile, --request-id, --reference is required")
            user_enrollment.poll(args.certfile, args.request_id, args.reference)

    except ApprovalPendingException as e:
        # output the "cookie" that can be used to later poll the status
        print("Certificate approval pending. Poll later with the following info.")
        print("Request ID:", e.request_id)
        print("Reference:", e.reference)
        sys.exit(2)

    except Exception as e:
        eprint(type(e).__name__, ':', e)
        sys.exit(1)
