Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIFI-13560 Change Parameter Provider handling to avoid storing values #9102

Merged
merged 1 commit into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,20 @@ public void fetchParameters() {
}
}

@Override
public Optional<ParameterGroup> findFetchedParameterGroup(final String parameterGroupName) {
Objects.requireNonNull(parameterGroupName, "Parameter Group Name required");

readLock.lock();
try {
return fetchedParameterGroups.stream()
.filter(parameterGroup -> parameterGroup.getGroupName().equals(parameterGroupName))
.findFirst();
} finally {
readLock.unlock();
}
}

@Override
public void verifyCanApplyParameters(final Collection<ParameterGroupConfiguration> parameterGroupConfigurations) {
if (fetchedParameterGroups.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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.parameter;

import java.util.Objects;

/**
* Filter values and return null for Parameter values with sensitive descriptors
*/
public class FilterSensitiveParameterValueMapper implements ParameterValueMapper {
/**
* Get mapped Parameter value based on properties
*
* @param parameter Parameter with descriptor of attributes for mapping
* @param value Parameter value to be mapped
* @return Mapped Parameter value
*/
@Override
public String getMapped(final Parameter parameter, final String value) {
Objects.requireNonNull(parameter, "Parameter required");

final ParameterDescriptor descriptor = parameter.getDescriptor();
final String mapped;

if (descriptor.isSensitive()) {
mapped = null;
} else {
mapped = value;
}

return mapped;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.parameter;

/**
* Abstraction for mapping Parameter values from runtime representation to versioned representation
*/
public interface ParameterValueMapper {
/**
* Get mapped Parameter value based on properties
*
* @param parameter Parameter with descriptor of attributes for mapping
* @param value Parameter value to be mapped
* @return Mapped Parameter value
*/
String getMapped(Parameter parameter, String value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.parameter;

import org.apache.nifi.registry.flow.mapping.SensitiveValueEncryptor;

import java.util.Objects;

/**
* Standard implementation with encryptor for sensitive values
*/
public class StandardParameterValueMapper implements ParameterValueMapper {
static final String PROVIDED_MAPPING = "provided:parameter";

private static final String ENCRYPTED_FORMAT = "enc{%s}";

private final SensitiveValueEncryptor sensitiveValueEncryptor;

public StandardParameterValueMapper(final SensitiveValueEncryptor sensitiveValueEncryptor) {
this.sensitiveValueEncryptor = sensitiveValueEncryptor;
}

/**
* Get mapped Parameter value based on properties
*
* @param parameter Parameter with descriptor of attributes for mapping
* @param value Parameter value to be mapped
* @return Mapped Parameter value
*/
@Override
public String getMapped(final Parameter parameter, final String value) {
Objects.requireNonNull(parameter, "Parameter required");

final ParameterDescriptor descriptor = parameter.getDescriptor();
final String mapped;

if (parameter.isProvided()) {
mapped = PROVIDED_MAPPING;
} else if (descriptor.isSensitive()) {
if (sensitiveValueEncryptor == null) {
mapped = value;
} else {
final String encrypted = sensitiveValueEncryptor.encrypt(value);
mapped = ENCRYPTED_FORMAT.formatted(encrypted);
}
} else {
mapped = value;
}

return mapped;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,15 @@
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.groups.RemoteProcessGroup;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.parameter.FilterSensitiveParameterValueMapper;
import org.apache.nifi.parameter.Parameter;
import org.apache.nifi.parameter.ParameterContext;
import org.apache.nifi.parameter.ParameterDescriptor;
import org.apache.nifi.parameter.ParameterProvider;
import org.apache.nifi.parameter.ParameterProviderConfiguration;
import org.apache.nifi.parameter.ParameterReferencedControllerServiceData;
import org.apache.nifi.parameter.ParameterValueMapper;
import org.apache.nifi.parameter.StandardParameterValueMapper;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.registry.flow.FlowRegistryClientNode;
import org.apache.nifi.registry.flow.VersionControlInformation;
Expand Down Expand Up @@ -107,6 +110,7 @@ public class NiFiRegistryFlowMapper {

private final ExtensionManager extensionManager;
private final FlowMappingOptions flowMappingOptions;
private final ParameterValueMapper parameterValueMapper;

// We need to keep a mapping of component id to versionedComponentId as we transform these objects. This way, when
// we call #mapConnectable, instead of generating a new UUID for the ConnectableComponent, we can lookup the 'versioned'
Expand All @@ -121,6 +125,12 @@ public NiFiRegistryFlowMapper(final ExtensionManager extensionManager) {
public NiFiRegistryFlowMapper(final ExtensionManager extensionManager, final FlowMappingOptions flowMappingOptions) {
this.extensionManager = extensionManager;
this.flowMappingOptions = flowMappingOptions;

if (flowMappingOptions.isMapSensitiveConfiguration()) {
this.parameterValueMapper = new StandardParameterValueMapper(flowMappingOptions.getSensitiveValueEncryptor());
} else {
this.parameterValueMapper = new FilterSensitiveParameterValueMapper();
}
}

/**
Expand Down Expand Up @@ -911,10 +921,10 @@ private VersionedParameter mapParameter(ParameterContext parameterContext, Param
if (referencedControllerServiceData.isEmpty()) {
versionedParameter = mapParameter(parameter);
} else {
versionedParameter = mapParameter(
parameter,
getId(Optional.ofNullable(referencedControllerServiceData.get(0).getVersionedServiceId()), parameter.getValue())
);
final String referencedVersionServiceId = referencedControllerServiceData.getFirst().getVersionedServiceId();
final String parameterValue = parameter.getValue();
final String serviceId = getId(Optional.ofNullable(referencedVersionServiceId), parameterValue);
versionedParameter = mapParameter(parameter, serviceId);
}
} else {
versionedParameter = mapParameter(parameter);
Expand Down Expand Up @@ -954,19 +964,8 @@ private VersionedParameter mapParameter(final Parameter parameter, final String
versionedParameter.setSensitive(descriptor.isSensitive());
versionedParameter.setProvided(parameter.isProvided());

final boolean mapParameterValue = flowMappingOptions.isMapSensitiveConfiguration() || !descriptor.isSensitive();
final String parameterValue;
if (mapParameterValue) {
if (descriptor.isSensitive()) {
parameterValue = encrypt(value);
} else {
parameterValue = value;
}
} else {
parameterValue = null;
}

versionedParameter.setValue(parameterValue);
final String mapped = parameterValueMapper.getMapped(parameter, value);
versionedParameter.setValue(mapped);
return versionedParameter;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.parameter;

import org.apache.nifi.registry.flow.mapping.SensitiveValueEncryptor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;

@ExtendWith(MockitoExtension.class)
class TestStandardParameterValueMapper {
private static final String NAME = "NamedParameter";

private static final String VALUE = "ParameterValue";

@Mock
private SensitiveValueEncryptor sensitiveValueEncryptor;

private StandardParameterValueMapper mapper;

@BeforeEach
void setMapper() {
mapper = new StandardParameterValueMapper(sensitiveValueEncryptor);
}

@Test
void testGetMappedNotSensitiveNotProvided() {
final Parameter parameter = getParameter(false, false);

final String mapped = mapper.getMapped(parameter, VALUE);

assertEquals(VALUE, mapped);
}

@Test
void testGetMappedNotSensitiveProvided() {
final Parameter parameter = getParameter(false, true);

final String mapped = mapper.getMapped(parameter, VALUE);

assertEquals(StandardParameterValueMapper.PROVIDED_MAPPING, mapped);
}

@Test
void testGetMappedSensitiveProvided() {
final Parameter parameter = getParameter(true, true);

final String mapped = mapper.getMapped(parameter, VALUE);

assertEquals(StandardParameterValueMapper.PROVIDED_MAPPING, mapped);
}

@Test
void testGetMappedSensitiveNotProvided() {
final Parameter parameter = getParameter(true, false);

final String mapped = mapper.getMapped(parameter, VALUE);

assertNotEquals(VALUE, mapped);
assertNotEquals(StandardParameterValueMapper.PROVIDED_MAPPING, mapped);
}

private Parameter getParameter(final boolean sensitive, final boolean provided) {
final ParameterDescriptor descriptor = new ParameterDescriptor.Builder().name(NAME).sensitive(sensitive).build();
return new Parameter(descriptor, VALUE, null, provided);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.parameter.ParameterContext;
import org.apache.nifi.parameter.ParameterGroup;
import org.apache.nifi.parameter.ParameterProvider;
import org.apache.nifi.parameter.ParameterGroupConfiguration;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;

public interface ParameterProviderNode extends ComponentNode {
Expand All @@ -41,12 +43,30 @@ public interface ParameterProviderNode extends ComponentNode {

void verifyCanFetchParameters();

/**
* Retrieve Parameter Groups from configured Parameter Provider and store for subsequent retrieval in others methods
*
*/
void fetchParameters();

/**
* Find a named Parameter Group cached from previous request to fetch Parameters from the configured Parameter Provider
*
* @param parameterGroupName Parameter Group Name to find
* @return Parameter Group with Parameter Names and Values or empty when not found
*/
Optional<ParameterGroup> findFetchedParameterGroup(String parameterGroupName);

void verifyCanApplyParameters(Collection<ParameterGroupConfiguration> parameterNames);

Collection<ParameterGroupConfiguration> getParameterGroupConfigurations();

/**
* Get Parameter Groups with Parameter Names and Values to be applied to associated Parameter Contexts
*
* @param parameterGroupConfigurations Parameter Group Configurations to be retrieved
* @return List of Parameter Groups and Parameter Contexts to be applied based on Parameters retrieved in previous fetch requests
*/
List<ParametersApplication> getFetchedParametersToApply(Collection<ParameterGroupConfiguration> parameterGroupConfigurations);

void verifyCanClearState();
Expand Down Expand Up @@ -76,7 +96,7 @@ public interface ParameterProviderNode extends ComponentNode {
* @param context the configuration to verify
* @param logger a logger that can be used when performing verification
* @param extensionManager extension manager that is used for obtaining appropriate NAR ClassLoaders
* @return a list of results indicating whether or not the given configuration is valid
* @return a list of results indicating whether the given configuration is valid
*/
List<ConfigVerificationResult> verifyConfiguration(ConfigurationContext context, ComponentLog logger, ExtensionManager extensionManager);
}
Loading