在IIS中托管时WCF“基本”传输安全性问题

时间:2013-08-08 09:58:50

标签: c# .net wcf wcf-security

我正在尝试使用HTTPS / SSL,基本客户端凭据和WebHttpBinding来保护新的.Net 4.5 WCF服务。通过在线阅读,我发现了一系列Blog Posts from Allen Conway的好用作模板。

WCF配置

 <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="webInteropSecureBinding" allowCookies="false" maxBufferPoolSize="2097152" maxBufferSize="2097152" maxReceivedMessageSize="2097152">
          <security mode="Transport">
            <transport clientCredentialType="Basic"></transport>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
    <services>
      <service name="PsmDataProvider.PsmProvider" behaviorConfiguration="SecureRest">
        <clear />
        <endpoint address="" binding="webHttpBinding" bindingConfiguration="webInteropSecureBinding" name="PsmProvider" contract="PsmDataProvider.IPsmProvider" behaviorConfiguration="webHttpBehavior" />
        <endpoint address="mex" binding="mexHttpsBinding" name="mex" contract="IMetadataExchange" listenUriMode="Explicit" />
        <host>
          <baseAddresses>
            <add baseAddress="https://localhost:44300/PsmProvider/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SecureRest">
          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" 
                                    customUserNamePasswordValidatorType="PsmDataProvider.Security.CustomerUserNamePasswordValidator, PsmDataProvider"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="webHttpBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

CustomerUserNamePasswordValidator

我已经删除了CustomerUserNamePasswordValidator实现,并确认在引发异常之前调用了构造函数。

using System;
using System.IdentityModel.Selectors;

namespace PsmDataProvider.Security
{
    internal class CustomerUserNamePasswordValidator : UserNamePasswordValidator, ICustomerUserNamePasswordValidator 
    {

        public CustomerUserNamePasswordValidator()
        {
        }

        public override void Validate(string userName, string password)
        {          
            if (userName == null) throw new ArgumentNullException("userName","The username must be provided in the request to access this service");
            if (password == null) throw new ArgumentNullException("password", "The password must be provided in the request to access this service");

        }
    }
}

当我尝试通过IIS Express在VS2012中运行代码时,服务无法以下面的错误启动。

enter image description here

如果我从配置中删除clientCredentialType,那么它可以工作,但我需要额外的安全性,即在服务上使用用户名/密码验证,并且可能在将来的方法级别。

这是我在WCF配置中错误配置的内容还是IISExpress中的配置问题?

请帮忙......

1 个答案:

答案 0 :(得分:3)

问题似乎是在IIS中托管服务时使用基本身份验证,因为IIS希望处理身份验证。

这在this MSDN blog post

中讨论
  

在.Net Framework 3.0附带的WCF版本中,我们没有   支持具有传输级HTTP安全性的自定义验证器。我们   从社区收到很多反馈意见,这是一个很高的评价   期望的功能,所以我很高兴地说我们增加了对此的支持   .Net Framework 3.5版本中的场景。请注意,这是   仅在自托管服务下受支持。

通过实施从Allen Conway's Blog Post

派生的自定义授权管理器,ServiceAuthorizationManager中讨论了一个解决方案

CustomAuthorizationManager

public class CustomAuthorizationManager : ServiceAuthorizationManager 
{
    private const string UserName = "username";
    private const string Password = "password";

    protected override bool CheckAccessCore(OperationContext operationContext)
    {
        string authHeader = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];

        if ((authHeader != null) && (authHeader != string.Empty))
        {
            string[] svcCredentials = System.Text.ASCIIEncoding.ASCII
                                        .GetString(Convert.FromBase64String(authHeader.Substring(6)))
                                        .Split(':');

            var user = new { Name = svcCredentials[0], Password = svcCredentials[1] };

            if ((user.Name.Equals(UserName) && user.Password.Equals(Password)))
                return true;
            else
                return false;
        }
        else
        {
            WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"PsmProvider\"");
            throw new WebFaultException(HttpStatusCode.Unauthorized);
        }
    }

}

<强>配置

  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="webInteropSecureBinding" allowCookies="false" maxBufferPoolSize="51200" maxBufferSize="51200" maxReceivedMessageSize="51200">
          <security mode="Transport"/>
        </binding>
      </webHttpBinding>
    </bindings>
    <services>
      <service name="PsmDataProvider.PsmProvider" behaviorConfiguration="SecureRest">
        <clear />
        <endpoint binding="webHttpBinding" bindingConfiguration="webInteropSecureBinding" 
                    name="PsmProvider" contract="PsmDataProvider.IPsmProvider" behaviorConfiguration="webHttpBehavior" />
        <endpoint address="mex" binding="mexHttpsBinding" name="mex" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="https://localhost:44300/PsmProvider/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SecureRest">
          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceAuthorization serviceAuthorizationManagerType="PsmDataProvider.Security.CustomAuthorizationManager, PsmDataProvider"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="webHttpBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

注意

另请注意Travich关于IIS / IIS Express配置的评论

  

Travich说......有一件事可以帮助其他用户。简要说明了,   但我忽略了一些事情......关闭IIS中的Basic Auth并删除   来自webHttpBinding的标记!

适合我。