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

[Proposal] Detect and fail fast for dangerous to deserialize types in task activity and task orchestration. #1070

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
146 changes: 146 additions & 0 deletions Test/DurableTask.Core.Tests/ReflectionBasedTaskActivityTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// ----------------------------------------------------------------------------------
// Copyright Microsoft Corporation
// Licensed 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.
// ----------------------------------------------------------------------------------

namespace DurableTask.Core.Tests
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using DurableTask.Core.Command;
using DurableTask.Core.History;
using DurableTask.Emulator;
using DurableTask.Test.Orchestrations;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class ReflectionBasedTaskActivityTests
{
public TaskHubWorker worker { get; private set; }

[TestInitialize]
public void Initialize()
{
var service = new LocalOrchestrationService();
this.worker = new TaskHubWorker(service);
}

[TestMethod]
public void Test_AddTaskActivitiesFromInterface()
{
IReflectionBasedTaskActivityTest reflectionBasedTaskActivityTest = new ReflectionBasedTaskActivityTest();

worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest);
worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest, useFullyQualifiedMethodNames: true);
}

[TestMethod]
public void Test_ReflectionBasedTaskActivity()
{
IReflectionBasedTaskActivityTest reflectionBasedTaskActivityTest = new ReflectionBasedTaskActivityTest();

worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest);
worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest, useFullyQualifiedMethodNames: true);
}

[TestMethod]
public void Test_ReflectionBasedTaskActivityWithGeneric()
{
IReflectionBasedTaskActivityWithGenericTest reflectionBasedTaskActivityTest = new ReflectionBasedTaskActivityTest();

worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest);
worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest, useFullyQualifiedMethodNames: true);
}

[TestMethod]
public void Test_AddTaskActivitiesFromInterfaceWithCancellationToken()
{
IReflectionBasedTaskActivityWithCancellationTokenTest reflectionBasedTaskActivityTest = new ReflectionBasedTaskActivityTest();
Action action = () =>
{
worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest);
};

Assert.ThrowsException<InvalidOperationException>(action);

action = () =>
{
worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest, useFullyQualifiedMethodNames: true);
};

Assert.ThrowsException<InvalidOperationException>(action);
}

[TestMethod]
public void Test_ReflectionBasedTaskActivityWithCancellationToken()
{
IReflectionBasedTaskActivityWithCancellationTokenTest reflectionBasedTaskActivityTest = new ReflectionBasedTaskActivityTest();
Action action = () =>
{
worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest);
};

Assert.ThrowsException<InvalidOperationException>(action);

action = () =>
{
worker.AddTaskActivitiesFromInterface(reflectionBasedTaskActivityTest, useFullyQualifiedMethodNames: true);
};

Assert.ThrowsException<InvalidOperationException>(action);
}

public interface IReflectionBasedTaskActivityTest
{
void TestMethod1();
void TestMethod2(int n1, int n2);
}

public interface IReflectionBasedTaskActivityWithGenericTest
{
void TestMethodG3<T>(T obj);
}

public interface IReflectionBasedTaskActivityWithCancellationTokenTest : IReflectionBasedTaskActivityTest
{
void TestMethod3(int n, CancellationToken cancellationToken);
}

public class ReflectionBasedTaskActivityTest : IReflectionBasedTaskActivityWithCancellationTokenTest, IReflectionBasedTaskActivityWithGenericTest
{
public void TestMethod1()
{
}

public void TestMethod2(int n1, int n2)
{
}

public void TestMethod3(int n, CancellationToken cancellationToken)
{
}

public void TestMethodG3<T>(T obj)
{
}
}
}
}
144 changes: 144 additions & 0 deletions Test/DurableTask.Core.Tests/TaskRegistrationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// ----------------------------------------------------------------------------------
// Copyright Microsoft Corporation
// Licensed 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.
// ----------------------------------------------------------------------------------

namespace DurableTask.Core.Tests
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using DurableTask.Core.Command;
using DurableTask.Core.History;
using DurableTask.Emulator;
using DurableTask.Test.Orchestrations;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class TaskRegistrationTests
{
public TaskHubWorker worker { get; private set; }

[TestInitialize]
public void Initialize()
{
var service = new LocalOrchestrationService();
this.worker = new TaskHubWorker(service);
}

[TestMethod]
[DataRow(typeof(TaskOrchInValid))]
[DataRow(typeof(TaskOrchInValidGeneric<CancellationToken>))]
[DataRow(typeof(TaskOrchInValidGeneric<string>))]
[DataRow(typeof(TaskOrchGeneric<CancellationToken, string>))]
[DataRow(typeof(TaskOrchGeneric<int, CancellationToken>))]
[DataRow(typeof(TaskOrchGeneric<CancellationToken, CancellationToken>))]
public void Test_RegistrationOfInValidTaskOrchestration(Type type)
{
Action action = () =>
{
this.worker.AddTaskOrchestrations(new[] { type });
};

Assert.ThrowsException<InvalidOperationException>(action);
}

[TestMethod]
[DataRow(typeof(TaskOrchValid))]
[DataRow(typeof(TaskOrchValidGeneric<CancellationToken>))]
[DataRow(typeof(TaskOrchValidGeneric<string>))]
[DataRow(typeof(TaskOrchGeneric<string, string>))]
[DataRow(typeof(TaskOrchGeneric<int, bool>))]
public void Test_RegistrationOfValidTaskOrchestration(Type type)
{
this.worker.AddTaskOrchestrations(new[] { type });
}

[TestMethod]
[DataRow(typeof(SampleTaskActivity<CancellationToken, CancellationToken, CancellationToken>))]
[DataRow(typeof(SampleTaskActivity<string, CancellationToken, string>))]
[DataRow(typeof(SampleTaskActivity<CancellationToken, string, int>))]
public void Test_RegistrationOfInValidTaskActivities(Type type)
{
Action action = () =>
{
this.worker.AddTaskActivities(new[] { type });
};

Assert.ThrowsException<InvalidOperationException>(action);
}

[TestMethod]
[DataRow(typeof(SampleTaskActivity<string, int, CancellationToken>))]
[DataRow(typeof(SampleTaskActivity<string, double, string>))]
[DataRow(typeof(SampleTaskActivity<string, string, int>))]
public void Test_RegistrationOfValidTaskActivities(Type type)
{
this.worker.AddTaskActivities(new[] { type });
}

public class TaskOrchValid : TaskOrchestration<string, string>
{
public override Task<string> RunTask(OrchestrationContext context, string input)
{
throw new NotImplementedException();
}
}

public class TaskOrchValidGeneric<T> : TaskOrchestration<string, string>
{
public override Task<string> RunTask(OrchestrationContext context, string input)
{
throw new NotImplementedException();
}
}

public class TaskOrchInValid : TaskOrchestration<string, CancellationToken>
{
public override Task<string> RunTask(OrchestrationContext context, CancellationToken input)
{
throw new NotImplementedException();
}
}

public class TaskOrchInValidGeneric<T> : TaskOrchestration<string, CancellationToken>
{
public override Task<string> RunTask(OrchestrationContext context, CancellationToken input)
{
throw new NotImplementedException();
}
}

public class TaskOrchGeneric<TOut, Tin> : TaskOrchestration<TOut, Tin>
{
public override Task<TOut> RunTask(OrchestrationContext context, Tin input)
{
throw new NotImplementedException();
}
}

public class SampleTaskActivity<Tin, Tout, T> : TaskActivity<Tin, Tout>
{
protected override Tout Execute(TaskContext context, Tin input)
{
throw new NotImplementedException();
}
}
}
}
94 changes: 94 additions & 0 deletions Test/DurableTask.Core.Tests/TypeExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// ----------------------------------------------------------------------------------
// Copyright Microsoft Corporation
// Licensed 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.
// ----------------------------------------------------------------------------------

namespace DurableTask.Core.Tests
{
using DurableTask.Core.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading.Tasks;
using System.Threading;

[TestClass]
public class TypeExtensionsTests
{
[TestMethod]
[DataRow(typeof(Task<TestClass1>), true)]
[DataRow(typeof(CancellationToken), true)]
[DataRow(typeof(Semaphore), true)]
[DataRow(typeof(Task<(bool, string)>), true)]
[DataRow(typeof(TestClass1), false)]
[DataRow(typeof(TestClass2), false)]
[DataRow(typeof(string), false)]
public void IsEqualOrContainsCancellationTokenType(Type typeContaining, bool isTrue)
{
if (isTrue)
{
Assert.IsTrue(typeContaining.IsEqualOrContainsNativeType());
}
else
{
Assert.IsFalse(typeContaining.IsEqualOrContainsNativeType());
}
}

[TestMethod]
[DataRow(typeof(Task<TestClass1>), typeof(CancellationToken), true)]
[DataRow(typeof(CancellationToken), typeof(CancellationToken), true)]
[DataRow(typeof(Task<TestClass1>), typeof(TestClass1), true)]
[DataRow(typeof(Task<(bool, string)>), typeof(string), true)]
[DataRow(typeof(Task<(bool, string)>), typeof(bool), true)]
[DataRow(typeof(TestClass1), typeof(TestClass1), true)]
[DataRow(typeof(TestClass1), typeof(string), true)]
[DataRow(typeof(TestClass1), typeof(double), true)]
[DataRow(typeof(TestClass1), typeof(TestClass2), true)]
[DataRow(typeof(TestClass2), typeof(double), true)]
[DataRow(typeof(TestClass2), typeof(string), false)]
public void Test_ContainsType(Type typeContaining, Type typeContained, bool isTrue)
{
if (isTrue)
{
Assert.IsTrue(typeContaining.IsEqualOrContainsType(typeContained));
}
else
{
Assert.IsFalse(typeContaining.IsEqualOrContainsType(typeContained));
}
}

internal class TestClass1
{
public string abc;

public TestClass2 t2;

public TestClass2 NewT2 { get; set; }

public TestClass1()
{
abc = string.Empty;
t2 = new TestClass2();
}
}

internal class TestClass2
{
public double def;

public TestClass2()
{
def = 1.0;
}
}
}
}
Loading