首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >同时使用用户名和证书的WCF消息身份验证

同时使用用户名和证书的WCF消息身份验证
EN

Stack Overflow用户
提问于 2013-07-11 06:56:28
回答 1查看 1K关注 0票数 0

长话短说:

我的WCF客户端应该能够向IIS中托管的服务提供用户名和证书,在IIS中,我应该使用这些信息来使用自定义策略验证请求。

完整故事:

我需要对一些WCF客户端进行身份验证,以验证它们是否可以执行操作。

我们有两种客户端: WPF应用程序和web应用程序。我们希望做以下工作:

  • web应用程序使用服务信任的证书,以便将其识别为具有所有权限的特殊用户( web应用程序本身已经验证了权限,我们现在不想碰它)
  • WPF客户端使用用户提供的用户名/密码进行身份验证。

在这些操作的实现中,我想验证是否提供了证书(然后我识别了“超级用户”),否则会退回到用户名/密码身份验证。

服务托管在IIS 7中,我们需要使用NetTcpBinding。我能够实现用户名验证,但问题是服务检查的AuthorizationContext只包含身份信息,而不包含证书。客户端使用以下代码初始化通道的创建(来自用于测试解决方案的尖峰):

代码语言:javascript
运行
复制
var factory = new ChannelFactory<T>(this.Binding, address);

        var defaultCredentials = factory.Endpoint.Behaviors.Find<ClientCredentials>();
        factory.Endpoint.Behaviors.Remove(defaultCredentials);

        var loginCredentials = new ClientCredentials();
        loginCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
                     X509CertificateValidationMode.None;
        loginCredentials.UserName.UserName = username;
        loginCredentials.UserName.Password = password;
        if (useCertificate)
        {
            loginCredentials.SetCertificate();
        }

        factory.Endpoint.Behaviors.Add(loginCredentials);
        return factory.CreateChannel();

随着SetCertificate扩展的实现如下:

代码语言:javascript
运行
复制
public static void SetCertificate(this ClientCredentials loginCredentials)
    {
        loginCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "SecureWcfClient");
    }

这是承载服务的web应用程序的配置:

代码语言:javascript
运行
复制
<system.serviceModel>
<behaviors>
  <serviceBehaviors>
    <behavior name="SecureBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
      <serviceCredentials>
        <serviceCertificate findValue="Test"
              storeLocation="LocalMachine"
              storeName="My"
              x509FindType="FindBySubjectName" />
        <clientCertificate>
          <authentication certificateValidationMode="Custom" customCertificateValidatorType="AuthenticationProtectedService.Security.CertificateValidator, AuthenticationProtectedService.Security"/>
        </clientCertificate>
        <userNameAuthentication userNamePasswordValidationMode="Custom"
         customUserNamePasswordValidatorType="AuthenticationProtectedService.Security.UserNamePassValidator, AuthenticationProtectedService.Security" />
      </serviceCredentials>
      <serviceAuthorization serviceAuthorizationManagerType="AuthenticationProtectedService.Security.CertificateAuthorizationManager, AuthenticationProtectedService.Security"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
<bindings>
  <netTcpBinding>
    <binding>
      <security mode="None"/>
    </binding>
    <binding name="SecureNetTcp">
      <security mode="Message">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </netTcpBinding>
</bindings>
  <service
  name="AuthenticationProtectedService.Services.OneWayServiceB"
  behaviorConfiguration="SecureBehavior">
    <endpoint
        address=""
        binding="wsHttpBinding"
        contract="AuthenticationProtectedService.ServiceModel.IOneWayServiceB">
    </endpoint>
  </service>
  <service
  name="AuthenticationProtectedService.Services.DuplexServiceB" behaviorConfiguration="SecureBehavior">
    <endpoint
        address=""
        binding="netTcpBinding"
        bindingConfiguration="SecureNetTcp"
        contract="AuthenticationProtectedService.ServiceModel.IDuplexServiceB">
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
  </service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

最后,这是自定义授权管理器的实现(我也尝试过使用自定义证书验证器,但该函数从未运行)

代码语言:javascript
运行
复制
public class CertificateAuthorizationManager : ServiceAuthorizationManager
{
    protected override bool CheckAccessCore(OperationContext operationContext)
    {
        if (!base.CheckAccessCore(operationContext))
        {
            return false;
        }

        string thumbprint = GetCertificateThumbprint(operationContext);

        // I'd need to verify the thumbprint, but it is always null
        return true;
    }

    private string GetCertificateThumbprint(OperationContext operationContext)
    {
        foreach (var claimSet in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
        {
            foreach (Claim claim in claimSet.FindClaims(ClaimTypes.Thumbprint, Rights.Identity))
            {
                string tb = BitConverter.ToString((byte[])claim.Resource);
                tb = tb.Replace("-", "");
                return tb;
            }
        }

        return null;
    }
}

我认为问题可能在服务配置上的clientCredentialType节点的nettcpbinding.Security.Message属性中,但我看不到在消息安全性中同时使用证书和用户名的选项。

感谢您的帮助,谢谢

注意:该项目的一个具体目标是对服务器设置和系统中的一般情况产生非常低的影响,因此,如果可能的话,也应该避免SSL。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-07-26 20:48:12

尝试此链接http://msdn.microsoft.com/en-us/library/ms733099.aspx ...it可能解决您的问题,您可以根据需要对同一绑定类型进行不同的绑定配置,并将相同的绑定配置关联到不同的端点。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17586906

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档