Merge pull request #337 from robwilkens/IdleThreadsFixes
[mono.git] / mcs / class / System.Core / Test / System.IO.Pipes / PipeSecurityTest.cs
1 // PipeSecurityTest.cs - NUnit Test Cases for PipeSecurity
2 //
3 // Authors:
4 //      James Bellinger  <jfb@zer7.com>
5 //
6 // Copyright (C) 2012 James Bellinger
7
8 using System;
9 using System.Collections.Generic;
10 using System.IO;
11 using System.IO.Pipes;
12 using System.Security.AccessControl;
13 using System.Security.Principal;
14 using System.Threading;
15 using NUnit.Framework;
16
17 namespace MonoTests.System.IO.Pipes
18 {
19         [TestFixture]
20         public class PipeSecurityTest
21         {
22                 [Test]
23                 public void NamedPipeDefaultPermissionsWork ()
24                 {
25                         if (PlatformID.Win32NT != Environment.OSVersion.Platform) {
26                                 Assert.Ignore (); return;
27                         }
28
29                         string name = @"Local\MonoTestPipeNPNPW";
30                         using (NamedPipeServerStream server = CreateNamedServer (false, name, null, 0)) {
31                                 PipeSecurity security = server.GetAccessControl ();
32
33                                 AuthorizationRuleCollection rules = security.GetAccessRules (true, false,
34                                                                                              typeof (SecurityIdentifier));
35                                 Assert.AreNotEqual (0, rules.Count);
36                         }
37                 }
38
39                 [Test]
40                 public void NamedPipeSetAccessControlFailsWithoutChangePermissionRight ()
41                 {
42                         if (PlatformID.Win32NT != Environment.OSVersion.Platform) {
43                                 Assert.Ignore (); return;
44                         }
45
46                         string name = @"Local\MonoTestPipeNPSACFWCPR";
47                         using (NamedPipeServerStream server = CreateNamedServer (false, name, null, 0)) {
48                                 bool unauthorized = false;
49                                 try {
50                                         AddDenyEveryone (server);
51                                 } catch (UnauthorizedAccessException) {
52                                         unauthorized = true;
53                                 }
54
55                                 Assert.IsTrue (unauthorized, "PipeAccessRights.ChangePermissions was not required");
56                         }
57                 }
58
59                 [Test]
60                 public void NamedPipePermissionsActuallyWorkSyncAllow ()
61                 {
62                         NamedPipePermissionsActuallyWorkSync (@"Local\MonoTestPipeNPPAWSA", false);
63                 }
64
65                 [Test]
66                 public void NamedPipePermissionsActuallyWorkSyncDeny ()
67                 {
68                         NamedPipePermissionsActuallyWorkSync (@"Local\MonoTestPipeNPPAWSD", true);
69                 }
70
71                 void NamedPipePermissionsActuallyWorkSync (string name, bool addDenyEveryone)
72                 {
73                         if (PlatformID.Win32NT != Environment.OSVersion.Platform) {
74                                 Assert.Ignore (); return;
75                         }
76
77                         PipeSecurity security = new PipeSecurity ();
78                         SecurityIdentifier worldSid = new SecurityIdentifier ("WD");
79                         PipeAccessRule rule = new PipeAccessRule (worldSid,
80                                                                   PipeAccessRights.FullControl,
81                                                                   AccessControlType.Allow);
82                         security.AddAccessRule (rule);
83
84                         using (NamedPipeServerStream server = CreateNamedServer (false, name, security,
85                                                                                  PipeAccessRights.ChangePermissions)) {
86                                 security = server.GetAccessControl ();
87
88                                 AuthorizationRuleCollection rules;
89                                 rules = security.GetAccessRules (true, true, typeof (SecurityIdentifier));
90                                 Assert.AreEqual (1, rules.Count);
91
92                                 rule = (PipeAccessRule)rules [0];
93                                 Assert.AreEqual (AccessControlType.Allow, rule.AccessControlType);
94                                 Assert.AreEqual (worldSid, rule.IdentityReference);
95                                 Assert.AreEqual (PipeAccessRights.FullControl, rule.PipeAccessRights);
96
97                                 if (addDenyEveryone)
98                                         AddDenyEveryone (server);
99
100                                 bool unauthorized = false;
101                                 using (NamedPipeClientStream client = CreateNamedClient (false, name)) {
102                                         try {
103                                                 client.Connect (1000);
104                                         } catch (UnauthorizedAccessException) {
105                                                 unauthorized = true;
106                                         }
107                                 }
108
109                                 Assert.AreEqual (addDenyEveryone, unauthorized);
110                         }
111                 }
112
113
114                 [Test]
115                 [Category ("NotWorking")] // Async is completely broken on Mono Win32 pipes.
116                 public void NamedPipePermissionsActuallyWorkAsync ()
117                 {
118                         if (PlatformID.Win32NT != Environment.OSVersion.Platform) {
119                                 Assert.Ignore (); return;
120                         }
121
122                         IAsyncResult waitForConnection;
123                         string name = @"Local\MonoTestPipeNPPAWA";
124
125                         using (NamedPipeServerStream server = CreateNamedServer (true, name, null,
126                                                                                  PipeAccessRights.ChangePermissions)) {
127                                 // Test connecting to make sure our later test throwing is due to permissions.
128                                 waitForConnection = server.BeginWaitForConnection (null, null);
129
130                                 using (NamedPipeClientStream client = CreateNamedClient (true, name)) {
131                                         client.Connect (1000);
132
133                                         if (!waitForConnection.AsyncWaitHandle.WaitOne (1000)) {
134                                                 Assert.Fail ("No connection request received."); return;
135                                         }
136                                         server.EndWaitForConnection (waitForConnection);
137                                         server.Disconnect ();
138                                 }
139
140                                 // Let's add a Deny for Everyone.
141                                 AddDenyEveryone (server);
142
143                                 // This Connect call should fail.
144                                 waitForConnection = server.BeginWaitForConnection (null, null);
145
146                                 bool unauthorized = false;
147                                 using (NamedPipeClientStream client = CreateNamedClient (true, name)) {
148                                         try {
149                                                 client.Connect (1000);
150                                         } catch (UnauthorizedAccessException) {
151                                                 unauthorized = true;
152                                         }
153                                 }
154
155                                 Assert.IsTrue (unauthorized, "Client was allowed to connect despite Deny ACE.");
156                         }
157                 }
158
159                 static void AddDenyEveryone (PipeStream stream)
160                 {
161                         PipeAccessRule rule; PipeSecurity security;
162                         AuthorizationRuleCollection inRules, outRules;
163
164                         // Let's add a Deny for Everyone.
165                         security = stream.GetAccessControl ();
166
167                         inRules = security.GetAccessRules (true, false, typeof (SecurityIdentifier));
168                         Assert.AreNotEqual (0, inRules.Count);
169
170                         rule = new PipeAccessRule (new SecurityIdentifier ("WD"),
171                                                    PipeAccessRights.FullControl,
172                                                    AccessControlType.Deny);
173                         security.AddAccessRule (rule);
174                         stream.SetAccessControl (security);
175
176                         security = stream.GetAccessControl ();
177                         outRules = security.GetAccessRules (true, false, typeof (SecurityIdentifier));
178                         Assert.AreEqual (inRules.Count + 1, outRules.Count);
179                 }
180
181                 static NamedPipeClientStream CreateNamedClient (bool @async, string name)
182                 {
183                         return new NamedPipeClientStream (".", name,
184                                                           PipeDirection.InOut,
185                                                           @async ? PipeOptions.Asynchronous : PipeOptions.None);
186                 }
187
188                 static NamedPipeServerStream CreateNamedServer (bool @async, string name,
189                                                            PipeSecurity security,
190                                                            PipeAccessRights additionalRights)
191                 {
192                         return new NamedPipeServerStream (name,
193                                                           PipeDirection.InOut, 1,
194                                                           PipeTransmissionMode.Byte,
195                                                           @async ? PipeOptions.Asynchronous : PipeOptions.None,
196                                                           512, 512, security,
197                                                           HandleInheritability.None,
198                                                           additionalRights);
199                 }
200         }
201 }
202