如何在IIS中的WCF端点上使用json托管的SSL进行基本身份验证?

时间:2022-09-27 22:55:02

I've got a restful WCF service that's hosted in IIS served up over SSL using a WebHttpBinding and json.

我有一个基于rest的WCF服务,它驻留在IIS中,通过使用WebHttpBinding和json通过SSL服务。

The service now requires authentication/authorization. There appears to be lots of old information that may or may not still be relevant promoting different ways of achieving authentication, but none of them appear to apply to this specific blend of endpoint binding.

该服务现在需要身份验证/授权。似乎有很多旧的信息可能与促进实现身份验证的不同方法相关,也可能不相关,但它们似乎都不适用于这个特定的端点绑定组合。

I've played with a bunch of different types of bindings and this appears relatively simple to achieve with SOAP based authentication, but not so with json. Most of the information points to the fact that authentication is usurped by IIS, but I've overcome that hurdle.

我使用过许多不同类型的绑定,这对于基于SOAP的身份验证来说似乎相对简单,但对于json就不是这样。大多数信息都指向一个事实,即验证被IIS取代,但我已经克服了这个障碍。

I'd like to use basic authentication like so (Example Fiddler request):

我想使用基本的身份验证,如so(示例Fiddler请求):

GET https://secure.dev.myco.local/api/users/v1/0b7478c5-d25a-4039-9cf4-614b2ef4e04d HTTP/1.1
User-Agent: Fiddler
Host: secure.dev.myco.local
Authorization: Basic dGVzdHVzZXI6UEAkJHcwcmQh

I have the following service behavior configuration:

我有以下服务行为配置:

<behavior name="SslBehavior">
  <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
  <serviceDebug includeExceptionDetailInFaults="true" />
  <serviceCredentials>
    <serviceCertificate findValue="CN=*.dev.myco.local" x509FindType="FindBySubjectDistinguishedName" storeLocation="LocalMachine" />
  </serviceCredentials>
  <serviceAuthenticationManager authenticationSchemes="Basic" 
                                serviceAuthenticationManagerType="Test.Api.TestAuthenticationManager, Test.Api" />
</behavior>

binding definition:

绑定定义:

<webHttpBinding>
  <binding name="ProductBinding">
    <security mode="Transport" />
  </binding>
  <binding name="UserBinding">
    <security mode="Transport" />
  </binding>
</webHttpBinding>

and service definition:

和服务定义:

<service name="Test.Api.ApiService" behaviorConfiguration="SslServiceBehavior">
    <host>
      <baseAddresses>
        <add baseAddress="https://secure.dev.myco.local/api/"/>
      </baseAddresses>
    </host>
    <endpoint address="products/v1" name="ProductService" contract="Test.Api.Product.V1.IProductService" binding="webHttpBinding" bindingConfiguration="ProductBinding" behaviorConfiguration="ProductEndpointWebHttpBehavior" />
    <endpoint address="users/v1" name="UserService" contract="Test.Api.User.V1.IUserService" binding="webHttpBinding" bindingConfiguration="UserBinding" behaviorConfiguration="UserEndpointWebHttpBehavior" />
</service>

My user accounts are to be held in a table in a database, and authentication passes off the credentials to an authentication provider that for all intents and purposes returns either an IIdentity, an IPrincipal or a boolean if the user authenticates. This will then be attached to the context as required. Because of this, I need my application to handle authentication and not just hand off authentication to IIS.

我的用户帐户将保存在数据库中的一个表中,身份验证将凭证传递给一个身份验证提供者,如果用户进行身份验证,该身份验证提供者将返回IIdentity、IPrincipal或boolean。这将根据需要附加到上下文。因此,我需要应用程序来处理身份验证,而不仅仅是将身份验证传递给IIS。

I am successfully able to access the credentials from the HTTP header and authenticate the user by deriving from the authentication manager and overriding the Authenticate method with the following example code - the IPrincipal is generated and attached to the context as I would expect:

我成功地从HTTP报头访问了凭证,并通过从身份验证管理器中获取身份验证用户,并使用下面的示例代码覆盖了验证方法——IPrincipal生成并附加到上下文,正如我所期望的那样:

public class TestAuthenticationManager : ServiceAuthenticationManager
{
    public override ReadOnlyCollection<IAuthorizationPolicy> Authenticate(ReadOnlyCollection<IAuthorizationPolicy> authPolicy, Uri listenUri, ref Message message)
    {
        var requestProperties =
            (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];

        var rawAuthHeader = requestProperties.Headers["Authorization"];

        AuthenticationHeader authHeader = null;
        if (AuthenticationHeader.TryDecode(rawAuthHeader, out authHeader)) ;
        {
            var identity = new GenericIdentity(authHeader.Username);
            var principal = new GenericPrincipal(identity, new string[] {});

            var httpContext = new HttpContextWrapper(HttpContext.Current)
            {
                User = principal,
            };

            if (httpContext.User != null)
                return null;
        }

        SendUnauthorizedResponse();

        return base.Authenticate(authPolicy, listenUri, ref message);
    }

    private void SendUnauthorizedResponse()
    {
        HttpContext.Current.Response.StatusCode = 401;
        HttpContext.Current.Response.StatusDescription = "Unauthorized";
        HttpContext.Current.Response.Headers.Add("WWW-Authenticate", "Basic realm=\"site\"");
        HttpContext.Current.Response.End();
    }
}

Where I'm coming unstuck is that upon exiting the validate method, my service responds with the following error:

我遇到的问题是,在退出验证方法时,我的服务响应如下错误:

The server encountered an error processing the request. The exception message is 'The caller was not authenticated by the service.'. See server logs for more details. The exception stack trace is: at System.ServiceModel.Dispatcher.AuthenticationBehavior.Authenticate(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

服务器在处理请求时遇到错误。异常消息是“调用方没有通过服务进行身份验证”。有关详细信息,请参阅服务器日志。异常堆栈跟踪是:at System.ServiceModel.Dispatcher.AuthenticationBehavior。(在System.ServiceModel.Dispatcher.ImmutableDispatchRuntime MessageRpc& rpc)进行身份验证。在System.ServiceModel.Dispatcher.MessageRpc ProcessMessage11(MessageRpc& rpc)。过程(布尔isOperationContextSet)

The service works fine if I remove the authentication reference from the configuration - as you'd expect, but the user is anauthenticated, and thus if I add any authorization to any of the service methods, it won't handle that piece.

如果我从配置中删除了身份验证引用(正如您所期望的那样),那么该服务可以正常工作,但是用户是经过身份验证的,因此,如果我向任何服务方法添加任何授权,它就不会处理该部分。

The method appears to exit without error. Can anyone shed any light on why I'm getting this exception with this configuration? I've Googled until the cows come home and the information I find all relates to a limited number of variations of other configurations, but none for WebHttpBinding with Json hosted in IIS with SSL.

该方法似乎可以毫无错误地退出。有人能解释一下为什么我得到这个配置的异常吗?我在谷歌上搜索了很久,直到牛回来,我发现的所有信息都与有限的其他配置变体有关,但没有一个用于使用SSL托管在IIS中的Json进行WebHttpBinding。

1 个解决方案

#1


1  

The line if (httpContext.User != null) return null; is the problem. if the Authenticate method return Null as Authorization policy the Dispatcher will throw exception.

如果(httpContext。用户!= null)返回null;是这个问题。如果身份验证方法返回Null作为授权策略,则分派器将抛出异常。

Here the condition is always true and so it will always return null.You need to return a authorization policy instead of null.

这里条件总是为真,所以它总是返回null。您需要返回一个授权策略,而不是null。

#1


1  

The line if (httpContext.User != null) return null; is the problem. if the Authenticate method return Null as Authorization policy the Dispatcher will throw exception.

如果(httpContext。用户!= null)返回null;是这个问题。如果身份验证方法返回Null作为授权策略,则分派器将抛出异常。

Here the condition is always true and so it will always return null.You need to return a authorization policy instead of null.

这里条件总是为真,所以它总是返回null。您需要返回一个授权策略,而不是null。