In KeyCLoak 15.0 (that is WildFly 23.0), I’m trying to configure access-log to also include username (or any ID of the user) when a user is logged in. In keycloak/standalone/configuration/standalone.xml
, I configured
XML:/server/profile/subsystem[@xmlns="urn:jboss:domain:undertow:12.0"]/server/host/access-log/@pattern
pattern="%h %l %u %t "%r" %s/%S %b %T %I "%{i,User-Agent}""
The log gets correctly printed in the file I configured. However, the value of %u
or %{REMOTE_USER}
is always empty (that is -
).
The only way to log some user ID I found was logging session cookie value with %{c,KEYCLOAK_SESSION}
(it contains realm/user-ID/secret
). Which isn’t a good idea to do in production.
Any idea on how to log username or userID in access-log?
Is it a KeyCLoak bug that %u
or %{REMOTE_USER}
is empty even when there is an active user session in KeyCloak? Or is it possible in KeyCLoak to configure which user attribute value goes in REMOTE_USER
?
Alternativelly, how to put the userID in some header to use one of the following?
%{i,xxx}
for incoming headers%{o,xxx}
for outgoing response headers%{c,xxx}
for a specific cookie%{r,xxx}
where xxx is an attribute in the ServletRequest%{s,xxx}
where xxx is an attribute in the HttpSession
Among others, I tried these. None of them was populated.
%{s,user}
%{s,userId}
%{s,client_id}
%{s,USER_ID}
%{s,USER}
%{s,org.keycloak.adapters.spi.KeycloakAccount}
%{s,KeycloakAccount}
%{s,org.keycloak.adapters.tomcat.CatalinaSessionTokenStore.SerializableKeycloakAccount}
%{s,SerializableKeycloakAccount}
%{s,org.keycloak.adapters.saml.SamlSession}
%{s,SamlSession}
%{s,org.keycloak.adapters.undertow.KeycloakUndertowAccount}
%{s,KeycloakUndertowAccount}
%{s,org.keycloak.KeycloakSecurityContext}
%{s,KeycloakSecurityContext}
%{s,io.undertow.servlet.util.SavedRequest}
%{s,SavedRequest}
%{r,tokenInfo}
%{r,KeycloakSecurityContext}
%{r,ElytronHttpFacade}
%{r,AdapterDeploymentContext}
%{r,TOKEN_STORE_NOTE}
I come over similar issue (my client asked me to log client id) and ended up looking for solution. From looking at the source code and how access log is populated I can tell you that there is pretty big gap between where log is formed and where actual work is being done.
If you have a look on Keycloak it is based on Wildfly which uses Undertow to host http server functionality. While access log entry is emitted once request was served there are few gaps and abstractions which complicate things.
From software perspective there is undertow handler, then servlet, then resteasy servlet, then keycloak application and specific resources. When you use Keycloak user or admin console then in most of places it is a "thin" client which is rendered by a web browser. And this browser calls rest resource.
If you wish to get user related information quite often it will not be found in the session, cause most of work being done by Kecloak is issuing tokens on behalf of users. Formally client who ships request acts on behalf of user which means that it is not a explicit information available for each incoming request. Additionally, most of rest resources by definition is stateless which means that they do operate somehow with user but do not populate session much. Only one part for which you can count on access for user information is when user actually logs in and does something within user account console. Beside that it might be lost fight since keycloak resources issuing tokens in most of cases will handle client or client related sessions.
To the point - I come to point where I located place which does the access log format parsing. It is based on Undertow
ExchangeAttribute
idea which allows to bring your own macro for log. This macro can be utilized to either traverse memory structures in pursue of the necessary information. For me it was a client_id which was doing the work. For that I ended up with implementation of aFormAttribute
. I still need to find a way to wire it in, but from unit test perspective it already "clicked", see how basic code is:Main point - by using form attribute to log value entered in "username" field of login form to get "who", then you can combine that with session cookie which will be retained by browser. By basic merger of above two aces you can achieve necessary result. Using above blueprint you can implement your own thing and keep track of tokens and other things which will let you build your application.
I may update the answer when I find a glue logic to properly inject additional attribute into log format into undertow. EDIT: Only one way I found so far to inject extra attributes is by copying them into
$JBOSS_HOME/modules/system/layers/base/org/wildfly/extension/undertow/main/
and updatingmodule.xml
within this directory: