API 调用声称用户拥有文件夹权限,但实际上他们没有
Windows 服务存在问题,需要监视/访问一组文件夹,并在这些文件夹之间移动文件。
过去使用过一些样板代码,它将检查给定文件夹中给定用户的特定细粒度权限。奇怪的是,我通过测试发现,如果我手动拒绝运行服务的帐户对该文件夹的所有权限,然后运行代码,它会报告一切正常,并且用户实际上拥有这些权限,尽管很明显(并且可以证明)他不这样做。
起初我认为这可能是因为该服务在本地系统帐户下运行,但如果它使用 NetworkService 以及本地用户帐户运行,则会出现同样的问题。这是在 Windows 7/2008 R2 上。
样板方法:
public static void ValidateFolderPermissions(WindowsIdentity userId, string folder, FileSystemRights[] requiredAccessRights)
{
SecurityIdentifier secId;
StringBuilder sb = new StringBuilder();
bool permissionsAreSufficient = false;
bool notAuthorized = false;
String errorMsg = String.Empty;
IdentityReferenceCollection irc = userId.Groups;
foreach (IdentityReference ir in irc)
{
secId = ir.Translate(typeof(SecurityIdentifier)) as SecurityIdentifier;
try
{
DirectoryInfo dInfo = new DirectoryInfo(folder);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
AuthorizationRuleCollection rules = dSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier));
foreach (FileSystemAccessRule ar in rules)
{
if (secId.CompareTo(ar.IdentityReference as SecurityIdentifier) == 0)
{
sb.AppendLine(ar.FileSystemRights.ToString());
foreach (FileSystemRights right in requiredAccessRights)
{
if (right == ar.FileSystemRights)
{
permissionsAreSufficient = true;
break;
}
}
}
}
}
catch (UnauthorizedAccessException)
{
notAuthorized = true;
errorMsg = "user not authorized";
}
catch (SecurityException)
{
// If we failed authorization do not update error
if (!notAuthorized)
errorMsg = "security error";
}
catch (Exception)
{
// If we failed authorization do not update error
if (!notAuthorized)
errorMsg = "invalid folder or folder not accessible";
}
}
if (!permissionsAreSufficient)
{
if (!String.IsNullOrEmpty(errorMsg))
throw new Exception(String.Format("User {0} does not have required access to folder {1}. The error is {2}.", userId.Name, folder, errorMsg));
else
throw new Exception(String.Format("User {0} does not have required access rights to folder {1}.", userId.Name, folder));
}
}
以及调用片段:
FileSystemRights[] requireAccessRights =
{
FileSystemRights.Delete,
FileSystemRights.Read,
FileSystemRights.FullControl
};
try
{
FolderPermissionValidator.ValidateFolderPermissions(WindowsIdentity.GetCurrent(), inputFolder, requireAccessRights);
Log.Debug("In ServiceConfigurationValidator: {0}, {1}", WindowsIdentity.GetCurrent().Name, inputFolder);
}
catch (Exception ex)
{
Log.Debug("Throwing exception {0}", ex.Message);
}
Having an issue with a Windows service that needs to monitor/have access to a set of folders, and move files around between those folders.
There's have a bit of boilerplate code that's been used in the past, which will check a given folder for the specific granular permissions for the given user. The odd thing is that I discovered through testing that if I manually deny all permissions on that folder for the account the service is running under, and then run the code, it reports that all is well and the user does in fact have those permissions, even though it's obvious (and demonstrable) that he doesn't.
At first I thought this might be because the service was running under the local System account, but the same issue crops up if it is run with NetworkService as well as with a local user account. This is on Windows 7/2008 R2.
Boilerplate method:
public static void ValidateFolderPermissions(WindowsIdentity userId, string folder, FileSystemRights[] requiredAccessRights)
{
SecurityIdentifier secId;
StringBuilder sb = new StringBuilder();
bool permissionsAreSufficient = false;
bool notAuthorized = false;
String errorMsg = String.Empty;
IdentityReferenceCollection irc = userId.Groups;
foreach (IdentityReference ir in irc)
{
secId = ir.Translate(typeof(SecurityIdentifier)) as SecurityIdentifier;
try
{
DirectoryInfo dInfo = new DirectoryInfo(folder);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
AuthorizationRuleCollection rules = dSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier));
foreach (FileSystemAccessRule ar in rules)
{
if (secId.CompareTo(ar.IdentityReference as SecurityIdentifier) == 0)
{
sb.AppendLine(ar.FileSystemRights.ToString());
foreach (FileSystemRights right in requiredAccessRights)
{
if (right == ar.FileSystemRights)
{
permissionsAreSufficient = true;
break;
}
}
}
}
}
catch (UnauthorizedAccessException)
{
notAuthorized = true;
errorMsg = "user not authorized";
}
catch (SecurityException)
{
// If we failed authorization do not update error
if (!notAuthorized)
errorMsg = "security error";
}
catch (Exception)
{
// If we failed authorization do not update error
if (!notAuthorized)
errorMsg = "invalid folder or folder not accessible";
}
}
if (!permissionsAreSufficient)
{
if (!String.IsNullOrEmpty(errorMsg))
throw new Exception(String.Format("User {0} does not have required access to folder {1}. The error is {2}.", userId.Name, folder, errorMsg));
else
throw new Exception(String.Format("User {0} does not have required access rights to folder {1}.", userId.Name, folder));
}
}
And the calling snippet:
FileSystemRights[] requireAccessRights =
{
FileSystemRights.Delete,
FileSystemRights.Read,
FileSystemRights.FullControl
};
try
{
FolderPermissionValidator.ValidateFolderPermissions(WindowsIdentity.GetCurrent(), inputFolder, requireAccessRights);
Log.Debug("In ServiceConfigurationValidator: {0}, {1}", WindowsIdentity.GetCurrent().Name, inputFolder);
}
catch (Exception ex)
{
Log.Debug("Throwing exception {0}", ex.Message);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在检查允许的权限之前,我在 ValidateFolderPermissions 中没有看到任何内容来检查拒绝。如果拒绝条目阻止访问,则任何允许条目都无法覆盖它。
I don't see anything in ValidateFolderPermissions to check for denials before checking for allowed permissions. If a deny entry prevents access then no amount of allow entries can override it.
此代码将 ACL 中的条目枚举为 FileSystemAccessRule 对象,但不检查 AccessControlType 是允许还是拒绝。
我还注意到,如果任何 ACE 完全匹配 requiredAccessRights 数组的任何元素,则逻辑返回 true;我怀疑预期的行为是,如果所有指定的权限都存在,则返回 true。如果仅存在某些请求的权限,这可能会导致误报,但因为它只查找精确匹配,所以也可能导致误报,例如,如果 ACE 实际上提供的权限多于正在提供的权限要求。 (不过,在给出的示例中并不是这样的问题,因为您要求完全控制。)
另一个缺陷是它只检查与用户所属组匹配的访问条目;用户帐户本身的访问条目将被忽略。 (我不确定 WindowsIdentity.Groups 对于不是实际用户帐户的安全原语(例如 SYSTEM 和 NetworkService)的行为是什么,尽管听起来该部分正在按预期工作。)
请注意,因为它很难应对正确处理所有可能的情况(例如,考虑每个人或服务的访问控制条目),如果管理员错误地报告帐户没有必要的访问权限,则允许管理员覆盖检查是明智的。
This code enumerates the entries in the ACL as FileSystemAccessRule objects, but doesn't bother to check whether AccessControlType is allow or deny.
I also note that the logic returns true if any ACE exactly matches any of the elements of the requiredAccessRights array; I suspect the intended behaviour is that it return true if all of the specified rights are present. This could cause false positives if only some of the requested rights are present, but because it only looks for exact matches it could also cause a false negative, e.g., if the ACE actually gives more rights than are being requested. (Not such a problem in the example given, though, because you're asking for Full Control.)
Another flaw is that it only checks for access entries matching groups the user belongs to; access entries for the user account itself will be ignored. (I'm not sure what the behaviour of WindowsIdentity.Groups is for security primitives such as SYSTEM and NetworkService that are not actual user accounts, although it sounds like that part was working as desired.)
Note that because it is very hard to cope properly with all the possible situations (consider, e.g., an access control entry for Everyone, or for SERVICE) it would be wise to allow the administrator to override the check if it is mistakenly reporting that the account doesn't have the necessary access.