Я следовал этому руководству, чтобы получить аутентификацию имени пользователя с защитой транспорта, работающей в моей службе WCF.Учебное пособие, однако, ссылается на использование basicHttpBinding
, что недопустимо - мне требуется wsHttpBinding
.
Идея состоит в том, чтобы использовать пользовательский BasicAuthenticationModule
для службы WCF, который будет считывать заголовок «Авторизация» из запроса HTTPи выполнить процесс аутентификации в соответствии с содержимым заголовка «Авторизация».Проблема в том, что отсутствует заголовок «Авторизация»!
Я реализовал IClientMessageInspector
с помощью пользовательского поведения для манипулирования исходящими сообщениями и добавления пользовательских заголовков SOAP.Я добавил следующий код в функцию BeforeSendRequest
:
HttpRequestMessageProperty httpRequest = request.Properties.Where(x => x.Key == "httpRequest").Single().Value;
httpRequest.Headers.Add("CustomHeader", "CustomValue");
Это должно работать и, согласно многим веб-ресурсам, оно работает для basicHttpBinding
, но не wsHttpBinding
.Когда я говорю «работает», я имею в виду, что заголовок успешно получен службой WCF.
Это упрощенная функция, которая проверяет полученное сообщение HTTP на стороне службы WCF:
public void OnAuthenticateRequest(object source, EventArgs eventArgs)
{
HttpApplication app = (HttpApplication)source;
//the Authorization header is checked if present
string authHeader = app.Request.Headers["Authorization"];
if (string.IsNullOrEmpty(authHeader))
{
app.Response.StatusCode = 401;
app.Response.End();
}
}
В нижних записях этой ветки от сентября 2011 года говорится, что это невозможно с wsHttpBinding
.Я не хочу принимать этот ответ.
В качестве примечания, если я использую модуль базовой аутентификации, встроенный в IIS, а не пользовательский, я получаю
параметр'username' не должен содержать запятых. ** сообщение об ошибке при попытке Roles.IsInRole("RoleName")
или `[PrincipalPermission (SecurityAction.Demand, Role =" RoleName ")]
, вероятно, потому что мое свойство PrimaryIdentity.Name
содержитимя субъекта сертификата, поскольку я использую TransportWithMessageCredential
безопасность с защитой сообщений на основе сертификатов.
Я открыт для предложений, а также альтернативных подходов к проблеме.Спасибо.
ОБНОВЛЕНИЕ
Как представляется, заголовок HTTP читается правильно позже во всем коде службы WCF.(HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties["httpRequest"]
содержит мой пользовательский заголовок.Однако это уже уровень сообщений. Как передать заголовок в процедуру проверки подлинности транспорта?
ОБНОВЛЕНИЕ 2
После небольшого исследования,Я пришел к выводу, что когда веб-браузер получает код состояния HTTP 401, он предоставляет мне диалоговое окно входа в систему, где я могу указать свои учетные данные.Однако клиент WCF просто выдает исключение и не хочет отправлять учетные данные.Мне удалось проверить это поведение при посещении https://myserver/myservice/service.svc
в Internet Explorer.Пытался исправить, используя информацию из этой ссылки, но безрезультатно.Это ошибка в WCF или я что-то упустил?
EDIT
Здесь приведены соответствующие разделы из моего system.servicemodel
(из * 1066)*) - Я почти уверен, что все правильно настроил.
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" />
</clientCertificate>
<serviceCertificate findValue="server.uprava.djurkovic-co.me" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
</serviceCredentials>
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="AspNetSqlRoleProvider" />
</behavior>
</serviceBehaviors>
................
<wsHttpBinding>
<binding name="EndPointWSHTTP" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="20480000" maxReceivedMessageSize="20480000" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="20480000" maxStringContentLength="20480000" maxArrayLength="20480000" maxBytesPerRead="20480000" maxNameTableCharCount="20480000" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true" algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
............
<service behaviorConfiguration="ServiceBehavior" name="DjurkovicService.Djurkovic">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="EndPointWSHTTP" name="EndPointWSHTTP" contract="DjurkovicService.IDjurkovic" />
</service>
Исключение, возвращаемое службой:
HTTP-запрос не авторизован с помощью схемы аутентификации клиента 'Anonymous'.Заголовок аутентификации, полученный от сервера, был «Базовая область, согласование, NTLM».(Удаленный сервер возвратил ошибку: (401) не авторизован.)