c#


C# Test if user has write access to a folder


I need to test if a user can write to a folder before actually attempting to do so.
I've implemented the following method (in C# 2.0) that attempts to retrieve the security permissions for the folder using Directory.GetAccessControl() method.
private bool hasWriteAccessToFolder(string folderPath)
{
try
{
// Attempt to get a list of security permissions from the folder.
// This will raise an exception if the path is read only or do not have access to view the permissions.
System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(folderPath);
return true;
}
catch (UnauthorizedAccessException)
{
return false;
}
}
When I was googling how to test for write access nothing like this came up and it appeared very complicated to actually test permissions in Windows. I am concerned that I am over-simplifying things and that this method is not robust, although it does seem to work.
Will my method to test if the current user has write access work correctly?
That's a perfectly valid way to check for folder access in C#. The only place it might fall down is if you need to call this in a tight loop where the overhead of an exception may be an issue.
There have been other similar questions asked previously.
I appreciate that this is a little late in the day for this post, but you might find this bit of code useful.
string path = #"c:\temp";
string NtAccountName = #"MyDomain\MyUserOrGroup";
DirectoryInfo di = new DirectoryInfo(path);
DirectorySecurity acl = di.GetAccessControl(AccessControlSections.All);
AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));
//Go through the rules returned from the DirectorySecurity
foreach (AuthorizationRule rule in rules)
{
//If we find one that matches the identity we are looking for
if (rule.IdentityReference.Value.Equals(NtAccountName,StringComparison.CurrentCultureIgnoreCase))
{
//Cast to a FileSystemAccessRule to check for access rights
if ((((FileSystemAccessRule)rule).FileSystemRights & FileSystemRights.WriteData)>0)
{
Console.WriteLine(string.Format("{0} has write access to {1}", NtAccountName, path));
}
else
{
Console.WriteLine(string.Format("{0} does not have write access to {1}", NtAccountName, path));
}
}
}
Console.ReadLine();
Drop that into a Console app and see if it does what you need.
public bool IsDirectoryWritable(string dirPath, bool throwIfFails = false)
{
try
{
using (FileStream fs = File.Create(
Path.Combine(
dirPath,
Path.GetRandomFileName()
),
1,
FileOptions.DeleteOnClose)
)
{ }
return true;
}
catch
{
if (throwIfFails)
throw;
else
return false;
}
}
For example for all users (Builtin\Users), this method works fine - enjoy.
public static bool HasFolderWritePermission(string destDir)
{
if(string.IsNullOrEmpty(destDir) || !Directory.Exists(destDir)) return false;
try
{
DirectorySecurity security = Directory.GetAccessControl(destDir);
SecurityIdentifier users = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
foreach(AuthorizationRule rule in security.GetAccessRules(true, true, typeof(SecurityIdentifier)))
{
if(rule.IdentityReference == users)
{
FileSystemAccessRule rights = ((FileSystemAccessRule)rule);
if(rights.AccessControlType == AccessControlType.Allow)
{
if(rights.FileSystemRights == (rights.FileSystemRights | FileSystemRights.Modify)) return true;
}
}
}
return false;
}
catch
{
return false;
}
}
I tried most of these, but they give false positives, all for the same reason.. It is not enough to test the directory for an available permission, you have to check that the logged in user is a member of a group that has that permission. To do this you get the users identity, and check if it is a member of a group that contains the FileSystemAccessRule IdentityReference. I have tested this, works flawlessly..
/// <summary>
/// Test a directory for create file access permissions
/// </summary>
/// <param name="DirectoryPath">Full path to directory </param>
/// <param name="AccessRight">File System right tested</param>
/// <returns>State [bool]</returns>
public static bool DirectoryHasPermission(string DirectoryPath, FileSystemRights AccessRight)
{
if (string.IsNullOrEmpty(DirectoryPath)) return false;
try
{
AuthorizationRuleCollection rules = Directory.GetAccessControl(DirectoryPath).GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
WindowsIdentity identity = WindowsIdentity.GetCurrent();
foreach (FileSystemAccessRule rule in rules)
{
if (identity.Groups.Contains(rule.IdentityReference))
{
if ((AccessRight & rule.FileSystemRights) == AccessRight)
{
if (rule.AccessControlType == AccessControlType.Allow)
return true;
}
}
}
}
catch { }
return false;
}
IMHO the only 100% reliable way to test if you can write to a directory is to actually write to it and eventually catch exceptions.
Try this:
try
{
DirectoryInfo di = new DirectoryInfo(path);
DirectorySecurity acl = di.GetAccessControl();
AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));
WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(currentUser);
foreach (AuthorizationRule rule in rules)
{
FileSystemAccessRule fsAccessRule = rule as FileSystemAccessRule;
if (fsAccessRule == null)
continue;
if ((fsAccessRule.FileSystemRights & FileSystemRights.WriteData) > 0)
{
NTAccount ntAccount = rule.IdentityReference as NTAccount;
if (ntAccount == null)
{
continue;
}
if (principal.IsInRole(ntAccount.Value))
{
Console.WriteLine("Current user is in role of {0}, has write access", ntAccount.Value);
continue;
}
Console.WriteLine("Current user is not in role of {0}, does not have write access", ntAccount.Value);
}
}
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("does not have write access");
}
Your code gets the DirectorySecurity for a given directory, and handles an exception (due to your not having access to the security info) correctly. However, in your sample you don't actually interrogate the returned object to see what access is allowed - and I think you need to add this in.
I used the same function for check if file hasWriteAccess:
private static bool HasWriteAccessToFile(string filePath)
{
try
{
// Attempt to get a list of security permissions from the file.
// This will raise an exception if the path is read only or do not have access to view the permissions.
File.GetAccessControl(filePath);
return true;
}
catch (UnauthorizedAccessException)
{
return false;
}
}
You can try following code block to check if the directory is having Write Access.
It checks the FileSystemAccessRule.
string directoryPath = "C:\\XYZ"; //folderBrowserDialog.SelectedPath;
bool isWriteAccess = false;
try
{
AuthorizationRuleCollection collection =
Directory.GetAccessControl(directoryPath)
.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
foreach (FileSystemAccessRule rule in collection)
{
if (rule.AccessControlType == AccessControlType.Allow)
{
isWriteAccess = true;
break;
}
}
}
catch (UnauthorizedAccessException ex)
{
isWriteAccess = false;
}
catch (Exception ex)
{
isWriteAccess = false;
}
if (!isWriteAccess)
{
//handle notifications
}
You have a potential race condition in your code--what happens if the user has permissions to write to the folder when you check, but before the user actually writes to the folder this permission is withdrawn? The write will throw an exception which you will need to catch and handle. So the initial check is pointless. You might as well just do the write and handle any exceptions. This is the standard pattern for your situation.
http://www.codeproject.com/KB/files/UserFileAccessRights.aspx
Very usefull Class, check for improved version in messages bellow.
Here is a modified version of CsabaS's answer, which accounts for explicit deny access rules. The function goes through all FileSystemAccessRules for a directory, and checks if the current user is in a role which has access to a directory. If no such roles are found or the user is in a role with denied access, the function returns false. To check read rights, pass FileSystemRights.Read to the function; for write rights, pass FileSystemRights.Write. If you want to check an arbitrary user's rights and not the current one's, substitute the currentUser WindowsIdentity for the desired WindowsIdentity. I would also advise against relying on functions like this to determine if the user can safely use the directory. This answer perfectly explains why.
public static bool UserHasDirectoryAccessRights(string path, FileSystemRights accessRights)
{
var isInRoleWithAccess = false;
try
{
var di = new DirectoryInfo(path);
var acl = di.GetAccessControl();
var rules = acl.GetAccessRules(true, true, typeof(NTAccount));
var currentUser = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(currentUser);
foreach (AuthorizationRule rule in rules)
{
var fsAccessRule = rule as FileSystemAccessRule;
if (fsAccessRule == null)
continue;
if ((fsAccessRule.FileSystemRights & accessRights) > 0)
{
var ntAccount = rule.IdentityReference as NTAccount;
if (ntAccount == null)
continue;
if (principal.IsInRole(ntAccount.Value))
{
if (fsAccessRule.AccessControlType == AccessControlType.Deny)
return false;
isInRoleWithAccess = true;
}
}
}
}
catch (UnauthorizedAccessException)
{
return false;
}
return isInRoleWithAccess;
}
Simply trying to access the file in question isn't necessarily enough. The test will run with the permissions of the user running the program - Which isn't necessarily the user permissions you want to test against.
I couldn't get GetAccessControl() to throw an exception on Windows 7 as recommended in the accepted answer.
I ended up using a variation of sdds's answer:
try
{
bool writeable = false;
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
DirectorySecurity security = Directory.GetAccessControl(pstrPath);
AuthorizationRuleCollection authRules = security.GetAccessRules(true, true, typeof(SecurityIdentifier));
foreach (FileSystemAccessRule accessRule in authRules)
{
if (principal.IsInRole(accessRule.IdentityReference as SecurityIdentifier))
{
if ((FileSystemRights.WriteData & accessRule.FileSystemRights) == FileSystemRights.WriteData)
{
if (accessRule.AccessControlType == AccessControlType.Allow)
{
writeable = true;
}
else if (accessRule.AccessControlType == AccessControlType.Deny)
{
//Deny usually overrides any Allow
return false;
}
}
}
}
return writeable;
}
catch (UnauthorizedAccessException)
{
return false;
}
Hope this helps.
I agree with Ash, that should be fine. Alternatively you could use declarative CAS and actually prevent the program from running in the first place if they don't have access.
I believe some of the CAS features may not be present in C# 4.0 from what I've heard, not sure if that might be an issue or not.
I faced the same problem: how to verify if I can read/write in a particular directory. I ended up with the easy solution to...actually test it.
Here is my simple though effective solution.
class Program
{
/// <summary>
/// Tests if can read files and if any are present
/// </summary>
/// <param name="dirPath"></param>
/// <returns></returns>
private genericResponse check_canRead(string dirPath)
{
try
{
IEnumerable<string> files = Directory.EnumerateFiles(dirPath);
if (files.Count().Equals(0))
return new genericResponse() { status = true, idMsg = genericResponseType.NothingToRead };
return new genericResponse() { status = true, idMsg = genericResponseType.OK };
}
catch (DirectoryNotFoundException ex)
{
return new genericResponse() { status = false, idMsg = genericResponseType.ItemNotFound };
}
catch (UnauthorizedAccessException ex)
{
return new genericResponse() { status = false, idMsg = genericResponseType.CannotRead };
}
}
/// <summary>
/// Tests if can wirte both files or Directory
/// </summary>
/// <param name="dirPath"></param>
/// <returns></returns>
private genericResponse check_canWrite(string dirPath)
{
try
{
string testDir = "__TESTDIR__";
Directory.CreateDirectory(string.Join("/", dirPath, testDir));
Directory.Delete(string.Join("/", dirPath, testDir));
string testFile = "__TESTFILE__.txt";
try
{
TextWriter tw = new StreamWriter(string.Join("/", dirPath, testFile), false);
tw.WriteLine(testFile);
tw.Close();
File.Delete(string.Join("/", dirPath, testFile));
return new genericResponse() { status = true, idMsg = genericResponseType.OK };
}
catch (UnauthorizedAccessException ex)
{
return new genericResponse() { status = false, idMsg = genericResponseType.CannotWriteFile };
}
}
catch (UnauthorizedAccessException ex)
{
return new genericResponse() { status = false, idMsg = genericResponseType.CannotWriteDir };
}
}
}
public class genericResponse
{
public bool status { get; set; }
public genericResponseType idMsg { get; set; }
public string msg { get; set; }
}
public enum genericResponseType
{
NothingToRead = 1,
OK = 0,
CannotRead = -1,
CannotWriteDir = -2,
CannotWriteFile = -3,
ItemNotFound = -4
}
Hope it helps !

Related Links

DateTime parsing - unexpected result
Measuring mb sent per second with C# sockets? (Multithread)
C# inheritance multiple for different children
IList to JSON fails
Convert to Nested JSON C#
Sending List<Object> WCF POST
Export to excel is exporting check box to excel instead of string
Loop iteration of an array string
Impersonate a user using the Session ID
Is it safe to store and update list in asp.net session via static methods?
Change of the edited cell in a datagridview cell
Trying a REST POST call in C# - using Postman code
List object initialization [duplicate]
How to access HttpContext.Current.User custom attributes in the view
Non-nullable property exception when inserting a new entity
Radio button limiting sets

Categories

HOME
cors
mysqli
opencv4android
data-modeling
lithium
crash
datetimepicker
css-selectors
coding-style
core-data
javascript-debugger
lambda-calculus
game-engine
owncloud
samba
android-wifi
inline-assembly
concatenation
continuous-fourier
windows-mobile
mongoose-im
orgchart
utc
android-6.0-marshmallow
workflow-foundation
multiple-inheritance
pypy
xlib
jmsserializerbundle
mplab
scene7
intersection
pyenv
abide
kepserverex
yelp
pygraphviz
stdin
superclass
qtwebkit
anonymous-function
emacs24
cancan
r-commander
android-vectordrawable
multi-select
group
scanf
huawei
lattice
blackberry-webworks
turbolinks
firebase-polymer
netlink
change-password
vitamio
gdi
custom-build-step
firefox-os
ooad
std
recode
libgcrypt
pushwoosh
textblob
data-representation
avd
radgrid
firebase-tools
numerical-recipes
javadb
report-builder2.0
livescript
farpoint-spread
db2-connect
logo-lang
nop
complete
lastinsertid
windows-scheduler
antixsslibrary
teamsystem
sipdroid
cinder
http-response-codes
chars
versions
newspeak
web-widget
dynamic-scope
user-preferences
cross-cutting-concerns

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App