use of org.nuxeo.ecm.platform.audit.api.ExtendedInfo in project nuxeo-drive-server by nuxeo.
the class AuditChangeFinder method getFileSystemChanges.
protected List<FileSystemItemChange> getFileSystemChanges(CoreSession session, Set<IdRef> lastActiveRootRefs, SynchronizationRoots activeRoots, Set<String> collectionSyncRootMemberIds, long lowerBound, long upperBound, boolean integerBounds, int limit) throws TooManyChangesException {
String principalName = session.getPrincipal().getName();
List<FileSystemItemChange> changes = new ArrayList<FileSystemItemChange>();
// Note: lastActiveRootRefs is not used: we could remove it from the
// public API
// and from the client as well but it might be useful to optimize future
// alternative implementations FileSystemChangeFinder component so it
// might
// be better to leave it part of the public API as currently.
// Find changes from the log under active roots or events that are
// linked to the un-registration or deletion of formerly synchronized
// roots
List<LogEntry> entries = queryAuditEntries(session, activeRoots, collectionSyncRootMemberIds, lowerBound, upperBound, integerBounds, limit);
// query with the actual active roots.
for (LogEntry entry : entries) {
if (NuxeoDriveEvents.EVENT_CATEGORY.equals(entry.getCategory())) {
if (log.isDebugEnabled()) {
log.debug(String.format("Detected sync root change for user '%s' in audit log:" + " invalidating the root cache and refetching the changes.", principalName));
}
NuxeoDriveManager driveManager = Framework.getService(NuxeoDriveManager.class);
driveManager.invalidateSynchronizationRootsCache(principalName);
driveManager.invalidateCollectionSyncRootMemberCache(principalName);
Map<String, SynchronizationRoots> synchronizationRoots = driveManager.getSynchronizationRoots(session.getPrincipal());
SynchronizationRoots updatedActiveRoots = synchronizationRoots.get(session.getRepositoryName());
Set<String> updatedCollectionSyncRootMemberIds = driveManager.getCollectionSyncRootMemberIds(session.getPrincipal()).get(session.getRepositoryName());
entries = queryAuditEntries(session, updatedActiveRoots, updatedCollectionSyncRootMemberIds, lowerBound, upperBound, integerBounds, limit);
break;
}
}
if (entries.size() >= limit) {
throw new TooManyChangesException("Too many changes found in the audit logs.");
}
for (LogEntry entry : entries) {
if (log.isDebugEnabled()) {
log.debug(String.format("Handling log entry %s", entry));
}
FileSystemItemChange change = null;
DocumentRef docRef = new IdRef(entry.getDocUUID());
ExtendedInfo fsIdInfo = entry.getExtendedInfos().get("fileSystemItemId");
if (fsIdInfo != null) {
// been updated, we just know the FileSystemItem id and name.
if (log.isDebugEnabled()) {
log.debug(String.format("Found extended info in audit log entry: document has been deleted, moved," + " is an unregistered synchronization root or its security has been updated," + " we just know the FileSystemItem id and name."));
}
boolean isChangeSet = false;
// current user still has access to the document.
if (!"deleted".equals(entry.getEventId()) && session.exists(docRef)) {
change = getFileSystemItemChange(session, docRef, entry, fsIdInfo.getValue(String.class));
if (change != null) {
if (NuxeoDriveEvents.MOVED_EVENT.equals(entry.getEventId())) {
// virtual event.
if (log.isDebugEnabled()) {
log.debug(String.format("Document %s (%s) has been moved to another synchronzation root, not adding entry to the change summary.", entry.getDocPath(), docRef));
}
continue;
}
isChangeSet = true;
}
}
if (!isChangeSet) {
// FileSystemItem id and name to the FileSystemItemChange entry.
if (log.isDebugEnabled()) {
log.debug(String.format("Document %s (%s) doesn't exist or is not adaptable as a FileSystemItem, only providing the FileSystemItem id and name to the FileSystemItemChange entry.", entry.getDocPath(), docRef));
}
String fsId = fsIdInfo.getValue(String.class);
String eventId;
if (NuxeoDriveEvents.MOVED_EVENT.equals(entry.getEventId())) {
// Move to a non synchronization root
eventId = NuxeoDriveEvents.DELETED_EVENT;
} else {
// Deletion, unregistration or security update
eventId = entry.getEventId();
}
change = new FileSystemItemChangeImpl(eventId, entry.getEventDate().getTime(), entry.getRepositoryId(), entry.getDocUUID(), fsId, null);
}
if (log.isDebugEnabled()) {
log.debug(String.format("Adding FileSystemItemChange entry to the change summary: %s", change));
}
changes.add(change);
} else {
// unregistered synchronization root nor a security update denying access to the current user.
if (log.isDebugEnabled()) {
log.debug(String.format("No extended info found in audit log entry %s (%s): this is not a deleted document, a moved document," + " an unregistered synchronization root nor a security update denying access to the current user.", entry.getDocPath(), docRef));
}
if (!session.exists(docRef)) {
if (log.isDebugEnabled()) {
log.debug(String.format("Document %s (%s) doesn't exist, not adding entry to the change summary.", entry.getDocPath(), docRef));
}
// try to propagate this event.
continue;
}
// Let's try to adapt the document as a FileSystemItem to
// provide it to the FileSystemItemChange entry.
change = getFileSystemItemChange(session, docRef, entry, null);
if (change == null) {
// Non-adaptable documents are ignored
if (log.isDebugEnabled()) {
log.debug(String.format("Document %s (%s) is not adaptable as a FileSystemItem, not adding any entry to the change summary.", entry.getDocPath(), docRef));
}
} else {
if (log.isDebugEnabled()) {
log.debug(String.format("Adding FileSystemItemChange entry to the change summary: %s", change));
}
changes.add(change);
}
}
}
return changes;
}
use of org.nuxeo.ecm.platform.audit.api.ExtendedInfo in project nuxeo-drive-server by nuxeo.
the class NuxeoDriveFileSystemDeletionListener method computeLogEntry.
protected LogEntry computeLogEntry(String eventName, Date eventDate, String docId, String docPath, String principal, String docType, String repositoryName, String currentLifeCycleState, String impactedUserName, FileSystemItem fsItem) {
AuditLogger logger = Framework.getService(AuditLogger.class);
LogEntry entry = logger.newLogEntry();
entry.setEventId(eventName);
entry.setEventDate(eventDate);
entry.setCategory(NuxeoDriveEvents.EVENT_CATEGORY);
entry.setDocUUID(docId);
entry.setDocPath(docPath);
entry.setPrincipalName(principal);
entry.setDocType(docType);
entry.setRepositoryId(repositoryName);
entry.setDocLifeCycle(currentLifeCycleState);
Map<String, ExtendedInfo> extendedInfos = new HashMap<String, ExtendedInfo>();
if (impactedUserName != null) {
extendedInfos.put("impactedUserName", logger.newExtendedInfo(impactedUserName));
}
// We do not serialize the whole object as it's too big to fit in a
// StringInfo column
extendedInfos.put("fileSystemItemId", logger.newExtendedInfo(fsItem.getId()));
extendedInfos.put("fileSystemItemName", logger.newExtendedInfo(fsItem.getName()));
entry.setExtendedInfos(extendedInfos);
return entry;
}
use of org.nuxeo.ecm.platform.audit.api.ExtendedInfo in project nuxeo-drive-server by nuxeo.
the class ESAuditChangeFinder method queryAuditEntries.
@Override
protected List<LogEntry> queryAuditEntries(CoreSession session, SynchronizationRoots activeRoots, Set<String> collectionSyncRootMemberIds, long lowerBound, long upperBound, boolean integerBounds, int limit) {
List<LogEntry> entries = queryESAuditEntries(session, activeRoots, collectionSyncRootMemberIds, lowerBound, upperBound, integerBounds, limit);
// Post filter the output to remove (un)registration that are unrelated
// to the current user.
// TODO move this to the ES query
List<LogEntry> postFilteredEntries = new ArrayList<>();
String principalName = session.getPrincipal().getName();
for (LogEntry entry : entries) {
ExtendedInfo impactedUserInfo = entry.getExtendedInfos().get("impactedUserName");
if (impactedUserInfo != null && !principalName.equals(impactedUserInfo.getValue(String.class))) {
// ignore event that only impact other users
continue;
}
if (log.isDebugEnabled()) {
if (log.isDebugEnabled()) {
log.debug(String.format("Change detected: %s", entry));
}
}
postFilteredEntries.add(entry);
}
return postFilteredEntries;
}
use of org.nuxeo.ecm.platform.audit.api.ExtendedInfo in project nuxeo-drive-server by nuxeo.
the class AuditChangeFinder method queryAuditEntries.
@SuppressWarnings("unchecked")
protected List<LogEntry> queryAuditEntries(CoreSession session, SynchronizationRoots activeRoots, Set<String> collectionSyncRootMemberIds, long lowerBound, long upperBound, boolean integerBounds, int limit) {
AuditReader auditService = Framework.getService(AuditReader.class);
// Set fixed query parameters
Map<String, Object> params = new HashMap<String, Object>();
params.put("repositoryId", session.getRepositoryName());
// Build query and set dynamic parameters
StringBuilder auditQuerySb = new StringBuilder("from LogEntry log where ");
auditQuerySb.append("log.repositoryId = :repositoryId");
auditQuerySb.append(" and ");
auditQuerySb.append("(");
if (!activeRoots.getPaths().isEmpty()) {
// detect changes under the currently active roots for the
// current user
auditQuerySb.append("(");
auditQuerySb.append("log.category = 'eventDocumentCategory'");
// TODO: don't hardcode event ids (contribute them?)
auditQuerySb.append(" and (log.eventId = 'documentCreated' or log.eventId = 'documentModified' or log.eventId = 'documentMoved' or log.eventId = 'documentCreatedByCopy' or log.eventId = 'documentRestored' or log.eventId = 'addedToCollection' or log.eventId = 'documentProxyPublished' or log.eventId = 'documentLocked' or log.eventId = 'documentUnlocked')");
auditQuerySb.append(" or ");
auditQuerySb.append("log.category = 'eventLifeCycleCategory'");
auditQuerySb.append(" and log.eventId = 'lifecycle_transition_event' and log.docLifeCycle != 'deleted' ");
auditQuerySb.append(") and (");
auditQuerySb.append("(");
auditQuerySb.append(getCurrentRootFilteringClause(activeRoots.getPaths(), params));
auditQuerySb.append(")");
if (collectionSyncRootMemberIds != null && !collectionSyncRootMemberIds.isEmpty()) {
auditQuerySb.append(" or (");
auditQuerySb.append(getCollectionSyncRootFilteringClause(collectionSyncRootMemberIds, params));
auditQuerySb.append(")");
}
auditQuerySb.append(") or ");
}
// Detect any root (un-)registration changes for the roots previously
// seen by the current user.
// Exclude 'rootUnregistered' since root unregistration is covered by a
// "deleted" virtual event.
auditQuerySb.append("(");
auditQuerySb.append("log.category = '");
auditQuerySb.append(NuxeoDriveEvents.EVENT_CATEGORY);
auditQuerySb.append("' and log.eventId != 'rootUnregistered'");
auditQuerySb.append(")");
auditQuerySb.append(") and (");
auditQuerySb.append(getJPARangeClause(lowerBound, upperBound, integerBounds, params));
// we intentionally sort by eventDate even if the range filtering is
// done on the log id: eventDate is useful to reflect the ordering of
// events occurring inside the same transaction while the
// monotonic behavior of log id is useful for ensuring that consecutive
// range queries to the audit won't miss any events even when long
// running transactions are logged after a delay.
auditQuerySb.append(") order by log.repositoryId asc, log.eventDate desc");
String auditQuery = auditQuerySb.toString();
if (log.isDebugEnabled()) {
log.debug("Querying audit log for changes: " + auditQuery + " with params: " + params);
}
List<LogEntry> entries = (List<LogEntry>) auditService.nativeQuery(auditQuery, params, 1, limit);
// Post filter the output to remove (un)registration that are unrelated
// to the current user.
List<LogEntry> postFilteredEntries = new ArrayList<LogEntry>();
String principalName = session.getPrincipal().getName();
for (LogEntry entry : entries) {
ExtendedInfo impactedUserInfo = entry.getExtendedInfos().get("impactedUserName");
if (impactedUserInfo != null && !principalName.equals(impactedUserInfo.getValue(String.class))) {
// ignore event that only impact other users
continue;
}
if (log.isDebugEnabled()) {
log.debug(String.format("Change detected: %s", entry));
}
postFilteredEntries.add(entry);
}
return postFilteredEntries;
}
Aggregations