PingFederate
Overview
PingFederate is an enterprise federation server from Ping Identity that provides secure single sign-on (SSO), API security, and identity bridging. It generates audit and operational logs (authentication events, token lifecycle actions, administrative changes) that can be forwarded via Syslog for centralized monitoring and detection.
In this documentation, you will learn how to collect and send PingFederate logs to Sekoia.io.
- Vendor: Ping Identity
- Supported environment: On Premise
- Detection based on: Telemetry
- Supported application or feature: Authentication, Authorization, Token lifecycle, Administrative audit logs
Warning
This format is currently in beta. We highly value your feedback to improve its performance.
High-Level Architecture Diagram
- Type of integration: Outbound (PUSH to Sekoia.io)
- Schema
Specification
Prerequisites
- Resource:
- Self-managed syslog forwarder (e.g. rsyslog, syslog-ng)
- Network:
- Outbound TCP allowed from the PingFederate appliance to the forwarder on your chosen port
- Permissions:
- Root (or equivalent) access on the PingFederate appliance
- Root (or equivalent) access on the Linux server hosting the syslog forwarder
Transport Protocol/Method
- Indirect Syslog (RFC5424)
Logs details
- Supported functionalities: See section Overview
- Supported type(s) of structure: Syslog messages (RFC5424)
- Supported verbosity level: Informational / Audit
Note
Log levels follow the RFC5424 taxonomy. Adapt your forwarder's parsing rules accordingly.
Step-by-Step Configuration Procedure
Instructions on the 3rd Party Solution
Forward PingFederate Logs to a syslog forwarder
This setup guide will lead you into forwarding PingFederate's logs to Sekoia.io by means of a syslog transport channel.
Detailed Procedure:
- Prerequisites:
-
An internal syslog concentrator is required to collect and forward events to Sekoia.io.
-
Create the Intake in Sekoia.io:
-
Go to the intake page and create a new intake from the format
PingFederate. Copy the intake key. -
Configure Log4j2 for Syslog Forwarding:
On the system hosting PingFederate:
-
SSH into your PingFederate server and open the Log4j2 configuration file:
vi /opt/pingfederate/server/default/conf/log4j2.xml -
Enable tracking ID correlation (recommended for event correlation):
Tracking IDs (
tid) allow you to correlate events across multiple log entries for the same transaction. Ensure theTrackingIdSupportis enabled in your PingFederate configuration. -
Add or modify the Syslog appender to forward logs with the proper format. The pattern must match the format expected by Sekoia.io's parser:
<Configuration> <Appenders> <!-- Existing appenders ... --> <!-- Syslog appender for Sekoia.io --> <Syslog name="SekoiaSyslog" format="RFC5424" host="<concentrator-ip-address>" port="<concentrator-port>" protocol="TCP" facility="LOCAL0" appName="pingfederate"> <!-- CRITICAL: Use this exact pattern for proper parsing --> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} tid:%X{trackingid} %-5level [%c] %msg%n"/> </Syslog> <!-- Optional: HTTP access logs appender (if using embedded Jetty logging) --> <Syslog name="SekoiaHttpAccess" format="RFC5424" host="<concentrator-ip-address>" port="<concentrator-port>" protocol="TCP" facility="LOCAL1" appName="pingfederate-http"> <PatternLayout pattern="%msg%n"/> </Syslog> </Appenders> <Loggers> <!-- Application logs: audit, authentication, token lifecycle --> <Root level="info"> <AppenderRef ref="SekoiaSyslog"/> </Root> <!-- Capture detailed authentication events --> <Logger name="org.sourceid.saml20.domain.mgmt.impl" level="info" additivity="false"> <AppenderRef ref="SekoiaSyslog"/> </Logger> <!-- Capture OAuth/OIDC token events --> <Logger name="org.sourceid.oauth20" level="info" additivity="false"> <AppenderRef ref="SekoiaSyslog"/> </Logger> <!-- Capture session and SSO events --> <Logger name="org.sourceid.websso" level="info" additivity="false"> <AppenderRef ref="SekoiaSyslog"/> </Logger> <!-- Capture administrative audit events --> <Logger name="com.pingidentity.console.audit" level="info" additivity="false"> <AppenderRef ref="SekoiaSyslog"/> </Logger> <!-- Optional: Capture DEBUG level for troubleshooting (generates more logs) --> <!-- Uncomment if needed for detailed debugging --> <!-- <Logger name="org.sourceid" level="debug" additivity="false"> <AppenderRef ref="SekoiaSyslog"/> </Logger> --> </Loggers> </Configuration>Key Configuration Notes:
- Pattern Layout: The pattern
%d{yyyy-MM-dd HH:mm:ss,SSS} tid:%X{trackingid} %-5level [%c] %msg%nensures compatibility with Sekoia.io's parser - Tracking ID:
%X{trackingid}includes the correlation ID in every log entry (appears astid:in logs) - Timestamp format:
yyyy-MM-dd HH:mm:ss,SSSmatches the expected ISO8601-like format with milliseconds - Logger name:
[%c]includes the full Java class name for better event categorization
- Pattern Layout: The pattern
-
Configure HTTP access logs (optional but recommended):
If you want to capture HTTP access logs separately, edit the Jetty configuration:
vi /opt/pingfederate/server/default/conf/jetty-runtime.xmlEnable request logging with the Common Log Format (CLF):
<Set name="RequestLog"> <New class="org.eclipse.jetty.server.NCSARequestLog"> <Arg> <SystemProperty name="pf.log.dir" default="<pf_install>/pingfederate/log"/> /pf-http-access.log </Arg> <Set name="extended">false</Set> <Set name="append">true</Set> <Set name="LogTimeZone">GMT</Set> </New> </Set>Then configure rsyslog on the PingFederate host to forward these logs to your concentrator (see step 5).
-
Forward HTTP access logs via rsyslog (if using file-based HTTP logs):
On the PingFederate host, configure rsyslog to monitor the HTTP access log file:
vi /etc/rsyslog.d/10-pingfederate-http.confAdd:
# Monitor PingFederate HTTP access logs module(load="imfile" PollingInterval="10") input(type="imfile" File="/opt/pingfederate/log/pf-http-access.log" Tag="pingfederate-http:" Severity="info" Facility="local1") # Forward to concentrator local1.* @@<concentrator-ip-address>:<concentrator-port>Restart rsyslog:
systemctl restart rsyslog -
Save
log4j2.xmland restart PingFederate:systemctl restart pingfederate -
Verify log format by checking the syslog output:
tail -f /var/log/messages | grep pingfederateYou should see logs in this format:
2025-09-02 11:02:32,869 tid:Z8I1vdotGu084PB7b2HrQ0A1kKU INFO [org.sourceid.saml20.service.impl.AuthnRequestProcessorImpl] Processing authentication request
Note
Important Pattern Requirements:
- The timestamp must use the format
yyyy-MM-dd HH:mm:ss,SSS(comma before milliseconds) - The tracking ID must appear as
tid:XXXXX(with the colon) - The log level must be 5 characters wide with left padding (
%-5level) - The logger name must be enclosed in brackets
[%c]
Any deviation from this pattern will cause parsing failures in Sekoia.io.
Instruction on Sekoia
Configure Your Intake
This section will guide you through creating the intake object in Sekoia, which provides a unique identifier called the "Intake key." The Intake key is essential for later configuration, as it references the Community, Entity, and Parser (Intake Format) used when receiving raw events on Sekoia.
- Go to the Sekoia Intake page.
- Click on the
+ New Intakebutton at the top right of the page. - Search for your Intake by the product name in the search bar.
- Give it a Name and associate it with an Entity (and a Community if using multi-tenant mode).
- Click on
Create.
Note
For more details on how to use the Intake page and to find the Intake key you just created, refer to this documentation.
Configure a forwarder
To forward events using syslog to Sekoia.io, you need to update the syslog header with the intake key you previously created. Here is an example of your message before the forwarder
<%pri%>1 %timestamp:::date-rfc3339% %hostname% %app-name% %procid% LOG RAW_MESSAGE
<%pri%>1 %timestamp:::date-rfc3339% %hostname% %app-name% %procid% LOG [SEKOIA@53288 intake_key=\"YOUR_INTAKE_KEY\"] RAW_MESSAGE
To achieve this you can:
- Use the Sekoia.io forwarder which is the official supported way to collect data using the syslog protocol in Sekoia.io. In charge of centralizing data coming from many equipments/sources and forwarding them to Sekoia.io with the apporpriated format, it is a prepackaged option. You only have to provide your intake key as parameter.
- Use your own Syslog service instance. Maybe you already have an intance of one of these components on your side and want to reuse it in order to centralize data before forwarding them to Sekoia.io. When using this mode, you have to configure and maintain your component in order to respect the expected Sekoia.io format.
Warning
Only the Sekoia.io forwarder is officially supported. Other options are documented for reference purposes but do not have official support.
Raw Events Samples
In this section, you will find examples of raw logs as generated natively by the source. These examples are provided to help integrators understand the data format before ingestion into Sekoia.io. It is crucial for setting up the correct parsing stages and ensuring that all relevant information is captured.
2025-09-02 11:02:32,869 tid:Z8I1vdotGu084PB7b2HrQ0A1kKU DEBUG [org.sourceid.servlet.HttpServletRespProxy] flush cookies: adding Cookie{OXS-U2A=hashedValue:Z8I1vdotGu084PB7b2HrQ0A1kKU; path=/; maxAge=-1; domain=.auth-int.xxxxgroup.com}
2025-09-02 11:02:34,353 tid:Q08PzbPCjfSJL8sbIj88OLO5YWg DEBUG [org.sourceid.websso.servlet.IntegrationControllerServlet] GET: https://hub-mtls.auth-int.hza.infra.xxxx/pf/heartbeat.ping
192.168.1.100 - john.doe [02/Sep/2025:13:02:34 +0000] "GET /pf/heartbeat.ping HTTP/1.1" 200 156
2025-09-02 11:02:34,353 tid:Q08PzbPCjfSJL8sbIj88OLO5YWg DEBUG [com.pingidentity.locale.LocaleUtil] Locale Override: none
2025-09-02 11:02:34,352 DEBUG [org.sourceid.util.log.internal.TrackingIdSupport] The incoming request does not contain a unique identifier. Assigning auto-generated request ID: C1CjegPq3VckLYpvYlzZEGTBe
Detection section
The following section provides information for those who wish to learn more about the detection capabilities enabled by collecting this intake. It includes details about the built-in rule catalog, event categories, and ECS fields extracted from raw events. This is essential for users aiming to create custom detection rules, perform hunting activities, or pivot in the events page.
No related built-in rules was found. This message is automatically generated.
Event Categories
The following table lists the data source offered by this integration.
| Data Source | Description |
|---|---|
Authentication logs |
authentication and SSO events including login attempts, session management, and federation transactions |
Application logs |
administrative actions, configuration changes, and security-related events |
Network device logs |
SAML, OAuth, OpenID Connect, and other federation protocol interactions |
Web logs |
Access logs |
In details, the following table denotes the type of events produced by this integration.
| Name | Values |
|---|---|
| Kind | event |
| Category | configuration, web |
| Type | access, info |
Transformed Events Samples after Ingestion
This section demonstrates how the raw logs will be transformed by our parsers. It shows the extracted fields that will be available for use in the built-in detection rules and hunting activities in the events page. Understanding these transformations is essential for analysts to create effective detection mechanisms with custom detection rules and to leverage the full potential of the collected data.
{
"message": "2025-09-02 11:02:32,869 tid:Z8I1vdotGu084PB7b2HrQ0A1kKU DEBUG [org.sourceid.servlet.HttpServletRespProxy] flush cookies: adding Cookie{OXS-U2A=hashedValue:Z8I1vdotGu084PB7b2HrQ0A1kKU; path=/; maxAge=-1; domain=.auth-int.xxxxgroup.com}",
"event": {
"category": [
"web"
],
"dataset": "pingfederate",
"kind": "event",
"module": "pingfederate",
"type": [
"info"
]
},
"@timestamp": "2025-09-02T11:02:32.869000Z",
"log": {
"level": "DEBUG",
"logger": "org.sourceid.servlet.HttpServletRespProxy"
},
"pingfederate": {
"labels": "flush cookies: adding Cookie{OXS-U2A=hashedValue:Z8I1vdotGu084PB7b2HrQ0A1kKU; path=/; maxAge=-1; domain=.auth-int.xxxxgroup.com}",
"transaction_id": "Z8I1vdotGu084PB7b2HrQ0A1kKU"
}
}
{
"message": "2025-09-02 11:02:34,353 tid:Q08PzbPCjfSJL8sbIj88OLO5YWg DEBUG [org.sourceid.websso.servlet.IntegrationControllerServlet] GET: https://hub-mtls.auth-int.hza.infra.xxxx/pf/heartbeat.ping",
"event": {
"category": [
"web"
],
"dataset": "pingfederate",
"kind": "event",
"module": "pingfederate",
"type": [
"access"
]
},
"@timestamp": "2025-09-02T11:02:34.353000Z",
"host": {
"name": "hub-mtls.auth-int.hza.infra.xxxx"
},
"http": {
"request": {
"method": "GET"
}
},
"log": {
"level": "DEBUG",
"logger": "org.sourceid.websso.servlet.IntegrationControllerServlet"
},
"pingfederate": {
"labels": "GET: https://hub-mtls.auth-int.hza.infra.xxxx/pf/heartbeat.ping",
"transaction_id": "Q08PzbPCjfSJL8sbIj88OLO5YWg"
},
"url": {
"domain": "hub-mtls.auth-int.hza.infra.xxxx",
"original": "https://hub-mtls.auth-int.hza.infra.xxxx/pf/heartbeat.ping",
"path": "/pf/heartbeat.ping",
"port": 443,
"scheme": "https",
"subdomain": "hub-mtls.auth-int.hza.infra"
}
}
{
"message": "192.168.1.100 - john.doe [02/Sep/2025:13:02:34 +0000] \"GET /pf/heartbeat.ping HTTP/1.1\" 200 156",
"event": {
"category": [
"web"
],
"dataset": "pingfederate",
"kind": "event",
"module": "pingfederate",
"type": [
"access"
]
},
"host": {
"name": "192.168.1.100"
},
"http": {
"request": {
"method": "GET"
},
"response": {
"body": {
"bytes": 156
},
"status_code": 200
},
"version": "1.1"
},
"related": {
"ip": [
"192.168.1.100"
],
"user": [
"john.doe"
]
},
"source": {
"address": "192.168.1.100",
"ip": "192.168.1.100"
},
"url": {
"original": "/pf/heartbeat.ping",
"path": "/pf/heartbeat.ping"
},
"user": {
"name": "john.doe"
}
}
{
"message": "2025-09-02 11:02:34,353 tid:Q08PzbPCjfSJL8sbIj88OLO5YWg DEBUG [com.pingidentity.locale.LocaleUtil] Locale Override: none",
"event": {
"category": [
"configuration"
],
"dataset": "pingfederate",
"kind": "event",
"module": "pingfederate",
"type": [
"info"
]
},
"@timestamp": "2025-09-02T11:02:34.353000Z",
"log": {
"level": "DEBUG",
"logger": "com.pingidentity.locale.LocaleUtil"
},
"pingfederate": {
"labels": "Locale Override: none",
"transaction_id": "Q08PzbPCjfSJL8sbIj88OLO5YWg"
}
}
{
"message": "2025-09-02 11:02:34,352 DEBUG [org.sourceid.util.log.internal.TrackingIdSupport] The incoming request does not contain a unique identifier. Assigning auto-generated request ID: C1CjegPq3VckLYpvYlzZEGTBe",
"event": {
"category": [
"web"
],
"dataset": "pingfederate",
"kind": "event",
"module": "pingfederate",
"type": [
"info"
]
},
"@timestamp": "2025-09-02T11:02:34.352000Z",
"log": {
"level": "DEBUG",
"logger": "org.sourceid.util.log.internal.TrackingIdSupport"
},
"pingfederate": {
"labels": "The incoming request does not contain a unique identifier. Assigning auto-generated request ID: C1CjegPq3VckLYpvYlzZEGTBe"
}
}
Extracted Fields
The following table lists the fields that are extracted, normalized under the ECS format, analyzed and indexed by the parser. It should be noted that infered fields are not listed.
| Name | Type | Description |
|---|---|---|
@timestamp |
date |
Date/time when the event originated. |
event.category |
keyword |
Event category. The second categorization field in the hierarchy. |
event.dataset |
keyword |
Name of the dataset. |
event.kind |
keyword |
The kind of the event. The highest categorization field in the hierarchy. |
event.module |
keyword |
Name of the module this data is coming from. |
event.type |
keyword |
Event type. The third categorization field in the hierarchy. |
host.name |
keyword |
Name of the host. |
http.request.method |
keyword |
HTTP request method. |
http.response.body.bytes |
long |
Size in bytes of the response body. |
http.response.status_code |
long |
HTTP response status code. |
http.version |
keyword |
HTTP version. |
log.level |
keyword |
Log level of the log event. |
log.logger |
keyword |
Name of the logger. |
pingfederate.labels |
keyword |
Key-value pairs extracted from original message for additional context |
pingfederate.transaction_id |
keyword |
Transaction ID (tid) for tracking requests across PingFederate components |
source.domain |
keyword |
The domain name of the source. |
source.ip |
ip |
IP address of the source. |
url.original |
wildcard |
Unmodified original url as seen in the event source. |
user.name |
keyword |
Short name or login of the user. |
For more information on the Intake Format, please find the code of the Parser, Smart Descriptions, and Supported Events here.