Skip to content

Commit

Permalink
Attempt to replicate the Keycloak implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
garronej committed Dec 11, 2024
1 parent 123b269 commit 86860cb
Show file tree
Hide file tree
Showing 4 changed files with 311 additions and 65 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
"java.configuration.updateBuildConfiguration": "automatic"
}
44 changes: 21 additions & 23 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,36 @@

<properties>
<java.version>17</java.version>
<keycloak.version>26.0.7</keycloak.version>
</properties>

<dependencies>
<!-- Keycloak Server dependencies -->

<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>26.0.0</version>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>26.0.0</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi-private</artifactId>
<version>26.0.0</version>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -1,18 +1,198 @@
package org.keycloakify.keycloak.event.logger;

import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.admin.AdminEvent;

public class AdminEventListenerProvider implements EventListenerProvider {

public void close() {
}

public void onEvent(Event event) {
}

public void onEvent(AdminEvent event, boolean includeRepresentation) {
System.out.println("UPDATE: " + event.getOperationType().toString());
}
}
import org.jboss.logging.Logger;
import org.keycloak.common.util.StackUtil;
import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventListenerTransaction;
import org.keycloak.events.admin.AdminEvent;
import org.keycloak.models.KeycloakContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.utils.StringUtil;

import jakarta.ws.rs.core.Cookie;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.UriInfo;
import java.util.Map;

/**
* @author <a href="mailto:[email protected]">Stian Thorgersen</a>
*/
public class AdminEventListenerProvider implements EventListenerProvider {

private final KeycloakSession session;
private final Logger logger;
private final Logger.Level successLevel;
private final Logger.Level errorLevel;
private final boolean sanitize;
private final Character quotes;
private final EventListenerTransaction tx = new EventListenerTransaction(this::logAdminEvent, this::logEvent);

public AdminEventListenerProvider(KeycloakSession session, Logger logger,
Logger.Level successLevel, Logger.Level errorLevel, Character quotes, boolean sanitize) {
this.session = session;
this.logger = logger;
this.successLevel = successLevel;
this.errorLevel = errorLevel;
this.sanitize = sanitize;
this.quotes = quotes;
this.session.getTransactionManager().enlistAfterCompletion(tx);
}

@Override
public void onEvent(Event event) {
tx.addEvent(event);
}

@Override
public void onEvent(AdminEvent adminEvent, boolean includeRepresentation) {
tx.addAdminEvent(adminEvent, includeRepresentation);
}

private void sanitize(StringBuilder sb, String str) {
if (quotes != null) {
sb.append(quotes);
}
if (sanitize) {
str = StringUtil.sanitizeSpacesAndQuotes(str, quotes);
}
sb.append(str);
if (quotes != null) {
sb.append(quotes);
}
}

private void logEvent(Event event) {
Logger.Level level = event.getError() != null ? errorLevel : successLevel;

if (logger.isEnabled(level)) {
StringBuilder sb = new StringBuilder();

sb.append("type=");
sanitize(sb, event.getType().toString());
sb.append(", realmId=");
sanitize(sb, event.getRealmId());
sb.append(", realmName=");
sanitize(sb, event.getRealmName());
sb.append(", clientId=");
sanitize(sb, event.getClientId());
sb.append(", userId=");
sanitize(sb, event.getUserId());
if (event.getSessionId() != null) {
sb.append(", sessionId=");
sanitize(sb, event.getSessionId());
}
sb.append(", ipAddress=");
sanitize(sb, event.getIpAddress());

if (event.getError() != null) {
sb.append(", error=");
sanitize(sb, event.getError());
}

if (event.getDetails() != null) {
for (Map.Entry<String, String> e : event.getDetails().entrySet()) {
sb.append(", ");
sb.append(StringUtil.sanitizeSpacesAndQuotes(e.getKey(), null));
sb.append("=");
sanitize(sb, e.getValue());
}
}

AuthenticationSessionModel authSession = session.getContext().getAuthenticationSession();
if(authSession!=null) {
sb.append(", authSessionParentId=");
sanitize(sb, authSession.getParentSession().getId());
sb.append(", authSessionTabId=");
sanitize(sb, authSession.getTabId());
}

if(logger.isTraceEnabled()) {
setKeycloakContext(sb);

if (StackUtil.isShortStackTraceEnabled()) {
sb.append(", stackTrace=").append(StackUtil.getShortStackTrace());
}
}

logger.log(logger.isTraceEnabled() ? Logger.Level.TRACE : level, sb.toString());
}
}

private void logAdminEvent(AdminEvent adminEvent, boolean includeRepresentation) {
Logger.Level level = adminEvent.getError() != null ? errorLevel : successLevel;

if (logger.isEnabled(level)) {
StringBuilder sb = new StringBuilder();

sb.append("operationType=");
sanitize(sb, adminEvent.getOperationType().toString());
sb.append(", realmId=");
sanitize(sb, adminEvent.getAuthDetails().getRealmId());
sb.append(", realmName=");
sanitize(sb, adminEvent.getAuthDetails().getRealmName());
sb.append(", clientId=");
sanitize(sb, adminEvent.getAuthDetails().getClientId());
sb.append(", userId=");
sanitize(sb, adminEvent.getAuthDetails().getUserId());
sb.append(", ipAddress=");
sanitize(sb, adminEvent.getAuthDetails().getIpAddress());
sb.append(", resourceType=");
sanitize(sb, adminEvent.getResourceTypeAsString());
sb.append(", resourcePath=");
sanitize(sb, adminEvent.getResourcePath());

if (adminEvent.getError() != null) {
sb.append(", error=");
sanitize(sb, adminEvent.getError());
}

if (adminEvent.getDetails() != null) {
for (Map.Entry<String, String> e : adminEvent.getDetails().entrySet()) {
sb.append(", ");
sb.append(StringUtil.sanitizeSpacesAndQuotes(e.getKey(), null));
sb.append("=");
sanitize(sb, e.getValue());
}
}

if(logger.isTraceEnabled()) {
setKeycloakContext(sb);
}

logger.log(logger.isTraceEnabled() ? Logger.Level.TRACE : level, sb.toString());
}
}

@Override
public void close() {
}

private void setKeycloakContext(StringBuilder sb) {
KeycloakContext context = session.getContext();
UriInfo uriInfo = context.getUri();
HttpHeaders headers = context.getRequestHeaders();
if (uriInfo != null) {
sb.append(", requestUri=");
sanitize(sb, uriInfo.getRequestUri().toString());
}

if (headers != null) {
sb.append(", cookies=[");
boolean f = true;
for (Map.Entry<String, Cookie> e : headers.getCookies().entrySet()) {
if (f) {
f = false;
} else {
sb.append(", ");
}
sb.append(StringUtil.sanitizeSpacesAndQuotes(e.getValue().toString(), null));
}
sb.append("]");
}

}

}

Loading

0 comments on commit 86860cb

Please sign in to comment.