Deny: Revisited
In a previous post, I talked about the deny option and how it’s evaluated. The documentation on MSDN is talking about conflicting permissions on the same level, however, in TFS2008 SP1, permissions are evaluated bottom up and the first match wins. If a user, Eve, is denied read on $/ but is a member of [Proj]\Readers (which has Read access), the read permission will be the first match and Eve will be to read $/Proj recursively. If you need to deny users read permission, you have to make sure to remove them from all groups that has read access. The reason behind this design is that administrators usually want to allow permissions for certain projects to certain users and the rest should be denied, consider the following tree structure:
$/
Proj A
Proj B
Proj C
You may want to grant Eve read permission on Proj B and only Proj B. To do so, you should deny Eve all permissions on $/ then allow Eve read permission on Proj B. Since permissions are evaluated bottom-up on first-match basis, Eve has read access to proj B, while the denied permissions are effective on both existing projects and future projects D, E, F, ..etc.
Let me explain again why the behavior is as such. If you have 100 projects on your server and you want to allow Eve read access on one project only, then you can deny at the $/ level then allow on the $/Proj level. However, if we don't permit you to do so, you'd have to go through 99 projects to deny read instead. And by the way, TFS behavior is the same as Windows when you set permissions on folders.
Please note that there are two types of permissions inheritance, member of a group (subjects of the ACL) inheritance, and namespace (objects of the ACL) inheritance. As a member of a group (directly or indirectly), you inherit permissions. The same thing applies to namespaces, if it's a child of a parent folder, it inherits the parent's permissions (this can be turned off on an item basis using tf perm itemSpec /inherit:no).
IMO, the right thing to do here is to create the groups correctly, use Windows and/or TFS groups to isolate users with different permissions.
If you still want set the permission on all exisiting projects individually, here's a script that can help:
FOR /F "delims=$ tokens=*" %i IN ('tf dir $/ ^| find /v "/" ^| find /v "(s)"') DO tf perm /deny:* /group:"[Server]\TFS External Users" "$/%i"
Comments
Anonymous
March 24, 2009
Ping back from the MSDN document: http://msdn.microsoft.com/en-us/library/ms252587.aspxAnonymous
June 16, 2009
This is then directly defeating "the principle of least privilege" security methodology. A simple example being that I have a group "mydomainguests" which I set deny permission to all roles at the TFS and Source Control $ root level. I also have a "Guests" project that I then allow the group access to in TFS and SC. The "mydomainguests" group now must be in the "Team Foundation Server Valid Users" group as well as it's own. If I give read permissions to the "Team Foundation Server Valid Users" group to any object in source control, the "mydomainguests" group now also has read access, even though read access has been set to deny on the "mydomainguests" group at the same level via inheritence, or even without inheritence. While this can be worked around by defining additional project level groups for the read permission desired, it is counter-intuitive to most security administrators who are used to "the principle of least privilege" security methodology.Anonymous
February 23, 2011
We tried out this approach (denying at the $/ level ) but it has the side effect that the project users then can't see or apply labels. Is there a solution for that?