Службы WCF показывают исключения при обеспечении сервиса с привязкой wshttpbinding и аутентификации имя пользователя
Я создал workflowservice в .net 4.0
Я пытаюсь защитить эту службу (WCF) и использовал следующую ссылку, чтобы увидеть, как это делается.
Я следовал инструкциям, однако, когда A определяет servicebehavior everthing работает нормально. Конфигурация выглядит следующим образом:
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials name="ServiceBehavior">
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider"
membershipProviderName="AspNetSqlMembershipProvider" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
Мои привязки задаются следующим образом:
<bindings>
<wsHttpBinding>
<binding name="CentralAdminBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
Когда я вызываю url для просмотра xamlx для службы, появляется следующая ошибка:
не удалось найти базу адрес, соответствующий схеме https для конечной точки с привязкой BasicHttpBinding. Зарегистрированные схемы базовых адресов являются [http]
Как я могу справиться с этой ошибкой ? Я вообще не использую https, но все равно получаю ошибку.
Я также попытался перейти на basichttpbinding вместо wshttp, но это дает аналогичную ошибку.
При смене securitymode на Message я получаю следующую ошибку: сервисный сертификат не предоставляется. Указать сертификат на обслуживание в ServiceCredentials
Есть ли способ использовать конфигурацию без сертификата?
2 ответа:
TransportWithMessageCredential означает, что вы хотите использовать безопасность транспорта и отправлять учетные данные в сообщении. Безопасность транспорта в данном случае означает HTTPS. Во-первых, realease WCF требовала, чтобы имя пользователя и пароль можно было использовать только при защищенной связи. Позже MS выпустила патч, который позволяет обходной путь, чтобы избежать HTTPS, но все еще не рекомендуется. В .NET 4.0 патч непосредственно включен.
Если вы хотите использовать учетные данные сообщения без защищенной связи, у вас есть чтобы создать пользовательскую привязку, аналогичную этой:
<bindings> <customBinding> <binding name="HttpWithAuthentication"> <security authenticationMode="UserNameOverTransport" allowInsecureTranpsort="true" /> <context /> <!-- needed for durable worklfows --> <textMessageEncoding messageVersion="Soap12Addressing10" /> <httpTransport /> </binding> </customBinding> </bindings>
Проблема с allowInsecurTransport заключается в том, что это некоторое "быстрое исправление", которое не интегрируется со всеми функциями WCF. Так, например, когда вы используете его, ваш сервис не может генерировать WSDL / метаданные, потому что эта часть все еще требует безопасной связи.
Вы использовали
TransportWithMessageCredential
, Что означает обязательный HTTPS. Поэтому вам нужно либо изменить настройки безопасности, либо включить SSL.WCF не допускает проверку подлинности открытым текстом по протоколу http, она требует https, и это поведение является преднамеренным - я бы на самом деле не согласился, но хорошо, что я не microsoft.
Если вам нужно включить аутентификацию открытым текстом, вам нужно вручную обработать сообщение в инспекторе сообщений.
Обновить
Вот моя реализация (это грубое и единственное доказательство концепции), но другой ответ лучше (встроенная поддержка в WCF 4.0):
[Serializable()] public class ConsoleMessageTracer : BehaviorExtensionElement, IClientMessageInspector ,IEndpointBehavior, System.Configuration.IConfigurationSectionHandler { private string _userName = string.Empty; private string _password = string.Empty; [XmlAttribute()] public string UserName { get { return _userName; } set { _userName = value; } } [XmlAttribute()] public string Password { get { return _password; } set { _password = value; } } private Message TraceMessage(MessageBuffer buffer) { Message msg = buffer.CreateMessage(); Console.WriteLine("\n{0}\n", msg); return buffer.CreateMessage(); } public void AfterReceiveReply(ref Message reply, object correlationState) { reply = TraceMessage(reply.CreateBufferedCopy(int.MaxValue)); } public object BeforeSendRequest(ref Message request, IClientChannel channel) { request.Headers.Add(MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", tt, true, "http://www.isban.es/soap/actor/wssecurityUserPass") ); return null; } public override Type BehaviorType { get { return this.GetType(); } } protected override object CreateBehavior() { return this; } #region IEndpointBehavior Members public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { return; } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new ConsoleMessageTracer()); //foreach (ClientOperation op in clientRuntime.Operations) // op.ParameterInspectors.Add(new ConsoleMessageTracer()); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { //endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new ConsoleMessageTracer()); //foreach (DispatchOperation op in endpointDispatcher.DispatchRuntime.Operations) // op.ParameterInspectors.Add(new ConsoleMessageTracer()); } public void Validate(ServiceEndpoint endpoint) { return; } #endregion #region IConfigurationSectionHandler Members public object Create(object parent, object configContext, XmlNode section) { return null; } #endregion } [DataContract(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")] //[DataContract(Namespace = "")] [Serializable()] public class UserNameTokenToken { [DataMember()] public UserNameToken UsernameToken; public UserNameTokenToken(UserNameToken token) { UsernameToken = token; } } [DataContract(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")] //[DataContract(Namespace = "")] [Serializable()] public class UserNameToken { [DataMember(Order = 1)] public string Username = string.Empty; [DataMember(Order = 2)] public string Password = string.Empty; public UserNameToken(string uname, string pass) { Username = uname; Password = pass; } }