/images/resources/tutorials/deploy/tutorials-logging.png

Logging client IP address to the audit database

On this page

Introduction

Logging originating client IP address to audit databases is quite a common requirement, in order to provide the most useful audit logs. The Curity Identity Server’s Scripting SDK provides an easy-to-use API to get the client IP address, via Request#getClientIpAddress()

This method will report the IP of the X-Forwarded-For (XFF) headers first entry.

Please note that storing IP addresses may have potential implications related to privacy and compliance with regulations such as the General Data Protection Regulation (GDPR).

Use Cases

In the context of logging to an audit database, storing the client IP address from the XFF header can have several benefits:

  • Accountability : By logging the client IP address, you can track which IP addresses are associated with specific actions or requests. This can help identify and attribute specific actions to individual clients or users. Also it helps in request tracing by tracking the path of the request as it traverses multiple proxy servers and/or load balancers. This information can be valuable for troubleshooting, performance analysis, and identifying potential bottlenecks.

  • Security and Intrusion Detection : The XFF header provides the original client IP address even when the request passes through intermediate proxies. By logging this information, you can analyze patterns of client requests and detect suspicious or malicious activity. For example, if a single IP address appears in the XFF header for multiple requests from different clients, it could indicate a proxy bypass attempt or an attack.

  • Compliance and auditing : Many compliance standards, such as the Payment Card Industry Data Security Standard (PCI DSS), require logging and monitoring of client IP addresses for certain types of transactions. By storing the XFF header information, you can ensure compliance with these requirements and have an audit trail for regulatory purposes

  • Forensic investigation : In the event of a security incident or breach, having the client IP address from the XFF header logged in an audit database can aid in forensic investigation. It enables you to trace the origin of the request and determine the source of the attack or unauthorized access.

It should be noted that XFF header can be spoofed or manipulated by attackers. Therefore, it's essential to implement appropriate security measures and validate the IP addresses to ensure the accuracy and integrity of the logged data.

Solution Overview

Let's look at the steps required in collecting the client IP address during an authentication workflow and storing it in a separate column in the audit database.

  1. Add an authentication action (script-transformation-procedure) in the authentication pipeline to store the client IP address into the context-attributes

    javascript
    123456
    function result(context) {
    var attributes = context.attributeMap;
    attributes.clientIpAddress = context.getRequest().clientIpAddress.replace(/\[/g, "").replace(/\]/g, "");
    return attributes;
    }
  2. Add a new column client_ip to the audit database

    sql
    12
    ALTER TABLE public.audit ADD client_ip varchar(64) NULL;
    COMMENT ON COLUMN public.audit.client_ip IS 'IP address of the originating client';
  3. Add an event-listener for SuccessAuthenticationEvent which stores the clientIpAddress in the client_ip column of the audit table.

    javascript
    123456789101112131415161718192021222324252627
    var listeners = {
    /**
    * @param {se.curity.identityserver.procedures.context.EventListenerProcedureContext} context
    * @param event
    */
    SuccessAuthenticationEvent: function (context, event) {
    var UUID = Java.type('java.util.UUID');
    var id = UUID.randomUUID().toString().replaceAll("-", "");
    var clientIpAddress = event.getAuthenticationAttributes().getContextAttributes().get("clientIpAddress").getValue();
    var message = event.getAuditData().getMessage();
    var additionalEventData = {
    subject: event.getSubject(),
    client: event.getOauthClientId(),
    acr: event.getAcr(),
    session: event.getSessionId(),
    clientIp: clientIpAddress
    };
    var StructuredDataMessage = new org.apache.logging.log4j.message.StructuredDataMessage(id, message , event.getAuditData().getType(), additionalEventData);
    var auditLogger = org.apache.logging.log4j.LogManager.getLogger("audit-events");
    auditLogger.info(StructuredDataMessage);
    },
    };
  4. Add a mapping in the JDBC appender audit-db in $IDSVR_HOME/etc/log4j2.xml file for column client_ip and pattern clientIp

    xml
    123456789101112131415161718
    <JDBC name="audit-db" tableName="audit">
    <ConnectionFactory class="se.curity.identityserver.logging.AuditDatabaseConnectionFactory" method="getDatabaseConnection" />
    <Column name="id" pattern="%structured_data_id" />
    <Column name="event_type" pattern="%structured_data_type" />
    <Column name="message" pattern="%structured_data_message" />
    <Column name="instant" isEventTimestamp="true" />
    <Column name="event_instant" pattern="%K{instant}" />
    <Column name="server" pattern="%K{server}" />
    <Column name="subject" pattern="%K{subject}" />
    <Column name="client" pattern="%K{client}" />
    <Column name="client_ip" pattern="%K{clientIp}" />
    <Column name="resource" pattern="%K{resource}" />
    <Column name="authenticated_subject" pattern="%K{authenticatedSubject}" />
    <Column name="authenticated_client" pattern="%K{authenticatedClient}" />
    <Column name="acr" pattern="%K{acr}" />
    <Column name="endpoint" pattern="%K{endpoint}" />
    <Column name="session" pattern="%K{session}" />
    </JDBC>

When an authentication request is sent to the Curity Identity Server from a client, the authentication action will capture originating client IP address and add it to the context attributes.

The event-listener procedure will then fetch the client IP address from the context attributes and write it to the audit database using log4j2 audit logger.

Once the technique of using event listeners is understood, it can be used for a number of additional audit events if required, including token refresh and logout events. See the auditing documentation for further details.

Conclusion

This tutorial explained a general approach for customizing audit logs, using a client IP address as an extra field. The same approach could be followed for other use cases, to collect data from the request object.

Join our Newsletter

Get the latest on identity management, API Security and authentication straight to your inbox.

Start Free Trial

Try the Curity Identity Server for Free. Get up and running in 10 minutes.

Start Free Trial