|
security
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Have a NTAccount, need FileSystem permissionsI have just started doing .NET 2.0 and I am a bit curious about the System.Security.Principal and System.Security.AccessControl namespaces and their interaction. I have a simple task: Given a NTAccount object (and a password), tell me whether that account can execute a file or not. I have now spent four hours to figure this out, and here is finally my solution (C#), which I personally dislike for many reasons: I am asking now the public how this should have been done. It goes along the lines with this code (Maybe faulty, but I guess you get the idea): using System; using System.IO; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Security; using System.Security.AccessControl; using System.Security.Principal; namespace Test { public class TestClass { public static bool CanExecute(NTAccount account, SecureString password, string file, FileSystemRights right) { return TestClass.HasRight(account, password, file, FileSystemRights.ExecuteFile); } private static bool HasRight(NTAccount account, SecureString password, string file, FileSystemRights right) { WindowsIdentity user = TestClass.getUser(account, password); FileInfo info = new FileInfo(file); FileSecurity fs = info.GetAccessControl(); foreach (FileSystemAccessRule rule in fs.GetAccessRules(true, true, typeof(IdentityReference))) { if ((user.Groups.Contains(rule.IdentityReference) || user.User.Equals(rule.IdentityReference)) &&rule.AccessControlType.Equals(AccessControlType.Allow) && ((rule.FileSystemRights & right) == right)) { return true; } } return false; } /* Taken and adapted from the net - credentials go to http://pluralsight.com/wiki/default.aspx/Keith.GuideBook/HowToGetATokenForAUser.html */ private static WindowsIdentity getUser(NTAccount account, SecureString password) { // need a full duplex stream - loopback is easiest way to get that TcpListener tcpListener = new TcpListener(IPAddress.Loopback, 0); tcpListener.Start(); WindowsIdentity id = null; tcpListener.BeginAcceptTcpClient(delegate(IAsyncResult asyncResult) { try { using (NegotiateStream serverSide = new NegotiateStream( tcpListener.EndAcceptTcpClient(asyncResult).GetStream())) { serverSide.AuthenticateAsServer(CredentialCache.DefaultNetworkCredentials, ProtectionLevel.None, TokenImpersonationLevel.Impersonation); id = (WindowsIdentity)serverSide.RemoteIdentity; } } catch { id = null; } }, null); TcpClient client = new TcpClient(new IPEndPoint(IPAddress.Loopback, ((IPEndPoint)tcpListener.LocalEndpoint).Port)); using (NegotiateStream clientSide = new NegotiateStream(client.GetStream())) { NetworkCredential netcred = new NetworkCredential(); netcred.UserName = account.ToString(); netcred.Password = Marshal.PtrToStringUni(Marshal.SecureStringToBSTR(password)); clientSide.AuthenticateAsClient(netcred, "", ProtectionLevel.None, TokenImpersonationLevel.Impersonation); } return id; } } } Is there a better way to achieve this? The whole getUser method is nothing other than a hack. I also dislike the way I have to check the permissions myself. There must be an easier way. (I am sorry should I have picked the wrong NG, in that case, can you tell me the correct one) Best regards, Franz Hi,
to get the SID of a user - you simply need to construct a NTAccount object like NTAccount acc = new NTAccount("domain\\user"); afterwards you translate to a SID: SecurityIdentifier sid = (SecurityIdentifier)acc.Translate(typeof(NTAccount)); you get the SID now using: sid.Value; thats the equivalent of user.User.IdentityReference. This eliminates the nees for the NegotiateStream handshake. dominick Show quoteHide quote > Hi NG, > > I have just started doing .NET 2.0 and I am a bit curious about the > System.Security.Principal and System.Security.AccessControl namespaces > and their interaction. > > I have a simple task: Given a NTAccount object (and a password), tell > me whether that account can execute a file or not. I have now spent > four hours to figure this out, and here is finally my solution (C#), > which I personally dislike for many reasons: > > I am asking now the public how this should have been done. It goes > along the lines with this code (Maybe faulty, but I guess you get the > idea): > > using System; > using System.IO; > using System.Net; > using System.Net.Security; > using System.Net.Sockets; > using System.Runtime.InteropServices; > using System.Security; > using System.Security.AccessControl; > using System.Security.Principal; > namespace Test > { > public class TestClass > { > public static bool CanExecute(NTAccount account, SecureString > password, string file, FileSystemRights right) > { > return TestClass.HasRight(account, password, file, > FileSystemRights.ExecuteFile); > } > private static bool HasRight(NTAccount account, SecureString > password, string file, FileSystemRights right) > { > WindowsIdentity user = TestClass.getUser(account, > password); > FileInfo info = new FileInfo(file); > FileSecurity fs = info.GetAccessControl(); > foreach (FileSystemAccessRule rule in > fs.GetAccessRules(true, true, typeof(IdentityReference))) > { > if ((user.Groups.Contains(rule.IdentityReference) > || user.User.Equals(rule.IdentityReference)) > && > rule.AccessControlType.Equals(AccessControlType.Allow) > && ((rule.FileSystemRights & right) == right)) > { > return true; > } > } > return false; > } > /* Taken and adapted from the net - credentials go to > http://pluralsight.com/wiki/default.aspx/Keith.GuideBook/HowToGetAToke > nForAUser.html > */ > private static WindowsIdentity getUser(NTAccount account, > SecureString password) > { > // need a full duplex stream - loopback is easiest way to > get that > TcpListener tcpListener = new > TcpListener(IPAddress.Loopback, 0); > tcpListener.Start(); > WindowsIdentity id = null; > tcpListener.BeginAcceptTcpClient(delegate(IAsyncResult > asyncResult) > { > try > { > using (NegotiateStream serverSide = new > NegotiateStream( > tcpListener.EndAcceptTcpClient(asyncResult).GetStream())) > { > serverSide.AuthenticateAsServer(CredentialCache.DefaultNetworkCredenti > als, > ProtectionLevel.None, > TokenImpersonationLevel.Impersonation); > id = > (WindowsIdentity)serverSide.RemoteIdentity; > } > } > catch > { id = null; } > }, null); > TcpClient client = new TcpClient(new > IPEndPoint(IPAddress.Loopback, > ((IPEndPoint)tcpListener.LocalEndpoint).Port)); > using (NegotiateStream clientSide = new > NegotiateStream(client.GetStream())) > { > NetworkCredential netcred = new NetworkCredential(); > netcred.UserName = account.ToString(); > netcred.Password = > Marshal.PtrToStringUni(Marshal.SecureStringToBSTR(password)); > clientSide.AuthenticateAsClient(netcred, > "", ProtectionLevel.None, > TokenImpersonationLevel.Impersonation); > } > return id; > } > } > } > Is there a better way to achieve this? The whole getUser method is > nothing other than a hack. I also dislike the way I have to check the > permissions myself. There must be an easier way. > > (I am sorry should I have picked the wrong NG, in that case, can you > tell me the correct one) > > Best regards, > Franz Hi Dominick,
Show quoteHide quote > to get the SID of a user - you simply need to construct a NTAccount object In some respect you are right, but the problem is that starting from a> like > > NTAccount acc = new NTAccount("domain\\user"); > > afterwards you translate to a SID: > > SecurityIdentifier sid = (SecurityIdentifier)acc.Translate(typeof(NTAccount)); > > you get the SID now using: > > sid.Value; > > thats the equivalent of user.User.IdentityReference. NTAccount object I don't know whether this is a group or an personal account. It was only possible using instances of WindowsIdentity where I got the User.IdentityReference property as a bonus, so I can safe myself that few lines of code (perfomance is not a key factor here). > No, it doesn't, since I need to know which groups a personal NTAccount> This eliminates the nees for the NegotiateStream handshake. > belongs to, to actually check the access rights for group membership as well. The more I look into it the less I like the .NET 2.0 changes of the namespaces System.Security.Principal and System.Security.AccessControl. There are lots of examples how to change a access/audit rules, but surprisingly(!) there are none to check these rules. Furthermore the object model is unbalanced, e.g. the rights enumerations don't have a common interface/class. Just a random frustration rant - please ignore. If OO would have been applied correctly, I should be able to implement such a method: public static bool HasRight ( System.Security.AccessControl.ObjectSecurity object, System.Security.Principal.IPrincipal principal, System.Security.AccessControl.AccessRule right ); (Actually something similar should be part of ObjectSecurity) Let's see what .NET 2.1 brings here :-( Basically I have to leave managed code and go to unmanaged. Best regards, Franz OK -
which OS is this?? if it is XP/2K3 you can use Win32 LogonUser to get a token - which in turn can be used to create a WindowsIdentity... You are right - whats totally missing in the API is the equivalent of the "effective permissions" tab in the security settings in explorer. Go wrap them! That'll be an awesome contribution to the community :)) dominick Show quoteHide quote > Hi Dominick, > >> to get the SID of a user - you simply need to construct a NTAccount >> object like >> >> NTAccount acc = new NTAccount("domain\\user"); >> >> afterwards you translate to a SID: >> >> SecurityIdentifier sid = >> (SecurityIdentifier)acc.Translate(typeof(NTAccount)); >> >> you get the SID now using: >> >> sid.Value; >> >> thats the equivalent of user.User.IdentityReference. >> > In some respect you are right, but the problem is that starting from a > NTAccount object I don't know whether this is a group or an personal > account. It was only possible using instances of WindowsIdentity where > I got the User.IdentityReference property as a bonus, so I can safe > myself that few lines of code (perfomance is not a key factor here). > >> This eliminates the nees for the NegotiateStream handshake. >> > No, it doesn't, since I need to know which groups a personal NTAccount > belongs to, to actually check the access rights for group membership > as well. > > The more I look into it the less I like the .NET 2.0 changes of the > namespaces System.Security.Principal and > System.Security.AccessControl. There are lots of examples how to > change a access/audit rules, but surprisingly(!) there are none to > check these rules. Furthermore the object model is unbalanced, e.g. > the rights enumerations don't have a common interface/class. Just a > random frustration rant - please ignore. > > If OO would have been applied correctly, I should be able to implement > such a method: > public static bool HasRight ( > System.Security.AccessControl.ObjectSecurity object, > System.Security.Principal.IPrincipal principal, > System.Security.AccessControl.AccessRule right ); > (Actually something similar should be part of ObjectSecurity) Let's > see what .NET 2.1 brings here :-( > > Basically I have to leave managed code and go to unmanaged. > > Best regards, > Franz He can also use protocol transition/S4U to create a token if he has 2003
server and 2003 AD. Probably the easiest thing to do is use AuthZAccessCheck though via p/invoke. It is a little ugly, but is the right way to do this given that he doesn't have a token for the user. If he had a token, then AccessCheck is the right way to do it. It would be nice if MS would wrap these up in .NET, as they always say not to try to interpret the results yourself by examining the security descriptor directly, but then they don't make it easy to use the built in stuff in .NET and only give us the security descriptor to look at (better than what we had in 1.x, but still not enough...). Joe K. -- Show quoteHide quoteJoe Kaplan-MS MVP Directory Services Programming Co-author of "The .NET Developer's Guide to Directory Services Programming" http://www.directoryprogramming.net -- "Dominick Baier" <dbaier@pleasepleasenospam_leastprivilege.com> wrote in message news:4580be63a75e8c883b5343ee040@news.microsoft.com... > OK - > which OS is this?? > > if it is XP/2K3 you can use Win32 LogonUser to get a token - which in turn > can be used to create a WindowsIdentity... > > You are right - whats totally missing in the API is the equivalent of the > "effective permissions" tab in the security settings in explorer. > > Go wrap them! That'll be an awesome contribution to the community :)) > > dominick > >> Hi Dominick, >> >>> to get the SID of a user - you simply need to construct a NTAccount >>> object like >>> >>> NTAccount acc = new NTAccount("domain\\user"); >>> >>> afterwards you translate to a SID: >>> >>> SecurityIdentifier sid = >>> (SecurityIdentifier)acc.Translate(typeof(NTAccount)); >>> >>> you get the SID now using: >>> >>> sid.Value; >>> >>> thats the equivalent of user.User.IdentityReference. >>> >> In some respect you are right, but the problem is that starting from a >> NTAccount object I don't know whether this is a group or an personal >> account. It was only possible using instances of WindowsIdentity where >> I got the User.IdentityReference property as a bonus, so I can safe >> myself that few lines of code (perfomance is not a key factor here). >> >>> This eliminates the nees for the NegotiateStream handshake. >>> >> No, it doesn't, since I need to know which groups a personal NTAccount >> belongs to, to actually check the access rights for group membership >> as well. >> >> The more I look into it the less I like the .NET 2.0 changes of the >> namespaces System.Security.Principal and >> System.Security.AccessControl. There are lots of examples how to >> change a access/audit rules, but surprisingly(!) there are none to >> check these rules. Furthermore the object model is unbalanced, e.g. >> the rights enumerations don't have a common interface/class. Just a >> random frustration rant - please ignore. >> >> If OO would have been applied correctly, I should be able to implement >> such a method: >> public static bool HasRight ( >> System.Security.AccessControl.ObjectSecurity object, >> System.Security.Principal.IPrincipal principal, >> System.Security.AccessControl.AccessRule right ); >> (Actually something similar should be part of ObjectSecurity) Let's >> see what .NET 2.1 brings here :-( >> >> Basically I have to leave managed code and go to unmanaged. >> >> Best regards, >> Franz > > I didn't mention PT because i knew you would suggest it :))
Yeah there should be proper wrappers around all these APIs... dominick Show quoteHide quote > He can also use protocol transition/S4U to create a token if he has > 2003 server and 2003 AD. > > Probably the easiest thing to do is use AuthZAccessCheck though via > p/invoke. It is a little ugly, but is the right way to do this given > that he doesn't have a token for the user. If he had a token, then > AccessCheck is the right way to do it. > > It would be nice if MS would wrap these up in .NET, as they always say > not to try to interpret the results yourself by examining the security > descriptor directly, but then they don't make it easy to use the built > in stuff in .NET and only give us the security descriptor to look at > (better than what we had in 1.x, but still not enough...). > > Joe K. > re: The ACL check.
I don't think you are catching the case where the user is in some nested group structure...there is unfortunately no wrapper for the Win32 AuthZ APIs, which do exactly what you are looking for. dominick Show quoteHide quote > Hi NG, > > I have just started doing .NET 2.0 and I am a bit curious about the > System.Security.Principal and System.Security.AccessControl namespaces > and their interaction. > > I have a simple task: Given a NTAccount object (and a password), tell > me whether that account can execute a file or not. I have now spent > four hours to figure this out, and here is finally my solution (C#), > which I personally dislike for many reasons: > > I am asking now the public how this should have been done. It goes > along the lines with this code (Maybe faulty, but I guess you get the > idea): > > using System; > using System.IO; > using System.Net; > using System.Net.Security; > using System.Net.Sockets; > using System.Runtime.InteropServices; > using System.Security; > using System.Security.AccessControl; > using System.Security.Principal; > namespace Test > { > public class TestClass > { > public static bool CanExecute(NTAccount account, SecureString > password, string file, FileSystemRights right) > { > return TestClass.HasRight(account, password, file, > FileSystemRights.ExecuteFile); > } > private static bool HasRight(NTAccount account, SecureString > password, string file, FileSystemRights right) > { > WindowsIdentity user = TestClass.getUser(account, > password); > FileInfo info = new FileInfo(file); > FileSecurity fs = info.GetAccessControl(); > foreach (FileSystemAccessRule rule in > fs.GetAccessRules(true, true, typeof(IdentityReference))) > { > if ((user.Groups.Contains(rule.IdentityReference) > || user.User.Equals(rule.IdentityReference)) > && > rule.AccessControlType.Equals(AccessControlType.Allow) > && ((rule.FileSystemRights & right) == right)) > { > return true; > } > } > return false; > } > /* Taken and adapted from the net - credentials go to > http://pluralsight.com/wiki/default.aspx/Keith.GuideBook/HowToGetAToke > nForAUser.html > */ > private static WindowsIdentity getUser(NTAccount account, > SecureString password) > { > // need a full duplex stream - loopback is easiest way to > get that > TcpListener tcpListener = new > TcpListener(IPAddress.Loopback, 0); > tcpListener.Start(); > WindowsIdentity id = null; > tcpListener.BeginAcceptTcpClient(delegate(IAsyncResult > asyncResult) > { > try > { > using (NegotiateStream serverSide = new > NegotiateStream( > tcpListener.EndAcceptTcpClient(asyncResult).GetStream())) > { > serverSide.AuthenticateAsServer(CredentialCache.DefaultNetworkCredenti > als, > ProtectionLevel.None, > TokenImpersonationLevel.Impersonation); > id = > (WindowsIdentity)serverSide.RemoteIdentity; > } > } > catch > { id = null; } > }, null); > TcpClient client = new TcpClient(new > IPEndPoint(IPAddress.Loopback, > ((IPEndPoint)tcpListener.LocalEndpoint).Port)); > using (NegotiateStream clientSide = new > NegotiateStream(client.GetStream())) > { > NetworkCredential netcred = new NetworkCredential(); > netcred.UserName = account.ToString(); > netcred.Password = > Marshal.PtrToStringUni(Marshal.SecureStringToBSTR(password)); > clientSide.AuthenticateAsClient(netcred, > "", ProtectionLevel.None, > TokenImpersonationLevel.Impersonation); > } > return id; > } > } > } > Is there a better way to achieve this? The whole getUser method is > nothing other than a hack. I also dislike the way I have to check the > permissions myself. There must be an easier way. > > (I am sorry should I have picked the wrong NG, in that case, can you > tell me the correct one) > > Best regards, > Franz
Machine hops - Basic Authentication
Another StrongNameIdentityPermission/LinkDemand question SIMple SSL question ?? Use of Unrestricted flag ??? security warning in self signed certificate Assigning Strong Name to COM dlls Authentication method ?? Client Certifcate Info in Web Service IIS 5.1 security deploying executable to network to be ran in logon script |
|||||||||||||||||||||||