summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--custodia/httpd/authenticators.py34
-rw-r--r--custodia/httpd/authorizers.py18
-rw-r--r--custodia/httpd/server.py16
-rw-r--r--custodia/log.py19
4 files changed, 77 insertions, 10 deletions
diff --git a/custodia/httpd/authenticators.py b/custodia/httpd/authenticators.py
index dbb34bd..bed2bc4 100644
--- a/custodia/httpd/authenticators.py
+++ b/custodia/httpd/authenticators.py
@@ -12,6 +12,7 @@ class HTTPAuthenticator(object):
def __init__(self, config=None):
self.config = config
+ self._auditlog = log.AuditLog(self.config)
def handle(self, request):
raise HTTPError(403)
@@ -32,8 +33,14 @@ class SimpleCredsAuth(HTTPAuthenticator):
uid = int(request['creds']['gid'])
gid = int(request['creds']['uid'])
if self._gid == gid or self._uid == uid:
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_PASS,
+ request['creds']['pid'],
+ "SCA", "%d, %d" % (uid, gid))
return True
else:
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
+ request['creds']['pid'],
+ "SCA", "%d, %d" % (uid, gid))
return False
@@ -57,13 +64,25 @@ class SimpleHeaderAuth(HTTPAuthenticator):
pass
elif isinstance(self.value, str):
if value != self.value:
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
+ request['creds']['pid'],
+ "SHA", value)
return False
elif isinstance(self.value, list):
if value not in self.value:
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
+ request['creds']['pid'],
+ "SHA", value)
return False
else:
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
+ request['creds']['pid'],
+ "SHA", value)
return False
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_PASS,
+ request['creds']['pid'],
+ "SHA", value)
request['remote_user'] = value
return True
@@ -77,7 +96,6 @@ class SimpleAuthKeys(HTTPAuthenticator):
self.store_name = self.config['store']
self.store = None
self.namespace = self.config.get('store_namespace', 'custodiaSAK')
- self._auditlog = log.AuditLog(self.config)
def _db_key(self, name):
return os.path.join(self.namespace, name)
@@ -96,14 +114,20 @@ class SimpleAuthKeys(HTTPAuthenticator):
if constant_time.bytes_eq(val.encode('utf-8'),
key.encode('utf-8')):
validated = True
- except Exception as err:
- self._auditlog._log("AUTH ERROR: (%s) %s" % (name, err))
+ except Exception:
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
+ request['creds']['pid'],
+ "SAK", name)
return False
if validated:
- self._auditlog._log("AUTH SUCCESS: %s" % name)
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_PASS,
+ request['creds']['pid'],
+ "SAK", name)
request['remote_user'] = name
return True
- self._auditlog._log("AUTH FAIL: %s" % name)
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
+ request['creds']['pid'],
+ "SAK", name)
return False
diff --git a/custodia/httpd/authorizers.py b/custodia/httpd/authorizers.py
index dbf3d37..d6fe7c7 100644
--- a/custodia/httpd/authorizers.py
+++ b/custodia/httpd/authorizers.py
@@ -2,11 +2,14 @@
import os
+from custodia import log
+
class HTTPAuthorizer(object):
def __init__(self, config=None):
self.config = config
+ self._auditlog = log.AuditLog(self.config)
self.store_name = None
if self.config and 'store' in self.config:
self.store_name = self.config['store']
@@ -36,10 +39,16 @@ class SimplePathAuthz(HTTPAuthorizer):
# special case to match a path ending in /
authz = authz[:-1]
if authz == path:
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTHZ_PASS,
+ request['creds']['pid'],
+ "SPA", path)
return True
while path != '':
if path in self.paths:
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTHZ_PASS,
+ request['creds']['pid'],
+ "SPA", path)
return True
if path == '/':
path = ''
@@ -63,12 +72,21 @@ class UserNameSpace(HTTPAuthorizer):
name = request.get('remote_user', None)
if name is None:
# UserNameSpace requires a user ...
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTHZ_FAIL,
+ request.get('creds', {'pid': 0})['pid'],
+ "UNS(%s)" % self.path, path)
return False
namespace = self.path.rstrip('/') + '/' + name + '/'
if not path.startswith(namespace):
# Not in the namespace
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTHZ_FAIL,
+ request.get('creds', {'pid': 0})['pid'],
+ "UNS(%s)" % self.path, path)
return False
request['default_namespace'] = name
+ self._auditlog.svc_access(log.AUDIT_SVC_AUTHZ_PASS,
+ request.get('creds', {'pid': 0})['pid'],
+ "UNS(%s)" % self.path, path)
return True
diff --git a/custodia/httpd/server.py b/custodia/httpd/server.py
index 7a84526..8f02a78 100644
--- a/custodia/httpd/server.py
+++ b/custodia/httpd/server.py
@@ -20,8 +20,7 @@ except ImportError:
from socketserver import ForkingMixIn, UnixStreamServer
from urllib.parse import urlparse, parse_qs, unquote
-from custodia.log import debug as log_debug
-from custodia.log import stacktrace
+from custodia import log
SO_PEERCRED = getattr(socket, 'SO_PEERCRED', 17)
@@ -36,7 +35,7 @@ class HTTPError(Exception):
self.code = code if code is not None else 500
self.mesg = message
errstring = '%d: %s' % (self.code, self.mesg)
- log_debug(errstring)
+ log.debug(errstring)
super(HTTPError, self).__init__(errstring)
@@ -63,6 +62,7 @@ class ForkingLocalHTTPServer(ForkingMixIn, UnixStreamServer):
self.config = config
if 'server_string' in self.config:
self.server_string = self.config['server_string']
+ self._auditlog = log.AuditLog(self.config)
def server_bind(self):
oldmask = os.umask(000)
@@ -144,7 +144,7 @@ class LocalHTTPRequestHandler(BaseHTTPRequestHandler):
SELINUX_CONTEXT_LEN)
context = creds.decode('utf-8')
except Exception as e:
- log_debug("Couldn't retrieve SELinux Context: (%s)" % str(e))
+ log.debug("Couldn't retrieve SELinux Context: (%s)" % str(e))
context = None
return {'pid': pid, 'uid': uid, 'gid': gid, 'context': context}
@@ -254,7 +254,7 @@ class LocalHTTPRequestHandler(BaseHTTPRequestHandler):
return
def log_traceback(self):
- self.log_error('Traceback:\n%s' % stacktrace())
+ self.log_error('Traceback:\n%s' % log.stacktrace())
def pipeline(self, config, request):
"""
@@ -299,6 +299,9 @@ class LocalHTTPRequestHandler(BaseHTTPRequestHandler):
elif valid is True:
valid_once = True
if valid_once is not True:
+ self.server._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
+ request['creds']['pid'], "MAIN",
+ 'No auth')
raise HTTPError(403)
# auhz framework here
@@ -310,6 +313,9 @@ class LocalHTTPRequestHandler(BaseHTTPRequestHandler):
if valid is not None:
break
if valid is not True:
+ self.server._auditlog.svc_access(log.AUDIT_SVC_AUTHZ_FAIL,
+ request['creds']['pid'], "MAIN",
+ request.get('path', '/'))
raise HTTPError(403)
# Select consumer
diff --git a/custodia/log.py b/custodia/log.py
index ff71137..c49a29e 100644
--- a/custodia/log.py
+++ b/custodia/log.py
@@ -52,6 +52,12 @@ AUDIT_SET_DENIED = 4
AUDIT_DEL_ALLOWED = 5
AUDIT_DEL_DENIED = 6
AUDIT_LAST = 7
+AUDIT_SVC_NONE = 8
+AUDIT_SVC_AUTH_PASS = 9
+AUDIT_SVC_AUTH_FAIL = 10
+AUDIT_SVC_AUTHZ_PASS = 11
+AUDIT_SVC_AUTHZ_FAIL = 12
+AUDIT_SVC_LAST = 13
AUDIT_MESSAGES = [
"AUDIT FAILURE",
"ALLOWED: '{client:s}' requested key '{key:s}'", # AUDIT_GET_ALLOWED
@@ -60,6 +66,13 @@ AUDIT_MESSAGES = [
"DENIED: '{client:s}' stored key '{key:s}'", # AUDIT_SET_DENIED
"ALLOWED: '{client:s}' deleted key '{key:s}'", # AUDIT_DEL_ALLOWED
"DENIED: '{client:s}' deleted key '{key:s}'", # AUDIT_DEL_DENIED
+ "AUDIT FAILURE 7",
+ "AUDIT FAILURE 8",
+ "PASS({tag:s}): '{cli:s}' authenticated as '{name:s}'", # SVC_AUTH_PASS
+ "FAIL({tag:s}): '{cli:s}' authenticated as '{name:s}'", # SVC_AUTH_FAIL
+ "PASS({tag:s}): '{cli:s}' authorized for '{name:s}'", # SVC_AUTHZ_PASS
+ "FAIL({tag:s}): '{cli:s}' authorized for '{name:s}'", # SVC_AUTHZ_FAIL
+ "AUDIT FAILURE 13",
]
@@ -79,3 +92,9 @@ class AuditLog(object):
if action <= AUDIT_NONE or action >= AUDIT_LAST:
action = AUDIT_NONE
self._log(AUDIT_MESSAGES[action].format(client=client, key=keyname))
+
+ def svc_access(self, action, client, tag, name):
+ if action <= AUDIT_SVC_NONE or action >= AUDIT_SVC_LAST:
+ action = AUDIT_NONE
+ self._log(AUDIT_MESSAGES[action].format(cli=str(client), tag=tag,
+ name=name))