[New] Implemented opt-in audit trail in Strolch

The audit trail has its own map on the Realm and a trail is written by
realm at the end of the transaction.

You can write your own audit trail using tx.getAuditTrail().

Enable the audit trail by setting the realm configuration value
'enableAuditTrail'.
This commit is contained in:
Robert von Burg 2014-08-23 20:50:10 +02:00
parent 7a88def08a
commit ab54378b66
11 changed files with 138 additions and 75 deletions

11
pom.xml
View File

@ -97,6 +97,17 @@
<artifactId>li.strolch.testbase</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>

View File

@ -23,7 +23,7 @@ import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchComponent;
import li.strolch.exception.StrolchException;
import li.strolch.runtime.configuration.ComponentConfiguration;
import li.strolch.runtime.privilege.StrolchPrivilegeHandler;
import li.strolch.runtime.privilege.PrivilegeHandler;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.utils.dbc.DBC;
@ -34,7 +34,7 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
private static final String SESSION_ORIGIN = "session.origin";
private static final String PROP_VALIDATE_ORIGIN = "validateOrigin";
private StrolchPrivilegeHandler privilegeHandler;
private PrivilegeHandler privilegeHandler;
private Map<String, Certificate> certificateMap;
private boolean validateOrigin;
@ -54,7 +54,7 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St
@Override
public void start() {
this.privilegeHandler = getContainer().getComponent(StrolchPrivilegeHandler.class);
this.privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
this.certificateMap = new HashMap<>();
super.start();
}

View File

@ -47,13 +47,14 @@ public class EnumQuery {
@Produces(MediaType.APPLICATION_JSON)
@Path("{name}")
public Response getEnum(@PathParam("name") String name, @Context HttpHeaders headers) {
try {
EnumHandler enumHandler = RestfulStrolchComponent.getInstance().getContainer()
.getComponent(EnumHandler.class);
Locale locale = RestfulHelper.getLocale(headers);
StrolchEnum strolchEnum = enumHandler.getEnum(name, locale);
StrolchEnum strolchEnum = enumHandler.getEnum(null, name, locale);
GenericEntity<StrolchEnum> entity = new GenericEntity<StrolchEnum>(strolchEnum, StrolchEnum.class) {
};

View File

@ -21,10 +21,12 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@ -32,12 +34,12 @@ import javax.ws.rs.core.Response;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.OrderMap;
import li.strolch.agent.api.ResourceMap;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.exception.StrolchException;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulConstants;
import li.strolch.rest.model.AgentOverview;
import li.strolch.rest.model.ElementMapOverview;
import li.strolch.rest.model.ElementMapType;
@ -51,7 +53,7 @@ import li.strolch.rest.model.ResourceOverview;
import li.strolch.rest.model.StrolchElementOverview;
import li.strolch.rest.model.TypeDetail;
import li.strolch.rest.model.TypeOverview;
import ch.eitchnet.utils.dbc.DBC;
import ch.eitchnet.privilege.model.Certificate;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
@ -59,6 +61,11 @@ import ch.eitchnet.utils.dbc.DBC;
@Path("strolch/inspector")
public class Inspector {
private StrolchTransaction openTx(Certificate certificate, String realm) {
return RestfulStrolchComponent.getInstance().getContainer().getRealm(realm)
.openTx(certificate, Inspector.class);
}
/**
* <p>
* Root path of the inspector
@ -74,19 +81,19 @@ public class Inspector {
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAgent() {
public Response getAgent(@Context HttpServletRequest request) {
try {
ComponentContainer container = RestfulStrolchComponent.getInstance().getContainer();
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Set<String> realmNames = container.getRealmNames();
List<RealmOverview> realmOverviews = new ArrayList<>(realmNames.size());
for (String realmName : realmNames) {
StrolchRealm realm = container.getRealm(realmName);
try (StrolchTransaction tx = realm.openTx()) {
try (StrolchTransaction tx = openTx(cert, realmName)) {
long size = 0;
size += realm.getResourceMap().querySize(tx);
size += realm.getOrderMap().querySize(tx);
size += tx.getResourceMap().querySize(tx);
size += tx.getOrderMap().querySize(tx);
RealmOverview realmOverview = new RealmOverview(realmName, size);
realmOverviews.add(realmOverview);
}
@ -122,20 +129,19 @@ public class Inspector {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}")
public Response getRealm(@PathParam("realm") String realm) {
DBC.PRE.assertNotEmpty("Realm must be set!", realm); //$NON-NLS-1$
public Response getRealm(@PathParam("realm") String realm, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
StrolchRealm strolchRealm = RestfulStrolchComponent.getInstance().getContainer().getRealm(realm);
List<ElementMapsOverview> elementMapOverviews = new ArrayList<>(2);
try (StrolchTransaction tx = strolchRealm.openTx()) {
try (StrolchTransaction tx = openTx(cert, realm)) {
ResourceMap resourceMap = strolchRealm.getResourceMap();
ResourceMap resourceMap = tx.getResourceMap();
ElementMapsOverview resourceOverview = new ElementMapsOverview(ElementMapType.RESOURCE);
resourceOverview.setNrOfElements(resourceMap.querySize(tx));
resourceOverview.setTypes(resourceMap.getTypes(tx));
elementMapOverviews.add(resourceOverview);
OrderMap orderMap = strolchRealm.getOrderMap();
OrderMap orderMap = tx.getOrderMap();
ElementMapsOverview orderOverview = new ElementMapsOverview(ElementMapType.ORDER);
orderOverview.setNrOfElements(orderMap.querySize(tx));
orderOverview.setTypes(orderMap.getTypes(tx));
@ -167,12 +173,11 @@ public class Inspector {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/resource")
public Response getResourcesOverview(@PathParam("realm") String realm) {
DBC.PRE.assertNotEmpty("Realm must be set!", realm); //$NON-NLS-1$
StrolchRealm strolchRealm = RestfulStrolchComponent.getInstance().getContainer().getRealm(realm);
public Response getResourcesOverview(@PathParam("realm") String realm, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
ElementMapOverview resourcesOverview;
try (StrolchTransaction tx = strolchRealm.openTx()) {
try (StrolchTransaction tx = openTx(cert, realm)) {
ResourceMap resourceMap = tx.getResourceMap();
List<String> types = new ArrayList<>(resourceMap.getTypes(tx));
Collections.sort(types);
@ -211,12 +216,11 @@ public class Inspector {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/order")
public Response getOrdersOverview(@PathParam("realm") String realm) {
DBC.PRE.assertNotEmpty("Realm must be set!", realm); //$NON-NLS-1$
StrolchRealm strolchRealm = RestfulStrolchComponent.getInstance().getContainer().getRealm(realm);
public Response getOrdersOverview(@PathParam("realm") String realm, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
ElementMapOverview ordersOverview;
try (StrolchTransaction tx = strolchRealm.openTx()) {
try (StrolchTransaction tx = openTx(cert, realm)) {
OrderMap orderMap = tx.getOrderMap();
List<String> types = new ArrayList<>(orderMap.getTypes(tx));
Collections.sort(types);
@ -261,12 +265,12 @@ public class Inspector {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/resource/{type}")
public Response getResourceTypeDetails(@PathParam("realm") String realm, @PathParam("type") String type) {
DBC.PRE.assertNotEmpty("Realm must be set!", realm); //$NON-NLS-1$
StrolchRealm strolchRealm = RestfulStrolchComponent.getInstance().getContainer().getRealm(realm);
public Response getResourceTypeDetails(@PathParam("realm") String realm, @PathParam("type") String type,
@Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
TypeDetail typeDetail;
try (StrolchTransaction tx = strolchRealm.openTx()) {
try (StrolchTransaction tx = openTx(cert, realm)) {
List<Resource> byType = tx.getResourceMap().getElementsBy(tx, type);
List<StrolchElementOverview> elementOverviews = new ArrayList<>(byType.size());
for (Resource resource : byType) {
@ -302,12 +306,12 @@ public class Inspector {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/order/{type}")
public Response getOrderTypeDetails(@PathParam("realm") String realm, @PathParam("type") String type) {
DBC.PRE.assertNotEmpty("Realm must be set!", realm); //$NON-NLS-1$
StrolchRealm strolchRealm = RestfulStrolchComponent.getInstance().getContainer().getRealm(realm);
public Response getOrderTypeDetails(@PathParam("realm") String realm, @PathParam("type") String type,
@Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
TypeDetail typeDetail;
try (StrolchTransaction tx = strolchRealm.openTx()) {
try (StrolchTransaction tx = openTx(cert, realm)) {
List<Order> byType = tx.getOrderMap().getElementsBy(tx, type);
List<StrolchElementOverview> elementOverviews = new ArrayList<>(byType.size());
for (Order order : byType) {
@ -347,12 +351,11 @@ public class Inspector {
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/resource/{type}/{id}")
public Response getResource(@PathParam("realm") String realm, @PathParam("type") String type,
@PathParam("id") String id) {
DBC.PRE.assertNotEmpty("Realm must be set!", realm); //$NON-NLS-1$
StrolchRealm strolchRealm = RestfulStrolchComponent.getInstance().getContainer().getRealm(realm);
@PathParam("id") String id, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Resource resource;
try (StrolchTransaction tx = strolchRealm.openTx()) {
try (StrolchTransaction tx = openTx(cert, realm)) {
resource = tx.getResourceMap().getBy(tx, type, id);
}
if (resource == null) {
@ -370,12 +373,11 @@ public class Inspector {
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/order/{type}/{id}")
public Response getOrder(@PathParam("realm") String realm, @PathParam("type") String type,
@PathParam("id") String id) {
DBC.PRE.assertNotEmpty("Realm must be set!", realm); //$NON-NLS-1$
StrolchRealm strolchRealm = RestfulStrolchComponent.getInstance().getContainer().getRealm(realm);
@PathParam("id") String id, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
Order order;
try (StrolchTransaction tx = strolchRealm.openTx()) {
try (StrolchTransaction tx = openTx(cert, realm)) {
order = tx.getOrderMap().getBy(tx, type, id);
}
if (order == null) {

View File

@ -21,17 +21,21 @@ import java.net.URI;
import javax.ws.rs.core.Application;
import li.strolch.rest.StrolchRestfulExceptionMapper;
import li.strolch.rest.endpoint.Inspector;
import li.strolch.rest.StrolchRestfulClasses;
import li.strolch.testbase.runtime.RuntimeMock;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.grizzly2.servlet.GrizzlyWebContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.server.TracingConfig;
import org.glassfish.jersey.servlet.ServletProperties;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.ServletDeploymentContext;
import org.glassfish.jersey.test.TestProperties;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerException;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.slf4j.Logger;
@ -47,7 +51,6 @@ public abstract class AbstractRestfulTest extends JerseyTest {
private static final String RUNTIME_PATH = "target/withPrivilegeRuntime/"; //$NON-NLS-1$
private static final String CONFIG_SRC = "src/test/resources/withPrivilegeRuntime"; //$NON-NLS-1$
private static RuntimeMock runtimeMock;
private static HttpServer server;
@BeforeClass
public static void beforeClass() throws IllegalArgumentException, IOException {
@ -57,29 +60,52 @@ public abstract class AbstractRestfulTest extends JerseyTest {
runtimeMock = new RuntimeMock();
runtimeMock.mockRuntime(rootPath, configSrc);
runtimeMock.startContainer();
}
server = GrizzlyWebContainerFactory.create(BASE_URI);
@Override
protected URI getBaseUri() {
return BASE_URI;
}
@AfterClass
public static void afterClass() {
server.shutdownNow();
runtimeMock.destroyRuntime();
}
@Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
return new GrizzlyWebTestContainerFactory();
}
@Override
protected DeploymentContext configureDeployment() {
return ServletDeploymentContext.builder(configure()).contextPath("rest").build();
}
@Override
protected Application configure() {
forceEnable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
return createApp();
}
public static ResourceConfig createApp() {
return new ResourceConfig()//
.packages(Inspector.class.getPackage().getName())//
.register(StrolchRestfulExceptionMapper.class)
//.register(createMoxyJsonResolver())
// Logging.
.register(LoggingFilter.class)
// Tracing support.
.property(ServerProperties.TRACING, TracingConfig.ON_DEMAND.name());
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.setApplicationName("RestTest");
for (Class<?> clazz : StrolchRestfulClasses.restfulClasses) {
resourceConfig.register(clazz);
}
for (Class<?> clazz : StrolchRestfulClasses.providerClasses) {
resourceConfig.register(clazz);
}
resourceConfig.register(LoggingFilter.class);
//.register(createMoxyJsonResolver())
// Logging
// Tracing support.
resourceConfig.property(ServerProperties.TRACING, TracingConfig.ALL.name());
resourceConfig.property(ServletProperties.FILTER_FORWARD_ON_404, true);
return resourceConfig;
}
}

View File

@ -33,14 +33,13 @@ import li.strolch.rest.model.Login;
import li.strolch.rest.model.LoginResult;
import li.strolch.rest.model.LogoutResult;
import org.junit.Ignore;
import org.junit.Test;
//import com.sun.jersey.api.client.ClientResponse;
//import com.sun.jersey.api.representation.Form;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@Ignore
public class AuthenticationTest extends AbstractRestfulTest {
private static final String ROOT_PATH = "strolch/authentication";

View File

@ -26,11 +26,13 @@ import javax.ws.rs.core.Response.Status;
import li.strolch.runtime.query.enums.StrolchEnum;
import org.junit.Ignore;
import org.junit.Test;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@Ignore
public class EnumTest extends AbstractRestfulTest {
private static final String ROOT_PATH = "strolch/enums";

View File

@ -23,6 +23,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@ -35,12 +36,14 @@ import li.strolch.rest.model.RealmDetail;
import li.strolch.rest.model.RealmOverview;
import li.strolch.rest.model.TypeOverview;
import org.junit.Ignore;
import org.junit.Test;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@SuppressWarnings("nls")
@Ignore
public class InspectorTest extends AbstractRestfulTest {
private static final String ROOT_PATH = "strolch/inspector/";
@ -48,6 +51,9 @@ public class InspectorTest extends AbstractRestfulTest {
@Test
public void shouldGetAgent() {
Response response = target().path("/").request(MediaType.TEXT_HTML).get();
assertEquals(Status.OK.getStatusCode(), response.getStatus());
// expected result
List<RealmOverview> realms = new ArrayList<>(1);
realms.add(new RealmOverview("defaultRealm", 6));
@ -132,8 +138,10 @@ public class InspectorTest extends AbstractRestfulTest {
public void shouldGetResourceTypeDetails() {
// query
Response result = target().path(ROOT_PATH + "defaultRealm/resource/Template")
.request(MediaType.APPLICATION_JSON).get();
WebTarget target = target();
Response result = target.path(ROOT_PATH + "defaultRealm/resource/Template").request(MediaType.APPLICATION_JSON)
.get();
assertEquals(Status.OK.getStatusCode(), result.getStatus());
String entity = result.readEntity(String.class);
String expected = "{\"type\":\"Template\",\"resources\":[{\"id\":\"TestType\",\"name\":\"TestType Template\",\"type\":\"Template\"}]}";

View File

@ -27,11 +27,13 @@ import li.strolch.agent.api.AgentVersion;
import li.strolch.agent.api.ComponentVersion;
import li.strolch.agent.api.VersionQueryResult;
import org.junit.Ignore;
import org.junit.Test;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@Ignore
public class VersionQueryTest extends AbstractRestfulTest {
private static final String ROOT_PATH = "strolch/version";

View File

@ -2,10 +2,15 @@
<UsersAndRoles>
<Users>
<User userId="1" username="agent">
<State>SYSTEM</State>
<Roles>
<Role>agent</Role>
</Roles>
</User>
<User userId="1" username="admin" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918">
<Firstname>Application</Firstname>
<Surname>Administrator</Surname>
<Lastname>Administrator</Lastname>
<State>ENABLED</State>
<Locale>en_GB</Locale>
<Roles>
@ -20,7 +25,7 @@
<User userId="2" username="bob" password="81b637d8fcd2c6da6359e6963113a1170de795e4b725b84d1e0b4cfd9ec58ce9">
<Firstname>Bob</Firstname>
<Surname>Bernstein</Surname>
<Lastname>Bernstein</Lastname>
<State>ENABLED</State>
<Locale>en_GB</Locale>
<Roles>
@ -30,7 +35,7 @@
</User>
<User userId="3" username="jill" password="8cf37351b60f00084392043ce2e6256b96cea92949f90c7abce464cf164fbfa6">
<Firstname>Jill</Firstname>
<Surname>Johnson</Surname>
<Lastname>Johnson</Lastname>
<State>ENABLED</State>
<Locale>en_GB</Locale>
<Roles>
@ -40,7 +45,7 @@
</User>
<User userId="4" username="sysAdmin" password="8cffb494ef5ff3f74a571206e141d4fb84f833e431b98c8b3be43727c4cbddc1">
<Firstname>System User</Firstname>
<Surname>Administrator</Surname>
<Lastname>Administrator</Lastname>
<State>SYSTEM</State>
<Locale>en_GB</Locale>
<Roles>
@ -55,6 +60,12 @@
<Role name="PrivilegeAdmin" />
<Role name="agent">
<Privilege name="li.strolch.agent.impl.StartRealms" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="AppUser">
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>

View File

@ -7,10 +7,19 @@
<verbose>true</verbose>
</Properties>
</Runtime>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
<Properties>
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
</Properties>
</Component>
<Component>
<name>RealmHandler</name>
<api>li.strolch.agent.api.RealmHandler</api>
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
<depends>PrivilegeHandler</depends>
<Properties>
<dataStoreMode>TRANSIENT</dataStoreMode>
<dataStoreFile>StrolchModel.xml</dataStoreFile>
@ -24,14 +33,6 @@
<verbose>true</verbose>
</Properties>
</Component>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.StrolchPrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
<Properties>
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
</Properties>
</Component>
<Component>
<name>RestfulHandler</name>
<api>li.strolch.rest.RestfulStrolchComponent</api>