KEYCLOAK-12473 Add possibility to specify length of event detail when storing to database
This commit is contained in:
parent
454ac3f415
commit
c3d80651bf
5 changed files with 55 additions and 6 deletions
|
@ -31,6 +31,7 @@ import org.keycloak.events.admin.OperationType;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -44,10 +45,12 @@ public class JpaEventStoreProvider implements EventStoreProvider {
|
||||||
};
|
};
|
||||||
private static final Logger logger = Logger.getLogger(JpaEventStoreProvider.class);
|
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.em = em;
|
||||||
|
this.maxDetailLength = maxDetailLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -104,7 +107,7 @@ public class JpaEventStoreProvider implements EventStoreProvider {
|
||||||
public void close() {
|
public void close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static EventEntity convertEvent(Event event) {
|
private EventEntity convertEvent(Event event) {
|
||||||
EventEntity eventEntity = new EventEntity();
|
EventEntity eventEntity = new EventEntity();
|
||||||
eventEntity.setId(UUID.randomUUID().toString());
|
eventEntity.setId(UUID.randomUUID().toString());
|
||||||
eventEntity.setTime(event.getTime());
|
eventEntity.setTime(event.getTime());
|
||||||
|
@ -116,13 +119,31 @@ public class JpaEventStoreProvider implements EventStoreProvider {
|
||||||
eventEntity.setIpAddress(event.getIpAddress());
|
eventEntity.setIpAddress(event.getIpAddress());
|
||||||
eventEntity.setError(event.getError());
|
eventEntity.setError(event.getError());
|
||||||
try {
|
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) {
|
} catch (IOException ex) {
|
||||||
logger.error("Failed to write log details", ex);
|
logger.error("Failed to write log details", ex);
|
||||||
}
|
}
|
||||||
return eventEntity;
|
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) {
|
static Event convertEvent(EventEntity eventEntity) {
|
||||||
Event event = new Event();
|
Event event = new Event();
|
||||||
event.setTime(eventEntity.getTime());
|
event.setTime(eventEntity.getTime());
|
||||||
|
|
|
@ -30,15 +30,17 @@ import org.keycloak.models.KeycloakSessionFactory;
|
||||||
public class JpaEventStoreProviderFactory implements EventStoreProviderFactory {
|
public class JpaEventStoreProviderFactory implements EventStoreProviderFactory {
|
||||||
|
|
||||||
public static final String ID = "jpa";
|
public static final String ID = "jpa";
|
||||||
|
private int maxDetailLength;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EventStoreProvider create(KeycloakSession session) {
|
public EventStoreProvider create(KeycloakSession session) {
|
||||||
JpaConnectionProvider connection = session.getProvider(JpaConnectionProvider.class);
|
JpaConnectionProvider connection = session.getProvider(JpaConnectionProvider.class);
|
||||||
return new JpaEventStoreProvider(connection.getEntityManager());
|
return new JpaEventStoreProvider(connection.getEntityManager(), maxDetailLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Config.Scope config) {
|
public void init(Config.Scope config) {
|
||||||
|
maxDetailLength = config.getInt("max-detail-length", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,3 +21,6 @@ echo ** Adding provider **
|
||||||
module:org.keycloak.testsuite.integration-arquillian-testsuite-providers \
|
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})
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.forms;
|
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.drone.api.annotation.Drone;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -68,6 +70,7 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
@ -210,6 +213,23 @@ public class LoginTest extends AbstractTestRealmKeycloakTest {
|
||||||
client.close();
|
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
|
@Test
|
||||||
public void loginChangeUserAfterInvalidPassword() {
|
public void loginChangeUserAfterInvalidPassword() {
|
||||||
loginPage.open();
|
loginPage.open();
|
||||||
|
|
|
@ -22,7 +22,10 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"eventsStore": {
|
"eventsStore": {
|
||||||
"provider": "${keycloak.eventsStore.provider:jpa}"
|
"provider": "${keycloak.eventsStore.provider:jpa}",
|
||||||
|
"jpa": {
|
||||||
|
"max-detail-length": "${keycloak.eventsStore.maxDetailLength:1000}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"eventsListener": {
|
"eventsListener": {
|
||||||
|
|
Loading…
Reference in a new issue