提交 96a2daf2 编写于 作者: C carlossanlop

Add AnonymousPipeServerStream method that takes an ACL

上级 ca2dec49
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27213.1
# Visual Studio Version 16
VisualStudioVersion = 16.0.29411.138
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.Pipes.AccessControl.Tests", "tests\System.IO.Pipes.AccessControl.Tests.csproj", "{A0356E61-19E1-4722-A53D-5D2616E16312}"
ProjectSection(ProjectDependencies) = postProject
......
......@@ -66,4 +66,9 @@ public partial class PipeSecurity : System.Security.AccessControl.NativeObjectSe
public void SetAccessRule(System.IO.Pipes.PipeAccessRule rule) { }
public void SetAuditRule(System.IO.Pipes.PipeAuditRule rule) { }
}
public static class AnonymousPipeServerStreamAcl
{
public static System.IO.Pipes.AnonymousPipeServerStream Create(System.IO.Pipes.PipeDirection direction, System.IO.HandleInheritability inheritability, int bufferSize, System.IO.Pipes.PipeSecurity pipeSecurity) { throw null; }
}
}
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
using Xunit;
namespace System.IO.Pipes.Tests
{
public class AnonymousPipeServerStreamAclTests : PipeServerStreamAclTestBase
{
private const PipeDirection DefaultPipeDirection = PipeDirection.In;
private const HandleInheritability DefaultInheritability = HandleInheritability.None;
private const int DefaultBufferSize = 1;
[Fact]
public void Create_NullSecurity()
{
CreateAndVerifyAnonymousPipe(expectedSecurity: null).Dispose();
}
[Fact]
public void Create_NotSupportedPipeDirection()
{
Assert.Throws<NotSupportedException>(() =>
{
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), PipeDirection.InOut).Dispose();
});
}
[Theory]
[InlineData((PipeDirection)(int.MinValue))]
[InlineData((PipeDirection)0)]
[InlineData((PipeDirection)4)]
[InlineData((PipeDirection)(int.MaxValue))]
public void Create_InvalidPipeDirection(PipeDirection direction)
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), direction).Dispose();
});
}
[Theory]
[InlineData((HandleInheritability)(int.MinValue))]
[InlineData((HandleInheritability)(-1))]
[InlineData((HandleInheritability)2)]
[InlineData((HandleInheritability)(int.MaxValue))]
public void Create_InvalidInheritability(HandleInheritability inheritability)
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), inheritability: inheritability).Dispose();
});
}
[Theory]
[InlineData(int.MinValue)]
[InlineData(-1)]
public void Create_InvalidBufferSize(int bufferSize)
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), bufferSize: bufferSize).Dispose();
});
}
public static IEnumerable<object[]> Create_ValidParameters_MemberData() =>
from direction in new[] { PipeDirection.In, PipeDirection.Out }
from inheritability in Enum.GetValues(typeof(HandleInheritability)).Cast<HandleInheritability>()
from bufferSize in new[] { 0, 1 }
select new object[] { direction, inheritability, bufferSize };
[Theory]
[MemberData(nameof(Create_ValidParameters_MemberData))]
public void Create_ValidParameters(PipeDirection direction, HandleInheritability inheritability, int bufferSize)
{
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), direction, inheritability, bufferSize).Dispose();
}
public static IEnumerable<object[]> Create_CombineRightsAndAccessControl_MemberData() =>
from rights in Enum.GetValues(typeof(PipeAccessRights)).Cast<PipeAccessRights>()
from accessControl in new[] { AccessControlType.Allow, AccessControlType.Deny }
select new object[] { rights, accessControl };
// These tests match NetFX behavior
[Theory]
[MemberData(nameof(Create_CombineRightsAndAccessControl_MemberData))]
public void Create_CombineRightsAndAccessControl(PipeAccessRights rights, AccessControlType accessControl)
{
// These are the two cases that create a valid pipe when using Allow
if ((rights == PipeAccessRights.FullControl || rights == PipeAccessRights.ReadWrite) &&
accessControl == AccessControlType.Allow)
{
VerifyValidSecurity(rights, accessControl);
}
// When creating the PipeAccessRule for the PipeSecurity, the PipeAccessRule constructor calls AccessMaskFromRights, which explicilty removes the Synchronize bit from rights when AccessControlType is Deny
// and rights is not FullControl, so using Synchronize with Deny is not allowed
else if (rights == PipeAccessRights.Synchronize && accessControl == AccessControlType.Deny)
{
Assert.Throws<ArgumentException>("accessMask", () =>
{
PipeSecurity security = GetPipeSecurity(WellKnownSidType.BuiltinUsersSid, PipeAccessRights.Synchronize, AccessControlType.Deny);
});
}
// Any other case is not authorized
else
{
PipeSecurity security = GetPipeSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl);
Assert.Throws<UnauthorizedAccessException>(() =>
{
AnonymousPipeServerStreamAcl.Create(DefaultPipeDirection, DefaultInheritability, DefaultBufferSize, security).Dispose();
});
}
}
[Theory]
[InlineData(PipeAccessRights.ReadWrite | PipeAccessRights.Synchronize, AccessControlType.Allow)]
public void Create_ValidBitwiseRightsSecurity(PipeAccessRights rights, AccessControlType accessControl)
{
VerifyValidSecurity(rights, accessControl);
}
private void VerifyValidSecurity(PipeAccessRights rights, AccessControlType accessControl)
{
PipeSecurity security = GetPipeSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl);
CreateAndVerifyAnonymousPipe(security).Dispose();
}
private AnonymousPipeServerStream CreateAndVerifyAnonymousPipe(
PipeSecurity expectedSecurity,
PipeDirection direction = DefaultPipeDirection,
HandleInheritability inheritability = DefaultInheritability,
int bufferSize = DefaultBufferSize)
{
AnonymousPipeServerStream pipe = AnonymousPipeServerStreamAcl.Create(direction, inheritability, bufferSize, expectedSecurity);
Assert.NotNull(pipe);
if (expectedSecurity != null)
{
PipeSecurity actualSecurity = pipe.GetAccessControl();
VerifyPipeSecurity(expectedSecurity, actualSecurity);
}
return pipe;
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
using Xunit;
namespace System.IO.Pipes.Tests
{
public class PipeServerStreamAclTestBase
{
protected PipeSecurity GetBasicPipeSecurity()
{
return GetPipeSecurity(
WellKnownSidType.BuiltinUsersSid,
PipeAccessRights.FullControl,
AccessControlType.Allow);
}
protected PipeSecurity GetPipeSecurity(WellKnownSidType sid, PipeAccessRights rights, AccessControlType accessControl)
{
var security = new PipeSecurity();
SecurityIdentifier identity = new SecurityIdentifier(sid, null);
var accessRule = new PipeAccessRule(identity, rights, accessControl);
security.AddAccessRule(accessRule);
return security;
}
protected void VerifyPipeSecurity(PipeSecurity expectedSecurity, PipeSecurity actualSecurity)
{
Assert.Equal(typeof(PipeAccessRights), expectedSecurity.AccessRightType);
Assert.Equal(typeof(PipeAccessRights), actualSecurity.AccessRightType);
List<PipeAccessRule> expectedAccessRules = expectedSecurity.GetAccessRules(includeExplicit: true, includeInherited: false, typeof(SecurityIdentifier))
.Cast<PipeAccessRule>().ToList();
List<PipeAccessRule> actualAccessRules = actualSecurity.GetAccessRules(includeExplicit: true, includeInherited: false, typeof(SecurityIdentifier))
.Cast<PipeAccessRule>().ToList();
Assert.Equal(expectedAccessRules.Count, actualAccessRules.Count);
if (expectedAccessRules.Count > 0)
{
Assert.All(expectedAccessRules, actualAccessRule =>
{
int count = expectedAccessRules.Count(expectedAccessRule => AreAccessRulesEqual(expectedAccessRule, actualAccessRule));
Assert.True(count > 0);
});
}
}
protected bool AreAccessRulesEqual(PipeAccessRule expectedRule, PipeAccessRule actualRule)
{
return
expectedRule.AccessControlType == actualRule.AccessControlType &&
expectedRule.PipeAccessRights == actualRule.PipeAccessRights &&
expectedRule.InheritanceFlags == actualRule.InheritanceFlags &&
expectedRule.PropagationFlags == actualRule.PropagationFlags;
}
}
}
......@@ -6,8 +6,10 @@
<AssembliesBeingTested Include="System.IO.Pipes" />
</ItemGroup>
<ItemGroup>
<Compile Include="AnonymousPipeTests\AnonymousPipeServerStreamAclTests.cs" />
<Compile Include="AnonymousPipeTests\AnonymousPipeTest.AclExtensions.cs" />
<Compile Include="NamedPipeTests\NamedPipeTest.AclExtensions.cs" />
<Compile Include="PipeServerStreamAclTestBase.cs" />
<Compile Include="PipeTest.AclExtensions.cs" />
<Compile Include="..\..\System.IO.Pipes\tests\PipeTestBase.cs" />
</ItemGroup>
......
# Exposed public in System.IO.Pipes.AccessControl but implemented in System.IO.Pipes
TypesMustExist : Type 'System.IO.Pipes.AnonymousPipeServerStreamAcl' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.IO.Pipes.PipeAccessRights' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.IO.Pipes.PipeAccessRule' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.IO.Pipes.PipeAuditRule' does not exist in the reference but it does exist in the implementation.
......
......@@ -2,10 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Security;
using Microsoft.Win32.SafeHandles;
namespace System.IO.Pipes
{
......
......@@ -2,9 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
using System.Security;
using Microsoft.Win32.SafeHandles;
namespace System.IO.Pipes
{
......
......@@ -2,11 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using Microsoft.Win32.SafeHandles;
namespace System.IO.Pipes
{
......@@ -15,13 +13,27 @@ namespace System.IO.Pipes
/// </summary>
public sealed partial class AnonymousPipeServerStream : PipeStream
{
// Creates the anonymous pipe.
internal AnonymousPipeServerStream(PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity)
: base(direction, bufferSize)
{
if (direction == PipeDirection.InOut)
{
throw new NotSupportedException(SR.NotSupported_AnonymousPipeUnidirectional);
}
if (inheritability < HandleInheritability.None || inheritability > HandleInheritability.Inheritable)
{
throw new ArgumentOutOfRangeException(nameof(inheritability), SR.ArgumentOutOfRange_HandleInheritabilityNoneOrInheritable);
}
Create(direction, inheritability, bufferSize, pipeSecurity);
}
private void Create(PipeDirection direction, HandleInheritability inheritability, int bufferSize)
{
Create(direction, inheritability, bufferSize, null);
}
// Creates the anonymous pipe. This overload is used in Mono to implement public constructors.
private void Create(PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity)
{
Debug.Assert(direction != PipeDirection.InOut, "Anonymous pipe direction shouldn't be InOut");
......
......@@ -2,9 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
using System.Diagnostics.CodeAnalysis;
using System.Security;
using Microsoft.Win32.SafeHandles;
namespace System.IO.Pipes
{
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace System.IO.Pipes
{
public static class AnonymousPipeServerStreamAcl
{
/// <summary>
/// Creates a new instance of the <see cref="AnonymousPipeServerStream" /> class with the specified pipe direction, inheritability mode, buffer size, and pipe security.
/// </summary>
/// <param name="direction">One of the enumeration values that determines the direction of the pipe. Anonymous pipes can only be in one direction, so direction cannot be set to <see cref="PipeDirection.InOut" />.</param>
/// <param name="inheritability">One of the enumeration values that determines whether the underlying handle can be inherited by child processes.</param>
/// <param name="bufferSize">The size of the buffer. This value must be greater than or equal to 0.</param>
/// <param name="pipeSecurity">An object that determines the access control and audit security for the pipe.</param>
/// <returns>A new anonymous pipe server stream instance.</returns>
/// <remarks>Setting <paramref name="pipeSecurity" /> to <see langword="null" /> is equivalent to calling the `System.IO.Pipes.AnonymousPipeServerStream(System.IO.Pipes.PipeDirection direction, System.IO.HandleInheritability inheritability, int bufferSize)` constructor directly.</remarks>
/// <exception cref="NotSupportedException"><paramref name="direction" /> is <see cref="PipeDirection.InOut" />.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="inheritability" /> is not set to a valid <see cref="HandleInheritability" /> enum value.</exception>
public static AnonymousPipeServerStream Create(PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity)
{
return new AnonymousPipeServerStream(direction, inheritability, bufferSize, pipeSecurity);
}
}
}
......@@ -139,9 +139,7 @@ private static CommonSecurityDescriptor CreateInternal(ResourceType resourceType
}
else if (error == Interop.Errors.ERROR_INVALID_NAME)
{
exception = new ArgumentException(
SR.Argument_InvalidName,
nameof(name));
exception = new ArgumentException(SR.Argument_InvalidName, nameof(name));
}
else if (error == Interop.Errors.ERROR_FILE_NOT_FOUND)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册