WCF身份验证 - 消息确认安全时出错 [英] WCF Authentication - An error occurred when verifying security for the message

查看:180
本文介绍了WCF身份验证 - 消息确认安全时出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我连接到我的WCF服务与 clientCredentialType =用户名

问题

当我运行code下面我得到一个错误


  

的FaultException:该消息确认安全时发生错误


在玩弄一些绑定值我也得到访问被拒绝。

菲德勒说,没有授权头,我也不能找到在请求中的用户名和密码。

下面是我的配置摘录:

 < system.webServer>
    <模块runAllManagedModulesForAllRequests =真/>
  < /system.webServer>
    <服务和GT;
      <服务名称=InventoryServices.MobileAPIbehaviorConfiguration =customBehaviour>
        <端点地址=
                  绑定=basicHttpBinding的
                  bindingConfiguration =secureHttpBinding
                  合同=InventoryServices.IMobileAPI/>        <端点地址=MEX
                  绑定=mexHttpsBinding
                  合同=IMetadataExchange接口/>
      < /服务>
    < /服务>
    <&行为GT;
      < serviceBehaviors>
        <行为NAME =customBehaviour>
          < serviceSecurityAudit auditLogLocation =应用程序serviceAuthorizationAuditLevel =失败messageAuthenticationAuditLevel =失败SUP pressAuditFailure =真/>
          <! - 为了避免泄露的元数据信息,下面设置为false的价值和部署之前删除上面的元数据终结点 - >
          < serviceMetadata httpsGetEnabled =真/>
          <! - 要接收故障中的异常细节进行调试,下面设置为true值。设置为false部署之前,以避免泄露异常信息 - >
          < serviceDebug includeExceptionDetailInFaults =真/>
          < serviceCredentials>
            < userNameAuthentication userNamePasswordValidationMode =自定义
               customUserNamePasswordValidatorType=\"InventoryLibrary.Helpers.UserAuthentication,InventoryLibrary\"/>
          < / serviceCredentials>
        < /行为>
      < / serviceBehaviors>
    < /行为>
    < serviceHostingEnvironment multipleSiteBindingsEnabled =真/>
    <&绑定GT;
      <&basicHttpBinding的GT;
        <绑定名称=secureHttpBinding>
          <安全模式=TransportWithMessageCredential>
            <运输clientCredentialType =基本proxyCredentialType =基本的境界=MYREALM/>
            <消息clientCredentialType =用户名algorithmSuite =默认/>
          < /安全>
        < /&结合GT;
      < / basicHttpBinding的>
    < /绑定>

我的用户名/密码验证程序看起来像这样:

 公共类UserAuthentication:UserNamePasswordValidator {
        公共覆盖无效验证(用户名字符串,字符串密码){            EntitiesContext DB =新EntitiesContext();
            db.Logs.Add(新DomainModels.Log(){
                DateLogged = DateTime.Now,
                消息=打AUTH
                类型= DomainModels.LogType.Info
            });
            db.SaveChanges();            尝试{                如果(用户名==测试和放大器;&放大器;密码==test123){
                    Console.WriteLine(正宗用户);
                }
            }
            赶上(例外前){
                抛出新的FaultException(未知的用户名或密码不正确);
            }
        }
    }

我这是对我的服务进行简单的测试:

  [OperationContract的]
[XmlSerializerFormat]
无效测试();[的PrincipalPermission(SecurityAction.Demand,名称=测试)]
公共无效测试(){}

我有我的服务器上的自签名SSL证书,我可以访问我的服务/元。

然后我添加在控制台应用程序的服务引用,并尝试与低于此code连接到服务:

 类节目{
    静态无效的主要(字串[] args){        Stuff.InitiateSSLTrust();        basicHttpBinding的约束力=新basicHttpBinding的();
        binding.Security.Mode = BasicHttpSecurityMode.Transport;
        binding.Security.Transport.Realm =MYREALM;        ServiceReference1.MobileAPIClient serviceProxy =新ServiceReference1.MobileAPIClient(绑定,新的EndpointAddress(HTTPS://xx.xx.xx.xx/InventoryServices.MobileApi.svc));        serviceProxy.ClientCredentials.UserName.UserName =测试;
        serviceProxy.ClientCredentials.UserName.Password =test123;        尝试{            变种一个= serviceProxy.Login(一,B);
        }
        赶上(例外前){
            VAR EX2 =前;
        }
    }
}公共类的东西{
    公共静态无效InitiateSSLTrust(){
        尝试{
            //改变SSL检查,使所有检查均通过
            ServicePointManager.ServerCertificateValidationCallback =
                新RemoteCertificateValidationCallback(
                    委托{返回true; }
                );
        }
        赶上(例外前){
        }
    }
}

我检查服务器上的事件查看器,并与每个请求出现这个错误:


  

MessageSecurityException:安全处理器是无法找到的消息在安全头。这可能是因为消息是不安全的故障还是因为在通信双方之间具有约束力的不匹配。如果服务被配置为安全和客户端不使用安全性可能出现这种情况。



解决方案

您指定的客户端使用 BasicHttpSecurityMode.Transport 而服务期待 BasicHttpSecurityMode.TransportWithMessageCredential 。这是一个问题,因为该服务正在寻找在SOAP消息头和客户端的客户端凭据不会与结合这种方式配置给他们。

因此​​,这就是为什么用户名/密码对是不是在邮件标题present如你所看到。因此,事件查看器是正确的,有通信双方之间的绑定不匹配。

还可以设置 ClientCredentialType 客户端 BasicHttpMessageCredentialType.UserName 关于消息级别的安全性。默认情况下 basicHttpBinding的使用这是匿名客户端。

下面是一个code片段描述了上述变化:

  VAR basicHttpBinding的=新basicHttpBinding的(
                              BasicHttpSecurityMode.TransportWithMessageCredential);
basicHttpBinding.Security.Message.ClientCredentialType =
                                     BasicHttpMessageCredentialType.UserName;

I have a problem connecting to my WCF service with clientCredentialType="UserName".

When I run the code below I get an error

FaultException: An error occurred when verifying security for the message.

When playing around with some of the binding values I also get Access is denied..

Fiddler says there is no authorization header and I cannot find the username or password in the request either.

Here are excerpts from my config:

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
    <services>
      <service name="InventoryServices.MobileAPI"  behaviorConfiguration="customBehaviour">
        <endpoint address=""
                  binding="basicHttpBinding"
                  bindingConfiguration="secureHttpBinding"
                  contract="InventoryServices.IMobileAPI"/>

        <endpoint address="mex"
                  binding="mexHttpsBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="customBehaviour">
          <serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" suppressAuditFailure="true" />
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom"
               customUserNamePasswordValidatorType="InventoryLibrary.Helpers.UserAuthentication,InventoryLibrary"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <bindings>
      <basicHttpBinding>
        <binding name="secureHttpBinding">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="MyRealm"/>
            <message clientCredentialType="UserName" algorithmSuite="Default"  />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>

My username/password validator looks like so:

  public class UserAuthentication : UserNamePasswordValidator {
        public override void Validate(string userName, string password) {

            EntitiesContext db = new EntitiesContext();
            db.Logs.Add(new DomainModels.Log() {
                DateLogged = DateTime.Now,
                Message = "hit auth",
                Type = DomainModels.LogType.Info
            });
            db.SaveChanges();

            try {

                if (userName == "test" && password == "test123") {
                    Console.WriteLine("Authentic User");
                }
            }
            catch (Exception ex) {
                throw new FaultException("Unknown Username or Incorrect Password");
            }
        }
    }

I have this as a simple test on my service:

[OperationContract]
[XmlSerializerFormat]
void Test();

[PrincipalPermission(SecurityAction.Demand, Name = "test")]
public void Test() {

}

I have a self signed SSL certificate on my server and I can access my service/metadata.

Then I have added a service reference in a console application, and attempt to connect to the service with this code below:

class Program {
    static void Main(string[] args) {

        Stuff.InitiateSSLTrust();

        BasicHttpBinding binding = new BasicHttpBinding();
        binding.Security.Mode = BasicHttpSecurityMode.Transport;
        binding.Security.Transport.Realm = "MyRealm";

        ServiceReference1.MobileAPIClient serviceProxy = new ServiceReference1.MobileAPIClient(binding, new EndpointAddress("https://xx.xx.xx.xx/InventoryServices.MobileApi.svc"));

        serviceProxy.ClientCredentials.UserName.UserName = "test";
        serviceProxy.ClientCredentials.UserName.Password = "test123";

        try {

            var a = serviceProxy.Login("a", "b");
        }
        catch (Exception ex) {
            var ex2 = ex;
        }
    }
}

public class Stuff {
    public static void InitiateSSLTrust() {
        try {
            //Change SSL checks so that all checks pass
            ServicePointManager.ServerCertificateValidationCallback =
                new RemoteCertificateValidationCallback(
                    delegate { return true; }
                );
        }
        catch (Exception ex) {
        }
    }
}

I've checked the event viewer on the server and this error appears with each request:

MessageSecurityException: Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.

解决方案

You are specifying the client side to use BasicHttpSecurityMode.Transport whereas the service is expecting BasicHttpSecurityMode.TransportWithMessageCredential. This is a problem because the service is looking for the client credentials in the SOAP Message Header and the client will not send them with the binding configured this way.

Hence, this is why the username/password pair is not present in the Message Header as you are witnessing. So the event viewer was correct that there was a binding mismatch between the communicating parties.

Also set the ClientCredentialType on the client to BasicHttpMessageCredentialType.UserName for Message level security. By default BasicHttpBinding uses None which are anonymous clients.

Here's a code snippet describing the above changes:

var basicHttpBinding = new BasicHttpBinding(
                              BasicHttpSecurityMode.TransportWithMessageCredential);
basicHttpBinding.Security.Message.ClientCredentialType = 
                                     BasicHttpMessageCredentialType.UserName;

这篇关于WCF身份验证 - 消息确认安全时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆