visual studio .net enterprise tools:
Problem: Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer
not receiving correct identity when being referenced from remote server using
Keberos delegation
Servers in play:
srv-tfs01 - Team Foundation Server
deb-web05 - Web application server
Server setup for srv-tfs01:
Enabled Kerberos authentication in IIS
cscript adsutil.vbs set w3svc/3/root/NTAuthenticationProviders "Negotiate,
NTLM"
Setup service principle names for TFS service account:
setspn -a http/srv-tfs01.<fully qualified domain> <domain>\<service account>
-- for TCP/IP
setspn -a http/srv-tfs01 <domain>\<service account> -- for NETBIOS
Server setup for dev-web05:
Enabled Kerberos delegation (for any service) through Active Directory Users
and Computers (ADUC)
IIS settings for web application
Turned off Enable anonymous access in Directory Security
Turned on Integrated Windows authentication in Directory Security
web.config
<identity impersonate="true"/>
Registry changes
Gave Domain Users group read athority to
HKEY_USERS\.Default\Software\Microsoft\VisualStudio\8.0\TeamFoundation\Servers -- necessary so users can resolve TFS servers
Domain:
Windows 2003 domain functional level
Scenario:
When a user attempts to use my web application to browse Team Foundation
server, their Kerberos credentials are not being picked up by the
VersionControlServer object in the Team Foundation Server API. Authorized
TFS users receive TF14002: <domain>\dev-web05$ is not a member of Team
Foundation Valid Users group when attempting to browse a project using my web
application. Examining the Security event log the srv-tfs01 server shows two
seperate Kerberos logins; one for the user using the web site, the second is
the DEV-WEB05$ machine account. Unauthorized users receive the message
TF50309: You do not have sufficient permissions to perform this operation.
When looking at the Security event log on srv-tfs01, I find only one Kerberos
login, the user who is attempting to browse.
There is an overload for the constructor of
Microsoft.TeamFoundation.Client.TeamFoundationServer that takes in a
NetworkCredential object. I've tried passing in
System.Net.CredentialCache.DefaultNetworkCredential with the same result.
However, if I create a new NetworkCredential object providing username,
password, and domain, the user is able to browse but under whatever identity
was provided by the NetworkCredential object I created, not their own. Also,
when attempting to download a file from TFS while using the NetworkCredential
object I created, I get the same TF14002: <domain>\dev-web05$ is not a member
of Team Foundation Valid Users group
To run some tests, I created a domain group and put the dev-web05 machine
account in it. Then I added it to Team Foundation by right clicking on the
server in Visual Studio 2005 > Team Foundation Server Settings > Security. I
gave the account the View Server-Level Information permission so it would
show up in the Team Foundation Valid Users group. I attempted to browse
again and nothing showed up.
I added the same group to a Readers group of a project in Visual Studio by
right clicking the server > Team Foundater Server Settings > Group
Membership. I specifically added it to the Reader group of a projcect my
test account did not have access to. When I logged on again to
browse, the entry in which the account did not have access to appeared in
the list.
Relavent code:
public override System.Collections.Generic.Dictionary<string,
string> listItemsInProject()
{
//declare local varaibles
string servername = "http://srv-tfs01:8080";
Microsoft.TeamFoundation.Client.TeamFoundationServer server =
new Microsoft.TeamFoundation.Client.TeamFoundationServer(servername);
Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer
versionControl = null;
System.Collections.Generic.Dictionary<string, string> collection
= new Dictionary<string, string>();
Microsoft.TeamFoundation.VersionControl.Client.ItemSet items =
null;
try
{
//authenticate user
server.EnsureAuthenticated();
//afer this statement, property server.AuthenticatedUserName returns
correct username
//create version control object
versionControl =
(Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer)server.GetService(typeof(Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer));
// versionControl object is created successfully
//retrieve all items for current project path
items = versionControl.GetItems(this.Project,
Microsoft.TeamFoundation.VersionControl.Client.RecursionType.OneLevel);
//this statement throws the error TF14002: <domain>\dev-web05$ is not a
member of Team Foundation Valid Users group.
//loop through items
foreach (Microsoft.TeamFoundation.VersionControl.Client.Item
item in items.Items)
{
//declare variables
System.Text.StringBuilder key = new StringBuilder();
System.Text.StringBuilder value = new StringBuilder();
//check to make sure it's not the folder it's in
if (item.ItemType ==
Microsoft.TeamFoundation.VersionControl.Client.ItemType.Folder &&
item.ServerItem.ToUpper() == this.Project.ToUpper())
{
//continue
continue;
}
//populate list item object
value.Append(item.ServerItem.Substring(item.ServerItem.LastIndexOf("/") + 1));
//check to see if it's a folder
if (item.ItemType ==
Microsoft.TeamFoundation.VersionControl.Client.ItemType.Folder)
{
//append folder
value.Append(" [Folder]");
}
//add value
key.Append(item.ServerItem);
//add to collection
collection.Add(key.ToString(), value.ToString());
}
//return the list
return collection;
}
catch (Exception ex)
{
//bubble error
throw ex;
}
finally
{
//cleanup
server.Dispose();
server = null;
versionControl = null;
collection = null;
}
}