Problems accessing TFS through ASP.NET using Kerberos delegation
Problem: Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer not using 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 groupTo 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, Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer
string> listItemsInProject()
{
//declare local varaibles
string servername = "http://srv-tfs01:8080";
Microsoft.TeamFoundation.Client.TeamFoundationServer server =
new Microsoft.TeamFoundation.Client.TeamFoundationServer(servername);
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 //retrieve all items for current project path
versionControl =
(Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer)server.GetService(typeof(Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer));
// versionControl object is created successfully
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;
}
}

