Apereo CAS provides a facility for auditing authentication activity, allowing them to be recorded to a variety of storage services. Essentially, audited authentication events attempt to provide the who, what, when, how, along with any additional contextual information that might be useful to track activity. Auditable events can be narrowed down and filtered, and may also be stored in a wide range of backend services.
This blog post briefly looks at the Audit Log in Apereo CAS. Our starting position is as follows:
6.5.x
By default, Apereo CAS uses a file-based auditing mechanism to store auditable events. File-based audit logs appear in a cas_audit.log file defined in the Logging configuration and they may look like this:
WHO: casuser
WHAT: supplied credentials: ...
ACTION: AUTHENTICATION_SUCCESS
APPLICATION: CAS
WHEN: Mon Aug 26 12:35:59 IST 2013
CLIENT IP ADDRESS: 172.16.5.181
SERVER IP ADDRESS: 192.168.200.22
Let’s review several essential configuration options that should immediately become useful. First, the auditing facility in Apereo CAS is on by default, and may be tweaked using the following setting:
cas.audit.engine.enabled=false
…and if you wanted to tweak the file-based audit log facility,
cas.audit.slf4j.enabled=false
By default, the structure of the audited record shows up in the log in a multi-line format. You could of course opt for a more compact syntax and switch to a single-line format:
cas.audit.slf4j.use-single-line=true
…or you could also switch to JSON:
cas.audit.engine.audit-format=JSON
You may also note that the audit record includes a special field for Client IP Address, which typically notes the IP address of the end-user attempting to authenticate, etc. Deployments that are behind a proxy or a load balancer often tend to mask the real IP address by default and expose it using a dedicated header, such as X-Forwarded-For
. This can be configured with CAS as well, so the correct IP is then recorded into the audit log:
cas.audit.engine.alternate-client-addr-header-name=X-Forwarded-For
A similar trick exists if you are using the embedded Apache Tomcat for the CAS deployment and wish to see the client ip address in the access logs. In this case, the following YAML properties should be effective:
server:
tomcat:
basedir: /etc/cas/config/logs
remote-ip-header: X-Forwarded-For
accesslog:
enabled: true
pattern: "%{X-Forwarded-For}i %l %u %t %r %s %b"
It’s often useful to track audit records in a relational database for future monitoring, data mining, and querying features that may be done outside CAS. Here, we try to configure CAS to push audit data into a PostgreSQL database.
First, ensure you have declared the appropriate module/intention in the build:
dependencies {
implementation "org.apereo.cas:cas-server-support-audit-jdbc"
}
Then, put specific audit settings in your cas.properties
:
cas.audit.jdbc.user=postgres
cas.audit.jdbc.password=password
cas.audit.jdbc.driver-class=org.postgresql.Driver
cas.audit.jdbc.url=jdbc:postgresql://localhost:5432/audit
cas.audit.jdbc.dialect=org.hibernate.dialect.PostgreSQL10Dialect
Note that the schema for the audit records should automatically be generated by CAS:
create table COM_AUDIT_TRAIL (
id int8 generated by default as identity,
AUD_ACTION varchar(255),
APPLIC_CD varchar(255),
AUD_CLIENT_IP varchar(255),
AUD_DATE timestamp not null,
AUD_RESOURCE varchar(2048),
AUD_SERVER_IP varchar(255),
AUD_USER varchar(255),
AUD_USERAGENT varchar(255),
primary key (id)
)
There are two specific actuator endpoints for fetching audited records from the storage: auditevents
that is provided by Spring Boot, and one is auditLog
which is owned by CAS.
First, ensure you have declared the appropriate module/intention in the build:
dependencies {
implementation "org.apereo.cas:cas-server-support-reports"
}
…and then let’s enable both endpoints:
management.endpoint.auditLog.enabled=true
management.endpoint.auditevents.enabled=true
management.endpoints.web.exposure.include=auditLog,auditevents
cas.monitor.endpoints.endpoint.auditevents.access=ANONYMOUS
cas.monitor.endpoints.endpoint.auditLog.access=ANONYMOUS
Working with actuator endpoints requires a 3-step configuration process:
The two endpoints essentially return the same data though using different HTTP methods and structures. For example, we could begin by invoking the CAS auditLog
endpoint:
curl -k -X POST https://localhost:8443/cas/actuator/auditLog
…where the output would be:
[{
"principal": "casuser",
"resourceOperatedUpon": "TGT-1-********zVvV7-M-mmoayyed-2656",
"actionPerformed": "TICKET_GRANTING_TICKET_CREATED",
"applicationCode": "CAS",
"whenActionWasPerformed": "...",
"clientIpAddress": "...",
"serverIpAddress": "...",
"userAgent": "Mozilla/5.0 ..."
}]
The Spring Boot auditevents
endpoint is also available using a GET
:
curl -k -X GET https://localhost:8443/cas/actuator/auditevents
…and that returns similar output:
{
"events": [
{
"timestamp": "...",
"principal": "casuser",
"type": "AUTHENTICATION_EVENT_TRIGGERED",
"data": { "[UsernamePasswordCredential(username": "casuser, source=null, customFields={})]" }
}
]
}
Note that you can instruct CAS to ignore certain audit activities and actions. For example, if you do not care to see AUTHENTICATION_EVENT_TRIGGERED
events in your audit log, you could always skip and exclude those:
# The value here must be a valid regular expression
cas.audit.engine.excluded-actions=AUTHENTICATION_EVENT_TRIGGERED
If you have questions about the contents and the topic of this blog post, or if you need additional guidance and support, feel free to send us a note and ask about consulting and support services.
I hope this review was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. Please feel free to engage and contribute as best as you can.
Happy Coding,
Monday-Friday
9am-6pm, Central European Time
7am-1pm, U.S. Eastern Time
Monday-Friday
9am-6pm, Central European Time