以编程方式从域外部访问 TFS 2010
我正在尝试从安装服务器的域外部以编程方式访问我的 TFS 服务器。基本的测试程序如下所示:
class Program
{
static void Main(string[] args)
{
Uri tfsUri = new Uri("<serverUri>");
TfsConfigurationServer _ConfigurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
CatalogNode projectCollectionCatalog = _ConfigurationServer.CatalogNode.QueryChildren(new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None)[0]; // actual connection tries to happen here
}
}
另一个版本,强制使用凭据:
class Program
{
static void Main(string[] args)
{
Uri tfsUri = new Uri("<serverURI>");
TfsConfigurationServer _ConfigurationServer = new TfsConfigurationServer(tfsUri, new NetworkCredential("<DifferentKindOfUsernames>", "<Password>"));
CatalogNode projectCollectionCatalog = _ConfigurationServer.CatalogNode.QueryChildren(new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None)[0];
}
}
另一个版本混合了以前的版本:
public class ConnectByImplementingCredentialsProvider : ICredentialsProvider
{
public ICredentials GetCredentials(Uri uri, ICredentials iCredentials)
{
return new NetworkCredential("<DifferentKindOfUsernames>", "<Password>", "<DomainOrNot>");
}
public void NotifyCredentialsAuthenticated(Uri uri)
{
throw new ApplicationException("Unable to authenticate");
}
}
class Program
{
static void Main(string[] args)
{
string _myUri = @"<serverUri>";
ConnectByImplementingCredentialsProvider connect = new ConnectByImplementingCredentialsProvider();
ICredentials iCred = new NetworkCredential("<DifferentKindOfUsernames>", "<Password>", "<DomainOrNot>");
connect.GetCredentials(new Uri(_myUri), iCred);
TfsConfigurationServer configurationServer =
TfsConfigurationServerFactory.GetConfigurationServer(new Uri(_myUri), connect);
configurationServer.EnsureAuthenticated();
}
}
以及一个带有活动目录的版本Impersonator :
class Program
{
static void Main(string[] args)
{
using (new Impersonator("<DifferentKindOfUsernames>", "<DomainOrNot>", "<Password>"))
{
Uri tfsUri = new Uri("<serverUri>");
TfsConfigurationServer _ConfigurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
CatalogNode projectCollectionCatalog = _ConfigurationServer.CatalogNode.QueryChildren(new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None)[0]; // actual connection tries to happen here
}
}
}
serverURI
的形式为http://
或 http://
(均经过测试,主机文件是最新的)这是在 TFS 服务器上设置为通知 URL 的内容。该程序在域内运行。
DifferentKindOfUsernames
是“DOMAIN\Username”、“LocallyDuplicatedUsername”、“LOCALMACHINE\Username”中的任何内容,并具有适当的密码,密码在域和计算机上相同。
这个简单的访问在域之外不起作用,并且我遇到了这个错误:
TF30063: You are not authorized to access <serverUri>
在 Web 上下文中进行翻译(在 asp.net 网站中使用相同的过程),这是一个 401 错误:
The remote server returned an error: (401) Unauthorized.
即使(到目前为止已测试的内容) :
- 我在域外部计算机上运行程序的本地用户/密码与具有 TFS 管理员访问权限的 Active Directory 帐户之间存在映射(即使激活了 TFS 上的模拟权限)。
- 我添加了一个
BackConnectionNames
注册表项,其中包含域外部计算机名称和 IP,如此处<所述< /a>. - 我按照此处所述禁用环回检查。
- 我使用具有不同用户/域或计算机名称组合的 Active Directory Impersonator。 此处描述了 Active Directory Impersonator。
- 我将 TFS 服务器 IP 添加到域外部服务器 IE 安全选项中的本地 Internet 区域(也尝试过受信任的站点),如所述 此处。
我已经测试了从浏览器对 serverURI 的访问。 uri 有效,如果我使用域名\用户 + 密码提供凭据,我就可以访问 TFS 集合。我在进行之前描述的任何修改之前对此进行了测试。我想知道除了我迄今为止测试过的所有内容之外,编程访问和浏览器访问之间可能有什么区别。
I'm trying to access my TFS server programmatically from outside the domain where the server is installed. A basic test program would look like this :
class Program
{
static void Main(string[] args)
{
Uri tfsUri = new Uri("<serverUri>");
TfsConfigurationServer _ConfigurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
CatalogNode projectCollectionCatalog = _ConfigurationServer.CatalogNode.QueryChildren(new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None)[0]; // actual connection tries to happen here
}
}
Another version, with credentials forced :
class Program
{
static void Main(string[] args)
{
Uri tfsUri = new Uri("<serverURI>");
TfsConfigurationServer _ConfigurationServer = new TfsConfigurationServer(tfsUri, new NetworkCredential("<DifferentKindOfUsernames>", "<Password>"));
CatalogNode projectCollectionCatalog = _ConfigurationServer.CatalogNode.QueryChildren(new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None)[0];
}
}
Another version with a mix of both previous version :
public class ConnectByImplementingCredentialsProvider : ICredentialsProvider
{
public ICredentials GetCredentials(Uri uri, ICredentials iCredentials)
{
return new NetworkCredential("<DifferentKindOfUsernames>", "<Password>", "<DomainOrNot>");
}
public void NotifyCredentialsAuthenticated(Uri uri)
{
throw new ApplicationException("Unable to authenticate");
}
}
class Program
{
static void Main(string[] args)
{
string _myUri = @"<serverUri>";
ConnectByImplementingCredentialsProvider connect = new ConnectByImplementingCredentialsProvider();
ICredentials iCred = new NetworkCredential("<DifferentKindOfUsernames>", "<Password>", "<DomainOrNot>");
connect.GetCredentials(new Uri(_myUri), iCred);
TfsConfigurationServer configurationServer =
TfsConfigurationServerFactory.GetConfigurationServer(new Uri(_myUri), connect);
configurationServer.EnsureAuthenticated();
}
}
And a version with an active directory Impersonator :
class Program
{
static void Main(string[] args)
{
using (new Impersonator("<DifferentKindOfUsernames>", "<DomainOrNot>", "<Password>"))
{
Uri tfsUri = new Uri("<serverUri>");
TfsConfigurationServer _ConfigurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
CatalogNode projectCollectionCatalog = _ConfigurationServer.CatalogNode.QueryChildren(new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None)[0]; // actual connection tries to happen here
}
}
}
serverURI
being in the form of http://<servername>:8080/tfs
or http://<serverip>:8080/tfs
(both tested, with hosts file up to date) which is what is set as Notification URL on the TFS Server. This program works inside the domain.
DifferentKindOfUsernames
being anything from 'DOMAIN\Username', 'LocallyDuplicatedUsername', 'LOCALMACHINE\Username' with the appropriate password, password being the same in the domain and on the machine.
This simple access won't work outside of the domain , and I have this error :
TF30063: You are not authorized to access <serverUri>
translated in a web context (using the same process in an asp.net website), it is a 401 error :
The remote server returned an error: (401) Unauthorized.
even if (things tested so far) :
- I have a mapping between the local user/password who runs the program on the domain outsider machine and an active directory account who has admin access to TFS(even with impersonation rights on TFS activated) .
- I add a
BackConnectionNames
registry key with the domain outsider machine name and ip like described here. - I disable the loopback check like described here.
- I use an Active Directory Impersonator with different combination of user / domain or machine name. Active Directory Impersonator being described here.
- I added the TFS Server IP to the local internet zone (tried trusted site as well) in the domain outsider server IE security options like described here.
I have tested the access to the serverURI from a browser. The uri works and I have access to the TFS Collection if I give the credentials with DomainName\User + Password. I tested this before any of the modifications I described before. I wonder what could be the difference between the programmatic access and the browser access besides all the things I have tested so far.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您没有传递凭据来建立连接。这意味着您正在使用当前从域外部的主机登录的凭据。我不是 Windows 身份验证方面的专家,但我认为在某些情况下,这可以透明地工作(如果用户名和密码相同),但它似乎取决于所使用的 NTLM 版本、客户端和服务器操作系统、信任关系和安全区域、IIS 配置,或许还有月相。
换句话说,您可能希望将凭据传递给连接:
请注意,如果您通过不受信任的(公共)网络连接到服务器,强烈建议启用 SSL/TLS。
(我更正了这一点,使用 NetworkCredential 的三参数构造函数——我的错误。正如您所注意到的,如果您将
DOMAIN\username
放入 NetworkCredential 的用户名参数中,它会将其视为\DOMAIN\username
而不是DOMAIN\username
。我想,这就是为什么没人让我编写 C# 代码的原因。)You're not passing credentials to build the connection. This means that you're using your currently logged in credentials from the host outside of the domain. I'm not an expert on Windows Authentication, but I think that this can, in certain circumstances, work transparently (if the username and password are identical) but it appears to depend on the NTLM version being used, the client and server operating systems, trust relationships and security zones, the IIS configuration and perhaps the phase of the moon.
In other words, you probably want to pass the credentials to the connection:
Note that it's strongly recommended to enable SSL/TLS if you're connecting to your server over an untrusted (public) network.
(I corrected this to use the three-arg constructor for NetworkCredential -- my mistake. As you note, if you put
DOMAIN\username
in the username argument to NetworkCredential, it will treat it as\DOMAIN\username
instead ofDOMAIN\username
. This, I suppose, it why nobody lets me write C# code.)