Skip to content

Commit

Permalink
Bump Hyperion to 0.12.0 (#5510)
Browse files Browse the repository at this point in the history
* Bump Hyperion from 0.11.2 to 0.12.0

* Implement Hyperion TypeFilter feature. Add HOCON config and HyperionSerializerSetup support.
  • Loading branch information
Arkatufus authored Jan 14, 2022
1 parent e1c89cc commit 5223ed4
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PropertyGroup>
<XunitVersion>2.4.1</XunitVersion>
<TestSdkVersion>17.0.0</TestSdkVersion>
<HyperionVersion>0.11.2</HyperionVersion>
<HyperionVersion>0.12.0</HyperionVersion>
<NewtonsoftJsonVersion>[12.0.3,)</NewtonsoftJsonVersion>
<NBenchVersion>2.0.1</NBenchVersion>
<ProtobufVersion>3.17.3</ProtobufVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Akka.Actor;
using Akka.Configuration;
using FluentAssertions;
using Hyperion;
using Hyperion.Internal;
using Xunit;

namespace Akka.Serialization.Hyperion.Tests
Expand All @@ -36,6 +38,7 @@ public void Hyperion_serializer_should_have_correct_defaults()
Assert.True(serializer.Settings.PreserveObjectReferences);
Assert.Equal("NoKnownTypes", serializer.Settings.KnownTypesProvider.Name);
Assert.True(serializer.Settings.DisallowUnsafeType);
Assert.Equal(serializer.Settings.TypeFilter, DisabledTypeFilter.Instance);
}
}

Expand All @@ -52,6 +55,7 @@ public void Hyperion_serializer_should_allow_to_setup_custom_flags()
preserve-object-references = false
version-tolerance = false
disallow-unsafe-type = false
allowed-types = [""Akka.Serialization.Hyperion.Tests.HyperionConfigTests+ClassA, Akka.Serialization.Hyperion.Tests""]
}
}
");
Expand All @@ -62,9 +66,52 @@ public void Hyperion_serializer_should_allow_to_setup_custom_flags()
Assert.False(serializer.Settings.PreserveObjectReferences);
Assert.Equal("NoKnownTypes", serializer.Settings.KnownTypesProvider.Name);
Assert.False(serializer.Settings.DisallowUnsafeType);
Assert.Equal("Akka.Serialization.Hyperion.Tests.HyperionConfigTests+ClassA, Akka.Serialization.Hyperion.Tests", ((TypeFilter) serializer.Settings.TypeFilter).FilteredTypes.First());
}
}

[Theory]
[MemberData(nameof(TypeFilterObjectFactory))]
public void TypeFilter_defined_in_config_should_filter_serializer_properly(object sampleObject, bool shouldSucceed)
{
var config = ConfigurationFactory.ParseString(@"
akka.actor {
serializers.hyperion = ""Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion""
serialization-bindings {
""System.Object"" = hyperion
}
serialization-settings.hyperion {
preserve-object-references = false
version-tolerance = false
disallow-unsafe-type = true
allowed-types = [
""Akka.Serialization.Hyperion.Tests.HyperionConfigTests+ClassA, Akka.Serialization.Hyperion.Tests""
""Akka.Serialization.Hyperion.Tests.HyperionConfigTests+ClassB, Akka.Serialization.Hyperion.Tests""
]
}
}
");
using (var system = ActorSystem.Create(nameof(HyperionConfigTests), config))
{
var serializer = (HyperionSerializer)system.Serialization.FindSerializerForType(typeof(object));

((TypeFilter)serializer.Settings.TypeFilter).FilteredTypes.Count.Should().Be(2);
var serialized = serializer.ToBinary(sampleObject);
object deserialized = null;
Action act = () => deserialized = serializer.FromBinary<object>(serialized);
if (shouldSucceed)
{
act.Should().NotThrow();
deserialized.GetType().Should().Be(sampleObject.GetType());
}
else
{
act.Should().Throw<SerializationException>()
.WithInnerException<UserEvilDeserializationException>();
}
}
}

[Fact]
public void Hyperion_serializer_should_allow_to_setup_custom_types_provider_with_default_constructor()
{
Expand Down Expand Up @@ -198,6 +245,18 @@ public void Hyperion_serializer_should_allow_to_setup_surrogates()
}
}

public static IEnumerable<object[]> TypeFilterObjectFactory()
{
yield return new object[] { new ClassA(), true };
yield return new object[] { new ClassB(), true };
yield return new object[] { new ClassC(), false };
}

public class ClassA { }

public class ClassB { }

public class ClassC { }
}

class DummyTypesProvider : IKnownTypesProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Xunit.Abstractions;
using FluentAssertions;
using Hyperion;
using Hyperion.Internal;

namespace Akka.Serialization.Hyperion.Tests
{
Expand Down Expand Up @@ -134,6 +135,35 @@ public void Setup_disallow_unsafe_type_should_work(object dangerousObject, Type
serializer.Invoking(s => s.FromBinary(serialized, type)).Should().Throw<SerializationException>();
}

[Theory]
[MemberData(nameof(TypeFilterObjectFactory))]
public void Setup_TypeFilter_should_filter_types_properly(object sampleObject, bool shouldSucceed)
{
var setup = HyperionSerializerSetup.Empty
.WithTypeFilter(TypeFilterBuilder.Create()
.Include<ClassA>()
.Include<ClassB>()
.Build());

var settings = setup.ApplySettings(HyperionSerializerSettings.Default);
var serializer = new HyperionSerializer((ExtendedActorSystem)Sys, settings);

((TypeFilter)serializer.Settings.TypeFilter).FilteredTypes.Count.Should().Be(2);
var serialized = serializer.ToBinary(sampleObject);
object deserialized = null;
Action act = () => deserialized = serializer.FromBinary<object>(serialized);
if (shouldSucceed)
{
act.Should().NotThrow();
deserialized.GetType().Should().Be(sampleObject.GetType());
}
else
{
act.Should().Throw<SerializationException>()
.WithInnerException<UserEvilDeserializationException>();
}
}

public static IEnumerable<object[]> DangerousObjectFactory()
{
var isWindow = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
Expand All @@ -150,5 +180,18 @@ public static IEnumerable<object[]> DangerousObjectFactory()
#endif
yield return new object[]{ new ClaimsIdentity(), typeof(ClaimsIdentity)};
}

public static IEnumerable<object[]> TypeFilterObjectFactory()
{
yield return new object[] { new ClassA(), true };
yield return new object[] { new ClassB(), true };
yield return new object[] { new ClassC(), false };
}

public class ClassA { }

public class ClassB { }

public class ClassC { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ public HyperionSerializer(ExtendedActorSystem system, HyperionSerializerSettings
knownTypes: provider.GetKnownTypes(),
ignoreISerializable:true,
packageNameOverrides: settings.PackageNameOverrides,
disallowUnsafeTypes: settings.DisallowUnsafeType));
disallowUnsafeTypes: settings.DisallowUnsafeType,
typeFilter: settings.TypeFilter));
}

/// <summary>
Expand Down Expand Up @@ -166,7 +167,8 @@ public sealed class HyperionSerializerSettings
knownTypesProvider: typeof(NoKnownTypes),
packageNameOverrides: new List<Func<string, string>>(),
surrogates: new Surrogate[0],
disallowUnsafeType: true);
disallowUnsafeType: true,
typeFilter: DisabledTypeFilter.Instance);

/// <summary>
/// Creates a new instance of <see cref="HyperionSerializerSettings"/> using provided HOCON config.
Expand Down Expand Up @@ -227,15 +229,31 @@ public static HyperionSerializerSettings Create(Config config)

surrogates.Add((Surrogate)Activator.CreateInstance(surrogateType));
}


var typeFilter = (ITypeFilter) DisabledTypeFilter.Instance;
var allowedList = config.GetStringList("allowed-types");
if (allowedList.Count > 0)
{
var filterBuilder = TypeFilterBuilder.Create();
foreach (var allowedFqcn in allowedList)
{
var allowedType = Type.GetType(allowedFqcn);
if (allowedType is null)
throw new ConfigurationException($"Could not load type [{allowedFqcn}] from allowed-type.");
filterBuilder.Include(allowedType);
}

typeFilter = filterBuilder.Build();
}

return new HyperionSerializerSettings(
preserveObjectReferences: config.GetBoolean("preserve-object-references", true),
versionTolerance: config.GetBoolean("version-tolerance", true),
knownTypesProvider: type,
packageNameOverrides: packageNameOverrides,
surrogates: surrogates,
disallowUnsafeType: config.GetBoolean("disallow-unsafe-type", true));
disallowUnsafeType: config.GetBoolean("disallow-unsafe-type", true),
typeFilter: typeFilter);
}

/// <summary>
Expand Down Expand Up @@ -278,6 +296,12 @@ public static HyperionSerializerSettings Create(Config config)
/// </summary>
public readonly bool DisallowUnsafeType;

/// <summary>
/// If set, Hyperion serializer will use the <see cref="ITypeFilter"/> to filter the types that are
/// being deserialized during run-time
/// </summary>
public readonly ITypeFilter TypeFilter;

/// <summary>
/// Creates a new instance of a <see cref="HyperionSerializerSettings"/>.
/// </summary>
Expand All @@ -287,7 +311,7 @@ public static HyperionSerializerSettings Create(Config config)
/// <exception cref="ArgumentException">Raised when `known-types-provider` type doesn't implement <see cref="IKnownTypesProvider"/> interface.</exception>
[Obsolete]
public HyperionSerializerSettings(bool preserveObjectReferences, bool versionTolerance, Type knownTypesProvider)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, new List<Func<string, string>>(), new Surrogate[0], true)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, new List<Func<string, string>>(), new Surrogate[0], true, DisabledTypeFilter.Instance)
{ }

/// <summary>
Expand All @@ -304,7 +328,7 @@ public HyperionSerializerSettings(
bool versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, new Surrogate[0], true)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, new Surrogate[0], true, DisabledTypeFilter.Instance)
{ }

/// <summary>
Expand All @@ -322,7 +346,27 @@ public HyperionSerializerSettings(
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides,
IEnumerable<Surrogate> surrogates)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, surrogates, true)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, surrogates, true, DisabledTypeFilter.Instance)
{ }

/// <summary>
/// Creates a new instance of a <see cref="HyperionSerializerSettings"/>.
/// </summary>
/// <param name="preserveObjectReferences">Flag which determines if serializer should keep track of references in serialized object graph.</param>
/// <param name="versionTolerance">Flag which determines if field data should be serialized as part of type manifest.</param>
/// <param name="knownTypesProvider">Type implementing <see cref="IKnownTypesProvider"/> to be used to determine a list of types implicitly known by all cooperating serializer.</param>
/// <param name="packageNameOverrides">An array of package name overrides for cross platform compatibility</param>
/// <param name="surrogates">A list of <see cref="Surrogate"/> instances that are used to de/serialize complex objects into a much simpler serialized objects.</param>
/// <param name="disallowUnsafeType">Block unsafe types from being deserialized.</param>
/// <exception cref="ArgumentException">Raised when `known-types-provider` type doesn't implement <see cref="IKnownTypesProvider"/> interface.</exception>
public HyperionSerializerSettings(
bool preserveObjectReferences,
bool versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides,
IEnumerable<Surrogate> surrogates,
bool disallowUnsafeType)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, surrogates, disallowUnsafeType, DisabledTypeFilter.Instance)
{ }

/// <summary>
Expand All @@ -334,14 +378,16 @@ public HyperionSerializerSettings(
/// <param name="packageNameOverrides">An array of package name overrides for cross platform compatibility</param>
/// <param name="surrogates">A list of <see cref="Surrogate"/> instances that are used to de/serialize complex objects into a much simpler serialized objects.</param>
/// <param name="disallowUnsafeType">Block unsafe types from being deserialized.</param>
/// <param name="typeFilter">A <see cref="ITypeFilter"/> instance that will filter types from being deserialized.</param>
/// <exception cref="ArgumentException">Raised when `known-types-provider` type doesn't implement <see cref="IKnownTypesProvider"/> interface.</exception>
public HyperionSerializerSettings(
bool preserveObjectReferences,
bool versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides,
IEnumerable<Surrogate> surrogates,
bool disallowUnsafeType)
bool disallowUnsafeType,
ITypeFilter typeFilter)
{
knownTypesProvider = knownTypesProvider ?? typeof(NoKnownTypes);
if (!typeof(IKnownTypesProvider).IsAssignableFrom(knownTypesProvider))
Expand All @@ -353,6 +399,7 @@ public HyperionSerializerSettings(
PackageNameOverrides = packageNameOverrides;
Surrogates = surrogates;
DisallowUnsafeType = disallowUnsafeType;
TypeFilter = typeFilter;
}
}
}
Loading

0 comments on commit 5223ed4

Please sign in to comment.