Repository: Azure/azure-functions-java-worker
Pull request #602 (2022-07-25 18:55:11)

Adding Microsoft SECURITY.MD
Please accept this contribution adding the standard Microsoft SECURITY.MD :lock: file to help the community understand the security policy and how to safely report security issues. GitHub uses the presence of this file to light-up security reminders and a link to the file. This pull request commits the latest official SECURITY.MD file from https://github.com/microsoft/repo-templates/blob/main/shared/SECURITY.md.

Microsoft teams can [learn more about this effort and share feedback](https://docs.opensource.microsoft.com/releasing/maintain/templates/) within the open source guidance available internally.



Patch:
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..869fdfe
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,41 @@
+<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
+
+## Security
+
+Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
+
+If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
+
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+  * Full paths of source file(s) related to the manifestation of the issue
+  * The location of the affected source code (tag/branch/commit or direct URL)
+  * Any special configuration required to reproduce the issue
+  * Step-by-step instructions to reproduce the issue
+  * Proof-of-concept or exploit code (if possible)
+  * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Policy
+
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
+
+<!-- END MICROSOFT SECURITY.MD BLOCK -->
diff --git a/pom.xml b/pom.xml
index 8826464..1c2fadb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -119,6 +119,7 @@
 		<dependency>
 			<groupId>junit</groupId>
 			<artifactId>junit</artifactId>
+			<version>4.13.1</version>
 			<scope>test</scope>
 		</dependency>
 		<dependency>
@@ -127,9 +128,9 @@
    			<version>5.3.0</version>
 		</dependency>
 		<dependency>
-			<groupId>org.jmockit</groupId>
-			<artifactId>jmockit</artifactId>
-			<version>1.49</version>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-core</artifactId>
+			<version>4.6.1</version>
 			<scope>test</scope>
 		</dependency>
 	</dependencies>
@@ -305,18 +306,6 @@
 					</execution>
 				</executions>
 			</plugin>
-
-			<!-- This plugin helps to config and run unit tests -->
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-surefire-plugin</artifactId>
-				<version>2.22.2</version> <!-- or some other version -->
-				<configuration>
-					<argLine>
-						-javaagent:"${settings.localRepository}"\org\jmockit\jmockit\1.49\jmockit-1.49.jar
-					</argLine>
-				</configuration>
-			</plugin>
 		</plugins>
 	</build>
 </project>
diff --git a/src/main/java/com/microsoft/azure/functions/worker/WorkerLogManager.java b/src/main/java/com/microsoft/azure/functions/worker/WorkerLogManager.java
index 54c571b..cea88fd 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/WorkerLogManager.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/WorkerLogManager.java
@@ -69,6 +69,7 @@ public class WorkerLogManager {
     private boolean logToConsole;
     private final Logger emptyLogger, systemLogger, hostLogger;
     private final static WorkerLogManager INSTANCE = new WorkerLogManager();
+    public final static String SYSTEM_LOG_PREFIX = "azure_functions_java_worker";
 }
 
 class SystemLoggerListener extends Handler {
diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java b/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
index bc8eda4..2a6a031 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
@@ -60,7 +60,7 @@ public class EnhancedJavaMethodExecutorImpl implements JavaMethodExecutor {
     }
 
     private Class<?> getContainingClass(String className) throws ClassNotFoundException {
-        return Class.forName(className, true, this.classLoader);
+        return Class.forName(className, false, this.classLoader);
     }
 
     private final Class<?> containingClass;
diff --git a/src/main/java/com/microsoft/azure/functions/worker/handler/RpcLogHandler.java b/src/main/java/com/microsoft/azure/functions/worker/handler/RpcLogHandler.java
index 7c9126b..5abc589 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/handler/RpcLogHandler.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/handler/RpcLogHandler.java
@@ -18,6 +18,18 @@ public class RpcLogHandler extends OutboundMessageHandler<RpcLog.Builder> {
 
     private static RpcLog.Builder generateRpcLog(LogRecord record, String invocationId) {
         RpcLog.Builder log = RpcLog.newBuilder();
+        /**
+         * Check if the logging namespace belongs to system logsq, invocation log should be categorized to user type (default), others should
+         * be categorized to system type.
+         *
+         *              local_console   customer_app_insight    functions_kusto_table
+         * system_log   false,           false,                   true
+         * user_log     true,            true,                    false
+         */
+        if (invocationId == null){
+            log.setLogCategory(RpcLog.RpcLogCategory.System);
+            log.setCategory(WorkerLogManager.SYSTEM_LOG_PREFIX);
+        }
         Optional.ofNullable(invocationId).ifPresent(log::setInvocationId);
         Optional.ofNullable(record.getLoggerName()).ifPresent(log::setCategory);
         Optional.ofNullable(mapLogLevel(record.getLevel())).ifPresent(log::setLevel);


Test patch:
diff --git a/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Fixtures/FixtureHelpers.cs b/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Fixtures/FixtureHelpers.cs
index 3b2450b..262e599 100644
--- a/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Fixtures/FixtureHelpers.cs
+++ b/endtoendtests/Azure.Functions.Java.Tests.E2E/Azure.Functions.Java.Tests.E2E/Fixtures/FixtureHelpers.cs
@@ -4,6 +4,7 @@
 using System;
 using System.Diagnostics;
 using System.IO;
+using System.Runtime.InteropServices;
 
 namespace Azure.Functions.Java.Tests.E2E
 {
@@ -12,14 +13,21 @@ namespace Azure.Functions.Java.Tests.E2E
         public static Process GetFuncHostProcess(bool enableAuth = false)
         {
             var funcHostProcess = new Process();
-            var rootDir = Path.GetFullPath(@"..\..\..\..\..\..");
+            var rootDir = Path.GetFullPath(@"../../../../../..");
 
             funcHostProcess.StartInfo.UseShellExecute = false;
             funcHostProcess.StartInfo.RedirectStandardError = true;
             funcHostProcess.StartInfo.RedirectStandardOutput = true;
             funcHostProcess.StartInfo.CreateNoWindow = true;
-            funcHostProcess.StartInfo.WorkingDirectory = Path.Combine(rootDir, @"endtoendtests\target\azure-functions\azure-functions-java-endtoendtests");
-            funcHostProcess.StartInfo.FileName = Path.Combine(rootDir, @"Azure.Functions.Cli\func.exe");
+            funcHostProcess.StartInfo.WorkingDirectory = Path.Combine(rootDir, @"endtoendtests/target/azure-functions/azure-functions-java-endtoendtests");
+            if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                funcHostProcess.StartInfo.FileName = Path.Combine(rootDir, @"Azure.Functions.Cli/func.exe");
+            }
+            else
+            {
+                funcHostProcess.StartInfo.FileName = Path.Combine(rootDir, @"Azure.Functions.Cli/func");
+            }
             funcHostProcess.StartInfo.ArgumentList.Add("start");
             if (enableAuth)
             {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java b/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java
index 2fb7e43..231c1d6 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java
@@ -3,53 +3,59 @@ package com.microsoft.azure.functions.worker.broker;
 import com.microsoft.azure.functions.rpc.messages.InvocationRequest;
 import com.microsoft.azure.functions.rpc.messages.ParameterBinding;
 import com.microsoft.azure.functions.rpc.messages.TypedData;
-import com.microsoft.azure.functions.worker.broker.JavaFunctionBroker;
-import com.microsoft.azure.functions.worker.description.FunctionMethodDescriptor;
 import com.microsoft.azure.functions.worker.reflect.DefaultClassLoaderProvider;
-import mockit.*;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.*;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.when;
 
+@RunWith(MockitoJUnitRunner.class)
 public class JavaFunctionBrokerTest {
+    @Mock InvocationRequest request;
+    @Mock ParameterBinding binding;
+    @Mock TypedData bindingData;
+    @Mock TypedData name;
+    @Mock TypedData query;
+    @Mock TypedData headers;
+    @Mock TypedData sys;
+    @Mock TypedData queueTrigger;
+    @Mock TypedData dequeueCount;
+    @Mock TypedData expirationTime;
+    @Mock TypedData id;
+    @Mock TypedData insertionTime;
+    @Mock TypedData nextVisibleTime;
+    @Mock TypedData popReceipt;
 
     @Test
-    public void getTriggerMetadataMap_success(
-            @Mocked InvocationRequest request,
-            @Mocked ParameterBinding binding,
-            @Mocked TypedData bindingData,
-            @Mocked TypedData name,
-            @Mocked TypedData query,
-            @Mocked TypedData headers,
-            @Mocked TypedData sys
-            ) throws Exception {
-
+    public void getTriggerMetadataMap_success() throws Exception {
         String expectedData = "http {\n  method: \"GET\"\n  url: \"https://localhost:5001/api/HttpExample?name=ushio\"\n  headers {\n    key: \"cache-control\"\n    value: \"max-age=0\"\n  }\n  headers {\n    key: \"connection\"\n    value: \"Keep-Alive\"\n  }\n  headers {\n    key: \"accept\"\n    value: \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\"\n  }\n  headers {\n    key: \"accept-encoding\"\n    value: \"gzip, deflate, br\"\n  }\n  headers {\n    key: \"accept-language\"\n    value: \"en-US,ja;q=0.8,en-GB;q=0.5,en;q=0.3\"\n  }\n  headers {\n    key: \"host\"\n    value: \"localhost:5001\"\n  }\n  headers {\n    key: \"user-agent\"\n    value: \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19041\"\n  }\n  headers {\n    key: \"upgrade-insecure-requests\"\n    value: \"1\"\n  }\n  query {\n    key: \"name\"\n    value: \"ushio\"\n  }\n  identities {\n    name_claim_type {\n      value: \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\"\n    }\n    role_claim_type {\n      value: \"http://schemas.microsoft.com/ws/2008/06/identity/claims/role\"\n    }\n  }\n}\n";
         String expectedName = "req";
-        new Expectations() {{
-            bindingData.hasHttp(); result = true;
-            bindingData.getString(); result = expectedData;
-            binding.getName(); result = expectedName;
-            binding.getData(); result = bindingData;
-            request.getInputDataList(); result = Arrays.asList(binding);
-
-            name.getString(); result = "string: \"John\"\n"; minTimes = 0;
-            query.getString(); result = "json: \"{\"name\":\"ushio\"}\""; minTimes = 0;
-            headers.getString(); result = "json: \"{\"Cache-Control\":\"max-age=0\",\"Connection\":\"Keep-Alive\",\"Accept\":\"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\"Accept-Encoding\":\"gzip, deflate, br\",\"Accept-Language\":\"en-US,ja;q=0.8,en-GB;q=0.5,en;q=0.3\",\"Host\":\"localhost:5001\",\"User-Agent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19041\",\"Upgrade-Insecure-Requests\":\"1\"}\""; minTimes = 0;
-            sys.getString(); result = "json: \"{\"MethodName\":\"HttpExample\",\"UtcNow\":\"2020-04-30T15:26:57.281277Z\",\"RandGuid\":\"cd332c4a-df9e-415a-acd4-973994072e46\"}\""; minTimes = 0;
-
-            Map<String,TypedData> triggerMetadata = new HashMap<String, TypedData>();
-            triggerMetadata.put("name", name);
-            triggerMetadata.put("Query", query);
-            triggerMetadata.put("Headers", headers);
-            triggerMetadata.put("sys", sys);
-            request.getTriggerMetadataMap(); result = Collections.unmodifiableMap(triggerMetadata);
-        }};
+
+        when(bindingData.hasHttp()).thenReturn(true);
+        when(bindingData.getString()).thenReturn(expectedData);
+        when(binding.getName()).thenReturn(expectedName);
+        when(binding.getData()).thenReturn(bindingData);
+        when(request.getInputDataList()).thenReturn(Arrays.asList(binding));
+
+        lenient().when(name.getString()).thenReturn("string: \"John\"\n");
+        lenient().when(query.getString()).thenReturn("json: \"{\"name\":\"ushio\"}\"");
+        lenient().when(headers.getString()).thenReturn("json: \"{\"Cache-Control\":\"max-age=0\",\"Connection\":\"Keep-Alive\",\"Accept\":\"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\"Accept-Encoding\":\"gzip, deflate, br\",\"Accept-Language\":\"en-US,ja;q=0.8,en-GB;q=0.5,en;q=0.3\",\"Host\":\"localhost:5001\",\"User-Agent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19041\",\"Upgrade-Insecure-Requests\":\"1\"}\"");
+        lenient().when(sys.getString()).thenReturn("json: \"{\"MethodName\":\"HttpExample\",\"UtcNow\":\"2020-04-30T15:26:57.281277Z\",\"RandGuid\":\"cd332c4a-df9e-415a-acd4-973994072e46\"}\"");
+
+        Map<String,TypedData> triggerMetadata = new HashMap<String, TypedData>();
+        triggerMetadata.put("name", name);
+        triggerMetadata.put("Query", query);
+        triggerMetadata.put("Headers", headers);
+        triggerMetadata.put("sys", sys);
+        when(request.getTriggerMetadataMap()).thenReturn(Collections.unmodifiableMap(triggerMetadata));
 
         JavaFunctionBroker broker = new JavaFunctionBroker(new DefaultClassLoaderProvider());
         Map<String, TypedData> actualTriggerMetadata = broker.getTriggerMetadataMap(request);
@@ -60,49 +66,35 @@ public class JavaFunctionBrokerTest {
     }
 
     @Test
-    public void getTriggerMetadataMap_ignored(
-            @Mocked InvocationRequest request,
-            @Mocked ParameterBinding binding,
-            @Mocked TypedData bindingData,
-            @Mocked TypedData queueTrigger,
-            @Mocked TypedData dequeueCount,
-            @Mocked TypedData expirationTime,
-            @Mocked TypedData id,
-            @Mocked TypedData insertionTime,
-            @Mocked TypedData nextVisibleTime,
-            @Mocked TypedData popReceipt,
-            @Mocked TypedData sys
-    ) throws Exception {
-
+    public void getTriggerMetadataMap_ignored() throws Exception {
         String data = "string: \"hello queue\"\n";
         String name = "msg";
-        new Expectations() {{
-            bindingData.hasHttp(); result = false;
-            bindingData.getString(); result = data; minTimes = 0;
-            binding.getName(); result = name; minTimes = 0;
-            binding.getData(); result = bindingData; minTimes = 0;
-            request.getInputDataList(); result = Arrays.asList(binding);
-
-            queueTrigger.getString(); result = "string: \"hello queue\"\n"; minTimes = 0;
-            dequeueCount.getString(); result = "json: \"1\"\n"; minTimes = 0;
-            expirationTime.getString(); result = "json: \"\"2020-05-08T17:47:22+00:00\"\n"; minTimes = 0;
-            id.getString(); result = "string: \"e4f4a332-df80-41a1-8ecd-c2f7fba91f28\"\n"; minTimes = 0;
-            insertionTime.getString(); result = "json: \"\"2020-05-01T17:47:22+00:00\"\n"; minTimes = 0;
-            nextVisibleTime.getString(); result = "json: \"\"2020-05-01T17:57:22+00:00\"\n"; minTimes = 0;
-            popReceipt.getString(); result = "string: \"oJCJGfnt1wgBAAAA\"\n"; minTimes = 0;
-            sys.getString(); result =  "json: \"{\"MethodName\":\"QueueProcessor\",\"UtcNow\":\"2020-05-01T17:47:29.2664174Z\",\"RandGuid\":\"7f67ac1c-b7b0-43f5-a51a-73af321d7d9f\"}\n"; minTimes = 0;
-
-            Map<String,TypedData> triggerMetadata = new HashMap<String, TypedData>();
-            triggerMetadata.put("QueueTrigger", queueTrigger);
-            triggerMetadata.put("DequeueCount", dequeueCount);
-            triggerMetadata.put("ExpirationTime", expirationTime);
-            triggerMetadata.put("Id", id);
-            triggerMetadata.put("InsertionTime", insertionTime);
-            triggerMetadata.put("NextVisibleTime", nextVisibleTime);
-            triggerMetadata.put("PopReceipt", popReceipt);
-            triggerMetadata.put("sys", sys);
-            request.getTriggerMetadataMap(); result = Collections.unmodifiableMap(triggerMetadata);
-        }};
+
+        when(bindingData.hasHttp()).thenReturn(false);
+        lenient().when(bindingData.getString()).thenReturn(data);
+        lenient().when(binding.getName()).thenReturn(name);
+        when(binding.getData()).thenReturn(bindingData);
+        when(request.getInputDataList()).thenReturn(Arrays.asList(binding));
+
+        lenient().when(queueTrigger.getString()).thenReturn("string: \"hello queue\"\n");
+        lenient().when(dequeueCount.getString()).thenReturn("json: \"1\"\n");
+        lenient().when(expirationTime.getString()).thenReturn("json: \"\"2020-05-08T17:47:22+00:00\"\n");
+        lenient().when(id.getString()).thenReturn("string: \"e4f4a332-df80-41a1-8ecd-c2f7fba91f28\"\n");
+        lenient().when(insertionTime.getString()).thenReturn("json: \"\"2020-05-01T17:47:22+00:00\"\n");
+        lenient().when(nextVisibleTime.getString()).thenReturn("json: \"\"2020-05-01T17:57:22+00:00\"\n");
+        lenient().when(popReceipt.getString()).thenReturn("string: \"oJCJGfnt1wgBAAAA\"\n");
+        lenient().when(sys.getString()).thenReturn( "json: \"{\"MethodName\":\"QueueProcessor\",\"UtcNow\":\"2020-05-01T17:47:29.2664174Z\",\"RandGuid\":\"7f67ac1c-b7b0-43f5-a51a-73af321d7d9f\"}\n");
+
+        Map<String,TypedData> triggerMetadata = new HashMap<String, TypedData>();
+        triggerMetadata.put("QueueTrigger", queueTrigger);
+        triggerMetadata.put("DequeueCount", dequeueCount);
+        triggerMetadata.put("ExpirationTime", expirationTime);
+        triggerMetadata.put("Id", id);
+        triggerMetadata.put("InsertionTime", insertionTime);
+        triggerMetadata.put("NextVisibleTime", nextVisibleTime);
+        triggerMetadata.put("PopReceipt", popReceipt);
+        triggerMetadata.put("sys", sys);
+        when(request.getTriggerMetadataMap()).thenReturn(Collections.unmodifiableMap(triggerMetadata));
 
         int expectedCount = request.getTriggerMetadataMap().size();
         JavaFunctionBroker broker = new JavaFunctionBroker(new DefaultClassLoaderProvider());
diff --git a/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..ca6ee9c
--- /dev/null
+++ b/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1,1 @@
+mock-maker-inline
\ No newline at end of file