Skip to content

Commit

Permalink
Merge branch '4.4' into dev-cloud-limits
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasTurina committed Oct 17, 2022
2 parents 87aaf72 + 23afd1e commit 74b748f
Show file tree
Hide file tree
Showing 129 changed files with 452,940 additions and 309,860 deletions.
Binary file added .coverage
Binary file not shown.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,26 @@ All notable changes to this project will be documented in this file.
- Prevented the Ruleset test suite from restarting the manager. ([#10773](https:/wazuh/wazuh/pull/10773))


## [v4.3.9] - 2022-10-13

### Agent

#### Fixed

- Fixed remote policy detection in SCA. ([#15007](https:/wazuh/wazuh/pull/15007))
- Fixed agent upgrade module settings parser to set a default CA file. ([#15023](https:/wazuh/wazuh/pull/15023))

#### Removed

- Removed obsolete Windows Audit SCA policy file. ([#14497](https:/wazuh/wazuh/issues/14497))

### Other

#### Changed

- Updated external protobuf python dependency to 3.19.6. ([#15067](https:/wazuh/wazuh/pull/15067))


## [v4.3.8] - 2022-09-19

### Manager
Expand Down
87 changes: 51 additions & 36 deletions api/api/alogging.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,26 @@
# Created by Wazuh, Inc. <[email protected]>.
# This program is a free software; you can redistribute it and/or modify it under the terms of GPLv2
import binascii
import hashlib
import json
import logging
import re
from base64 import b64decode

from aiohttp.abc import AbstractAccessLogger
from pythonjsonlogger import jsonlogger
from wazuh.core.wlogging import WazuhLogger

from api.configuration import api_conf
from wazuh.core.wlogging import WazuhLogger

# compile regex when the module is imported so it's not necessary to compile it everytime log.info is called
# Compile regex when the module is imported so it's not necessary to compile it everytime log.info is called
request_pattern = re.compile(r'\[.+]|\s+\*\s+')

# Variable used to specify an unknown user
UNKNOWN_USER_STRING = "unknown_user"

# Run_as login endpoint path
RUN_AS_LOGIN_ENDPOINT = "/security/user/authenticate/run_as"


class AccessLogger(AbstractAccessLogger):
"""
Expand All @@ -30,7 +33,7 @@ def check_stream(self):
if not handler.stream or handler.stream.closed:
handler.stream = handler._open()

def custom_logging(self, user, remote, method, path, query, body, time, status):
def custom_logging(self, user, remote, method, path, query, body, time, status, hash_auth_context=''):
"""Provide the log entry structure depending on the logging format.
Parameters
Expand All @@ -51,27 +54,35 @@ def custom_logging(self, user, remote, method, path, query, body, time, status):
Required time to compute the request.
status : int
Status code of the request.
hash_auth_context : str, optional
Hash representing the authorization context. Default: ''
"""

self.logger.info(f'{user} '
f'{remote} '
f'"{method} {path}" '
f'with parameters {json.dumps(query)} and body {json.dumps(body)} '
f'done in {time:.3f}s: {status}',
extra={'log_type': 'log'}
)

self.logger.info({'user': user,
'ip': remote,
'http_method': method,
'uri': f'{method} {path}',
'parameters': query,
'body': body,
'time': f'{time:.3f}s',
'status_code': status
},
extra={'log_type': 'json'}
)
if not hash_auth_context:
log_info = f'{user} {remote} "{method} {path}" with parameters {json.dumps(query)} ' \
f'and body {json.dumps(body)} done in {time:.3f}s: {status}'
json_info = {'user': user,
'ip': remote,
'http_method': method,
'uri': f'{method} {path}',
'parameters': query,
'body': body,
'time': f'{time:.3f}s',
'status_code': status}
else:
log_info = f'{user} ({hash_auth_context}) {remote} "{method} {path}" with parameters {json.dumps(query)} ' \
f'and body {json.dumps(body)} done in {time:.3f}s: {status}'
json_info = {'user': user,
'hash_auth_context': hash_auth_context,
'ip': remote,
'http_method': method,
'uri': f'{method} {path}',
'parameters': query,
'body': body,
'time': f'{time:.3f}s',
'status_code': status}

self.logger.info(log_info, extra={'log_type': 'log'})
self.logger.info(json_info, extra={'log_type': 'json'})

def log(self, request, response, time):
self.check_stream()
Expand All @@ -83,6 +94,7 @@ def log(self, request, response, time):
body['password'] = '****'
if 'key' in body and '/agents' in request.path:
body['key'] = '****'

# With permanent redirect, not found responses or any response with no token information,
# decode the JWT token to get the username
user = request.get('user', '')
Expand All @@ -92,15 +104,17 @@ def log(self, request, response, time):
except (KeyError, IndexError, binascii.Error):
user = UNKNOWN_USER_STRING

self.custom_logging(user,
request.remote,
request.method,
request.path,
query,
body,
time,
response.status
)
# Get or create authorization context hash
hash_auth_context = ''
# Get hash from token information
if 'token_info' in request:
hash_auth_context = request['token_info'].get('hash_auth_context', '')
# Create hash if run_as login
if not hash_auth_context and request.path == RUN_AS_LOGIN_ENDPOINT:
hash_auth_context = hashlib.blake2b(json.dumps(body).encode(), digest_size=16).hexdigest()

self.custom_logging(user, request.remote, request.method, request.path, query, body, time, response.status,
hash_auth_context=hash_auth_context)


class APILogger(WazuhLogger):
Expand Down Expand Up @@ -143,6 +157,7 @@ class WazuhJsonFormatter(jsonlogger.JsonFormatter):
"""
Define the custom JSON log formatter used by wlogging.
"""

def add_fields(self, log_record, record, message_dict):
"""Implement custom logic for adding fields in a log entry.
Expand All @@ -160,21 +175,21 @@ def add_fields(self, log_record, record, message_dict):
record.message = {
'type': 'request',
'payload': message_dict
}
}
else:
# Traceback handling
traceback = message_dict.get('exc_info')
if traceback is not None:
record.message = {
'type': 'error',
'payload': f'{record.message}. {traceback}'
}
}
else:
# Plain text messages
record.message = {
'type': 'informative',
'payload': record.message
}
}
log_record['timestamp'] = self.formatTime(record, self.datefmt)
log_record['levelname'] = record.levelname
log_record['data'] = record.message
33 changes: 18 additions & 15 deletions api/api/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# This program is a free software; you can redistribute it and/or modify it under the terms of GPLv2

import asyncio
import hashlib
import json
import logging
import os
from concurrent.futures import ThreadPoolExecutor
Expand Down Expand Up @@ -135,17 +137,17 @@ def get_security_conf():
return conf.security_conf


def generate_token(user_id=None, data=None, run_as=False):
"""Generate an encoded jwt token. This method should be called once a user is properly logged on.
def generate_token(user_id=None, data=None, auth_context=None):
"""Generate an encoded JWT token. This method should be called once a user is properly logged on.
Parameters
----------
user_id : str
Unique username
Unique username.
data : dict
Roles permissions for the user
run_as : bool
Indicate if the user has logged in with run_as or not
Roles permissions for the user.
auth_context : dict
Authorization context used in the run as login request.
Returns
-------
Expand All @@ -161,15 +163,16 @@ def generate_token(user_id=None, data=None, run_as=False):
timestamp = int(core_utils.get_utc_now().timestamp())

payload = {
"iss": JWT_ISSUER,
"aud": "Wazuh API REST",
"nbf": timestamp,
"exp": timestamp + result['auth_token_exp_timeout'],
"sub": str(user_id),
"run_as": run_as,
"rbac_roles": data['roles'],
"rbac_mode": result['rbac_mode']
}
"iss": JWT_ISSUER,
"aud": "Wazuh API REST",
"nbf": timestamp,
"exp": timestamp + result['auth_token_exp_timeout'],
"sub": str(user_id),
"run_as": auth_context is not None,
"rbac_roles": data['roles'],
"rbac_mode": result['rbac_mode']
} | ({"hash_auth_context": hashlib.blake2b(json.dumps(auth_context).encode(), digest_size=16).hexdigest()}
if auth_context is not None else {})

return jwt.encode(payload, generate_keypair()[0], algorithm=JWT_ALGORITHM)

Expand Down
3 changes: 1 addition & 2 deletions api/api/controllers/cluster_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from connexion.lifecycle import ConnexionResponse

import wazuh.cluster as cluster
import wazuh.core.cluster.cluster as core_cluster
import wazuh.core.common as common
import wazuh.manager as manager
import wazuh.stats as stats
Expand Down Expand Up @@ -144,7 +143,7 @@ async def get_nodes_ruleset_sync_status(request, pretty=False, wait_for_complete
"""
nodes = raise_if_exc(await get_system_nodes())

master_dapi = DistributedAPI(f=core_cluster.get_node_ruleset_integrity,
master_dapi = DistributedAPI(f=cluster.get_node_ruleset_integrity,
request_type='local_master',
is_async=True,
wait_for_complete=wait_for_complete,
Expand Down
1 change: 0 additions & 1 deletion api/api/controllers/mitre_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

logger = logging.getLogger('wazuh-api')


async def get_metadata(request, pretty=False, wait_for_complete=False):
"""Return the metadata of the MITRE's database
Expand Down
Loading

0 comments on commit 74b748f

Please sign in to comment.