设置文件所有者抛出InvalidOperation异常

时间:2012-12-10 13:02:49

标签: c# security

我正在使用以下代码更改文件的所有者。此代码在使用C#,4.0版编写的Windows服务中运行。它运行在运行Windows Server 2008 R2 Standard,Service Pack 1的本地服务器上。

我需要将通过FTP接收的文件的所有者更改为域帐户。我可以登录到框并使用资源管理器手动执行,但是当我尝试通过代码运行时,我得到一个InvalidOperation异常。我可以将所有者更改为本地系统帐户,但不能更改为网络帐户。任何有关这方面的帮助将不胜感激。

我正在处理一些处理EDI文件的奇怪的Microsoft Dynamics AX代码。该过程要求文件的所有者是有效的DAX用户,在这种情况下是域用户。我们有供应商通过FTP向我们发送EDI数据。我们的DAX应用程序每10分钟检查一次FTP目录并处理这些文件。该进程当前失败,因为所有者无效。所以,我写了一个服务,以便在文件到达时更改文件的所有者。但是,下面的代码失败,代码示例下面显示异常。

var ediFileOwner = new NTAccount("MyDomain", _ediEndpointUserAccount);

var fileSecurity = File.GetAccessControl(fileName);

var everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);

fileSecurity.AddAccessRule(new FileSystemAccessRule(everyone, FileSystemRights.FullControl, AccessControlType.Allow));
fileSecurity.AddAccessRule(new FileSystemAccessRule(ediFileOwner, FileSystemRights.TakeOwnership, AccessControlType.Allow));


fileSecurity.SetOwner(ediFileOwner); //Change our owner from to our desired User

File.SetAccessControl(fileName, fileSecurity);

以下是完整的例外:

System.InvalidOperationException: The security identifier is not allowed to be the owner of this object.
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, AccessControlSections includeSections, Object exceptionContext)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, AccessControlSections includeSections)
at System.Security.AccessControl.FileSystemSecurity.Persist(String fullPath)
at System.IO.File.SetAccessControl(String path, FileSecurity fileSecurity)

更新

如果我将服务运行的帐户更改为我尝试更改为所有者的帐户,我会得到一个不同的例外。

  

意外异常:System.UnauthorizedAccessException:试图   执行未经授权的操作。在   System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType类型,   字符串名称,SafeHandle句柄,SecurityInfos securityInformation,   SecurityIdentifier所有者,SecurityIdentifier组,GenericAcl sacl,   GenericAcl dacl)

1 个答案:

答案 0 :(得分:2)

我最终使用了我在此处找到的一些代码,http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User

为了让一切都完成,我不得不跳过一些箍,但它有效。为了避免我遇到的错误,除了在整个用户之间切换之外,我还必须使用我发现的Impersonate内容。

using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

// ...        

//Copy the file. This allows our service account to take ownership of the copied file
var tempFileName = Path.Combine(Path.GetDirectoryName(file.FileName), "TEMP_" + file.FileNameOnly);
File.Copy(file.FileName, tempFileName);


var windowID = WindowsIdentity.GetCurrent();

var currUserName = windowID.User.Translate(typeof(NTAccount)).Value;
var splitChar = new[] { '\\' };

//var name = currUserName.Split(splitChar)[1];
//var domain = currUserName.Split(splitChar)[0];

var ediFileOwner = new NTAccount("TricorBraun", _radleyEDIEndpointUserAccount);

//We have to give Access to the service account to delete the original file
var fileSecurity = File.GetAccessControl(file.FileName);
var everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
fileSecurity.AddAccessRule(new FileSystemAccessRule(everyone, FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(file.FileName, fileSecurity);
File.Delete(file.FileName);



//We rename our file to get our original file name back
File.Move(tempFileName, file.FileName);


//The following give our desired user permissions to take Ownership of the file.
//We have to do this while running under the service account.
fileSecurity = File.GetAccessControl(file.FileName);
var aosSID =  (SecurityIdentifier) ediFileOwner.Translate(typeof(SecurityIdentifier));
fileSecurity.AddAccessRule(new FileSystemAccessRule(aosSID, FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(file.FileName, fileSecurity);

//Now we user the Impersonator (http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User)
//This allows us to manage the file as the Account we wish to change ownership to.
//It makes itself the owner.
using (new Impersonator(_radleyEDIEndpointUserAccount, "MyDomain", "password")) {
    _logger.Debug(string.Format("Attempting changing owner to Tricorbraun\\{0}", _radleyEDIEndpointUserAccount));
    fileSecurity = File.GetAccessControl(file.FileName);
    fileSecurity.SetOwner(ediFileOwner); //Change our owner from LocalAdmin to our chosen DAX User
    _logger.Debug(string.Format("Setting owner to Tricorbraun - {0}", _radleyEDIEndpointUserAccount));
    File.SetAccessControl(file.FileName, fileSecurity);
}