From fa85a05a2ba9ed7c9c613f880efaf53ca720c2f8 Mon Sep 17 00:00:00 2001 From: exceptionfactory Date: Mon, 15 Aug 2022 11:01:54 -0500 Subject: [PATCH] NIFI-9374 Added Deprecation Logger - Added nifi-deprecation-log module with interface and implementation using SLF4J - Updated standard logback.xml with nifi-deprecation.log appender - Updated NiFiLegacyCipherProvider with deprecation logging - Set Size, Time Policy, and Total Size Limit for Deprecation Log This closes #6300 Signed-off-by: Paul Grey --- nifi-commons/nifi-deprecation-log/pom.xml | 37 ++++++++++ .../deprecation/log/DeprecationException.java | 36 +++++++++ .../deprecation/log/DeprecationLogger.java | 30 ++++++++ .../log/DeprecationLoggerFactory.java | 35 +++++++++ .../log/StandardDeprecationLogger.java | 67 +++++++++++++++++ .../log/DeprecationExceptionTest.java | 37 ++++++++++ .../log/DeprecationLoggerFactoryTest.java | 37 ++++++++++ .../log/StandardDeprecationLoggerTest.java | 73 +++++++++++++++++++ nifi-commons/nifi-security-utils/pom.xml | 5 ++ .../util/crypto/NiFiLegacyCipherProvider.java | 10 +++ nifi-commons/pom.xml | 1 + .../src/main/resources/conf/logback.xml | 18 +++++ 12 files changed, 386 insertions(+) create mode 100644 nifi-commons/nifi-deprecation-log/pom.xml create mode 100644 nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationException.java create mode 100644 nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationLogger.java create mode 100644 nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationLoggerFactory.java create mode 100644 nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/StandardDeprecationLogger.java create mode 100644 nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/DeprecationExceptionTest.java create mode 100644 nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/DeprecationLoggerFactoryTest.java create mode 100644 nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/StandardDeprecationLoggerTest.java diff --git a/nifi-commons/nifi-deprecation-log/pom.xml b/nifi-commons/nifi-deprecation-log/pom.xml new file mode 100644 index 0000000000..69815a440d --- /dev/null +++ b/nifi-commons/nifi-deprecation-log/pom.xml @@ -0,0 +1,37 @@ + + + + 4.0.0 + + org.apache.nifi + nifi-commons + 1.18.0-SNAPSHOT + + nifi-deprecation-log + jar + + + org.slf4j + slf4j-api + + + org.mockito + mockito-inline + ${mockito.version} + test + + + diff --git a/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationException.java b/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationException.java new file mode 100644 index 0000000000..6493e2f7f7 --- /dev/null +++ b/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationException.java @@ -0,0 +1,36 @@ +/* + * 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.deprecation.log; + +/** + * Deprecation Exception provides stack traces referencing deprecated features or capabilities + */ +class DeprecationException extends RuntimeException { + /** + * Deprecation Exception package-private constructor for internal usage within Standard Deprecation Logger + * + * @param referenceClass Reference Class + */ + DeprecationException(final Class referenceClass) { + super(getMessage(referenceClass)); + } + + private static String getMessage(final Class referenceClass) { + final ClassLoader classLoader = referenceClass.getClassLoader(); + return String.format("Reference Class [%s] ClassLoader [%s]", referenceClass.getName(), classLoader); + } +} diff --git a/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationLogger.java b/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationLogger.java new file mode 100644 index 0000000000..edda9696aa --- /dev/null +++ b/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationLogger.java @@ -0,0 +1,30 @@ +/* + * 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.deprecation.log; + +/** + * Logger interface to indicate use of deprecated components or features + */ +public interface DeprecationLogger { + /** + * Log deprecation warning with optional arguments for message placeholders + * + * @param message Message required + * @param arguments Variable array of arguments to populate message placeholders + */ + void warn(String message, Object... arguments); +} diff --git a/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationLoggerFactory.java b/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationLoggerFactory.java new file mode 100644 index 0000000000..8acfbde5f4 --- /dev/null +++ b/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/DeprecationLoggerFactory.java @@ -0,0 +1,35 @@ +/* + * 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.deprecation.log; + +import java.util.Objects; + +/** + * Logger Factory provides concrete instances of Deprecation Loggers + */ +public class DeprecationLoggerFactory { + /** + * Get Deprecation Logger for Reference Class + * + * @param referenceClass Reference Class for deriving Logger + * @return Deprecation Logger + */ + public static DeprecationLogger getLogger(final Class referenceClass) { + Objects.requireNonNull(referenceClass, "Reference Class required"); + return new StandardDeprecationLogger(referenceClass); + } +} diff --git a/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/StandardDeprecationLogger.java b/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/StandardDeprecationLogger.java new file mode 100644 index 0000000000..768ec4f98d --- /dev/null +++ b/nifi-commons/nifi-deprecation-log/src/main/java/org/apache/nifi/deprecation/log/StandardDeprecationLogger.java @@ -0,0 +1,67 @@ +/* + * 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.deprecation.log; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Standard implementation of Deprecation Logger based on SLF4J + */ +class StandardDeprecationLogger implements DeprecationLogger { + private static final String LOGGER_NAME_FORMAT = "deprecation.%s"; + + private final Class referenceClass; + + private final Logger logger; + + /** + * Standard Deprecation Logger constructor with reference class for deriving logger + * + * @param referenceClass Reference Class + */ + StandardDeprecationLogger(final Class referenceClass) { + this.referenceClass = Objects.requireNonNull(referenceClass, "Reference Class required"); + this.logger = LoggerFactory.getLogger(String.format(LOGGER_NAME_FORMAT, referenceClass.getName())); + } + + /** + * Log deprecation warning with optional arguments for message placeholders and Deprecation Exception for tracking + * + * @param message Message required + * @param arguments Variable array of arguments to populate message placeholders + */ + @Override + public void warn(final String message, final Object... arguments) { + Objects.requireNonNull(message, "Message required"); + final Object[] extendedArguments = getExtendedArguments(arguments); + logger.warn(message, extendedArguments); + } + + private Object[] getExtendedArguments(final Object... arguments) { + final Object[] messageArguments = arguments == null ? new Object[0] : arguments; + final int messageArgumentsLength = messageArguments.length; + + final Object[] extendedArguments = Arrays.copyOf(messageArguments, messageArgumentsLength + 1); + extendedArguments[messageArgumentsLength] = new DeprecationException(referenceClass); + + return extendedArguments; + } +} diff --git a/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/DeprecationExceptionTest.java b/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/DeprecationExceptionTest.java new file mode 100644 index 0000000000..fd15c0bed8 --- /dev/null +++ b/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/DeprecationExceptionTest.java @@ -0,0 +1,37 @@ +/* + * 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.deprecation.log; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(MockitoExtension.class) +class DeprecationExceptionTest { + private static final Class REFERENCE_CLASS = DeprecationExceptionTest.class; + + @Test + void testGetMessageReferenceClassFound() { + final DeprecationException deprecationException = new DeprecationException(REFERENCE_CLASS); + + final String message = deprecationException.getMessage(); + + assertTrue(message.contains(REFERENCE_CLASS.getName())); + } +} diff --git a/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/DeprecationLoggerFactoryTest.java b/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/DeprecationLoggerFactoryTest.java new file mode 100644 index 0000000000..9e9ccd7c20 --- /dev/null +++ b/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/DeprecationLoggerFactoryTest.java @@ -0,0 +1,37 @@ +/* + * 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.deprecation.log; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class DeprecationLoggerFactoryTest { + + @Test + void testGetLogger() { + final DeprecationLogger deprecationLogger = DeprecationLoggerFactory.getLogger(DeprecationLoggerFactoryTest.class); + + assertNotNull(deprecationLogger); + } + + @Test + void testGetLoggerClassRequired() { + assertThrows(NullPointerException.class, () -> DeprecationLoggerFactory.getLogger(null)); + } +} diff --git a/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/StandardDeprecationLoggerTest.java b/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/StandardDeprecationLoggerTest.java new file mode 100644 index 0000000000..827cd3aca0 --- /dev/null +++ b/nifi-commons/nifi-deprecation-log/src/test/java/org/apache/nifi/deprecation/log/StandardDeprecationLoggerTest.java @@ -0,0 +1,73 @@ +/* + * 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.deprecation.log; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class StandardDeprecationLoggerTest { + private static final Class REFERENCE_CLASS = StandardDeprecationLoggerTest.class; + + private static final String LOGGER_NAME = String.format("deprecation.%s", REFERENCE_CLASS.getName()); + + private static final String MESSAGE = "Feature not used"; + + private static final String MESSAGE_PLACEHOLDER = "Feature not used [{}]"; + + private static final String PLACEHOLDER = "PLACEHOLDER"; + + @Mock + Logger logger; + + @Test + void testWarn() { + try (final MockedStatic ignored = mockStatic(LoggerFactory.class)) { + when(LoggerFactory.getLogger(eq(LOGGER_NAME))).thenReturn(logger); + + final DeprecationLogger deprecationLogger = new StandardDeprecationLogger(REFERENCE_CLASS); + + deprecationLogger.warn(MESSAGE); + + verify(logger).warn(eq(MESSAGE), ArgumentMatchers.any()); + } + } + + @Test + void testWarnArguments() { + try (final MockedStatic ignored = mockStatic(LoggerFactory.class)) { + when(LoggerFactory.getLogger(eq(LOGGER_NAME))).thenReturn(logger); + + final DeprecationLogger deprecationLogger = new StandardDeprecationLogger(REFERENCE_CLASS); + + deprecationLogger.warn(MESSAGE_PLACEHOLDER, PLACEHOLDER); + + verify(logger).warn(eq(MESSAGE_PLACEHOLDER), ArgumentMatchers.any()); + } + } +} diff --git a/nifi-commons/nifi-security-utils/pom.xml b/nifi-commons/nifi-security-utils/pom.xml index 689a783f9d..f589472878 100644 --- a/nifi-commons/nifi-security-utils/pom.xml +++ b/nifi-commons/nifi-security-utils/pom.xml @@ -37,6 +37,11 @@ nifi-utils 1.18.0-SNAPSHOT + + org.apache.nifi + nifi-deprecation-log + 1.18.0-SNAPSHOT + org.apache.nifi nifi-security-utils-api diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/crypto/NiFiLegacyCipherProvider.java b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/crypto/NiFiLegacyCipherProvider.java index df8a54d89d..daac724b53 100644 --- a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/crypto/NiFiLegacyCipherProvider.java +++ b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/crypto/NiFiLegacyCipherProvider.java @@ -21,6 +21,9 @@ import java.io.InputStream; import java.io.OutputStream; import java.security.SecureRandom; import javax.crypto.Cipher; + +import org.apache.nifi.deprecation.log.DeprecationLogger; +import org.apache.nifi.deprecation.log.DeprecationLoggerFactory; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.security.util.EncryptionMethod; import org.apache.nifi.stream.io.StreamUtils; @@ -40,9 +43,12 @@ import org.slf4j.LoggerFactory; public class NiFiLegacyCipherProvider extends OpenSSLPKCS5CipherProvider implements PBECipherProvider { private static final Logger logger = LoggerFactory.getLogger(NiFiLegacyCipherProvider.class); + private static final DeprecationLogger deprecationLogger = DeprecationLoggerFactory.getLogger(NiFiLegacyCipherProvider.class); + // Legacy magic number value private static final int ITERATION_COUNT = 1000; + /** * Returns an initialized cipher for the specified algorithm. The key (and IV if necessary) are derived using the NiFi legacy code, based on @see org.apache.nifi.crypto * .OpenSSLPKCS5CipherProvider#getCipher(java.lang.String, java.lang.String, java.lang.String, byte[], boolean) [essentially {@code MD5(password || salt) * 1000 }]. @@ -57,6 +63,7 @@ public class NiFiLegacyCipherProvider extends OpenSSLPKCS5CipherProvider impleme */ @Override public Cipher getCipher(EncryptionMethod encryptionMethod, String password, byte[] salt, int keyLength, boolean encryptMode) throws Exception { + deprecationLogger.warn("Insecure Cipher Provider Algorithm [{}] cipher requested", encryptionMethod.getAlgorithm()); try { // This method is defined in the OpenSSL implementation and just uses a locally-overridden iteration count return getInitializedCipher(encryptionMethod, password, salt, encryptMode); @@ -68,6 +75,7 @@ public class NiFiLegacyCipherProvider extends OpenSSLPKCS5CipherProvider impleme } public byte[] generateSalt(EncryptionMethod encryptionMethod) { + deprecationLogger.warn("Insecure Cipher Provider Algorithm [{}] generate salt requested", encryptionMethod.getAlgorithm()); byte[] salt = new byte[calculateSaltLength(encryptionMethod)]; new SecureRandom().nextBytes(salt); return salt; @@ -106,6 +114,7 @@ public class NiFiLegacyCipherProvider extends OpenSSLPKCS5CipherProvider impleme * @return the salt */ public byte[] readSalt(EncryptionMethod encryptionMethod, InputStream in) throws IOException { + deprecationLogger.warn("Insecure Cipher Provider Algorithm [{}] read salt requested", encryptionMethod.getAlgorithm()); if (in == null) { throw new IllegalArgumentException("Cannot read salt from null InputStream"); } @@ -122,6 +131,7 @@ public class NiFiLegacyCipherProvider extends OpenSSLPKCS5CipherProvider impleme @Override public void writeSalt(byte[] salt, OutputStream out) throws IOException { + deprecationLogger.warn("Insecure Cipher Provider write salt requested"); if (out == null) { throw new IllegalArgumentException("Cannot write salt to null OutputStream"); } diff --git a/nifi-commons/pom.xml b/nifi-commons/pom.xml index 1789e2fe4f..3dcdf77ef1 100644 --- a/nifi-commons/pom.xml +++ b/nifi-commons/pom.xml @@ -26,6 +26,7 @@ nifi-bootstrap-utils nifi-build nifi-data-provenance-utils + nifi-deprecation-log nifi-expression-language nifi-external-resource-utils nifi-flowfile-packager diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/logback.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/logback.xml index 507bbdd38f..c578c8ba3d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/logback.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/logback.xml @@ -88,6 +88,19 @@ + + ${org.apache.nifi.bootstrap.config.log.dir}/nifi-deprecation.log + + ${org.apache.nifi.bootstrap.config.log.dir}/nifi-deprecation_%d.%i.log + 10MB + 10 + 100MB + + + %date %level [%thread] %logger %msg%n + + + %date %level [%thread] %logger{40} %msg%n @@ -96,6 +109,11 @@ + + + + +