diff --git a/Source/Csla.TestHelpers/ApplicationContextManagerUnitTests.cs b/Source/Csla.TestHelpers/ApplicationContextManagerUnitTests.cs index d73a39c35b..012b9b9ebb 100644 --- a/Source/Csla.TestHelpers/ApplicationContextManagerUnitTests.cs +++ b/Source/Csla.TestHelpers/ApplicationContextManagerUnitTests.cs @@ -1,9 +1,19 @@ -namespace Csla.TestHelpers +using System.Security.Principal; + +namespace Csla.TestHelpers { public class ApplicationContextManagerUnitTests : Core.ApplicationContextManagerAsyncLocal { + public IPrincipal LastSetUserPrincipal { get; private set; } + public Guid InstanceId { get; private set; } = Guid.NewGuid(); public DateTime CreatedAt { get; private set; } = DateTime.Now; + + public override void SetUser(IPrincipal principal) + { + LastSetUserPrincipal = principal; + base.SetUser(principal); + } } } diff --git a/Source/Csla.TestHelpers/TestDIContextFactory.cs b/Source/Csla.TestHelpers/TestDIContextFactory.cs index ff9afba1e1..6a7f9b6084 100644 --- a/Source/Csla.TestHelpers/TestDIContextFactory.cs +++ b/Source/Csla.TestHelpers/TestDIContextFactory.cs @@ -74,10 +74,9 @@ public static TestDIContext CreateContext(Action customCslaOptions, var services = new ServiceCollection(); // Add Csla - //services.AddSingleton(); services.TryAddSingleton(); - services.AddCsla(customCslaOptions); services.AddSingleton(); + services.AddCsla(customCslaOptions); serviceProvider = services.BuildServiceProvider(); diff --git a/Source/Csla.test/DPException/DataPortalExceptionTests.cs b/Source/Csla.test/DPException/DataPortalExceptionTests.cs index 9f0672313d..f379c04791 100644 --- a/Source/Csla.test/DPException/DataPortalExceptionTests.cs +++ b/Source/Csla.test/DPException/DataPortalExceptionTests.cs @@ -71,7 +71,7 @@ public void CheckInnerExceptionsOnSave() #if (NETFRAMEWORK) Assert.AreEqual(".Net SqlClient Data Provider", exceptionSource); #else - Assert.AreEqual("Core .Net SqlClient Data Provider", exceptionSource); + Assert.AreEqual("Core Microsoft SqlClient Data Provider", exceptionSource); #endif //verify that the implemented method, DataPortal_OnDataPortal diff --git a/Source/Csla.test/DataPortal/DataPortalTests.cs b/Source/Csla.test/DataPortal/DataPortalTests.cs index c247113518..5f79e2cb21 100644 --- a/Source/Csla.test/DataPortal/DataPortalTests.cs +++ b/Source/Csla.test/DataPortal/DataPortalTests.cs @@ -15,6 +15,10 @@ using Csla.Rules; using Csla.Core; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Csla.Testing.Business.DataPortal; +using Csla.Server; +using System.Security.Principal; +using FluentAssertions.Execution; namespace Csla.Test.DataPortal { @@ -311,6 +315,29 @@ public async Task WhenCreatingANewObjectThePortalMustWaitAfterCreateUntilTheObje } } + [TestMethod] + public async Task CleanupShouldSetThePrincipalToAnUnathenticatedOne() + { + // We have to use an extra DI context here to setup the TestableDataPortal and set necessary options + var diContext = TestDIContextFactory.CreateContext(options => + { + options.Services.AddTransient(); + options.Security(s => s.FlowSecurityPrincipalFromClient = true); + options.DataPortal(dpo => dpo.AddServerSideDataPortal()); + }); + + var applicationContext = diContext.CreateTestApplicationContext(); + var contextManager = (ApplicationContextManagerUnitTests)applicationContext.ContextManager; + var dp = diContext.ServiceProvider.GetRequiredService(); + _ = await dp.Create(typeof(TestBO), null, new DataPortalContext(applicationContext, applicationContext.Principal, true, "en-US", "en-US", new Core.ContextDictionary()), true); + + using (new AssertionScope()) + { + contextManager.LastSetUserPrincipal.Should().NotBeNull(); + contextManager.LastSetUserPrincipal.Should().Match(p => !p.Identity.IsAuthenticated); + } + } + private void ClientPortal_DataPortalInvoke(DataPortalEventArgs obj) { TestResults.Add("dpinvoke", "true"); diff --git a/Source/Csla/ApplicationContext.cs b/Source/Csla/ApplicationContext.cs index a387fdcf52..aa00aef5ec 100644 --- a/Source/Csla/ApplicationContext.cs +++ b/Source/Csla/ApplicationContext.cs @@ -47,8 +47,8 @@ public ApplicationContext(ApplicationContextAccessor applicationContextAccessor) /// public ClaimsPrincipal Principal { - get { return (ClaimsPrincipal)ContextManager.GetUser(); } - set { ContextManager.SetUser(value); } + get { return (ClaimsPrincipal)User; } + set { User = value; } } /// @@ -64,7 +64,7 @@ public ClaimsPrincipal Principal public IPrincipal User { get { return ContextManager.GetUser(); } - set { ContextManager.SetUser(value); } + set { ContextManager.SetUser(value ?? new ClaimsPrincipal(new ClaimsIdentity())); } } /// diff --git a/Source/Csla/Server/DataPortal.cs b/Source/Csla/Server/DataPortal.cs index 3b19eb3d83..3483a85ef3 100644 --- a/Source/Csla/Server/DataPortal.cs +++ b/Source/Csla/Server/DataPortal.cs @@ -7,6 +7,7 @@ //----------------------------------------------------------------------- using System.Diagnostics.CodeAnalysis; +using System.Security.Claims; using System.Security.Principal; using Csla.Configuration; using Csla.Properties; diff --git a/docs/Upgrading to CSLA 9.md b/docs/Upgrading to CSLA 9.md index 6c50e6aec2..4180438c8a 100644 --- a/docs/Upgrading to CSLA 9.md +++ b/docs/Upgrading to CSLA 9.md @@ -191,6 +191,8 @@ Supporting nullable types means that some APIs have changed to support nullable * Type `Csla.Serialization.SerializationFormatterFactory` was removed. To get the serializer resolve an instance of type `ISerializationFormatter`. For example `ApplicationContext.GetRequiredService()`(from within a business object) * `Csla.Core.IParent` * `ApplyEditChild` and `RemoveChild` changed from `void` to `Task` return type +* `void Csla.Core.IContextManager.SetUser(IPrincipal principal)` does not accept `null` anymore + * This change only affects you when you use the `IContextManager` directly. If you use `ApplicationContext.User` CSLA will take care of translating it into a non-null IPrincipal. #### Using Timeout in `HttpProxy` and `HttpCompressionProxy`