KEYCLOAK-12473 Add possibility to specify length of event detail when storing to database

This commit is contained in:
vramik 2019-12-04 11:41:01 +01:00 committed by Hynek Mlnařík
parent 454ac3f415
commit c3d80651bf
5 changed files with 55 additions and 6 deletions

View file

@ -31,6 +31,7 @@ import org.keycloak.events.admin.OperationType;
import javax.persistence.EntityManager;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@ -44,10 +45,12 @@ public class JpaEventStoreProvider implements EventStoreProvider {
};
private static final Logger logger = Logger.getLogger(JpaEventStoreProvider.class);
private EntityManager em;
private final EntityManager em;
private final int maxDetailLength;
public JpaEventStoreProvider(EntityManager em) {
public JpaEventStoreProvider(EntityManager em, int maxDetailLength) {
this.em = em;
this.maxDetailLength = maxDetailLength;
}
@Override
@ -104,7 +107,7 @@ public class JpaEventStoreProvider implements EventStoreProvider {
public void close() {
}
static EventEntity convertEvent(Event event) {
private EventEntity convertEvent(Event event) {
EventEntity eventEntity = new EventEntity();
eventEntity.setId(UUID.randomUUID().toString());
eventEntity.setTime(event.getTime());
@ -116,13 +119,31 @@ public class JpaEventStoreProvider implements EventStoreProvider {
eventEntity.setIpAddress(event.getIpAddress());
eventEntity.setError(event.getError());
try {
eventEntity.setDetailsJson(mapper.writeValueAsString(event.getDetails()));
if (maxDetailLength > 0 && event.getDetails() != null) {
Map<String, String> result = new HashMap<>(event.getDetails());
result.entrySet().forEach(t -> t.setValue(trimToMaxLength(t.getValue())));
eventEntity.setDetailsJson(mapper.writeValueAsString(result));
} else {
eventEntity.setDetailsJson(mapper.writeValueAsString(event.getDetails()));
}
} catch (IOException ex) {
logger.error("Failed to write log details", ex);
}
return eventEntity;
}
private String trimToMaxLength(String detail) {
if (detail != null && detail.length() > maxDetailLength) {
// (maxDetailLength - 3) takes "..." into account
String result = detail.substring(0, maxDetailLength - 3).concat("...");
logger.warn("Detail was truncated to " + result);
return result;
} else {
return detail;
}
}
static Event convertEvent(EventEntity eventEntity) {
Event event = new Event();
event.setTime(eventEntity.getTime());

View file

@ -30,15 +30,17 @@ import org.keycloak.models.KeycloakSessionFactory;
public class JpaEventStoreProviderFactory implements EventStoreProviderFactory {
public static final String ID = "jpa";
private int maxDetailLength;
@Override
public EventStoreProvider create(KeycloakSession session) {
JpaConnectionProvider connection = session.getProvider(JpaConnectionProvider.class);
return new JpaEventStoreProvider(connection.getEntityManager());
return new JpaEventStoreProvider(connection.getEntityManager(), maxDetailLength);
}
@Override
public void init(Config.Scope config) {
maxDetailLength = config.getInt("max-detail-length", 0);
}
@Override

View file

@ -21,3 +21,6 @@ echo ** Adding provider **
module:org.keycloak.testsuite.integration-arquillian-testsuite-providers \
] \
)
echo ** Adding max-detail-length to eventsStore spi **
/subsystem=keycloak-server/spi=eventsStore/provider=jpa/:write-attribute(name=properties.max-detail-length,value=${keycloak.eventsStore.maxDetailLength:1000})

View file

@ -16,6 +16,8 @@
*/
package org.keycloak.testsuite.forms;
import java.net.MalformedURLException;
import java.net.URI;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Assert;
@ -68,6 +70,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.RandomStringUtils;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
@ -210,6 +213,23 @@ public class LoginTest extends AbstractTestRealmKeycloakTest {
client.close();
}
@Test
public void loginWithLongRedirectUri() throws Exception {
try (AutoCloseable c = new RealmAttributeUpdater(adminClient.realm("test"))
.updateWith(r -> r.setEventsEnabled(true)).update()) {
String randomLongString = RandomStringUtils.random(2500, true, true);
String longRedirectUri = oauth.getRedirectUri() + "?longQueryParameterValue=" + randomLongString;
UriBuilder longLoginUri = UriBuilder.fromUri(oauth.getLoginFormUrl()).replaceQueryParam(OAuth2Constants.REDIRECT_URI, longRedirectUri);
DroneUtils.getCurrentDriver().navigate().to(longLoginUri.build().toString());
loginPage.assertCurrent();
loginPage.login("login-test", "password");
events.expectLogin().user(userId).detail(OAuth2Constants.REDIRECT_URI, longRedirectUri).assertEvent();
}
}
@Test
public void loginChangeUserAfterInvalidPassword() {
loginPage.open();

View file

@ -22,7 +22,10 @@
},
"eventsStore": {
"provider": "${keycloak.eventsStore.provider:jpa}"
"provider": "${keycloak.eventsStore.provider:jpa}",
"jpa": {
"max-detail-length": "${keycloak.eventsStore.maxDetailLength:1000}"
}
},
"eventsListener": {