Search in sources :

Example 1 with ExtendedInfo

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;
}
Also used : DocumentRef(org.nuxeo.ecm.core.api.DocumentRef) ArrayList(java.util.ArrayList) SynchronizationRoots(org.nuxeo.drive.service.SynchronizationRoots) IdRef(org.nuxeo.ecm.core.api.IdRef) ExtendedInfo(org.nuxeo.ecm.platform.audit.api.ExtendedInfo) FileSystemItemChange(org.nuxeo.drive.service.FileSystemItemChange) TooManyChangesException(org.nuxeo.drive.service.TooManyChangesException) LogEntry(org.nuxeo.ecm.platform.audit.api.LogEntry) NuxeoDriveManager(org.nuxeo.drive.service.NuxeoDriveManager)

Example 2 with ExtendedInfo

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;
}
Also used : AuditLogger(org.nuxeo.ecm.platform.audit.api.AuditLogger) HashMap(java.util.HashMap) ExtendedInfo(org.nuxeo.ecm.platform.audit.api.ExtendedInfo) LogEntry(org.nuxeo.ecm.platform.audit.api.LogEntry)

Example 3 with ExtendedInfo

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;
}
Also used : ArrayList(java.util.ArrayList) ExtendedInfo(org.nuxeo.ecm.platform.audit.api.ExtendedInfo) LogEntry(org.nuxeo.ecm.platform.audit.api.LogEntry)

Example 4 with ExtendedInfo

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;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) AuditReader(org.nuxeo.ecm.platform.audit.api.AuditReader) ExtendedInfo(org.nuxeo.ecm.platform.audit.api.ExtendedInfo) LogEntry(org.nuxeo.ecm.platform.audit.api.LogEntry)

Aggregations

ExtendedInfo (org.nuxeo.ecm.platform.audit.api.ExtendedInfo)4 LogEntry (org.nuxeo.ecm.platform.audit.api.LogEntry)4 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)2 List (java.util.List)1 FileSystemItemChange (org.nuxeo.drive.service.FileSystemItemChange)1 NuxeoDriveManager (org.nuxeo.drive.service.NuxeoDriveManager)1 SynchronizationRoots (org.nuxeo.drive.service.SynchronizationRoots)1 TooManyChangesException (org.nuxeo.drive.service.TooManyChangesException)1 DocumentRef (org.nuxeo.ecm.core.api.DocumentRef)1 IdRef (org.nuxeo.ecm.core.api.IdRef)1 AuditLogger (org.nuxeo.ecm.platform.audit.api.AuditLogger)1 AuditReader (org.nuxeo.ecm.platform.audit.api.AuditReader)1