[New] Added REST API to query Audits

This commit is contained in:
Robert von Burg 2015-04-02 20:25:57 +02:00
parent 9ca7b5f26f
commit 30608ba99a
16 changed files with 570 additions and 2 deletions

View File

@ -67,5 +67,7 @@ public interface AuditTrail {
public long removeAll(StrolchTransaction tx, String type, DateRange dateRange);
public List<Audit> doQuery(StrolchTransaction tx, AuditQuery query);
public <U> List<U> doQuery(StrolchTransaction tx, AuditQuery query, AuditVisitor<U> auditVisitor);
}

View File

@ -31,6 +31,7 @@ import li.strolch.agent.api.AuditTrail;
import li.strolch.model.audit.Audit;
import li.strolch.model.audit.AuditQuery;
import li.strolch.model.audit.AuditVisitor;
import li.strolch.model.audit.NoStrategyAuditVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import ch.eitchnet.utils.collections.DateRange;
import ch.eitchnet.utils.dbc.DBC;
@ -197,6 +198,13 @@ public class AuditingAuditMapFacade implements AuditTrail {
return removed;
}
@Override
public List<Audit> doQuery(StrolchTransaction tx, AuditQuery query) {
List<Audit> elements = this.auditTrail.doQuery(tx, query, new NoStrategyAuditVisitor());
// TODO decide how to audit these queried elements
return elements;
}
@Override
public <U> List<U> doQuery(StrolchTransaction tx, AuditQuery query, AuditVisitor<U> auditVisitor) {
List<U> elements = this.auditTrail.doQuery(tx, query, auditVisitor);

View File

@ -23,6 +23,7 @@ import li.strolch.agent.api.AuditTrail;
import li.strolch.model.audit.Audit;
import li.strolch.model.audit.AuditQuery;
import li.strolch.model.audit.AuditVisitor;
import li.strolch.model.audit.NoStrategyAuditVisitor;
import li.strolch.persistence.api.AuditDao;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.persistence.inmemory.InMemoryAuditDao;
@ -154,6 +155,11 @@ public class CachedAuditTrail implements AuditTrail {
return removed;
}
@Override
public List<Audit> doQuery(StrolchTransaction tx, AuditQuery query) {
return getDbDao(tx).doQuery(query, new NoStrategyAuditVisitor());
}
@Override
public <U> List<U> doQuery(StrolchTransaction tx, AuditQuery query, AuditVisitor<U> auditVisitor) {
return getDbDao(tx).doQuery(query, auditVisitor);

View File

@ -100,6 +100,11 @@ public class NoStrategyAuditTrail implements AuditTrail {
return 0;
}
@Override
public List<Audit> doQuery(StrolchTransaction tx, AuditQuery query) {
return null;
}
@Override
public <U> List<U> doQuery(StrolchTransaction tx, AuditQuery query, AuditVisitor<U> auditVisitor) {
return null;

View File

@ -22,6 +22,7 @@ import li.strolch.agent.api.AuditTrail;
import li.strolch.model.audit.Audit;
import li.strolch.model.audit.AuditQuery;
import li.strolch.model.audit.AuditVisitor;
import li.strolch.model.audit.NoStrategyAuditVisitor;
import li.strolch.persistence.api.AuditDao;
import li.strolch.persistence.api.StrolchTransaction;
import ch.eitchnet.utils.collections.DateRange;
@ -107,6 +108,11 @@ public class TransactionalAuditTrail implements AuditTrail {
return getDao(tx).removeAll(type, dateRange);
}
@Override
public List<Audit> doQuery(StrolchTransaction tx, AuditQuery query) {
return getDao(tx).doQuery(query, new NoStrategyAuditVisitor());
}
@Override
public <U> List<U> doQuery(StrolchTransaction tx, AuditQuery query, AuditVisitor<U> auditVisitor) {
return getDao(tx).doQuery(query, auditVisitor);

View File

@ -18,28 +18,57 @@ package li.strolch.model.audit;
import java.io.Serializable;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.xml.Iso8601DateAdapter;
/**
* Used to log/audit access to {@link StrolchRootElement}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@XmlRootElement(name = "Audit")
@XmlAccessorType(XmlAccessType.NONE)
public class Audit implements Comparable<Audit>, Serializable {
private static final long serialVersionUID = 1L;
@XmlAttribute(name = "id")
private Long id;
@XmlAttribute(name = "username")
private String username;
@XmlAttribute(name = "firstname")
private String firstname;
@XmlAttribute(name = "lastname")
private String lastname;
@XmlElement(name = "date")
@XmlJavaTypeAdapter(Iso8601DateAdapter.class)
private Date date;
@XmlAttribute(name = "elementType")
private String elementType;
@XmlAttribute(name = "elementAccessed")
private String elementAccessed;
@XmlElement(name = "newVersion")
@XmlJavaTypeAdapter(Iso8601DateAdapter.class)
private Date newVersion;
@XmlAttribute(name = "action")
private String action;
@XmlAttribute(name = "accessType")
private AccessType accessType;
/**

View File

@ -32,6 +32,7 @@ public class AuditQuery implements StrolchQuery {
private DateRange dateRange;
public AuditQuery(String elementTypeSelection, DateRange dateRange) {
DBC.PRE.assertNotEmpty("No elementTypeSelection (navigation) set!", elementTypeSelection); //$NON-NLS-1$
DBC.PRE.assertFalse("dateRange may not be unbounded!", dateRange.isUnbounded());
this.elementTypeSelection = elementTypeSelection;
this.dateRange = dateRange;
@ -65,8 +66,6 @@ public class AuditQuery implements StrolchQuery {
}
public void accept(AuditQueryVisitor visitor) {
DBC.PRE.assertNotNull("No elementTypeSelection (navigation) set!", this.elementTypeSelection); //$NON-NLS-1$
DBC.PRE.assertNotNull("No dateRange set!", this.dateRange); //$NON-NLS-1$
visitor.visit(this);
for (AuditSelection selection : this.selections) {
selection.accept(visitor);

View File

@ -19,6 +19,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import li.strolch.rest.endpoint.AuditsService;
import li.strolch.rest.endpoint.AuthenticationService;
import li.strolch.rest.endpoint.EnumQuery;
import li.strolch.rest.endpoint.Inspector;
@ -53,6 +54,7 @@ public class StrolchRestfulClasses {
restfulClasses.add(PrivilegeRolesService.class);
restfulClasses.add(PrivilegePoliciesService.class);
restfulClasses.add(UserSessionsService.class);
restfulClasses.add(AuditsService.class);
Set<Class<?>> providerClasses = new HashSet<>();
providerClasses.add(StrolchRestfulExceptionMapper.class);

View File

@ -0,0 +1,61 @@
package li.strolch.rest.endpoint;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.model.audit.Audit;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulConstants;
import li.strolch.rest.model.AuditQuery;
import li.strolch.rest.model.AuditQueryResult;
import li.strolch.rest.model.StringListResult;
import li.strolch.rest.model.visitor.ToAuditQueryVisitor;
import ch.eitchnet.privilege.model.Certificate;
@Path("strolch/audits")
public class AuditsService {
@GET
@Path("types")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response queryTypes(@Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
StrolchRealm realm = RestfulStrolchComponent.getInstance().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, AuditsService.class)) {
Set<String> data = tx.getAuditTrail().getTypes(tx);
return Response.ok(new StringListResult(new ArrayList<>(data)), MediaType.APPLICATION_JSON).build();
}
}
@POST
@Path("query")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response queryAudits(AuditQuery query, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
StrolchRealm realm = RestfulStrolchComponent.getInstance().getContainer().getRealm(cert);
try (StrolchTransaction tx = realm.openTx(cert, AuditsService.class)) {
li.strolch.model.audit.AuditQuery auditQuery = new ToAuditQueryVisitor().create(query);
List<Audit> audits = tx.getAuditTrail().doQuery(tx, auditQuery);
return Response.ok(new AuditQueryResult(audits), MediaType.APPLICATION_JSON).build();
}
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.rest.model;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import li.strolch.model.audit.AccessType;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@XmlRootElement(name = "ActionSelection")
@XmlAccessorType(XmlAccessType.NONE)
public class ActionSelection {
@XmlAttribute(name = "action")
private String action;
@XmlElement(name = "accessTypes")
private List<AccessType> accessTypes;
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public List<AccessType> getAccessTypes() {
return accessTypes;
}
public void setAccessTypes(List<AccessType> accessTypes) {
this.accessTypes = accessTypes;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.rest.model;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@XmlRootElement(name = "AuditQuery")
@XmlAccessorType(XmlAccessType.NONE)
public class AuditQuery {
@XmlAttribute(name = "elementType")
private String elementType;
@XmlAttribute(name = "elementId")
private String elementId;
@XmlElement(name = "identity")
private IdentitySelection identity;
@XmlElement(name = "action")
private ActionSelection action;
@XmlElement(name = "dateRange")
private DateRange dateRange;
public String getElementType() {
return elementType;
}
public void setElementType(String elementType) {
this.elementType = elementType;
}
public String getElementId() {
return elementId;
}
public void setElementId(String elementId) {
this.elementId = elementId;
}
public IdentitySelection getIdentity() {
return identity;
}
public void setIdentity(IdentitySelection identity) {
this.identity = identity;
}
public ActionSelection getAction() {
return action;
}
public void setAction(ActionSelection action) {
this.action = action;
}
public DateRange getDateRange() {
return dateRange;
}
public void setDateRange(DateRange dateRange) {
this.dateRange = dateRange;
}
}

View File

@ -0,0 +1,48 @@
package li.strolch.rest.model;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import li.strolch.model.audit.Audit;
import ch.eitchnet.utils.helper.StringHelper;
@XmlRootElement(name = "AuditQueryResult")
@XmlAccessorType(XmlAccessType.NONE)
public class AuditQueryResult {
@XmlAttribute(name = "msg")
private String msg;
@XmlElement(name = "audits")
private List<Audit> audits;
public AuditQueryResult() {
this.msg = StringHelper.DASH;
}
public AuditQueryResult(List<Audit> audits) {
this.msg = StringHelper.DASH;
this.audits = audits;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public List<Audit> getAudits() {
return audits;
}
public void setAudits(List<Audit> audits) {
this.audits = audits;
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.rest.model;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import li.strolch.model.xml.Iso8601DateAdapter;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@XmlRootElement(name = "DateRange")
@XmlAccessorType(XmlAccessType.NONE)
public class DateRange {
@XmlAttribute(name = "fromInclusive")
private boolean fromInclusive;
@XmlAttribute(name = "toInclusive")
private boolean toInclusive;
@XmlElement(name = "fromDate")
@XmlJavaTypeAdapter(Iso8601DateAdapter.class)
private Date fromDate;
@XmlElement(name = "toDate")
@XmlJavaTypeAdapter(Iso8601DateAdapter.class)
private Date toDate;
public boolean isFromInclusive() {
return fromInclusive;
}
public void setFromInclusive(boolean fromInclusive) {
this.fromInclusive = fromInclusive;
}
public boolean isToInclusive() {
return toInclusive;
}
public void setToInclusive(boolean toInclusive) {
this.toInclusive = toInclusive;
}
public Date getFromDate() {
return fromDate;
}
public void setFromDate(Date fromDate) {
this.fromDate = fromDate;
}
public Date getToDate() {
return toDate;
}
public void setToDate(Date toDate) {
this.toDate = toDate;
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.rest.model;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@XmlRootElement(name = "IdentitySelection")
@XmlAccessorType(XmlAccessType.NONE)
public class IdentitySelection {
@XmlAttribute(name = "username")
private String username;
@XmlAttribute(name = "firstname")
private String firstname;
@XmlAttribute(name = "lastname")
private String lastname;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}

View File

@ -0,0 +1,47 @@
package li.strolch.rest.model;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import ch.eitchnet.utils.helper.StringHelper;
@XmlRootElement(name = "StringListResult")
@XmlAccessorType(XmlAccessType.NONE)
public class StringListResult {
@XmlAttribute(name = "msg")
private String msg;
@XmlElement(name = "data")
private List<String> data;
public StringListResult() {
this.msg = StringHelper.DASH;
}
public StringListResult(List<String> data) {
this.msg = StringHelper.DASH;
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
}

View File

@ -0,0 +1,70 @@
package li.strolch.rest.model.visitor;
import java.util.List;
import li.strolch.model.audit.AccessType;
import li.strolch.rest.model.ActionSelection;
import li.strolch.rest.model.AuditQuery;
import li.strolch.rest.model.DateRange;
import li.strolch.rest.model.IdentitySelection;
import ch.eitchnet.utils.StringMatchMode;
import ch.eitchnet.utils.helper.StringHelper;
public class ToAuditQueryVisitor {
public li.strolch.model.audit.AuditQuery create(AuditQuery query) {
// validate element type
String elementType = query.getElementType();
if (StringHelper.isEmpty(elementType)) {
throw new IllegalArgumentException("elementType on AuditQuery is empty!");
}
// validate date range
DateRange dateRange = query.getDateRange();
if (dateRange == null || dateRange.getFromDate() == null || dateRange.getToDate() == null) {
throw new IllegalArgumentException("DateRange on AuditQuery is not valid or is missing!");
}
ch.eitchnet.utils.collections.DateRange dr = new ch.eitchnet.utils.collections.DateRange().from(
dateRange.getFromDate(), dateRange.isFromInclusive()).to(dateRange.getToDate(),
dateRange.isToInclusive());
// create query
li.strolch.model.audit.AuditQuery auditQuery = new li.strolch.model.audit.AuditQuery(elementType, dr);
// element Id
String elementId = query.getElementId();
if (StringHelper.isNotEmpty(elementId)) {
auditQuery.element().elementsAccessed(StringMatchMode.ci(), elementId);
}
// action
ActionSelection action = query.getAction();
if (action != null) {
String actionS = action.getAction();
li.strolch.model.audit.ActionSelection actionSelection = auditQuery.action();
if (StringHelper.isNotEmpty(actionS))
actionSelection.actions(StringMatchMode.ci(), actionS);
List<AccessType> accessTypes = action.getAccessTypes();
if (accessTypes != null && !accessTypes.isEmpty()) {
AccessType[] accessTypesArr = new AccessType[accessTypes.size()];
accessTypes.toArray(accessTypesArr);
actionSelection.accessTypes(accessTypesArr);
}
}
// identity
IdentitySelection identity = query.getIdentity();
if (identity != null) {
li.strolch.model.audit.IdentitySelection identitySelection = auditQuery.identity();
if (StringHelper.isNotEmpty(identity.getFirstname()))
identitySelection.firstnames(StringMatchMode.ci(), identity.getFirstname());
if (StringHelper.isNotEmpty(identity.getLastname()))
identitySelection.lastnames(StringMatchMode.ci(), identity.getLastname());
if (StringHelper.isNotEmpty(identity.getUsername()))
identitySelection.usernames(StringMatchMode.ci(), identity.getUsername());
}
return auditQuery;
}
}