|
|
@@ -23,6 +23,7 @@ import logging
|
|
|
import os.path
|
|
|
import re
|
|
|
import tempfile
|
|
|
+import time
|
|
|
|
|
|
import kerberos
|
|
|
|
|
|
@@ -46,7 +47,7 @@ import desktop.views
|
|
|
import desktop.conf
|
|
|
from desktop.context_processors import get_app_name
|
|
|
from desktop.lib import apputil, i18n
|
|
|
-from desktop.lib.django_util import render, render_json, is_jframe_request
|
|
|
+from desktop.lib.django_util import render, render_json, is_jframe_request, get_username_re_rule, get_groupname_re_rule
|
|
|
from desktop.lib.exceptions import StructuredException
|
|
|
from desktop.lib.exceptions_renderable import PopupException
|
|
|
from desktop.log.access import access_log, log_page_hit
|
|
|
@@ -341,32 +342,105 @@ class JsonMessage(object):
|
|
|
|
|
|
class AuditLoggingMiddleware(object):
|
|
|
|
|
|
+ username_re = get_username_re_rule()
|
|
|
+ groupname_re = get_groupname_re_rule()
|
|
|
+
|
|
|
+ operations = {
|
|
|
+ '/accounts/login': 'USER_LOGIN',
|
|
|
+ '/accounts/logout': 'USER_LOGOUT',
|
|
|
+ '/useradmin/users/add_ldap_users': 'ADD_LDAP_USERS',
|
|
|
+ '/useradmin/users/add_ldap_groups': 'ADD_LDAP_GROUPS',
|
|
|
+ '/useradmin/users/sync_ldap_users_groups': 'SYNC_LDAP_USERS_GROUPS',
|
|
|
+ '/useradmin/users/new': 'CREATE_USER',
|
|
|
+ '/useradmin/groups/new': 'CREATE_GROUP',
|
|
|
+ '/useradmin/users/delete': 'DELETE_USER',
|
|
|
+ '/useradmin/groups/delete': 'DELETE_GROUP'
|
|
|
+ }
|
|
|
+
|
|
|
+ operation_patterns = {
|
|
|
+ '/useradmin/permissions/edit/(?P<app>.*)/(?P<priv>.*)': 'EDIT_PERMISSION',
|
|
|
+ '/useradmin/users/edit/(?P<username>%s)' % (username_re,): 'EDIT_USER',
|
|
|
+ '/useradmin/groups/edit/(?P<name>%s)' % (groupname_re,): 'EDIT_GROUP'
|
|
|
+ }
|
|
|
+
|
|
|
def __init__(self):
|
|
|
- from desktop.conf import AUDIT_EVENT_LOG_DIR
|
|
|
+ from desktop.conf import AUDIT_EVENT_LOG_DIR, SERVER_USER
|
|
|
+
|
|
|
+ self.impersonator = SERVER_USER.get()
|
|
|
|
|
|
if not AUDIT_EVENT_LOG_DIR.get():
|
|
|
LOG.info('Unloading AuditLoggingMiddleware')
|
|
|
raise exceptions.MiddlewareNotUsed
|
|
|
|
|
|
+ def process_view(self, request, view_func, view_args, view_kwargs):
|
|
|
+ try:
|
|
|
+ operation = self._get_operation(request.path)
|
|
|
+ if operation == 'USER_LOGOUT':
|
|
|
+ self._log_message(operation, request)
|
|
|
+ except Exception, e:
|
|
|
+ LOG.error('Could not audit the request: %s' % e)
|
|
|
+
|
|
|
+ return None
|
|
|
+
|
|
|
def process_response(self, request, response):
|
|
|
+ response['audited'] = False
|
|
|
try:
|
|
|
- audit_logger = get_audit_logger()
|
|
|
- audit_logger.debug(JsonMessage(**{
|
|
|
- datetime.utcnow().strftime('%s'): {
|
|
|
- 'user': request.user.username if hasattr(request, 'user') else 'anonymous',
|
|
|
- "status": response.status_code,
|
|
|
- "impersonator": None,
|
|
|
- "ip_address": request.META.get('REMOTE_ADDR'),
|
|
|
- "authorization_failure": response.status_code == 401,
|
|
|
- "service": get_app_name(request),
|
|
|
- "url": request.path,
|
|
|
- }
|
|
|
- }))
|
|
|
- response['audited'] = True
|
|
|
+ operation = self._get_operation(request.path)
|
|
|
+ if request.method == 'POST' and operation and operation != 'USER_LOGOUT':
|
|
|
+ self._log_message(operation, request, response)
|
|
|
+ response['audited'] = True
|
|
|
except Exception, e:
|
|
|
LOG.error('Could not audit the request: %s' % e)
|
|
|
return response
|
|
|
|
|
|
+ def _log_message(self, operation, request, response=None):
|
|
|
+ audit_logger = get_audit_logger()
|
|
|
+
|
|
|
+ allowed = True
|
|
|
+ status = 200
|
|
|
+ if response is not None:
|
|
|
+ allowed = response.status_code != 401
|
|
|
+ status = response.status_code
|
|
|
+
|
|
|
+ audit_logger.debug(JsonMessage(**{
|
|
|
+ 'username': self._get_username(request),
|
|
|
+ 'impersonator': self.impersonator,
|
|
|
+ 'ipAddress': self._get_client_ip(request),
|
|
|
+ 'operation': operation,
|
|
|
+ 'eventTime': self._milliseconds_since_epoch(),
|
|
|
+ 'allowed': allowed,
|
|
|
+ 'status': status,
|
|
|
+ 'service': get_app_name(request),
|
|
|
+ 'url': request.path
|
|
|
+ }))
|
|
|
+
|
|
|
+ def _get_client_ip(self, request):
|
|
|
+ x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
|
|
+ if x_forwarded_for:
|
|
|
+ x_forwarded_for = x_forwarded_for.split(',')[0]
|
|
|
+ return request.META.get('HTTP_CLIENT_IP') or x_forwarded_for or request.META.get('REMOTE_ADDR')
|
|
|
+
|
|
|
+ def _get_username(self, request):
|
|
|
+ if hasattr(request, 'user') and not request.user.is_anonymous():
|
|
|
+ return request.user.get_username()
|
|
|
+ else:
|
|
|
+ return 'anonymous'
|
|
|
+
|
|
|
+ def _milliseconds_since_epoch(self):
|
|
|
+ return int(time.time() * 1000)
|
|
|
+
|
|
|
+ def _get_operation(self, path):
|
|
|
+ url = path.rstrip('/')
|
|
|
+
|
|
|
+ if url in AuditLoggingMiddleware.operations:
|
|
|
+ return AuditLoggingMiddleware.operations[url]
|
|
|
+ else:
|
|
|
+ for regex, operation in AuditLoggingMiddleware.operation_patterns.items():
|
|
|
+ pattern = re.compile(regex)
|
|
|
+ if pattern.match(url):
|
|
|
+ return operation
|
|
|
+
|
|
|
+ return None
|
|
|
|
|
|
try:
|
|
|
import tidylib
|