【问题标题】:Username and password authentication for WCF service behind DMZ firewallDMZ 防火墙后 WCF 服务的用户名和密码验证
【发布时间】:2017-04-26 08:04:20
【问题描述】:

场景

客户端 DMZ 防火墙 WCF 服务

当客户端尝试连接到 WCF 服务时,它必须通过 HTTPS (SSL) 进行。如果它尝试通过 HTTP 连接,DMZ 防火墙无论如何都会将其重定向到 HTTPS。 当请求到达 DMZ 防火墙时,它会通过不安全的连接(仅限 HTTP)转发到 WCF 服务。

我希望通过用户名和密码身份验证来保护我的服务,因此我尝试使用模式 TransportWithMessageCredential 和自定义 UserNamePasswordValidator 设置 wsHttpBinding

我的 web.config 文件看起来像

<system.serviceModel>
<services>
  <service name="WcfService1.TestWcfService" behaviorConfiguration="WcfService1.TestWcfServiceBehavior">
    <!-- Service Endpoints -->
    <endpoint address="" binding="wsHttpBinding" bindingName="wsHttpBinding_behind_firewall" contract="WcfService1.ITestWcfService">
      <identity>
        <dns value="localhost"/>
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="WcfService1.TestWcfServiceBehavior">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="true"/>
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.WcfAuthenticationValidator, WcfService1"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>
<bindings>
  <wsHttpBinding>
    <binding name="wsHttpBinding_behind_firewall">
      <security mode="TransportWithMessageCredential">
        <transport clientCredentialType="None" />
        <message clientCredentialType="UserName" />
      </security>
    </binding>
  </wsHttpBinding>
</bindings>
</system.serviceModel>

我的密码验证器类看起来像:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;
using System.ServiceModel;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;

namespace WcfService1
{
    public class WcfAuthenticationValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName == null)
            {
                throw new ArgumentNullException(nameof(userName));
            }

            if (password == null)
            {
                throw new ArgumentNullException(nameof(password));
            }

            //TODO: get username and password from DB and compare incoming password with one stored in DB.

            if (!(userName == "hello" && password == "world"))
            {
                throw new SecurityTokenException("Unknown Username or Incorrect Password");
            }
        }
    }
}

要连接到这个 WCF 服务,我的客户端代码如下所示:

TestWcfService.TestWcfServiceClient client = new TestWcfService.TestWcfServiceClient();
client.ClientCredentials.UserName.UserName = "hello";
client.ClientCredentials.UserName.Password = "world";
Console.WriteLine(client.GetData(0));

并且此客户端应用的 app.config 包含:

<system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="wsHttpBinding_behind_firewall_ITestWcfService" />
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://example.com/TestWcfService.svc"
                binding="wsHttpBinding" bindingConfiguration="wsHttpBinding_behind_firewall_ITestWcfService"
                contract="TestWcfService.ITestWcfService" name="wsHttpBinding_behind_firewall_ITestWcfService">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>

wsHttpBinding 的棘手之处在于 WCF 服务预计所有传入流量都将通过 HTTPS。

我希望服务器接受 HTTP 和 HTTPS 传入流量并进行用户名和密码验证。谁能帮我解决这个问题?

【问题讨论】:

  • 我会配置或要求管理员将 WAF 配置为仅接受 HTTPS 连接并拒绝 HTTP 请求,并仅通过 HTTPS 重定向到 WCF 服务。将 HTTP 重定向到 HTTPS 会被中间代理中的人拦截,因此从不推荐。

标签: c# wcf authentication


【解决方案1】:

您可以在 web.config 中添加两个具有两种不同绑定配置的端点 - 一个用于 http,一个用于 https。

类似的东西:

<bindings>
  <wsHttpBinding>

    <binding name="wsHttpsBindingConfig" >          
      <security mode="TransportWithMessageCredential">
        <transport clientCredentialType="None">
        </transport>
      </security>

    </binding>
    <binding name="wsHttpBindingConfig" >
    </binding>
  </wsHttpBinding>
</bindings>

<services>
  <service name="WcfService1.Service1">
    <endpoint name="wsHttpBinding"
              contract="WcfService1.IService1"
              binding="wsHttpBinding" 
              bindingConfiguration="wsHttpBindingConfig"
              address=""  >          
    </endpoint>

    <endpoint name="wsHttpsBinding" 
              binding="wsHttpBinding" 
              bindingName="wsHttpBinding_secure"
              contract="WcfService1.IService1" 
              bindingConfiguration="wsHttpsBindingConfig"
              address="">
      <identity>

        <dns value="localhost"/>
      </identity>
    </endpoint>
  </service>   

【讨论】:

  • 我不确定此解决方案是否会验证用户名和密码。
猜你喜欢
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-22
  • 2014-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多