From 2fb036f508903bf1886b7afdbe14c656e71a115e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20K=C3=A1cha?= <ph@cesnet.cz>
Date: Tue, 11 Jul 2017 15:53:34 +0200
Subject: [PATCH] RA now allows for enabling/disabling cert generation
 (necessary for preventing prolongation)

---
 warden3/contrib/warden_ra/warden_ra.py | 75 ++++++++++++++++++++++++--
 1 file changed, 72 insertions(+), 3 deletions(-)

diff --git a/warden3/contrib/warden_ra/warden_ra.py b/warden3/contrib/warden_ra/warden_ra.py
index 9437bf1..f524153 100755
--- a/warden3/contrib/warden_ra/warden_ra.py
+++ b/warden3/contrib/warden_ra/warden_ra.py
@@ -25,6 +25,10 @@ import warden_server
 from warden_server import Request, ObjectBase, FileLogger, SysLogger, Server, expose, read_cfg
 
 
+class ClientDisabledError(Exception):
+    pass
+
+
 class EjbcaClient(object):
 
     def __init__(self, registry, ejbca_data=None):
@@ -51,6 +55,19 @@ class EjbcaClient(object):
         self.ejbca_data["username"] = new + self.registry.username_suffix
         self.ejbca_data["subjectDN"] = self.registry.subject_dn_template % new
 
+    @property
+    def enabled(self):
+        return self.ejbca_data["status"] != ejbcaws.STATUS_HISTORICAL
+
+    @enabled.setter
+    def enabled(self, new):
+        if self.enabled:
+            if not new:
+                self.ejbca_data["status"] = ejbcaws.STATUS_HISTORICAL
+        else:
+            if new:
+                self.ejbca_data["status"] = ejbcaws.STATUS_GENERATED
+
     @property
     def status(self):
         s = self.ejbca_data["status"]
@@ -60,6 +77,8 @@ class EjbcaClient(object):
             return "Passive"
         elif s == ejbcaws.STATUS_INITIALIZED:
             return "New"
+        elif s == ejbcaws.STATUS_HISTORICAL:
+            return "Disabled"
         else:
             return "EJBCA status %d" % s
 
@@ -67,6 +86,8 @@ class EjbcaClient(object):
         return self.registry.ejbca.find_certs(self.ejbca_data["username"], validOnly=False)
 
     def allow_new_cert(self, pwd=None):
+        if not self.enabled:
+            raise ClientDisabledError("This client is disabled")
         self.ejbca_data["status"] = ejbcaws.STATUS_NEW
         if pwd is not None:
             self.ejbca_data["password"] = pwd
@@ -227,7 +248,10 @@ class CertHandler(ObjectBase):
             # so generate oneshot password and allow now
             password = "".join((random.choice(string.ascii_letters + string.digits) for dummy in range(16)))
             self.log.debug("Authorized by X509, enabling cert generation with password %s" % password)
-            client.allow_new_cert(pwd=password)
+            try:
+                client.allow_new_cert(pwd=password)
+            except ClientDisabledError as e:
+                raise self.req.error(message="Error enabling cert generation", error=403, exc=sys.exc_info())
             client.save()
         if not password:
             raise self.req.error(message="Missing password and certificate validation failed", error=403, name=name, password=password)
@@ -323,10 +347,37 @@ def register_client(registry, name, admins=None, verbose=False):
 
 def applicant(registry, name, password=None, verbose=False):
     client = registry.get_client(name)
+    if not client:
+        print "No such client."
+        return
     if password is None:
         password = "".join((random.choice(string.ascii_letters + string.digits) for dummy in range(16)))
-        print("Application password is: %s\n" % password)
-    client.allow_new_cert(pwd=password)
+    try:
+        client.allow_new_cert(pwd=password)
+    except ClientDisabledError:
+        print "This client is disabled. Use 'enable' first."
+        return
+    client.save()
+    list_clients(registry, name, verbose)
+    print("Application password is: %s\n" % password)
+
+
+def enable(registry, name, verbose=False):
+    client = registry.get_client(name)
+    if not client:
+        print "No such client."
+        return
+    client.enabled = True
+    client.save()
+    list_clients(registry, name, verbose)
+
+
+def disable(registry, name, verbose=False):
+    client = registry.get_client(name)
+    if not client:
+        print "No such client."
+        return
+    client.enabled = False
     client.save()
     list_clients(registry, name, verbose)
 
@@ -410,6 +461,24 @@ def get_args():
     subargp_apply.add_argument("--password", action="store", type=str,
         help="password for application (will be autogenerated if not set)")
 
+    subargp_enable = subargp.add_parser("enable", add_help=False,
+        description="Enable this client",
+        help="enable this client")
+    subargp_enable.set_defaults(command=enable)
+    subargp_enable.add_argument("--help", action="help",
+        help="show this help message and exit")
+    subargp_enable.add_argument("--name", action="store", type=str,
+        required=True, help="client name")
+
+    subargp_disable = subargp.add_parser("disable", add_help=False,
+        description="Disable this client",
+        help="disable this client (no more applications until enabled again)")
+    subargp_disable.set_defaults(command=disable)
+    subargp_disable.add_argument("--help", action="help",
+        help="show this help message and exit")
+    subargp_disable.add_argument("--name", action="store", type=str,
+        required=True, help="client name")
+
     subargp_req = subargp.add_parser("request", add_help=False,
         description="Generate certificate request",
         help="generate CSR")
-- 
GitLab