Программный доступ к 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://<servername>:8080/tfs или http://<serverip>:8080/tfs (оба протестированы, с обновленным файлом hosts), который установлен как URL-адрес уведомления на сервере TFS. Эта программа работает внутри домена.

DifferentKindOfUsernames может быть любым из 'DOMAIN \ Username', 'LocallyDuplicatedUsername', 'LOCALMACHINE \ Username' с соответствующим паролем, паролем, одинаковым в домене и на машине.

Этот простой доступ не будет работать вне домена, и у меня такая ошибка:

TF30063: You are not authorized to access <serverUri>

переведенный в веб-контексте (с использованием того же процесса на веб-сайте asp.net), это ошибка 401:

The remote server returned an error: (401) Unauthorized.

даже если (пока что проверено):

  • У меня есть сопоставление между локальным пользователем / паролем, который запускает программу на компьютере постороннего домена, и учетной записью активного каталога, у которой есть доступ администратора к TFS (даже с активированными правами олицетворения в TFS).
  • Я добавляю BackConnectionNames раздел реестра с именем компьютера постороннего домена и IP, как описано здесь.
  • Я отключаю проверку обратной связи, как описано здесь.
  • Я использую имитатор Active Directory с другой комбинацией имени пользователя / домена или машины. Описание имитатора Active Directory можно найти здесь.
  • Я добавил IP-адрес сервера TFS в локальную интернет-зону (также попробовал доверенный сайт) в параметрах безопасности IE внешнего сервера домена, как описано здесь.

Я протестировал доступ к serverURI из браузера. URI работает, и у меня есть доступ к коллекции TFS, если я предоставлю учетные данные с помощью DomainName \ User + Password. Я тестировал это перед любой из описанных мною ранее модификаций. Интересно, в чем может быть разница между программным доступом и доступом через браузер, помимо всего того, что я тестировал до сих пор.


person Matthieu    schedule 29.09.2011    source источник
comment
У вас по-прежнему нет доступа к серверу TFS с компьютера, на котором в настоящее время выполняется этот код. Вам необходимо проверить наличие дополнительных настроек безопасности / разрешений в TFS. Я не верю, что это проблема программирования.   -  person qJake    schedule 30.09.2011
comment
@SpikeX: у меня есть доступ к серверу TFS с машины. Я открыл необходимые порты и получил доступ к URI через веб-браузер с теми же учетными данными, которые я использовал с имитатором. Если веб-клиент работает, я ожидаю, что моя программа будет делать то же самое, но это не так. Я вижу информацию, которая должна быть получена моей программой, если ей удалось подключиться (Коллекция и Список проектов). Я могу понять, почему между ошибкой программирования (отсутствующая или неправильная инициализация учетных данных) и ошибкой сети / сервера (проблема конфигурации) размыто.   -  person Matthieu    schedule 30.09.2011
comment
Тогда мой следующий глупый вопрос: ваш URI содержит http:// и номер порта, правильно?   -  person qJake    schedule 30.09.2011
comment
Это делает: http: // ‹servername›: 8080 / tfs. Я тоже пробовал с ip, даже если имя сервера установлено в файле hosts. программа отлично работает, если я нахожусь внутри домена. Если программного решения этой проблемы нет, я подумываю попробовать RODC (technet.microsoft.com/en-us/library/cc732801 (WS.10) .aspx), а затем я перенесу этот вопрос на ошибку сервера. Но должно быть что-то, чего мне не хватает, чтобы программа работала как веб-клиент на машине, не являющейся доменом.   -  person Matthieu    schedule 30.09.2011
comment
Вы пробовали без /tfs? В моем коде TFS, который подключается к серверу интрасети, этого нет (библиотека может добавить его автоматически).   -  person qJake    schedule 30.09.2011
comment
@SpikeX: это 404 без / tfs: службы Team Foundation недоступны с сервера http: // ‹servername›: 8080 / Техническая информация (для администратора): HTTP-код 404: не найдено. У вас есть 3 основных URL-адреса на TFS: Уведомление / Сервер / Веб-доступ. Их можно менять самостоятельно на все, что угодно. В вашем случае URL-адрес вашего уведомления должен быть упрощен, или он перенаправлен.   -  person Matthieu    schedule 30.09.2011
comment
Использовали ли вы сетевой анализатор, такой как wirehark, или отладочный прокси, такой как fiddler, чтобы определить, что передается серверу между вызовами TFS OM и вызовом веб-браузера?   -  person Edward Thomson    schedule 30.09.2011
comment
@EdwardThomson: ты понял! после нескольких сеансов wirehark было очевидно, что пользователь был искажен или не был отправлен, в зависимости от метода, который я использовал. Ближе всего к хорошему пользователю я подошел к вашему ответу, но я использовал другой конструктор: new NetworkCredential (имя пользователя, пароль, DOMAIN), иначе пользователь окажется искаженным (\ DOMAIN \ User вместо DOMAIN \ User). Я с радостью проголосую и приму ваш ответ, если вы измените его на правильный конструктор :) (PS: я знал, что это программирование !!: P)   -  person Matthieu    schedule 30.09.2011
comment
Ага, я определенно дал вам неправильный код, извините! Я забыл, что для домена нужно использовать ctor с тремя аргументами, по моей вине. Поправлю. Рад, что он работает!   -  person Edward Thomson    schedule 30.09.2011


Ответы (1)


Вы не передаете учетные данные для установления соединения. Это означает, что вы используете свои текущие учетные данные с хоста за пределами домена. Я не эксперт по аутентификации Windows, но думаю, что при определенных обстоятельствах это может работать прозрачно (если имя пользователя и пароль идентичны), но, похоже, это зависит от используемой версии NTLM, клиентской и серверной операционных систем. , доверительные отношения и зоны безопасности, конфигурация IIS и, возможно, фаза луны.

Другими словами, вы, вероятно, захотите передать учетные данные в соединение:

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

Обратите внимание, что настоятельно рекомендуется включить SSL / TLS, если вы подключаетесь к серверу через ненадежную (общедоступную) сеть.

(Я исправил это, чтобы использовать конструктор с тремя аргументами для NetworkCredential - моя ошибка. Как вы заметили, если вы поместите DOMAIN\username в аргумент имени пользователя для NetworkCredential, он будет рассматривать его как \DOMAIN\username вместо DOMAIN\username. Это, я полагаю, почему никто не позволяет мне писать код на C #.)

person Edward Thomson    schedule 29.09.2011
comment
Нет, все еще не работает. Есть много способов выдать себя за пользователя для TFS, и я безуспешно протестировал некоторые из них. Это дает ту же ошибку TF30063. Я обновлю свой вопрос, чтобы представить другую версию кода, которую я тестировал до сих пор. - person Matthieu; 30.09.2011
comment
Спасибо за правку, это намного яснее. Что произойдет из любопытства, если вы вызовете tfs.ensureAuthenticated () вместо того, чтобы пытаться запросить данные каталога? Я полагаю, у вас все еще возникает ошибка? - person Edward Thomson; 30.09.2011
comment
Да, это та же ошибка. Я занимался анализом сети. Я отвечу на ваш комментарий с результатом. - person Matthieu; 30.09.2011