【问题标题】:Programmatically access to TFS 2010 from outside the domain从域外以编程方式访问 TFS 2010
【发布时间】:2011-11-27 23:50:06
【问题描述】:

我正在尝试从安装服务器的域外部以编程方式访问我的 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://&lt;servername&gt;:8080/tfshttp://&lt;serverip&gt;:8080/tfs 的形式(均经过测试,主机文件为最新),这是在 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 具有管理员访问权限的活动目录帐户之间有一个映射(即使已激活 TFS 的模拟权限)。
  • 我添加了一个 BackConnectionNames 注册表项,其中包含域外部机器名称和 ip,如 here 所述。
  • 我禁用了环回检查,如 here 所述。
  • 我使用具有不同用户/域或计算机名称组合的 Active Directory 模拟程序。 Active Directory Impersonator 被描述为here
  • 我在域外部服务器 IE 安全选项中将 TFS 服务器 IP 添加到本地 Internet 区域(也尝试过受信任的站点),如 here 所述。

我已经测试了从浏览器对 serverURI 的访问。如果我使用 DomainName\User + Password 提供凭据,则 uri 有效,并且我可以访问 TFS 集合。在我之前描述的任何修改之前,我对此进行了测试。除了我迄今为止测试过的所有内容之外,我想知道编程访问和浏览器访问之间可能有什么区别。

【问题讨论】:

  • 您仍然无法从当前运行此代码的计算机访问 TFS 服务器。您需要检查 TFS 中的任何其他安全/权限设置。我不认为这是一个编程问题。
  • @SpikeX :我可以从机器访问 TFS 服务器。我打开了所需的端口,并可以通过 Web 浏览器使用与 Impersonator 相同的凭据访问 URI。如果 Web 客户端工作正常,我希望我的程序也能做同样的事情,但事实并非如此。如果我的程序能够连接,我可以看到它应该检索的信息(集合和项目列表)。我可以看到为什么编程错误(缺少或错误的凭据初始化)和网络/服务器错误(配置问题)之间模糊不清。
  • 那么我的下一个愚蠢的问题是,你的 URI 包含 http:// 和一个端口号,对吗?
  • 确实如此:http://:8080/tfs。即使在主机文件中设置了服务器名称,我也尝试使用 ip。如果我在域内,该程序可以完美运行。如果这个问题没有编程解决方案,我正在考虑尝试 RODC (technet.microsoft.com/en-us/library/cc732801(WS.10).aspx),然后我会将这个问题迁移到服务器故障。但是我必须缺少一些东西才能让程序在非域机器上像 webclient 一样工作。
  • 你试过没有/tfs吗?我这里连接到 Intranet 服务器的 TFS 代码没有那个(库可能会自动添加它)。

标签: c# active-directory impersonation tfs-sdk


【解决方案1】:

您没有传递凭据来建立连接。这意味着您正在使用来自域外主机的当前登录凭据。我不是 Windows 身份验证方面的专家,但我认为这在某些情况下可以透明地工作(如果用户名和密码相同),但它似乎取决于所使用的 NTLM 版本、客户端和服务器操作系统、信任关系和安全区域、IIS 配置,也许还有月相。

换句话说,您可能希望将凭据传递给连接:

TfsConfigurationServer _ConfigurationServer = new TfsConfigurationServer(uri, new NetworkCredential("username", "password", "DOMAIN"));

请注意,如果您通过不受信任的(公共)网络连接到服务器,强烈建议启用 SSL/TLS。

(我更正了这一点,使用 NetworkCredential 的三参数构造函数——我的错误。如您所见,如果您将 DOMAIN\username 放在 NetworkCredential 的用户名参数中,它将把它视为 \DOMAIN\username 而不是 @987654324 @. 我想这就是为什么没人让我写 C# 代码的原因。)

【讨论】:

  • 没有仍然无法工作。有很多方法可以模拟 TFS 的用户,我测试了其中的一些但没有成功。这给出了相同的 TF30063 错误。我将更新我的问题以呈现我迄今为止测试的不同版本的代码。
  • 感谢编辑,这更清楚了。出于好奇,如果您调用 tfs.ensureAuthenticated() 而不是尝试查询目录数据,会发生什么?我假设您仍然收到错误消息?
  • 是的,同样的错误。我一直在做一些网络分析。我会用结果来回答你的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-31
  • 1970-01-01
  • 2012-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多