refactor: standardize audit logging for ISO27001 compliance
This commit is contained in:
@@ -6,6 +6,8 @@ from gatehouse_app.utils.response import api_response
|
|||||||
from gatehouse_app.utils.decorators import login_required, require_admin
|
from gatehouse_app.utils.decorators import login_required, require_admin
|
||||||
from gatehouse_app.extensions import db
|
from gatehouse_app.extensions import db
|
||||||
from gatehouse_app.api.v1.organizations._helpers import _get_system_ca_dict
|
from gatehouse_app.api.v1.organizations._helpers import _get_system_ca_dict
|
||||||
|
from gatehouse_app.utils.constants import AuditAction
|
||||||
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
|
|
||||||
|
|
||||||
@api_v1_bp.route("/organizations/<org_id>/cas", methods=["GET"])
|
@api_v1_bp.route("/organizations/<org_id>/cas", methods=["GET"])
|
||||||
@@ -182,13 +184,12 @@ def delete_org_ca(org_id, ca_id):
|
|||||||
ca.is_active = False
|
ca.is_active = False
|
||||||
ca.delete(soft=True)
|
ca.delete(soft=True)
|
||||||
|
|
||||||
AuditLog.log(
|
AuditService.log_action(
|
||||||
action=AuditAction.CA_DELETED,
|
action=AuditAction.CA_DELETED,
|
||||||
user_id=g.current_user.id,
|
user_id=g.current_user.id,
|
||||||
|
organization_id=org_id,
|
||||||
resource_type="CA",
|
resource_type="CA",
|
||||||
resource_id=ca_id,
|
resource_id=ca_id,
|
||||||
organization_id=org_id,
|
|
||||||
ip_address=request.remote_addr,
|
|
||||||
description=f"CA '{ca_name}' ({ca_type}) deleted",
|
description=f"CA '{ca_name}' ({ca_type}) deleted",
|
||||||
)
|
)
|
||||||
return api_response(data={"ca_id": ca_id}, message="CA deleted successfully")
|
return api_response(data={"ca_id": ca_id}, message="CA deleted successfully")
|
||||||
@@ -206,8 +207,6 @@ def rotate_org_ca(org_id, ca_id):
|
|||||||
from gatehouse_app.models.organization.organization import Organization
|
from gatehouse_app.models.organization.organization import Organization
|
||||||
from gatehouse_app.utils.crypto import compute_ssh_fingerprint
|
from gatehouse_app.utils.crypto import compute_ssh_fingerprint
|
||||||
from gatehouse_app.utils.ca_key_encryption import encrypt_ca_key
|
from gatehouse_app.utils.ca_key_encryption import encrypt_ca_key
|
||||||
from gatehouse_app.utils.constants import AuditAction
|
|
||||||
from gatehouse_app.models import AuditLog
|
|
||||||
from sshkey_tools.keys import Ed25519PrivateKey, RsaPrivateKey, EcdsaPrivateKey
|
from sshkey_tools.keys import Ed25519PrivateKey, RsaPrivateKey, EcdsaPrivateKey
|
||||||
|
|
||||||
org = Organization.query.filter_by(id=org_id, deleted_at=None).first()
|
org = Organization.query.filter_by(id=org_id, deleted_at=None).first()
|
||||||
@@ -244,14 +243,13 @@ def rotate_org_ca(org_id, ca_id):
|
|||||||
ca.key_type = KeyType(new_key_type)
|
ca.key_type = KeyType(new_key_type)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
AuditLog.log(
|
AuditService.log_action(
|
||||||
action=AuditAction.CA_KEY_ROTATED,
|
action=AuditAction.CA_KEY_ROTATED,
|
||||||
user_id=g.current_user.id,
|
user_id=g.current_user.id,
|
||||||
|
organization_id=org_id,
|
||||||
resource_type="CA",
|
resource_type="CA",
|
||||||
resource_id=ca_id,
|
resource_id=ca_id,
|
||||||
organization_id=org_id,
|
description=f"CA '{ca.name}' key rotated. Old fingerprint: {old_fingerprint}, New fingerprint: {new_fingerprint}. Reason: {reason}",
|
||||||
ip_address=request.remote_addr,
|
|
||||||
description=(f"CA '{ca.name}' key rotated. Old fingerprint: {old_fingerprint}, New fingerprint: {new_fingerprint}. Reason: {reason}"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return api_response(data={"ca": ca.to_dict(), "old_fingerprint": old_fingerprint}, message="CA key rotated successfully. Update TrustedUserCAKeys / known_hosts on your servers.")
|
return api_response(data={"ca": ca.to_dict(), "old_fingerprint": old_fingerprint}, message="CA key rotated successfully. Update TrustedUserCAKeys / known_hosts on your servers.")
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ from gatehouse_app.utils.response import api_response
|
|||||||
from gatehouse_app.utils.decorators import login_required, require_admin, full_access_required
|
from gatehouse_app.utils.decorators import login_required, require_admin, full_access_required
|
||||||
from gatehouse_app.services.mfa_policy_service import MfaPolicyService
|
from gatehouse_app.services.mfa_policy_service import MfaPolicyService
|
||||||
from gatehouse_app.services.organization_service import OrganizationService
|
from gatehouse_app.services.organization_service import OrganizationService
|
||||||
from gatehouse_app.services.audit_service import AuditService
|
from gatehouse_app.utils.constants import MfaPolicyMode, MfaRequirementOverride, MfaComplianceStatus
|
||||||
from gatehouse_app.utils.constants import MfaPolicyMode, MfaRequirementOverride, MfaComplianceStatus, AuditAction
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateOrgPolicySchema(Schema):
|
class UpdateOrgPolicySchema(Schema):
|
||||||
@@ -291,16 +290,6 @@ def update_user_security_policy(org_id, user_id):
|
|||||||
updated_by_user_id=g.current_user.id,
|
updated_by_user_id=g.current_user.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Log the override change with details
|
|
||||||
AuditService.log_action(
|
|
||||||
action=AuditAction.USER_SECURITY_POLICY_OVERRIDE_UPDATE,
|
|
||||||
user_id=g.current_user.id,
|
|
||||||
organization_id=org_id,
|
|
||||||
resource_type="user",
|
|
||||||
resource_id=user_id,
|
|
||||||
description=f"User security policy override changed to {data['mfa_override_mode']} for user {user_id}",
|
|
||||||
)
|
|
||||||
|
|
||||||
return api_response(
|
return api_response(
|
||||||
data={
|
data={
|
||||||
"user_security_policy": {
|
"user_security_policy": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
from flask import request, g
|
from flask import request, g
|
||||||
from gatehouse_app.api.v1.ssh._helpers import ssh_bp
|
from gatehouse_app.api.v1.ssh._helpers import ssh_bp
|
||||||
from gatehouse_app.utils.constants import AuditAction, OrganizationRole
|
from gatehouse_app.utils.constants import AuditAction, OrganizationRole
|
||||||
from gatehouse_app.models import AuditLog
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
from gatehouse_app.utils.decorators import login_required
|
from gatehouse_app.utils.decorators import login_required
|
||||||
from gatehouse_app.utils.response import api_response
|
from gatehouse_app.utils.response import api_response
|
||||||
|
|
||||||
@@ -78,7 +78,14 @@ def add_ca_permission(ca_id):
|
|||||||
db.session.add(perm)
|
db.session.add(perm)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
AuditLog.log(action=AuditAction.CA_UPDATED, user_id=user.id, resource_type="CAPermission", resource_id=perm.id, ip_address=request.remote_addr, description=f"Granted '{permission}' on CA '{ca.name}' to user {target_user.email}")
|
AuditService.log_action(
|
||||||
|
action=AuditAction.CA_UPDATED,
|
||||||
|
user_id=user.id,
|
||||||
|
organization_id=ca.organization_id,
|
||||||
|
resource_type="CAPermission",
|
||||||
|
resource_id=perm.id,
|
||||||
|
description=f"Granted '{permission}' on CA '{ca.name}' to user {target_user.email}",
|
||||||
|
)
|
||||||
|
|
||||||
d = perm.to_dict()
|
d = perm.to_dict()
|
||||||
d["user_email"] = target_user.email
|
d["user_email"] = target_user.email
|
||||||
@@ -102,10 +109,21 @@ def remove_ca_permission(ca_id, target_user_id):
|
|||||||
if not membership or membership.role not in (OrganizationRole.ADMIN, OrganizationRole.OWNER):
|
if not membership or membership.role not in (OrganizationRole.ADMIN, OrganizationRole.OWNER):
|
||||||
return api_response(success=False, message="Admin access required", status=403, error_type="FORBIDDEN")
|
return api_response(success=False, message="Admin access required", status=403, error_type="FORBIDDEN")
|
||||||
|
|
||||||
|
target_user = User.query.filter_by(id=target_user_id, deleted_at=None).first()
|
||||||
|
if not target_user:
|
||||||
|
return api_response(success=False, message="User not found", status=404, error_type="NOT_FOUND")
|
||||||
|
|
||||||
perm = CAPermission.query.filter_by(ca_id=ca_id, user_id=target_user_id, deleted_at=None).first()
|
perm = CAPermission.query.filter_by(ca_id=ca_id, user_id=target_user_id, deleted_at=None).first()
|
||||||
if not perm:
|
if not perm:
|
||||||
return api_response(success=False, message="Permission not found", status=404, error_type="NOT_FOUND")
|
return api_response(success=False, message="Permission not found", status=404, error_type="NOT_FOUND")
|
||||||
|
|
||||||
perm.delete(soft=True)
|
perm.delete(soft=True)
|
||||||
AuditLog.log(action=AuditAction.CA_UPDATED, user_id=user.id, resource_type="CAPermission", resource_id=perm.id, ip_address=request.remote_addr, description=f"Revoked permission on CA '{ca.name}' from user {target_user_id}")
|
AuditService.log_action(
|
||||||
|
action=AuditAction.CA_UPDATED,
|
||||||
|
user_id=user.id,
|
||||||
|
organization_id=ca.organization_id,
|
||||||
|
resource_type="CAPermission",
|
||||||
|
resource_id=perm.id,
|
||||||
|
description=f"Revoked permission on CA '{ca.name}' from user {target_user.email}",
|
||||||
|
)
|
||||||
return api_response(data={}, message="Permission revoked")
|
return api_response(data={}, message="Permission revoked")
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from gatehouse_app.api.v1.ssh._helpers import (
|
|||||||
from gatehouse_app.services.ssh_ca_signing_service import SSHCertificateSigningRequest
|
from gatehouse_app.services.ssh_ca_signing_service import SSHCertificateSigningRequest
|
||||||
from gatehouse_app.exceptions import SSHKeyNotFoundError, SSHCertificateError
|
from gatehouse_app.exceptions import SSHKeyNotFoundError, SSHCertificateError
|
||||||
from gatehouse_app.utils.constants import AuditAction, OrganizationRole
|
from gatehouse_app.utils.constants import AuditAction, OrganizationRole
|
||||||
from gatehouse_app.models import AuditLog
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
from gatehouse_app.models.ssh_ca.certificate_audit_log import CertificateAuditLog
|
from gatehouse_app.models.ssh_ca.certificate_audit_log import CertificateAuditLog
|
||||||
from gatehouse_app.utils.decorators import login_required
|
from gatehouse_app.utils.decorators import login_required
|
||||||
from gatehouse_app.utils.response import api_response
|
from gatehouse_app.utils.response import api_response
|
||||||
@@ -68,10 +68,11 @@ def sign_certificate():
|
|||||||
expiry_hours = data.get('expiry_hours')
|
expiry_hours = data.get('expiry_hours')
|
||||||
requested_org_id = data.get('organization_id')
|
requested_org_id = data.get('organization_id')
|
||||||
|
|
||||||
AuditLog.log(
|
AuditService.log_action(
|
||||||
action=AuditAction.SSH_CERT_REQUESTED,
|
action=AuditAction.SSH_CERT_REQUESTED,
|
||||||
user_id=user_id, resource_type='SSHCertificate', ip_address=request.remote_addr,
|
user_id=user_id,
|
||||||
description=(f'{user.email} requested a certificate' + (f' for principals: {", ".join(requested_principals)}' if requested_principals else '')),
|
resource_type="SSHCertificate",
|
||||||
|
description=f"{user.email} requested a certificate" + (f" for principals: {', '.join(requested_principals)}" if requested_principals else ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validate organization_id if provided
|
# Validate organization_id if provided
|
||||||
@@ -209,10 +210,24 @@ def sign_certificate():
|
|||||||
ca_private_key_pem = decrypt_ca_key(db_ca.private_key)
|
ca_private_key_pem = decrypt_ca_key(db_ca.private_key)
|
||||||
response = ssh_ca_service.sign_certificate(signing_request, ca_private_key=ca_private_key_pem, ca_obj=db_ca)
|
response = ssh_ca_service.sign_certificate(signing_request, ca_private_key=ca_private_key_pem, ca_obj=db_ca)
|
||||||
except SSHCertificateError as e:
|
except SSHCertificateError as e:
|
||||||
AuditLog.log(action=AuditAction.SSH_CERT_FAILED, user_id=user_id, resource_type='SSHCertificate', ip_address=request.remote_addr, success=False, error_message=str(e))
|
AuditService.log_action(
|
||||||
|
action=AuditAction.SSH_CERT_FAILED,
|
||||||
|
user_id=user_id,
|
||||||
|
resource_type="SSHCertificate",
|
||||||
|
description=f"Certificate signing failed",
|
||||||
|
success=False,
|
||||||
|
error_message=str(e),
|
||||||
|
)
|
||||||
return api_response(success=False, message=str(e), status=400, error_type="SIGNING_FAILED")
|
return api_response(success=False, message=str(e), status=400, error_type="SIGNING_FAILED")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
AuditLog.log(action=AuditAction.SSH_CERT_FAILED, user_id=user_id, resource_type='SSHCertificate', ip_address=request.remote_addr, success=False, error_message=str(e))
|
AuditService.log_action(
|
||||||
|
action=AuditAction.SSH_CERT_FAILED,
|
||||||
|
user_id=user_id,
|
||||||
|
resource_type="SSHCertificate",
|
||||||
|
description=f"Certificate signing failed",
|
||||||
|
success=False,
|
||||||
|
error_message=str(e),
|
||||||
|
)
|
||||||
return api_response(success=False, message="Certificate signing failed", status=500, error_type="SERVER_ERROR")
|
return api_response(success=False, message="Certificate signing failed", status=500, error_type="SERVER_ERROR")
|
||||||
|
|
||||||
cert_record = _persist_certificate(
|
cert_record = _persist_certificate(
|
||||||
@@ -221,12 +236,14 @@ def sign_certificate():
|
|||||||
cert_type_str=cert_type, cert_identity=cert_identity,
|
cert_type_str=cert_type, cert_identity=cert_identity,
|
||||||
)
|
)
|
||||||
|
|
||||||
AuditLog.log(
|
AuditService.log_action(
|
||||||
action=AuditAction.SSH_CERT_ISSUED, user_id=user_id,
|
action=AuditAction.SSH_CERT_ISSUED,
|
||||||
resource_type='SSHCertificate', resource_id=cert_record.id if cert_record else key_id,
|
user_id=user_id,
|
||||||
ip_address=request.remote_addr,
|
organization_id=str(target_org.id),
|
||||||
description=f'Certificate serial={response.serial} issued for {user.email}; principals: {", ".join(principals)}',
|
resource_type="SSHCertificate",
|
||||||
extra_data={'serial': response.serial, 'key_id': cert_identity, 'principals': principals, 'ca_id': str(db_ca.id), 'ssh_key_id': str(key_id), 'organization_id': str(target_org.id), 'organization_name': target_org.name},
|
resource_id=cert_record.id if cert_record else key_id,
|
||||||
|
metadata={"serial": response.serial, "key_id": cert_identity, "principals": principals, "ca_id": str(db_ca.id), "ssh_key_id": str(key_id)},
|
||||||
|
description=f"Certificate serial={response.serial} issued for {user.email}; principals: {', '.join(principals)}",
|
||||||
)
|
)
|
||||||
|
|
||||||
if cert_record:
|
if cert_record:
|
||||||
@@ -340,7 +357,15 @@ def sign_host_certificate():
|
|||||||
ca_private_key_pem = decrypt_ca_key(host_ca.private_key)
|
ca_private_key_pem = decrypt_ca_key(host_ca.private_key)
|
||||||
response = ssh_ca_service.sign_certificate(signing_request, ca_private_key=ca_private_key_pem, ca_obj=host_ca)
|
response = ssh_ca_service.sign_certificate(signing_request, ca_private_key=ca_private_key_pem, ca_obj=host_ca)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
AuditLog.log(action=AuditAction.SSH_CERT_FAILED, user_id=user_id, resource_type="SSHCertificate", ip_address=request.remote_addr, success=False, error_message=str(exc))
|
AuditService.log_action(
|
||||||
|
action=AuditAction.SSH_CERT_FAILED,
|
||||||
|
user_id=user_id,
|
||||||
|
organization_id=host_ca.organization_id,
|
||||||
|
resource_type="SSHCertificate",
|
||||||
|
description=f"Host certificate signing failed",
|
||||||
|
success=False,
|
||||||
|
error_message=str(exc),
|
||||||
|
)
|
||||||
return api_response(success=False, message=f"Host certificate signing failed: {exc}", status=500, error_type="SIGNING_FAILED")
|
return api_response(success=False, message=f"Host certificate signing failed: {exc}", status=500, error_type="SIGNING_FAILED")
|
||||||
|
|
||||||
cert_record = _persist_certificate(
|
cert_record = _persist_certificate(
|
||||||
@@ -349,12 +374,14 @@ def sign_host_certificate():
|
|||||||
cert_type_str="host", cert_identity=cert_identity,
|
cert_type_str="host", cert_identity=cert_identity,
|
||||||
)
|
)
|
||||||
|
|
||||||
AuditLog.log(
|
AuditService.log_action(
|
||||||
action=AuditAction.SSH_CERT_ISSUED, user_id=user_id,
|
action=AuditAction.SSH_CERT_ISSUED,
|
||||||
resource_type="SSHCertificate", resource_id=cert_record.id if cert_record else None,
|
user_id=user_id,
|
||||||
ip_address=request.remote_addr,
|
organization_id=host_ca.organization_id,
|
||||||
|
resource_type="SSHCertificate",
|
||||||
|
resource_id=cert_record.id if cert_record else None,
|
||||||
|
metadata={"serial": response.serial, "principals": principals, "ca_id": str(host_ca.id), "cert_type": "host"},
|
||||||
description=f"Host certificate serial={response.serial} issued for {primary_principal} by {user.email}",
|
description=f"Host certificate serial={response.serial} issued for {primary_principal} by {user.email}",
|
||||||
extra_data={"serial": response.serial, "principals": principals, "ca_id": str(host_ca.id), "cert_type": "host"},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
@@ -415,7 +442,13 @@ def revoke_certificate(cert_id):
|
|||||||
return api_response(success=False, message='Certificate is already revoked', status=409, error_type='ALREADY_REVOKED')
|
return api_response(success=False, message='Certificate is already revoked', status=409, error_type='ALREADY_REVOKED')
|
||||||
|
|
||||||
cert.revoke(reason=reason)
|
cert.revoke(reason=reason)
|
||||||
AuditLog.log(action=AuditAction.SSH_CERT_REVOKED, user_id=user_id, resource_type='SSHCertificate', resource_id=cert_id, ip_address=request.remote_addr, description=f'Revoked: {reason}')
|
AuditService.log_action(
|
||||||
|
action=AuditAction.SSH_CERT_REVOKED,
|
||||||
|
user_id=user_id,
|
||||||
|
resource_type="SSHCertificate",
|
||||||
|
resource_id=cert_id,
|
||||||
|
description=f"Certificate revoked: {reason}",
|
||||||
|
)
|
||||||
|
|
||||||
# Get organization from certificate's CA for audit logging
|
# Get organization from certificate's CA for audit logging
|
||||||
from gatehouse_app.models.ssh_ca.ca import CA
|
from gatehouse_app.models.ssh_ca.ca import CA
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from flask import request, g
|
|||||||
from gatehouse_app.api.v1.ssh._helpers import ssh_bp, ssh_key_service
|
from gatehouse_app.api.v1.ssh._helpers import ssh_bp, ssh_key_service
|
||||||
from gatehouse_app.exceptions import SSHKeyError, SSHKeyNotFoundError, ValidationError, SSHKeyAlreadyExistsError
|
from gatehouse_app.exceptions import SSHKeyError, SSHKeyNotFoundError, ValidationError, SSHKeyAlreadyExistsError
|
||||||
from gatehouse_app.utils.constants import AuditAction
|
from gatehouse_app.utils.constants import AuditAction
|
||||||
from gatehouse_app.models import AuditLog
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
from gatehouse_app.utils.decorators import login_required
|
from gatehouse_app.utils.decorators import login_required
|
||||||
from gatehouse_app.utils.response import api_response
|
from gatehouse_app.utils.response import api_response
|
||||||
|
|
||||||
@@ -34,7 +34,13 @@ def add_ssh_key():
|
|||||||
try:
|
try:
|
||||||
ssh_key, is_new = ssh_key_service.add_ssh_key(user_id=user_id, public_key=public_key, description=description)
|
ssh_key, is_new = ssh_key_service.add_ssh_key(user_id=user_id, public_key=public_key, description=description)
|
||||||
if is_new:
|
if is_new:
|
||||||
AuditLog.log(action=AuditAction.SSH_KEY_ADDED, user_id=user_id, resource_type='SSHKey', resource_id=ssh_key.id, ip_address=request.remote_addr)
|
AuditService.log_action(
|
||||||
|
action=AuditAction.SSH_KEY_ADDED,
|
||||||
|
user_id=user_id,
|
||||||
|
resource_type="SSHKey",
|
||||||
|
resource_id=ssh_key.id,
|
||||||
|
description=f"SSH key added",
|
||||||
|
)
|
||||||
return api_response(success=True, message='SSH key added', data=ssh_key.to_dict(), status=201)
|
return api_response(success=True, message='SSH key added', data=ssh_key.to_dict(), status=201)
|
||||||
else:
|
else:
|
||||||
return api_response(success=True, message='SSH key already exists', data=ssh_key.to_dict(), status=200)
|
return api_response(success=True, message='SSH key already exists', data=ssh_key.to_dict(), status=200)
|
||||||
@@ -68,7 +74,13 @@ def delete_ssh_key(key_id):
|
|||||||
if ssh_key.user_id != user_id:
|
if ssh_key.user_id != user_id:
|
||||||
return api_response(success=False, message='Forbidden', status=403, error_type='FORBIDDEN')
|
return api_response(success=False, message='Forbidden', status=403, error_type='FORBIDDEN')
|
||||||
ssh_key_service.delete_ssh_key(key_id)
|
ssh_key_service.delete_ssh_key(key_id)
|
||||||
AuditLog.log(action=AuditAction.SSH_KEY_DELETED, user_id=user_id, resource_type='SSHKey', resource_id=key_id, ip_address=request.remote_addr)
|
AuditService.log_action(
|
||||||
|
action=AuditAction.SSH_KEY_DELETED,
|
||||||
|
user_id=user_id,
|
||||||
|
resource_type="SSHKey",
|
||||||
|
resource_id=key_id,
|
||||||
|
description=f"SSH key deleted",
|
||||||
|
)
|
||||||
return api_response(success=True, message='SSH key deleted', data={'status': 'deleted'}, status=200)
|
return api_response(success=True, message='SSH key deleted', data={'status': 'deleted'}, status=200)
|
||||||
except SSHKeyNotFoundError:
|
except SSHKeyNotFoundError:
|
||||||
return api_response(success=False, message='SSH key not found', status=404, error_type='NOT_FOUND')
|
return api_response(success=False, message='SSH key not found', status=404, error_type='NOT_FOUND')
|
||||||
@@ -96,10 +108,25 @@ def verify_ssh_key(key_id):
|
|||||||
return api_response(success=False, message='signature is required', status=400, error_type='BAD_REQUEST')
|
return api_response(success=False, message='signature is required', status=400, error_type='BAD_REQUEST')
|
||||||
try:
|
try:
|
||||||
verified = ssh_key_service.verify_ssh_key_ownership(key_id, signature)
|
verified = ssh_key_service.verify_ssh_key_ownership(key_id, signature)
|
||||||
AuditLog.log(action=AuditAction.SSH_KEY_VERIFIED, user_id=user_id, resource_type='SSHKey', resource_id=key_id, ip_address=request.remote_addr, success=verified)
|
AuditService.log_action(
|
||||||
|
action=AuditAction.SSH_KEY_VERIFIED,
|
||||||
|
user_id=user_id,
|
||||||
|
resource_type="SSHKey",
|
||||||
|
resource_id=key_id,
|
||||||
|
description=f"SSH key verified",
|
||||||
|
success=verified,
|
||||||
|
)
|
||||||
return api_response(success=True, message='Verification complete', data={'verified': verified}, status=200)
|
return api_response(success=True, message='Verification complete', data={'verified': verified}, status=200)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
AuditLog.log(action=AuditAction.SSH_KEY_VALIDATION_FAILED, user_id=user_id, resource_type='SSHKey', resource_id=key_id, ip_address=request.remote_addr, success=False, error_message=str(e))
|
AuditService.log_action(
|
||||||
|
action=AuditAction.SSH_KEY_VALIDATION_FAILED,
|
||||||
|
user_id=user_id,
|
||||||
|
resource_type="SSHKey",
|
||||||
|
resource_id=key_id,
|
||||||
|
description=f"SSH key validation failed",
|
||||||
|
success=False,
|
||||||
|
error_message=str(e),
|
||||||
|
)
|
||||||
return api_response(success=False, message=str(e), status=400, error_type='VERIFICATION_FAILED')
|
return api_response(success=False, message=str(e), status=400, error_type='VERIFICATION_FAILED')
|
||||||
else:
|
else:
|
||||||
challenge = ssh_key_service.generate_verification_challenge(key_id)
|
challenge = ssh_key_service.generate_verification_challenge(key_id)
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ def admin_restore_user(user_id):
|
|||||||
_db.session.commit()
|
_db.session.commit()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action=AuditAction.USER_UNSUSPEND, # closest existing action
|
action=AuditAction.USER_RESTORE,
|
||||||
user_id=caller.id,
|
user_id=caller.id,
|
||||||
organization_id=_get_admin_access(caller, target).organization_id,
|
organization_id=_get_admin_access(caller, target).organization_id,
|
||||||
resource_type="user", resource_id=str(target.id),
|
resource_type="user", resource_id=str(target.id),
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from gatehouse_app.models import (
|
|||||||
)
|
)
|
||||||
from gatehouse_app.models.organization import Organization
|
from gatehouse_app.models.organization import Organization
|
||||||
from gatehouse_app.models.organization.organization_member import OrganizationMember
|
from gatehouse_app.models.organization.organization_member import OrganizationMember
|
||||||
from gatehouse_app.utils.constants import OrganizationRole
|
from gatehouse_app.utils.constants import OrganizationRole, AuditAction
|
||||||
from gatehouse_app.exceptions import (
|
from gatehouse_app.exceptions import (
|
||||||
ValidationError as AppValidationError,
|
ValidationError as AppValidationError,
|
||||||
ZeroTierAPIError,
|
ZeroTierAPIError,
|
||||||
@@ -1154,7 +1154,7 @@ def set_zerotier_config(org_id):
|
|||||||
|
|
||||||
from gatehouse_app.services.audit_service import AuditService
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="org.zerotier_config.updated",
|
action=AuditAction.ZT_CONFIG_UPDATED,
|
||||||
user_id=g.current_user.id,
|
user_id=g.current_user.id,
|
||||||
organization_id=org_id,
|
organization_id=org_id,
|
||||||
resource_type="organization",
|
resource_type="organization",
|
||||||
@@ -1206,7 +1206,7 @@ def delete_zerotier_config(org_id):
|
|||||||
|
|
||||||
from gatehouse_app.services.audit_service import AuditService
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="org.zerotier_config.deleted",
|
action=AuditAction.ZT_CONFIG_DELETED,
|
||||||
user_id=g.current_user.id,
|
user_id=g.current_user.id,
|
||||||
organization_id=org_id,
|
organization_id=org_id,
|
||||||
resource_type="organization",
|
resource_type="organization",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""Audit log model."""
|
"""Audit log model."""
|
||||||
from gatehouse_app.extensions import db
|
from gatehouse_app.extensions import db
|
||||||
from gatehouse_app.models.base import BaseModel
|
from gatehouse_app.models.base import BaseModel
|
||||||
from gatehouse_app.utils.constants import AuditAction
|
|
||||||
|
|
||||||
|
|
||||||
class AuditLog(BaseModel):
|
class AuditLog(BaseModel):
|
||||||
@@ -42,19 +41,3 @@ class AuditLog(BaseModel):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""String representation of AuditLog."""
|
"""String representation of AuditLog."""
|
||||||
return f"<AuditLog action={self.action} user_id={self.user_id}>"
|
return f"<AuditLog action={self.action} user_id={self.user_id}>"
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def log(cls, action, user_id=None, **kwargs) -> "AuditLog":
|
|
||||||
"""Create an audit log entry.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
action: AuditAction enum value
|
|
||||||
user_id: ID of the user performing the action
|
|
||||||
**kwargs: Additional audit log fields
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
AuditLog instance
|
|
||||||
"""
|
|
||||||
log_entry = cls(action=action, user_id=user_id, **kwargs)
|
|
||||||
log_entry.save()
|
|
||||||
return log_entry
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from gatehouse_app.extensions import db
|
|||||||
from gatehouse_app.models import Device
|
from gatehouse_app.models import Device
|
||||||
from gatehouse_app.models.user import User
|
from gatehouse_app.models.user import User
|
||||||
from gatehouse_app.services.audit_service import AuditService
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
|
from gatehouse_app.utils.constants import AuditAction
|
||||||
from gatehouse_app.exceptions import (
|
from gatehouse_app.exceptions import (
|
||||||
DeviceNotFoundError,
|
DeviceNotFoundError,
|
||||||
DeviceAlreadyExistsError,
|
DeviceAlreadyExistsError,
|
||||||
@@ -74,7 +75,7 @@ def register_device(
|
|||||||
device.save()
|
device.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="device.registered",
|
action=AuditAction.DEVICE_REGISTERED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=organization_id,
|
organization_id=organization_id,
|
||||||
resource_type="device",
|
resource_type="device",
|
||||||
@@ -142,7 +143,7 @@ def update_device(
|
|||||||
device.update(**kwargs)
|
device.update(**kwargs)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="device.updated",
|
action=AuditAction.DEVICE_UPDATED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=device.organization_id,
|
organization_id=device.organization_id,
|
||||||
resource_type="device",
|
resource_type="device",
|
||||||
@@ -175,7 +176,7 @@ def remove_device(device_id: str, user_id: str) -> None:
|
|||||||
device.delete(soft=True)
|
device.delete(soft=True)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="device.removed",
|
action=AuditAction.DEVICE_REMOVED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=device.organization_id,
|
organization_id=device.organization_id,
|
||||||
resource_type="device",
|
resource_type="device",
|
||||||
|
|||||||
@@ -871,7 +871,7 @@ class MfaPolicyService:
|
|||||||
org_ids = [org.organization_id for org in suspended_orgs]
|
org_ids = [org.organization_id for org in suspended_orgs]
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action=AuditAction.USER_LOGIN,
|
action=AuditAction.LOGIN_BLOCKED_COMPLIANCE,
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
organization_id=org_ids[0] if org_ids else None,
|
organization_id=org_ids[0] if org_ids else None,
|
||||||
description=f"Login attempt while compliance suspended. Suspended orgs: {org_ids}",
|
description=f"Login attempt while compliance suspended. Suspended orgs: {org_ids}",
|
||||||
@@ -898,7 +898,7 @@ class MfaPolicyService:
|
|||||||
user_agent: Client user agent
|
user_agent: Client user agent
|
||||||
"""
|
"""
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action=AuditAction.USER_LOGIN, # Reusing USER_LOGIN for audit
|
action=AuditAction.MFA_COMPLIANCE_BYPASS_ATTEMPT,
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
resource_type="endpoint",
|
resource_type="endpoint",
|
||||||
resource_id=endpoint,
|
resource_id=endpoint,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from gatehouse_app.utils.constants import (
|
|||||||
ApprovalState,
|
ApprovalState,
|
||||||
ActivationEndReason,
|
ActivationEndReason,
|
||||||
KillSwitchScope,
|
KillSwitchScope,
|
||||||
|
AuditAction,
|
||||||
)
|
)
|
||||||
from gatehouse_app.exceptions import (
|
from gatehouse_app.exceptions import (
|
||||||
ApprovalNotFoundError,
|
ApprovalNotFoundError,
|
||||||
@@ -89,7 +90,7 @@ def request_access(
|
|||||||
_ensure_zerotier_member(device.node_id, portal_network_id, authorized=False)
|
_ensure_zerotier_member(device.node_id, portal_network_id, authorized=False)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.approval.reopened",
|
action=AuditAction.ZT_APPROVAL_REOPENED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=organization_id,
|
organization_id=organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -122,7 +123,7 @@ def request_access(
|
|||||||
_ensure_zerotier_member(device.node_id, portal_network_id, authorized=False)
|
_ensure_zerotier_member(device.node_id, portal_network_id, authorized=False)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.approval.requested",
|
action=AuditAction.ZT_APPROVAL_REQUESTED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=organization_id,
|
organization_id=organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -206,7 +207,7 @@ def assign_access(
|
|||||||
_ensure_zerotier_member(device.node_id, portal_network_id, authorized=False)
|
_ensure_zerotier_member(device.node_id, portal_network_id, authorized=False)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.approval.granted",
|
action=AuditAction.ZT_APPROVAL_GRANTED,
|
||||||
user_id=granted_by_user_id,
|
user_id=granted_by_user_id,
|
||||||
organization_id=organization_id,
|
organization_id=organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -238,7 +239,7 @@ def approve_request(
|
|||||||
request.save()
|
request.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.approval.granted",
|
action=AuditAction.ZT_APPROVAL_GRANTED,
|
||||||
user_id=approver_user_id,
|
user_id=approver_user_id,
|
||||||
organization_id=request.organization_id,
|
organization_id=request.organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -266,7 +267,7 @@ def reject_request(
|
|||||||
request.save()
|
request.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.approval.rejected",
|
action=AuditAction.ZT_APPROVAL_REJECTED,
|
||||||
user_id=rejecter_user_id,
|
user_id=rejecter_user_id,
|
||||||
organization_id=request.organization_id,
|
organization_id=request.organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -307,7 +308,7 @@ def revoke_access(
|
|||||||
logger.warning(f"[revoke_access] Could not deauthorize {device.node_id}: {exc}")
|
logger.warning(f"[revoke_access] Could not deauthorize {device.node_id}: {exc}")
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.approval.revoked",
|
action=AuditAction.ZT_APPROVAL_REVOKED,
|
||||||
user_id=revoker_user_id,
|
user_id=revoker_user_id,
|
||||||
organization_id=request.organization_id,
|
organization_id=request.organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -417,7 +418,7 @@ def activate_request(
|
|||||||
_authorize_in_zerotier(device.node_id, network.zerotier_network_id, request)
|
_authorize_in_zerotier(device.node_id, network.zerotier_network_id, request)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.membership.activated",
|
action=AuditAction.ZT_MEMBERSHIP_ACTIVATED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=request.organization_id,
|
organization_id=request.organization_id,
|
||||||
resource_type="activation_session",
|
resource_type="activation_session",
|
||||||
@@ -485,7 +486,7 @@ def deactivate_request(
|
|||||||
request.save()
|
request.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.membership.deactivated",
|
action=AuditAction.ZT_MEMBERSHIP_DEACTIVATED,
|
||||||
user_id=deactivated_by_user_id,
|
user_id=deactivated_by_user_id,
|
||||||
organization_id=request.organization_id,
|
organization_id=request.organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -548,7 +549,7 @@ def kill_switch(
|
|||||||
|
|
||||||
# Log audit
|
# Log audit
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.kill_switch.activated",
|
action=AuditAction.ZT_KILL_SWITCH_ACTIVATED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=org_id,
|
organization_id=org_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -637,7 +638,7 @@ def _authorize_in_zerotier(
|
|||||||
zt_membership.save()
|
zt_membership.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.member.authorized",
|
action=AuditAction.ZT_MEMBER_AUTHORIZED,
|
||||||
user_id=request.user_id,
|
user_id=request.user_id,
|
||||||
organization_id=request.organization_id,
|
organization_id=request.organization_id,
|
||||||
resource_type="zerotier_membership",
|
resource_type="zerotier_membership",
|
||||||
@@ -677,7 +678,7 @@ def _deauthorize_in_zerotier(node_id: str, zerotier_network_id: str,
|
|||||||
zt_membership.save()
|
zt_membership.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.member.deauthorized",
|
action=AuditAction.ZT_MEMBER_DEAUTHORIZED,
|
||||||
user_id=None,
|
user_id=None,
|
||||||
organization_id=zt_membership.organization_id,
|
organization_id=zt_membership.organization_id,
|
||||||
resource_type="zerotier_membership",
|
resource_type="zerotier_membership",
|
||||||
@@ -785,7 +786,7 @@ def join_network_for_device(
|
|||||||
_ensure_zerotier_member(device.node_id, portal_network_id, authorized=False)
|
_ensure_zerotier_member(device.node_id, portal_network_id, authorized=False)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.membership.created",
|
action=AuditAction.ZT_MEMBERSHIP_CREATED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=organization_id,
|
organization_id=organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
@@ -832,7 +833,7 @@ def revoke_request_soft(
|
|||||||
request.save()
|
request.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.request.revoked",
|
action=AuditAction.ZT_REQUEST_REVOKED,
|
||||||
user_id=revoker_user_id,
|
user_id=revoker_user_id,
|
||||||
organization_id=request.organization_id,
|
organization_id=request.organization_id,
|
||||||
resource_type="network_access_request",
|
resource_type="network_access_request",
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class NotificationService:
|
|||||||
f"({days_until_deadline} days remaining)"
|
f"({days_until_deadline} days remaining)"
|
||||||
)
|
)
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action=AuditAction.MFA_POLICY_USER_COMPLIANT,
|
action=AuditAction.MFA_NOTIFICATION_SENT,
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
organization_id=compliance.organization_id,
|
organization_id=compliance.organization_id,
|
||||||
description=f"MFA deadline reminder sent. Days remaining: {days_until_deadline}",
|
description=f"MFA deadline reminder sent. Days remaining: {days_until_deadline}",
|
||||||
@@ -196,7 +196,7 @@ class NotificationService:
|
|||||||
)
|
)
|
||||||
logger.info(f"Sent MFA suspension notification to {user.email}")
|
logger.info(f"Sent MFA suspension notification to {user.email}")
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action=AuditAction.MFA_POLICY_USER_SUSPENDED,
|
action=AuditAction.MFA_SUSPENSION_NOTIFICATION_SENT,
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
organization_id=compliance.organization_id,
|
organization_id=compliance.organization_id,
|
||||||
description="MFA compliance suspension notification sent",
|
description="MFA compliance suspension notification sent",
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ def handle_login_callback(
|
|||||||
auth_method.save()
|
auth_method.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="user.register",
|
action=AuditAction.USER_REGISTER,
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
organization_id=state_record.organization_id,
|
organization_id=state_record.organization_id,
|
||||||
resource_type="user",
|
resource_type="user",
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ def handle_register_callback(
|
|||||||
state_record.mark_used()
|
state_record.mark_used()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="user.register",
|
action=AuditAction.USER_REGISTER,
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
organization_id=state_record.organization_id,
|
organization_id=state_record.organization_id,
|
||||||
resource_type="user",
|
resource_type="user",
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ class OrganizationService:
|
|||||||
resource_type="organization_member",
|
resource_type="organization_member",
|
||||||
resource_id=member.id,
|
resource_id=member.id,
|
||||||
metadata={"added_user_id": user_id, "role": role.value},
|
metadata={"added_user_id": user_id, "role": role.value},
|
||||||
description=f"Member added to organization with role: {role.value}",
|
description=f"Member {user_id} added to organization with role: {role.value}",
|
||||||
)
|
)
|
||||||
|
|
||||||
return member
|
return member
|
||||||
@@ -398,7 +398,7 @@ class OrganizationService:
|
|||||||
resource_type="organization_member",
|
resource_type="organization_member",
|
||||||
resource_id=member.id,
|
resource_id=member.id,
|
||||||
metadata={"removed_user_id": user_id},
|
metadata={"removed_user_id": user_id},
|
||||||
description="Member removed from organization",
|
description=f"Member {user_id} removed from organization",
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -438,7 +438,7 @@ class OrganizationService:
|
|||||||
"old_role": old_role.value,
|
"old_role": old_role.value,
|
||||||
"new_role": new_role.value,
|
"new_role": new_role.value,
|
||||||
},
|
},
|
||||||
description=f"Member role changed from {old_role.value} to {new_role.value}",
|
description=f"Member {user_id} role changed from {old_role.value} to {new_role.value}",
|
||||||
)
|
)
|
||||||
|
|
||||||
return member
|
return member
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from gatehouse_app.models.organization import Organization
|
|||||||
from gatehouse_app.models.user import User
|
from gatehouse_app.models.user import User
|
||||||
from gatehouse_app.services.audit_service import AuditService
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
from gatehouse_app.services import zerotier_api_service as zt
|
from gatehouse_app.services import zerotier_api_service as zt
|
||||||
from gatehouse_app.utils.constants import NetworkRequestMode, NetworkEnvironment
|
from gatehouse_app.utils.constants import NetworkRequestMode, NetworkEnvironment, AuditAction
|
||||||
from gatehouse_app.exceptions import (
|
from gatehouse_app.exceptions import (
|
||||||
NetworkNotFoundError,
|
NetworkNotFoundError,
|
||||||
InvalidNetworkIdError,
|
InvalidNetworkIdError,
|
||||||
@@ -110,7 +110,7 @@ def create_network(
|
|||||||
deleted.save()
|
deleted.save()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.network.restored",
|
action=AuditAction.ZT_NETWORK_RESTORED,
|
||||||
user_id=owner_user_id,
|
user_id=owner_user_id,
|
||||||
organization_id=organization_id,
|
organization_id=organization_id,
|
||||||
resource_type="portal_network",
|
resource_type="portal_network",
|
||||||
@@ -157,7 +157,7 @@ def create_network(
|
|||||||
)
|
)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.network.created",
|
action=AuditAction.ZT_NETWORK_CREATED,
|
||||||
user_id=owner_user_id,
|
user_id=owner_user_id,
|
||||||
organization_id=organization_id,
|
organization_id=organization_id,
|
||||||
resource_type="portal_network",
|
resource_type="portal_network",
|
||||||
@@ -246,7 +246,7 @@ def update_network(
|
|||||||
network.update(**kwargs)
|
network.update(**kwargs)
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.network.updated",
|
action=AuditAction.ZT_NETWORK_UPDATED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=network.organization_id,
|
organization_id=network.organization_id,
|
||||||
resource_type="portal_network",
|
resource_type="portal_network",
|
||||||
@@ -292,7 +292,7 @@ def delete_network(network_id: str, user_id: str) -> None:
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.network.deleted",
|
action=AuditAction.ZT_NETWORK_DELETED,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
organization_id=network.organization_id,
|
organization_id=network.organization_id,
|
||||||
resource_type="portal_network",
|
resource_type="portal_network",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from gatehouse_app.services import zerotier_api_service as zt
|
|||||||
from gatehouse_app.utils.constants import (
|
from gatehouse_app.utils.constants import (
|
||||||
ActivationEndReason,
|
ActivationEndReason,
|
||||||
ApprovalState,
|
ApprovalState,
|
||||||
|
AuditAction,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -452,7 +453,7 @@ def _expire_session(session: ActivationSession) -> None:
|
|||||||
|
|
||||||
from gatehouse_app.services.audit_service import AuditService
|
from gatehouse_app.services.audit_service import AuditService
|
||||||
AuditService.log_action(
|
AuditService.log_action(
|
||||||
action="zt.activation.expired",
|
action=AuditAction.ZT_ACTIVATION_EXPIRED,
|
||||||
user_id=session.user_id,
|
user_id=session.user_id,
|
||||||
organization_id=session.organization_id,
|
organization_id=session.organization_id,
|
||||||
resource_type="activation_session",
|
resource_type="activation_session",
|
||||||
|
|||||||
@@ -64,9 +64,16 @@ class AuditAction(str, Enum):
|
|||||||
USER_HARD_DELETE = "user.hard_delete"
|
USER_HARD_DELETE = "user.hard_delete"
|
||||||
USER_SUSPEND = "user.suspend"
|
USER_SUSPEND = "user.suspend"
|
||||||
USER_UNSUSPEND = "user.unsuspend"
|
USER_UNSUSPEND = "user.unsuspend"
|
||||||
|
USER_RESTORE = "user.restore"
|
||||||
PASSWORD_CHANGE = "user.password_change"
|
PASSWORD_CHANGE = "user.password_change"
|
||||||
PASSWORD_RESET = "user.password_reset"
|
PASSWORD_RESET = "user.password_reset"
|
||||||
|
|
||||||
|
# Login/security events
|
||||||
|
LOGIN_BLOCKED_COMPLIANCE = "login.blocked.compliance"
|
||||||
|
MFA_COMPLIANCE_BYPASS_ATTEMPT = "mfa.compliance.bypass_attempt"
|
||||||
|
MFA_NOTIFICATION_SENT = "mfa.notification.sent"
|
||||||
|
MFA_SUSPENSION_NOTIFICATION_SENT = "mfa.suspension_notification.sent"
|
||||||
|
|
||||||
# Organization actions
|
# Organization actions
|
||||||
ORG_CREATE = "org.create"
|
ORG_CREATE = "org.create"
|
||||||
ORG_UPDATE = "org.update"
|
ORG_UPDATE = "org.update"
|
||||||
@@ -155,6 +162,32 @@ class AuditAction(str, Enum):
|
|||||||
DEPARTMENT_MEMBER_ADDED = "department.member.added"
|
DEPARTMENT_MEMBER_ADDED = "department.member.added"
|
||||||
DEPARTMENT_MEMBER_REMOVED = "department.member.removed"
|
DEPARTMENT_MEMBER_REMOVED = "department.member.removed"
|
||||||
|
|
||||||
|
# ZeroTier network actions
|
||||||
|
ZT_APPROVAL_REOPENED = "zt.approval.reopened"
|
||||||
|
ZT_APPROVAL_REQUESTED = "zt.approval.requested"
|
||||||
|
ZT_APPROVAL_GRANTED = "zt.approval.granted"
|
||||||
|
ZT_APPROVAL_REJECTED = "zt.approval.rejected"
|
||||||
|
ZT_APPROVAL_REVOKED = "zt.approval.revoked"
|
||||||
|
ZT_MEMBERSHIP_ACTIVATED = "zt.membership.activated"
|
||||||
|
ZT_MEMBERSHIP_DEACTIVATED = "zt.membership.deactivated"
|
||||||
|
ZT_MEMBERSHIP_CREATED = "zt.membership.created"
|
||||||
|
ZT_MEMBER_AUTHORIZED = "zt.member.authorized"
|
||||||
|
ZT_MEMBER_DEAUTHORIZED = "zt.member.deauthorized"
|
||||||
|
ZT_REQUEST_REVOKED = "zt.request.revoked"
|
||||||
|
ZT_KILL_SWITCH_ACTIVATED = "zt.kill_switch.activated"
|
||||||
|
ZT_ACTIVATION_EXPIRED = "zt.activation.expired"
|
||||||
|
ZT_NETWORK_CREATED = "zt.network.created"
|
||||||
|
ZT_NETWORK_UPDATED = "zt.network.updated"
|
||||||
|
ZT_NETWORK_DELETED = "zt.network.deleted"
|
||||||
|
ZT_NETWORK_RESTORED = "zt.network.restored"
|
||||||
|
ZT_CONFIG_UPDATED = "org.zerotier_config.updated"
|
||||||
|
ZT_CONFIG_DELETED = "org.zerotier_config.deleted"
|
||||||
|
|
||||||
|
# Device actions
|
||||||
|
DEVICE_REGISTERED = "device.registered"
|
||||||
|
DEVICE_UPDATED = "device.updated"
|
||||||
|
DEVICE_REMOVED = "device.removed"
|
||||||
|
|
||||||
|
|
||||||
class OIDCGrantType(str, Enum):
|
class OIDCGrantType(str, Enum):
|
||||||
"""OIDC grant types."""
|
"""OIDC grant types."""
|
||||||
|
|||||||
Reference in New Issue
Block a user