8716cc763d995e5c8609cf60bd3101c72cc8af7a
[mono.git] / mcs / class / corlib / Test / System.Security.AccessControl / CommonAclTest.cs
1 // CommonAclTest.cs - NUnit Test Cases for ObjectSecurity<T>
2 //
3 // Authors:
4 //      James Bellinger (jfb@zer7.com)
5 //
6 // Copyright 2012 James Bellinger
7
8 using System;
9 using System.Collections.Generic;
10 using System.Security.AccessControl;
11 using System.Security.Principal;
12 using NUnit.Framework;
13
14 namespace MonoTests.System.Security.AccessControl
15 {
16         [TestFixture]
17         public class CommonAclTest
18         {
19                 [Test]
20                 public void RevisionOK ()
21                 {
22                         DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, 0);
23                         Assert.AreEqual (2, dacl.Revision);
24                 }
25
26                 [Test]
27                 public void RevisionDSOK ()
28                 {
29                         DiscretionaryAcl dacl = new DiscretionaryAcl(false, true, 0);
30                         Assert.AreEqual (4, dacl.Revision);
31                 }
32
33                 [Test]
34                 public void NullRawAclRevisionOK ()
35                 {
36                         DiscretionaryAcl dacl1 = new DiscretionaryAcl (false, false, null);
37                         Assert.AreEqual (2, dacl1.Revision);
38
39                         DiscretionaryAcl dacl2 = new DiscretionaryAcl (false, true, null);
40                         Assert.AreEqual (4, dacl2.Revision);
41                 }
42
43                 [Test]
44                 public void UsesRawAclRevision ()
45                 {
46                         RawAcl acl1 = new RawAcl (RawAcl.AclRevisionDS, 0);
47                         DiscretionaryAcl dacl1 = new DiscretionaryAcl (false, false, acl1);
48                         Assert.AreEqual (4, dacl1.Revision);
49
50                         RawAcl acl2 = new RawAcl (RawAcl.AclRevision, 0);
51                         DiscretionaryAcl dacl2 = new DiscretionaryAcl (false, true, acl2);
52                         Assert.AreEqual (2, dacl2.Revision);
53                 }
54
55                 [Test]
56                 public void EmptyBinaryLengthOK()
57                 {
58                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
59                         Assert.AreEqual (8, dacl.BinaryLength);
60                 }
61
62                 [Test]
63                 public void EmptyBinaryFormOK()
64                 {
65                         DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, 0);
66                         byte[] buffer = new byte[8];
67                         dacl.GetBinaryForm (buffer, 0);
68
69                         Assert.AreEqual (2, buffer [0]); // Revision
70                         Assert.AreEqual (8, ToUInt16 (buffer, 2)); // ACL Size
71                         Assert.AreEqual (0, ToUInt16 (buffer, 4)); // ACE Count
72                 }
73
74                 [Test]
75                 public void EmptyBinaryFormDSOK()
76                 {
77                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, true, 0);
78                         byte[] buffer = new byte[8];
79                         dacl.GetBinaryForm (buffer, 0);
80
81                         Assert.AreEqual (4, buffer [0]); // Revision
82                         Assert.AreEqual (8, ToUInt16 (buffer, 2)); // ACL Size
83                         Assert.AreEqual (0, ToUInt16 (buffer, 4)); // ACE Count
84                 }
85
86                 [Test] // ... stumbled upon this by choosing Guid.Empty when needing an arbitrary GUID ...
87                 public void GuidEmptyMergesRegardlessOfFlagsAndOpaqueDataIsNotConsidered ()
88                 {
89                         SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
90
91                         RawAcl acl = MakeRawAcl (new GenericAce[] {
92                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 1, sid, true, new byte[12]),
93                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 4, sid, false, new byte[8]), // gets merged
94                                 new ObjectAce (AceFlags.None, AceQualifier.AccessAllowed, 1, sid,
95                                                ObjectAceFlags.ObjectAceTypePresent, Guid.Empty, Guid.Empty, false, new byte[8]),
96                                 new ObjectAce (AceFlags.None, AceQualifier.AccessAllowed, 2, sid,
97                                                ObjectAceFlags.InheritedObjectAceTypePresent, Guid.Empty, Guid.Empty, true, new byte[16]), // gets merged
98                                 new ObjectAce (AceFlags.None, AceQualifier.AccessAllowed, 4, sid,
99                                                ObjectAceFlags.InheritedObjectAceTypePresent, Guid.Empty, Guid.NewGuid (), true, new byte[4])
100                         });
101
102                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
103                         Assert.IsTrue (dacl.IsCanonical);
104                         Assert.AreEqual (3, dacl.Count);
105
106                         CommonAce cace = (CommonAce)dacl [0];
107                         Assert.AreEqual (12, cace.OpaqueLength);
108                         Assert.AreEqual (5, cace.AccessMask);
109                         Assert.IsTrue (cace.IsCallback);
110
111                         ObjectAce oace = (ObjectAce)dacl [1];
112                         Assert.AreEqual (8, oace.OpaqueLength);
113                         Assert.AreEqual (3, oace.AccessMask);
114                         Assert.AreEqual (ObjectAceFlags.ObjectAceTypePresent, oace.ObjectAceFlags);
115                         Assert.AreEqual (Guid.Empty, oace.ObjectAceType);
116                         Assert.IsFalse (oace.IsCallback);
117                 }
118
119                 [Test]
120                 public void DetectsCanonicalMergesAndRemovesInheritedAces ()
121                 {
122                         SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
123
124                         RawAcl acl = MakeRawAcl(new GenericAce[] {
125                                 new CommonAce (AceFlags.None, AceQualifier.AccessDenied, 4, sid, false, null),
126                                 new CommonAce (AceFlags.None, AceQualifier.AccessDenied, 8, sid, false, null),
127                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 1, sid, false, null),
128                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 2, sid, false, null),
129                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 4, sid, false, null),
130                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 4, sid, false, null)
131                         });
132                         Assert.AreEqual (6, acl.Count);
133
134                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
135                         Assert.IsTrue (dacl.IsCanonical);
136                         Assert.AreEqual (4, dacl.Count);
137
138                         Assert.AreEqual (AceFlags.None, ((CommonAce)dacl [0]).AceFlags);
139                         Assert.AreEqual (AceFlags.None, ((CommonAce)dacl [1]).AceFlags);
140                         Assert.AreEqual (AceFlags.Inherited, ((CommonAce)dacl [2]).AceFlags);
141                         Assert.AreEqual (AceFlags.Inherited, ((CommonAce)dacl [3]).AceFlags);
142                         Assert.AreEqual (AceQualifier.AccessDenied, ((CommonAce)dacl [0]).AceQualifier);
143                         Assert.AreEqual (AceQualifier.AccessAllowed, ((CommonAce)dacl [1]).AceQualifier);
144                         Assert.AreEqual (AceQualifier.AccessAllowed, ((CommonAce)dacl [2]).AceQualifier);
145                         Assert.AreEqual (AceQualifier.AccessAllowed, ((CommonAce)dacl [3]).AceQualifier);
146                         GenericAce ace7 = dacl[0];
147                         Assert.IsInstanceOfType (typeof (CommonAce), ace7);
148
149                         dacl.RemoveInheritedAces ();
150                         Assert.AreEqual (2, dacl.Count);
151
152                         dacl.Purge (sid);
153                         Assert.AreEqual (0, dacl.Count);
154                 }
155
156                 [Test]
157                 public void DetectsNonCanonicalAndDoesNotMerge ()
158                 {
159                         SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
160
161                         RawAcl acl = MakeRawAcl(new GenericAce[] {
162                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 1, sid, false, null),
163                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 2, sid, false, null),
164                                 new CommonAce (AceFlags.None, AceQualifier.AccessDenied, 4, sid, false, null),
165                                 new CommonAce (AceFlags.None, AceQualifier.AccessDenied, 8, sid, false, null)
166                         });
167
168                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
169                         Assert.IsFalse (dacl.IsCanonical);
170                         Assert.AreEqual (4, dacl.Count);
171                 }
172
173                 [Test]
174                 public void DoesNotMergeOrEvaluateOrderingForInherited ()
175                 {
176                         SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
177
178                         RawAcl acl = MakeRawAcl(new GenericAce[] {
179                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessDenied, 1, sid, false, null),
180                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 2, sid, false, null),
181                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 4, sid, false, null),
182                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessDenied, 8, sid, false, null)
183                         });
184
185                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
186                         Assert.IsTrue (dacl.IsCanonical);
187                         Assert.AreEqual (4, dacl.Count);
188                 }
189
190                 [Test]
191                 public void SetterNotSupported ()
192                 {
193                         SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
194
195                         RawAcl acl = MakeRawAcl(new GenericAce[] {
196                                 new CommonAce (AceFlags.None, AceQualifier.AccessDenied, 1, sid, false, null),
197                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessDenied, 2, sid, false, null),
198                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 4, sid, false, null),
199                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 4, sid, false, null)
200                         });
201
202                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
203                         Assert.IsTrue (dacl.IsCanonical);
204                         Assert.AreEqual (4, dacl.Count);
205
206                         bool throws1 = false;
207                         try { dacl[0] = acl[0]; } catch (NotSupportedException) { throws1 = true; }
208                         Assert.IsTrue (throws1);
209
210                         bool throws2 = false;
211                         try { dacl[0] = acl[2]; } catch (NotSupportedException) { throws2 = true; }
212                         Assert.IsTrue (throws2);
213                 }
214
215                 [Test]
216                 public void CompoundAcesAreNotCanonical ()
217                 {
218                         SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
219
220                         RawAcl acl = MakeRawAcl(new GenericAce[] {
221                                 new CompoundAce (AceFlags.None, 1, CompoundAceType.Impersonation, sid)
222                         });
223
224                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
225                         Assert.IsFalse (dacl.IsCanonical);
226                 }
227
228                 [Test]
229                 public void RemovesMeaninglessAces ()
230                 {
231                         RawAcl acl = GetRemovesMeaninglessAcesAcl ();
232
233                         DiscretionaryAcl dacl1 = new DiscretionaryAcl (false, false, acl);
234                         Assert.IsTrue (dacl1.IsCanonical);
235                         Assert.AreEqual (7, dacl1.Count);
236                         Assert.AreEqual (12, ((KnownAce)dacl1 [0]).AccessMask);
237
238                         DiscretionaryAcl dacl2 = new DiscretionaryAcl (true, false, acl);
239                         Assert.IsTrue (dacl2.IsCanonical);
240                         Assert.AreEqual (8, dacl2.Count);
241                         Assert.AreEqual (12, ((KnownAce)dacl1 [0]).AccessMask);
242                 }
243
244                 // shared with BinaryRoundtrip as well
245                 static RawAcl GetRemovesMeaninglessAcesAcl ()
246                 {
247                         SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
248
249                         return MakeRawAcl(new GenericAce[] {
250                                 new CommonAce (AceFlags.None, AceQualifier.AccessDenied, 4, sid, false, null),
251                                 new CommonAce (AceFlags.None, AceQualifier.AccessDenied, 8, sid, false, null), // merged
252                                 new CommonAce (AceFlags.InheritOnly|AceFlags.ObjectInherit,
253                                                AceQualifier.AccessDenied, 42, sid, false, null), // removed ONLY if !IsContainer
254                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 0, sid, false, null), // removed
255                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 1, sid, false, null),
256                                 new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 2, sid, false, null), // merged
257                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 1, sid, false, null),
258                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 2, sid, false, null),
259                                 new ObjectAce (AceFlags.None, AceQualifier.AccessAllowed, 0, sid,
260                                                ObjectAceFlags.None, Guid.NewGuid (), Guid.NewGuid (), false, null), // removed
261                                 new ObjectAce (AceFlags.InheritOnly, AceQualifier.AccessAllowed, 1, sid,
262                                                ObjectAceFlags.ObjectAceTypePresent, Guid.NewGuid (), Guid.NewGuid (), false, null), // removed
263                                 new ObjectAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 1, sid,
264                                                ObjectAceFlags.None, Guid.NewGuid (), Guid.NewGuid (), false, null),
265                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessAllowed, 0, sid, false, null), // removed
266                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessDenied, 4, sid, false, null),
267                                 new CommonAce (AceFlags.Inherited, AceQualifier.AccessDenied, 4, sid, false, null),
268                                 new CommonAce (AceFlags.Inherited, AceQualifier.SystemAlarm, 4, sid, false, null), // removed
269                                 new CommonAce (AceFlags.Inherited, AceQualifier.SystemAudit, 4, sid, false, null) // removed
270                         });
271                 }
272
273                 [Test]
274                 public void BinaryRoundtrip ()
275                 {
276                         RawAcl acl = GetRemovesMeaninglessAcesAcl ();
277
278                         DiscretionaryAcl dacl1 = new DiscretionaryAcl (false, false, acl);
279                         byte[] binaryForm1 = new byte[dacl1.BinaryLength];
280                         dacl1.GetBinaryForm (binaryForm1, 0);
281
282                         DiscretionaryAcl dacl2 = new DiscretionaryAcl (false, false, new RawAcl (binaryForm1, 0));
283                         byte[] binaryForm2 = new byte[dacl2.BinaryLength];
284                         dacl2.GetBinaryForm (binaryForm2, 0);
285
286                         Assert.AreEqual (binaryForm1.Length, binaryForm2.Length);
287                         for (int i = 0; i < binaryForm1.Length; i ++)
288                                 Assert.AreEqual (binaryForm1 [i], binaryForm2 [i]);
289                 }
290
291                 [Test]
292                 public void ContiguousRangeSorting ()
293                 {
294                         SecurityIdentifier[] sids = new SecurityIdentifier[] {
295                                 new SecurityIdentifier (WellKnownSidType.BuiltinAdministratorsSid, null), // S-1-5-32-544
296                                 new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null),          // S-1-5-32-545
297                                 new SecurityIdentifier (WellKnownSidType.WorldSid, null),                 // S-1-1-0
298                                 new SecurityIdentifier ("S-1-5-40"),
299                                 new SecurityIdentifier ("S-1-5-30-123"),
300                                 new SecurityIdentifier ("S-1-5-32-99"),
301                                 new SecurityIdentifier ("S-1-5-23-45-67"),
302                                 new SecurityIdentifier ("S-1-5-32-5432"),
303                                 new SecurityIdentifier ("S-1-0-2"),
304                                 new SecurityIdentifier ("S-1-6-0")
305                         };
306
307                         GenericAce[] aces = new GenericAce[sids.Length];
308                         for (int i = 0; i < aces.Length; i ++)
309                                 aces [i] = new CommonAce (AceFlags.None, AceQualifier.AccessAllowed, 1, sids[i], false, null);
310                         RawAcl acl = MakeRawAcl (aces);
311
312                         DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
313                         Assert.IsTrue (dacl.IsCanonical);
314                         Assert.AreEqual (sids[8], ((CommonAce)dacl [0]).SecurityIdentifier); // S-1-0-2
315                         Assert.AreEqual (sids[2], ((CommonAce)dacl [1]).SecurityIdentifier); // S-1-1-0
316                         Assert.AreEqual (sids[3], ((CommonAce)dacl [2]).SecurityIdentifier); // S-1-5-40
317                         Assert.AreEqual (sids[4], ((CommonAce)dacl [3]).SecurityIdentifier); // S-1-5-30-123
318                         Assert.AreEqual (sids[5], ((CommonAce)dacl [4]).SecurityIdentifier); // S-1-5-32-99
319                         Assert.AreEqual (sids[0], ((CommonAce)dacl [5]).SecurityIdentifier); // S-1-5-32-544
320                         Assert.AreEqual (sids[1], ((CommonAce)dacl [6]).SecurityIdentifier); // S-1-5-32-545
321                         Assert.AreEqual (sids[7], ((CommonAce)dacl [7]).SecurityIdentifier); // S-1-5-32-5432
322                         Assert.AreEqual (sids[6], ((CommonAce)dacl [8]).SecurityIdentifier); // S-1-5-23-45-67
323                         Assert.AreEqual (sids[9], ((CommonAce)dacl [9]).SecurityIdentifier); // S-1-6-0
324                 }
325
326                 static RawAcl MakeRawAcl (GenericAce[] aces)
327                 {
328                         RawAcl acl = new RawAcl (RawAcl.AclRevision, 0);
329                         for (int i = 0; i < aces.Length; i ++) { acl.InsertAce (i, aces [i]); }
330                         return acl;
331                 }
332
333                 static ushort ToUInt16(byte[] buffer, int offset)
334                 {
335                         return (ushort)(buffer [offset] | buffer [offset + 1]);
336                 }
337         }
338 }
339
340