Совместимы ли операции OneWay в WCF с ClientCertificateMappingAuthorization? - PullRequest
0 голосов
/ 11 января 2019

Я сделал WCF с одним пустым методом и развернул его на IIS; он работает нормально (ответ службы - код 202) до тех пор, пока я не включу его в SSL с проверкой подлинности сертификата клиента: в этом случае код операции не выполняется, а ответ сервера равен 200. Кажется, что не возникло никаких исключений (No Failed Request) отслеживается, нет ошибок в окне просмотра событий), но я не могу получить выполнение вызванного метода

Вот реализация и конфигурация WCF:

namespace WcfTestService
{
    [ServiceContract]
    public interface IWcfTestService
    {
        [OperationContract(IsOneWay =true)]
        void OneWay(int value);

    }

    [ServiceBehavior]
    public class Service1 : IWcfTestService
    {
        [OperationBehavior]
        public void OneWay(int value)
        {
            Trace.TraceInformation(DateTime.Now.ToString() + " Oneway method invoked!" );
        }
    }
}


<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="WcfTestBinding" messageEncoding="Text" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="50000000" maxReceivedMessageSize="50000000">
                    <readerQuotas maxDepth="500000000" maxStringContentLength="500000000" maxArrayLength="500000000" maxBytesPerRead="500000000" maxNameTableCharCount="500000000" />
                    <security mode="Transport">
                        <transport clientCredentialType="Certificate" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <services>
            <service name="WcfTestService.Service1" behaviorConfiguration="WcfTestBehaviors">
                <endpoint address="" binding="basicHttpBinding" bindingConfiguration="WcfTestBinding" contract="WcfTestService.IWcfTestService" />
                <endpoint contract="IMetadataExchange" binding="mexHttpsBinding" address="mex" />
            </service>
        </services>
        <protocolMapping>
            <add binding="wsHttpBinding" scheme="https" />
        </protocolMapping>

        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfTestBehaviors">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceThrottling maxConcurrentCalls="500" maxConcurrentInstances="500" maxConcurrentSessions="500" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
        <directoryBrowse enabled="true" />
        <security>
            <authentication>
                <anonymousAuthentication enabled="true" />
                <iisClientCertificateMappingAuthentication enabled="true">
                    <oneToOneMappings>
                        <clear />
                    </oneToOneMappings>
                </iisClientCertificateMappingAuthentication>
            </authentication>
            <authorization>
                <remove users="*" roles="" verbs="" />
                <add accessType="Allow" users="" roles="Users" />
            </authorization>
        </security>
        <tracing>
            <traceFailedRequests>
                <remove path="*" />
                <add path="*">
                    <traceAreas>
                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI" verbosity="Verbose" />
                    </traceAreas>
                    <failureDefinitions timeTaken="00:00:00" statusCodes="401.2,202" />
                </add>
            </traceFailedRequests>
        </tracing>
    </system.webServer>
    <system.diagnostics>
        <switches>
            <add name="DataMessagesSwitch" value="1" />
            <add name="TraceLevelSwitch" value="4" />
        </switches>
        <trace autoflush="true" indentsize="4">
            <listeners>
                <add name="WcfTestServiceTraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="logs\WcfTestService.txt" />
                <remove name="Default" />
            </listeners>
        </trace>
    </system.diagnostics>
</configuration>

Код клиента и его конфигурация:

static bool Test()
        {
            string certPath = @"C:\myCertName.pfx";
            string pwdValue = "myPassword";
            bool res = false;
            EndpointAddress newEP = new EndpointAddress("https://myservername/WcfTestService");
            BasicHttpsBinding newBind = new BasicHttpsBinding();

            newBind.Security.Mode = BasicHttpsSecurityMode.Transport;
            newBind.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

            srvRefTest.WcfTestServiceClient myWS = new srvRefTest.WcfTestServiceClient(newBind,newEP);

            System.Net.ServicePointManager.ServerCertificateValidationCallback +=
                            (se, cert, chain, sslerror) =>
                            {
                                return true;
                            };

            X509Certificate2 ccert = new X509Certificate2(certPath, pwdValue);
            myWS.ClientCredentials.ClientCertificate.Certificate = ccert;
            myWS.OneWay(1);
            return res;
        }

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IWcfTestService">
                    <security mode="Transport">
                        <transport clientCredentialType="Certificate" />
                        <message clientCredentialType="UserName" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://myservername/WcfTestService/WcfTestService.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IWcfTestService"
                contract="srvRefTest.IWcfTestService" name="BasicHttpBinding_IWcfTestService" />
        </client>
    </system.serviceModel>
</configuration>        

В журналах сервера я вижу этот вызов:

2019-01-11 14:45:01 W3SVC1 10.0.0.4 POST /WcfTestService - 443 SDI_user 130.0.139.146 - 200 0 0 187

где SDI_user - имя пользователя, указанное в разделе manyToOneMapping в IIS, как показано на рисунке: (https://drive.google.com/open?id=1gGN6HrIDC9u160FuWx6MBwgi7MW7ppRS)

Ответы [ 3 ]

0 голосов
/ 16 января 2019

Я просмотрел вашу конфигурацию и хотел узнать, почему не используется сертификат клиента стандартным способом - не понимал режим безопасности - транспорт выполняет как транспорт, так и безопасность сообщений Я предлагаю вам следовать примеру из: https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication Используйте wsHttpBinding, посмотрите здесь для сравнения: https://www.codeproject.com/Articles/36396/Difference-between-BasicHttpBinding-and-WsHttpBind

0 голосов
/ 17 января 2019

спасибо всем (особенно ошварцу); Я просто нашел причину: в коде клиента мне нужно было указать адрес конечной точки, полный файла .svc. Вот полный код и конфигурация.

Реализация и настройка WCF:

namespace WcfTestService
{
    [ServiceContract]
    public interface IWcfTestService
    {
        [OperationContract(IsOneWay =true)]
        [XmlSerializerFormat()]
        void OneWay(int value);
    }
}

namespace WcfTestService
{
     [ServiceBehavior]
    public class Service1 : IWcfTestService
    {

        [OperationBehavior]
        public void OneWay(int value)
        {
            Trace.TraceInformation(DateTime.Now.ToString() + " " + "Oneway method invoked! Parameter= " + value.ToString());
            Trace.Flush();
        }
    }
}

Конфигурация WCF:

<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WcfTestBinding" messageEncoding="Mtom" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="50000000" maxReceivedMessageSize="50000000">
                    <readerQuotas maxDepth="500000000" maxStringContentLength="500000000" maxArrayLength="500000000" maxBytesPerRead="500000000" maxNameTableCharCount="500000000" />
                    <security mode="TransportWithMessageCredential">
                        <message clientCredentialType="Certificate" />
                        <transport clientCredentialType="Certificate" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <services>
            <service name="WcfTestService.Service1" behaviorConfiguration="WcfTestBehaviors">
                <endpoint address="" binding="wsHttpBinding" bindingConfiguration="WcfTestBinding" contract="WcfTestService.IWcfTestService" />
                <endpoint contract="IMetadataExchange" binding="mexHttpsBinding" address="mex" />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfTestBehaviors">
                    <serviceMetadata httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
        <directoryBrowse enabled="true" />
        <security>
                        <authentication>
                <anonymousAuthentication enabled="true" />
            </authentication>
            <authorization>
                <remove users="*" roles="" verbs="" />
                <add accessType="Allow" users="myuser" />
            </authorization>
        </security>
        <tracing>
            <traceFailedRequests>
                <remove path="*" />
                <add path="*">
                    <traceAreas>
                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI" verbosity="Verbose" />
                    </traceAreas>
                    <failureDefinitions timeTaken="00:00:00" statusCodes="401-500" />
                </add>
            </traceFailedRequests>
        </tracing>
    </system.webServer>
   <system.diagnostics>
        <switches>
            <add name="DataMessagesSwitch" value="1" />
            <add name="TraceLevelSwitch" value="4" />
        </switches>
        <trace autoflush="true" indentsize="4">
            <listeners>
                <add name="WCFConsumerTraceListener" type="System.Diagnostics.TextWriterTraceListener" 
                     initializeData="logs\WcfTestService.txt" />
            </listeners>
        </trace>
    </system.diagnostics>
</configuration>

Клиентская реализация:

static void Test1Remoto()
        {
            EndpointAddress newEP = new EndpointAddress("https://mydomain/WcfTestService/WcfTestService.svc");
            BasicHttpsBinding newBind = new BasicHttpsBinding();

            newBind.Security.Mode = BasicHttpsSecurityMode.Transport;
            newBind.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

            srvRefTest.WcfTestServiceClient myWS = new srvRefTest.WcfTestServiceClient(newBind,newEP);

            System.Net.ServicePointManager.ServerCertificateValidationCallback +=
                            (se, cert, chain, sslerror) =>
                            {
                                return true;
                            };

            X509Certificate2 ccert = new X509Certificate2(certPath, pwdValue);
            myWS.ClientCredentials.ClientCertificate.Certificate = ccert;
            myWS.OneWay(1);
            myWS.Close();
        }

Конфигурация клиента:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IWcfTestService" messageEncoding="Mtom">
                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="None" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://mydomain/WcfTestService/WcfTestService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWcfTestService"
                contract="srvRefTest.IWcfTestService" name="WSHttpBinding_IWcfTestService" />
        </client>
    </system.serviceModel>
</configuration>    
0 голосов
/ 13 января 2019

Лучше всего добавить трассировку WCF как на сервере, так и на стороне клиента. https://docs.microsoft.com/en-us/dotnet/framework/wcf/diagnostics/tracing/configuring-tracing это должно дать вам подробную информацию о том, что происходит. При необходимости выложите сюда файл svclog

...