NIFI-6384:

- Adding auditing of parameter contexts.

This closes #3699.

Signed-off-by: Mark Payne <markap14@hotmail.com>
This commit is contained in:
Matt Gilman 2019-09-03 16:38:35 -04:00 committed by Mark Payne
parent 7af710f168
commit f867e92606
5 changed files with 326 additions and 2 deletions

View File

@ -31,6 +31,7 @@ public enum Component {
Connection,
ControllerService,
ReportingTask,
ParameterContext,
AccessPolicy,
User,
UserGroup;

View File

@ -0,0 +1,284 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.nifi.audit;
import org.apache.nifi.action.Action;
import org.apache.nifi.action.Component;
import org.apache.nifi.action.FlowChangeAction;
import org.apache.nifi.action.Operation;
import org.apache.nifi.action.details.FlowChangeConfigureDetails;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.parameter.Parameter;
import org.apache.nifi.parameter.ParameterContext;
import org.apache.nifi.web.api.dto.ParameterContextDTO;
import org.apache.nifi.web.api.dto.ParameterDTO;
import org.apache.nifi.web.dao.ParameterContextDAO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Audits processor creation/removal and configuration changes.
*/
@Aspect
public class ParameterContextAuditor extends NiFiAuditor {
private static final Logger logger = LoggerFactory.getLogger(ParameterContextAuditor.class);
/**
* Audits the creation of parameter contexts via createParameterContext().
*
* @param proceedingJoinPoint join point
* @param parameterContextDTO dto
* @param parameterContextDAO dao
* @return context
* @throws Throwable ex
*/
@Around("within(org.apache.nifi.web.dao.ParameterContextDAO+) && "
+ "execution(org.apache.nifi.parameter.ParameterContext createParameterContext(org.apache.nifi.web.api.dto.ParameterContextDTO)) && "
+ "args(parameterContextDTO) && "
+ "target(parameterContextDAO)")
public ParameterContext createParameterContextAdvice(ProceedingJoinPoint proceedingJoinPoint, ParameterContextDTO parameterContextDTO, ParameterContextDAO parameterContextDAO) throws Throwable {
// update the processor state
ParameterContext parameterContext = (ParameterContext) proceedingJoinPoint.proceed();
// get the current user
NiFiUser user = NiFiUserUtils.getNiFiUser();
// ensure the user was found
if (user != null) {
// create a parameter context action
Collection<Action> actions = new ArrayList<>();
// if no exceptions were thrown, add the processor action...
final Action createAction = generateAuditRecord(parameterContext, Operation.Add);
actions.add(createAction);
// determine the updated values
Map<String, String> updatedValues = extractConfiguredParameterContextValues(parameterContext, parameterContextDTO);
// determine the actions performed in this request
final Date actionTimestamp = new Date(createAction.getTimestamp().getTime() + 1);
determineActions(user, parameterContext, actions, actionTimestamp, updatedValues, Collections.EMPTY_MAP);
// save the actions
saveActions(actions, logger);
}
return parameterContext;
}
/**
* Audits the configuration of a parameter context via updateParameterContext().
*
* @param proceedingJoinPoint join point
* @param parameterContextDTO dto
* @param parameterContextDAO dao
* @return parameter context
* @throws Throwable ex
*/
@Around("within(org.apache.nifi.web.dao.ParameterContextDAO+) && "
+ "execution(org.apache.nifi.parameter.ParameterContext updateParameterContext(org.apache.nifi.web.api.dto.ParameterContextDTO)) && "
+ "args(parameterContextDTO) && "
+ "target(parameterContextDAO)")
public ParameterContext updateParameterContextAdvice(ProceedingJoinPoint proceedingJoinPoint, ParameterContextDTO parameterContextDTO, ParameterContextDAO parameterContextDAO) throws Throwable {
// determine the initial values for each property/setting that's changing
ParameterContext parameterContext = parameterContextDAO.getParameterContext(parameterContextDTO.getId());
final Map<String, String> values = extractConfiguredParameterContextValues(parameterContext, parameterContextDTO);
// update the processor state
final ParameterContext updatedParameterContext = (ParameterContext) proceedingJoinPoint.proceed();
// if no exceptions were thrown, add the processor action...
parameterContext = parameterContextDAO.getParameterContext(updatedParameterContext.getIdentifier());
// get the current user
NiFiUser user = NiFiUserUtils.getNiFiUser();
// ensure the user was found
if (user != null) {
// determine the updated values
Map<String, String> updatedValues = extractConfiguredParameterContextValues(parameterContext, parameterContextDTO);
// create a parameter context action
Date actionTimestamp = new Date();
Collection<Action> actions = new ArrayList<>();
// determine the actions performed in this request
determineActions(user, parameterContext, actions, actionTimestamp, updatedValues, values);
// ensure there are actions to record
if (!actions.isEmpty()) {
// save the actions
saveActions(actions, logger);
}
}
return updatedParameterContext;
}
/**
* Extract configuration changes.
*
* @param user the user
* @param parameterContext the parameter context
* @param actions actions list
* @param actionTimestamp timestamp of the request
* @param updatedValues the updated values
* @param values the current values
*/
private void determineActions(final NiFiUser user, final ParameterContext parameterContext, final Collection<Action> actions,
final Date actionTimestamp, final Map<String, String> updatedValues, final Map<String, String> values) {
// go through each updated value
for (String key : updatedValues.keySet()) {
String newValue = updatedValues.get(key);
String oldValue = values.get(key);
Operation operation = null;
// determine the type of operation
if (oldValue == null || newValue == null || !newValue.equals(oldValue)) {
operation = Operation.Configure;
}
// create a configuration action accordingly
if (operation != null) {
// clear the value if this property is sensitive
final Parameter parameter = parameterContext.getParameter(key).orElse(null);
if (parameter != null && parameter.getDescriptor().isSensitive()) {
if (newValue != null) {
newValue = "********";
}
if (oldValue != null) {
oldValue = "********";
}
}
final FlowChangeConfigureDetails actionDetails = new FlowChangeConfigureDetails();
actionDetails.setName(key);
actionDetails.setValue(newValue);
actionDetails.setPreviousValue(oldValue);
// create a configuration action
FlowChangeAction configurationAction = new FlowChangeAction();
configurationAction.setUserIdentity(user.getIdentity());
configurationAction.setOperation(operation);
configurationAction.setTimestamp(actionTimestamp);
configurationAction.setSourceId(parameterContext.getIdentifier());
configurationAction.setSourceName(parameterContext.getName());
configurationAction.setSourceType(Component.ParameterContext);
configurationAction.setActionDetails(actionDetails);
actions.add(configurationAction);
}
}
}
/**
* Audits the removal of a parameter context via deleteParameterContext().
*
* @param proceedingJoinPoint join point
* @param parameterContextId parameterContextId
* @param parameterContextDAO dao
* @throws Throwable ex
*/
@Around("within(org.apache.nifi.web.dao.ParameterContextDAO+) && "
+ "execution(void deleteParameterContext(java.lang.String)) && "
+ "args(parameterContextId) && "
+ "target(parameterContextDAO)")
public void removeParameterContextAdvice(ProceedingJoinPoint proceedingJoinPoint, String parameterContextId, ParameterContextDAO parameterContextDAO) throws Throwable {
// get the parameter context before removing it
ParameterContext parameterContext = parameterContextDAO.getParameterContext(parameterContextId);
// remove the processor
proceedingJoinPoint.proceed();
// if no exceptions were thrown, add removal actions...
// audit the processor removal
final Action action = generateAuditRecord(parameterContext, Operation.Remove);
// save the actions
if (action != null) {
saveAction(action, logger);
}
}
/**
* Generates an audit record for the creation of a ParameterContext.
*
* @param parameterContext parameterContext
* @param operation operation
* @return action
*/
private Action generateAuditRecord(ParameterContext parameterContext, Operation operation) {
FlowChangeAction action = null;
// get the current user
NiFiUser user = NiFiUserUtils.getNiFiUser();
// ensure the user was found
if (user != null) {
// create the processor action for adding this processor
action = new FlowChangeAction();
action.setUserIdentity(user.getIdentity());
action.setOperation(operation);
action.setTimestamp(new Date());
action.setSourceId(parameterContext.getIdentifier());
action.setSourceName(parameterContext.getName());
action.setSourceType(Component.ParameterContext);
}
return action;
}
/**
* Extracts the values for the configured fields from the specified ParameterContext.
*/
private Map<String, String> extractConfiguredParameterContextValues(ParameterContext parameterContext, ParameterContextDTO parameterContextDTO) {
Map<String, String> values = new HashMap<>();
if (parameterContextDTO.getDescription() != null) {
values.put("Name", parameterContext.getName());
}
if (parameterContextDTO.getDescription() != null) {
values.put("Description", parameterContext.getDescription());
}
if (parameterContextDTO.getParameters() != null) {
parameterContextDTO.getParameters().forEach(parameterEntity -> {
final ParameterDTO parameterDTO = parameterEntity.getParameter();
final Parameter parameter = parameterContext.getParameter(parameterDTO.getName()).orElse(null);
if (parameter == null) {
values.put(parameterDTO.getName(), null);
} else {
values.put(parameterDTO.getName(), parameter.getValue());
}
});
}
return values;
}
}

View File

@ -28,6 +28,7 @@ import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.parameter.ParameterContext;
import org.apache.nifi.registry.flow.VersionControlInformation;
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
import org.apache.nifi.web.api.dto.VariableRegistryDTO;
@ -97,6 +98,7 @@ public class ProcessGroupAuditor extends NiFiAuditor {
ProcessGroup processGroup = processGroupDAO.getProcessGroup(processGroupDTO.getId());
String name = processGroup.getName();
ParameterContext parameterContext = processGroup.getParameterContext();
String comments = processGroup.getComments();
// perform the underlying operation
@ -113,7 +115,7 @@ public class ProcessGroupAuditor extends NiFiAuditor {
if (name != null && updatedProcessGroup.getName() != null && !name.equals(updatedProcessGroup.getName())) {
// create the config details
FlowChangeConfigureDetails configDetails = new FlowChangeConfigureDetails();
configDetails.setName("name");
configDetails.setName("Name");
configDetails.setValue(updatedProcessGroup.getName());
configDetails.setPreviousValue(name);
@ -124,13 +126,42 @@ public class ProcessGroupAuditor extends NiFiAuditor {
if (comments != null && updatedProcessGroup.getComments() != null && !comments.equals(updatedProcessGroup.getComments())) {
// create the config details
FlowChangeConfigureDetails configDetails = new FlowChangeConfigureDetails();
configDetails.setName("comments");
configDetails.setName("Comments");
configDetails.setValue(updatedProcessGroup.getComments());
configDetails.setPreviousValue(comments);
details.add(configDetails);
}
// see if the parameter context has changed
if (parameterContext != null && updatedProcessGroup.getParameterContext() != null) {
if (!parameterContext.getIdentifier().equals(updatedProcessGroup.getParameterContext().getIdentifier())) {
// create the config details
FlowChangeConfigureDetails configDetails = new FlowChangeConfigureDetails();
configDetails.setName("Parameter Context");
configDetails.setValue(updatedProcessGroup.getParameterContext().getIdentifier());
configDetails.setPreviousValue(parameterContext.getIdentifier());
details.add(configDetails);
}
} else if (updatedProcessGroup.getParameterContext() != null) {
// create the config details
FlowChangeConfigureDetails configDetails = new FlowChangeConfigureDetails();
configDetails.setName("Parameter Context");
configDetails.setValue(updatedProcessGroup.getParameterContext().getIdentifier());
configDetails.setPreviousValue(null);
details.add(configDetails);
} else if (parameterContext != null) {
// create the config details
FlowChangeConfigureDetails configDetails = new FlowChangeConfigureDetails();
configDetails.setName("Parameter Context");
configDetails.setValue(null);
configDetails.setPreviousValue(parameterContext.getIdentifier());
details.add(configDetails);
}
// hold all actions
Collection<Action> actions = new ArrayList<>();

View File

@ -5016,6 +5016,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
case Connection:
authorizable = authorizableLookup.getConnection(sourceId).getAuthorizable();
break;
case ParameterContext:
authorizable = authorizableLookup.getParameterContext(sourceId);
break;
case AccessPolicy:
authorizable = authorizableLookup.getAccessPolicyById(sourceId);
break;

View File

@ -546,6 +546,11 @@
<property name="auditService" ref="auditService"/>
<property name="processGroupDAO" ref="processGroupDAO"/>
</bean>
<bean id="parameterContextAuditor" class="org.apache.nifi.audit.ParameterContextAuditor">
<property name="serviceFacade" ref="serviceFacade"/>
<property name="auditService" ref="auditService"/>
<property name="processGroupDAO" ref="processGroupDAO"/>
</bean>
<bean id="policyAuditor" class="org.apache.nifi.audit.AccessPolicyAuditor">
<property name="serviceFacade" ref="serviceFacade"/>
<property name="auditService" ref="auditService"/>