Как отлаживать аутентификацию NTLM в Windows Server 2012 r2

Я настроил службу SOAP на виртуальной машине под управлением Windows Server 2012 r2. Я защитил его с помощью NTLM, и мне удалось получить к нему доступ с главного компьютера с помощью SoapUI. . Все идет нормально...

Сейчас я пытаюсь получить доступ к своему сервису, все еще с хоста, но на этот раз с помощью программы golang. Для этого я использую эту библиотеку (мне нужно было только реализовать метод GenerateNegotiateMessage() и сделать убедитесь, что флаги Negotiate такие же, как у SoapUI).

Чтобы убедиться, что я все сделал правильно, я скачал исходный код SoapUI и сравнил выходные данные (NegotiateMessage и AuthenticateMessage) моей программы golang и SoapUI. Если я исправляю входные данные (временную метку и случайный вызов клиента), я получаю те же выходные данные. Однако, когда я пытаюсь подключиться к службе, я получаю 401 с сообщением «Доступ запрещен из-за неверных учетных данных». Нет необходимости говорить, что я на 100% уверен, что учетные данные верны, поскольку я могу получить доступ к службе с теми же учетными данными, используя SoapUI. Значит, в моем коде go должно быть что-то не так. Но чтобы понять это, мне нужно больше журналов с моего Windows Server. Любая идея о том, где я мог бы начать искать?

Ниже приведен файл web.config моего сервиса Soap:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5"/>
    <httpRuntime targetFramework="4.5"/>
    <trace enabled="true" pageOutput="true" requestLimit="40" localOnly="false"/>
  </system.web>
  <system.serviceModel>

    <diagnostics wmiProviderEnabled="true">
      <messageLogging
           logEntireMessage="true"
           logMalformedMessages="true"
           logMessagesAtServiceLevel="true"
           logMessagesAtTransportLevel="true"
           maxMessagesToLog="3000"
       />
    </diagnostics>

    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <bindings>
      <basicHttpBinding>
        <binding>
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Ntlm" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel" switchValue="All" propagateActivity="true">
        <listeners>
          <add name="myListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="C:\logs\TextWriterOutput.log"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
</configuration>

Спасибо большое за вашу помощь!


person Gpack    schedule 13.07.2015    source источник
comment
Gpack, FYI Stack Overflow - это не форум, нежелательно вообще отмечать заголовки с помощью [РЕШЕНО]. Вместо этого наличие принятого ответа помечает его как ответ для отображения и поиска.   -  person Dave C    schedule 22.07.2015
comment
Понял. Извиняюсь...   -  person Gpack    schedule 23.07.2015


Ответы (1)


В конце концов мне удалось решить мою проблему. Это произошло из-за того, что я не читал полностью тело ответа на мой HTTP-запрос в моей программе golang. Поэтому каждый раз, когда я делал запрос, сервер интерпретировал это как новое соединение, но схема аутентификации NTLM требует, чтобы все запросы выполнялись в одном соединении. На самом деле этот ответ решил мою проблему.

Для будущих кодеров, это код, который вы должны использовать, если хотите повторно использовать одно и то же соединение:

res, _ := client.Do(req)
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()

В заключение, мне не удалось получить много информации из журналов Windows. Инструменты, которые поставили меня на правильный путь, — это Failed Request Tracer, к которому вы можете получить доступ из диспетчера IIS, и старый добрый Wireshark для сравнения запросов, сделанных моей программой, и запросов SoapUI.

Надеюсь, это может быть полезно для кого-то.

person Gpack    schedule 22.07.2015