// Copyright (C) Stichting Deltares 2016. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
using NUnit.Framework;
namespace Core.Common.TestUtil.Test
{
[TestFixture]
public class DirectoryPermissionsRevokerTest
{
private readonly string testWorkDir = Path.Combine(".", "DirectoryPermissionsRevokerTest");
[Test]
[TestCase(null)]
[TestCase("")]
[TestCase(" ")]
public void Constructor_NullPath_ThrowsArgumentException(string invalidPath)
{
// Call
TestDelegate test = () => new DirectoryPermissionsRevoker(invalidPath, FileSystemRights.Modify);
// Assert
string paramName = Assert.Throws(test).ParamName;
Assert.AreEqual("folderPath", paramName);
}
[Test]
public void Constructor_PathDoesNotExist_ThrowsDirectoryNotFoundException()
{
// Setup
const string invalidPath = @".\DirectoryDoesNotExist\fileDoesNotExist";
// Call
TestDelegate test = () => new DirectoryPermissionsRevoker(invalidPath, FileSystemRights.Modify);
// Assert
Assert.Throws(test);
}
[Test]
public void Constructor_UnsupportedRight_ThrowsNotSupportedException()
{
// Setup
const FileSystemRights rights = FileSystemRights.Synchronize;
var accessDirectory = Path.Combine(testWorkDir, "Constructor_UnsupportedRight_ThrowsNotSupportedException", rights.ToString());
Directory.CreateDirectory(accessDirectory);
try
{
// Call
TestDelegate test = () => { new DirectoryPermissionsRevoker(accessDirectory, rights); };
// Assert
Assert.Throws(test);
}
finally
{
Directory.Delete(accessDirectory, true);
}
}
[Test]
[TestCase(FileSystemRights.AppendData)]
[TestCase(FileSystemRights.ChangePermissions)]
[TestCase(FileSystemRights.Delete)]
[TestCase(FileSystemRights.DeleteSubdirectoriesAndFiles)]
[TestCase(FileSystemRights.ExecuteFile)]
[TestCase(FileSystemRights.FullControl)]
[TestCase(FileSystemRights.Modify)]
[TestCase(FileSystemRights.Read)]
[TestCase(FileSystemRights.ReadAndExecute)]
[TestCase(FileSystemRights.ReadAttributes)]
[TestCase(FileSystemRights.ReadData)]
[TestCase(FileSystemRights.ReadExtendedAttributes)]
[TestCase(FileSystemRights.ReadPermissions)]
[TestCase(FileSystemRights.TakeOwnership)]
[TestCase(FileSystemRights.Write)]
[TestCase(FileSystemRights.WriteData)]
[TestCase(FileSystemRights.WriteAttributes)]
[TestCase(FileSystemRights.WriteExtendedAttributes)]
[TestCase(FileSystemRights.Delete | FileSystemRights.Read)]
[TestCase(FileSystemRights.Delete | FileSystemRights.Synchronize)]
public void Constructor_ValidPathDenyRight_SetsDenyRight(FileSystemRights rights)
{
// Setup
var accessDirectory = Path.Combine(testWorkDir, "Constructor_ValidPathDenyRight_SetsDenyRight", rights.ToString());
Directory.CreateDirectory(accessDirectory);
try
{
// Call
using (new DirectoryPermissionsRevoker(accessDirectory, rights))
{
// Assert
AssertPathHasAccessRuleSet(accessDirectory, rights);
}
AssertPathHasAccessRuleNotSet(accessDirectory, rights);
}
finally
{
Directory.Delete(accessDirectory, true);
}
}
[Test]
[TestCase(FileSystemRights.AppendData)]
[TestCase(FileSystemRights.ChangePermissions)]
[TestCase(FileSystemRights.Delete)]
[TestCase(FileSystemRights.DeleteSubdirectoriesAndFiles)]
[TestCase(FileSystemRights.ExecuteFile)]
[TestCase(FileSystemRights.FullControl)]
[TestCase(FileSystemRights.Modify)]
[TestCase(FileSystemRights.Read)]
[TestCase(FileSystemRights.ReadAndExecute)]
[TestCase(FileSystemRights.ReadAttributes)]
[TestCase(FileSystemRights.ReadData)]
[TestCase(FileSystemRights.ReadExtendedAttributes)]
[TestCase(FileSystemRights.ReadPermissions)]
[TestCase(FileSystemRights.TakeOwnership)]
[TestCase(FileSystemRights.Write)]
[TestCase(FileSystemRights.WriteData)]
[TestCase(FileSystemRights.WriteAttributes)]
[TestCase(FileSystemRights.WriteExtendedAttributes)]
[TestCase(FileSystemRights.Delete | FileSystemRights.Read)]
[TestCase(FileSystemRights.Delete | FileSystemRights.Synchronize)]
public void Dispose_RightAlreadySet_DoesNotRemoveRight(FileSystemRights rights)
{
// Setup
var accessDirectory = Path.Combine(testWorkDir, "Dispose_RightAlreadySet_DoesNotRemoveRight", rights.ToString());
Directory.CreateDirectory(accessDirectory);
AddDirectoryAccessRule(accessDirectory, rights);
// Precondition
AssertPathHasAccessRuleSet(accessDirectory, rights);
try
{
// Call
using (new DirectoryPermissionsRevoker(accessDirectory, rights))
{
// Assert
AssertPathHasAccessRuleSet(accessDirectory, rights);
}
AssertPathHasAccessRuleSet(accessDirectory, rights);
}
finally
{
RemoveDirectoryAccessRule(accessDirectory, rights);
Directory.Delete(accessDirectory, true);
}
}
[Test]
public void Dispose_DirectoryAlreadyRemoved_DoesNotThrowException()
{
// Setup
var accessDirectory = Path.Combine(testWorkDir, "Deleted");
Directory.CreateDirectory(accessDirectory);
TestDelegate test = () =>
{
// Call
using (new DirectoryPermissionsRevoker(accessDirectory, FileSystemRights.Write))
{
Directory.Delete(accessDirectory, true);
}
};
// Assert
Assert.DoesNotThrow(test);
}
#region Assert access rules
private static void AssertPathHasAccessRuleNotSet(string filePath, FileSystemRights rights)
{
DirectoryInfo directoryInfo = new DirectoryInfo(filePath);
DirectorySecurity directorySecurity = directoryInfo.GetAccessControl();
var rules = directorySecurity.GetAccessRules(true, false, typeof(SecurityIdentifier));
var supportedFileSystemRights = GetSupportedFileSystemRights(rights);
var fileSystemAccessRule = rules.OfType().FirstOrDefault(
fs => fs.FileSystemRights.HasFlag(supportedFileSystemRights) && fs.AccessControlType == AccessControlType.Deny);
Assert.IsNull(fileSystemAccessRule, string.Format("Rights '{0} {1}' are set for '{2}'", AccessControlType.Deny, supportedFileSystemRights, filePath));
}
private static FileSystemRights GetSupportedFileSystemRights(FileSystemRights rights)
{
return rights & ~FileSystemRights.Synchronize;
}
private void AssertPathHasAccessRuleSet(string filePath, FileSystemRights rights)
{
DirectoryInfo directoryInfo = new DirectoryInfo(filePath);
DirectorySecurity directorySecurity = directoryInfo.GetAccessControl();
var rules = directorySecurity.GetAccessRules(true, false, typeof(SecurityIdentifier));
var supportedFileSystemRights = GetSupportedFileSystemRights(rights);
var fileSystemAccessRule = rules.OfType().FirstOrDefault(
fs => fs.FileSystemRights.HasFlag(supportedFileSystemRights) && fs.AccessControlType == AccessControlType.Deny);
Assert.IsNotNull(fileSystemAccessRule, string.Format("Rights '{0} {1}' not set for '{2}'", AccessControlType.Deny, (supportedFileSystemRights), filePath));
}
#endregion
#region Apply access rules
private static void AddDirectoryAccessRule(string filePath, FileSystemRights rights)
{
var sid = GetSecurityIdentifier();
DirectoryInfo directoryInfo = new DirectoryInfo(filePath);
DirectorySecurity directorySecurity = directoryInfo.GetAccessControl();
directorySecurity.AddAccessRule(new FileSystemAccessRule(sid, rights, AccessControlType.Deny));
directoryInfo.SetAccessControl(directorySecurity);
}
private static void RemoveDirectoryAccessRule(string filePath, FileSystemRights rights)
{
var sid = GetSecurityIdentifier();
DirectoryInfo directoryInfo = new DirectoryInfo(filePath);
DirectorySecurity directorySecurity = directoryInfo.GetAccessControl();
directorySecurity.RemoveAccessRule(new FileSystemAccessRule(sid, rights, AccessControlType.Deny));
directoryInfo.SetAccessControl(directorySecurity);
}
private static SecurityIdentifier GetSecurityIdentifier()
{
SecurityIdentifier id = WindowsIdentity.GetCurrent().User.AccountDomainSid;
return new SecurityIdentifier(WellKnownSidType.WorldSid, id);
}
#endregion
}
}