1 // CommonAclTest.cs - NUnit Test Cases for ObjectSecurity<T>
4 // James Bellinger (jfb@zer7.com)
6 // Copyright 2012 James Bellinger
9 using System.Collections.Generic;
10 using System.Security.AccessControl;
11 using System.Security.Principal;
12 using NUnit.Framework;
14 namespace MonoTests.System.Security.AccessControl
17 public class CommonAclTest
20 public void RevisionOK ()
22 DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, 0);
23 Assert.AreEqual (2, dacl.Revision);
27 public void RevisionDSOK ()
29 DiscretionaryAcl dacl = new DiscretionaryAcl(false, true, 0);
30 Assert.AreEqual (4, dacl.Revision);
34 public void NullRawAclRevisionOK ()
36 DiscretionaryAcl dacl1 = new DiscretionaryAcl (false, false, null);
37 Assert.AreEqual (2, dacl1.Revision);
39 DiscretionaryAcl dacl2 = new DiscretionaryAcl (false, true, null);
40 Assert.AreEqual (4, dacl2.Revision);
44 public void UsesRawAclRevision ()
46 RawAcl acl1 = new RawAcl (RawAcl.AclRevisionDS, 0);
47 DiscretionaryAcl dacl1 = new DiscretionaryAcl (false, false, acl1);
48 Assert.AreEqual (4, dacl1.Revision);
50 RawAcl acl2 = new RawAcl (RawAcl.AclRevision, 0);
51 DiscretionaryAcl dacl2 = new DiscretionaryAcl (false, true, acl2);
52 Assert.AreEqual (2, dacl2.Revision);
56 public void EmptyBinaryLengthOK()
58 DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, 0);
59 Assert.AreEqual (8, dacl.BinaryLength);
63 public void EmptyBinaryFormOK()
65 DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, 0);
66 byte[] buffer = new byte[8];
67 dacl.GetBinaryForm (buffer, 0);
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
75 public void EmptyBinaryFormDSOK()
77 DiscretionaryAcl dacl = new DiscretionaryAcl (false, true, 0);
78 byte[] buffer = new byte[8];
79 dacl.GetBinaryForm (buffer, 0);
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
86 [Test] // ... stumbled upon this by choosing Guid.Empty when needing an arbitrary GUID ...
87 public void GuidEmptyMergesRegardlessOfFlagsAndOpaqueDataIsNotConsidered ()
89 SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
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])
102 DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
103 Assert.IsTrue (dacl.IsCanonical);
104 Assert.AreEqual (3, dacl.Count);
106 CommonAce cace = (CommonAce)dacl [0];
107 Assert.AreEqual (12, cace.OpaqueLength);
108 Assert.AreEqual (5, cace.AccessMask);
109 Assert.IsTrue (cace.IsCallback);
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);
120 public void DetectsCanonicalMergesAndRemovesInheritedAces ()
122 SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
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)
132 Assert.AreEqual (6, acl.Count);
134 DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
135 Assert.IsTrue (dacl.IsCanonical);
136 Assert.AreEqual (4, dacl.Count);
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);
149 dacl.RemoveInheritedAces ();
150 Assert.AreEqual (2, dacl.Count);
153 Assert.AreEqual (0, dacl.Count);
157 public void DetectsNonCanonicalAndDoesNotMerge ()
159 SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
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)
168 DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
169 Assert.IsFalse (dacl.IsCanonical);
170 Assert.AreEqual (4, dacl.Count);
174 public void DoesNotMergeOrEvaluateOrderingForInherited ()
176 SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
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)
185 DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
186 Assert.IsTrue (dacl.IsCanonical);
187 Assert.AreEqual (4, dacl.Count);
191 public void SetterNotSupported ()
193 SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
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)
202 DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
203 Assert.IsTrue (dacl.IsCanonical);
204 Assert.AreEqual (4, dacl.Count);
206 bool throws1 = false;
207 try { dacl[0] = acl[0]; } catch (NotSupportedException) { throws1 = true; }
208 Assert.IsTrue (throws1);
210 bool throws2 = false;
211 try { dacl[0] = acl[2]; } catch (NotSupportedException) { throws2 = true; }
212 Assert.IsTrue (throws2);
216 public void CompoundAcesAreNotCanonical ()
218 SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
220 RawAcl acl = MakeRawAcl(new GenericAce[] {
221 new CompoundAce (AceFlags.None, 1, CompoundAceType.Impersonation, sid)
224 DiscretionaryAcl dacl = new DiscretionaryAcl (false, false, acl);
225 Assert.IsFalse (dacl.IsCanonical);
229 public void RemovesMeaninglessAces ()
231 RawAcl acl = GetRemovesMeaninglessAcesAcl ();
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);
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);
244 // shared with BinaryRoundtrip as well
245 static RawAcl GetRemovesMeaninglessAcesAcl ()
247 SecurityIdentifier sid = new SecurityIdentifier (WellKnownSidType.BuiltinUsersSid, null);
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
274 public void BinaryRoundtrip ()
276 RawAcl acl = GetRemovesMeaninglessAcesAcl ();
278 DiscretionaryAcl dacl1 = new DiscretionaryAcl (false, false, acl);
279 byte[] binaryForm1 = new byte[dacl1.BinaryLength];
280 dacl1.GetBinaryForm (binaryForm1, 0);
282 DiscretionaryAcl dacl2 = new DiscretionaryAcl (false, false, new RawAcl (binaryForm1, 0));
283 byte[] binaryForm2 = new byte[dacl2.BinaryLength];
284 dacl2.GetBinaryForm (binaryForm2, 0);
286 Assert.AreEqual (binaryForm1.Length, binaryForm2.Length);
287 for (int i = 0; i < binaryForm1.Length; i ++)
288 Assert.AreEqual (binaryForm1 [i], binaryForm2 [i]);
292 public void ContiguousRangeSorting ()
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")
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);
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
326 static RawAcl MakeRawAcl (GenericAce[] aces)
328 RawAcl acl = new RawAcl (RawAcl.AclRevision, 0);
329 for (int i = 0; i < aces.Length; i ++) { acl.InsertAce (i, aces [i]); }
333 static ushort ToUInt16(byte[] buffer, int offset)
335 return (ushort)(buffer [offset] | buffer [offset + 1]);