12 Replies Latest reply on Jul 28, 2015 12:28 PM by dng

    InsertPIData Client Certificate issue

    DSmith1

      I am writing a C# application that calls our PI Web Service. I have tried to generate code using both "Add a Service Reference (based off .NET 2.0 framework)" and "Add a Web Reference (based off .NET 4.0 framework)".

       

      WIth both instances, I generate a PITimeSeries client and add the client certificate from my certificate store. I verified that the correct certificate is part of the client.ClientCertificates X509 certificate collection after adding it.

      But when I call the InsertPIData method I get an error that says "Policy Falsified". A certificate is not being sent with the request to the designated endpoint.

       

      Why is the InsertPIData method not sending the client certificate with it?

       

      Here is a code snippet to show what I'm doing. First one is with the .NET 2.0 framework

       

      PITimeSeriesService client = new PITimeSeriesService();
      
                  // string to the destination PI tag
                  const string PATH = @"pi:\\MYSERVER\PITAG";
      
                  // String to host name of client certificate
                  const string thumbprint = "correct thumbprint (excluded for confidentiality)";
      
                  X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                  certStore.Open(OpenFlags.ReadOnly);
                  X509Certificate myCert = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, true)[0];
                  certStore.Close();
                  client.ClientCertificates.Add(myCert);
      
                  // Set the timestamp & value for the PI tag
                  // Here is where generators need logic to pull mw output from their system
                  TimedValue mWoutput = new TimedValue();
                  mWoutput.Time = DateTime.Now;
                  mWoutput.Value = "38";     // mWoutput should come from provider
      
                  // insertPIData method requires a TimeSeries array object
                  TimeSeries series = new TimeSeries();
                  series.Path = PATH;
                  TimedValue[] values = { mWoutput };
                  series.TimedValues = values;
                  TimeSeries[] data = { series };   // here is where multiple PI points could be updated
      
                  // use client variable to call InsertPIData method, replacing duplicate values
                  try
                  {
                      client.InsertPIData(data, InsertPIDataDuplicateSwitch.InsertDuplicate);
                  }
                  catch (Exception e)
                  {
                      string error = "Exception occured when calling method: " + e;
                      Console.Write(error);
                  }
      

       

       

      Here is with using .NET 4.0 framework

       

      // string to the destination PI tag
                  const string PATH = @"pi:\\MYSERVER\PITAG";
      
                  // String to host name of client certificate
                  const string thumbprint = "correct thumbprint (excluded for confidentiality)";
      
                  X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                  certStore.Open(OpenFlags.ReadOnly);
                  X509Certificate2 myCert = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, true)[0];
                  certStore.Close();
      
                  // Declare web-service client and set certificate from Local Cert Store
                  PITimeSeriesClient client = new PITimeSeriesClient();
                  client.ClientCredentials.ClientCertificate.Certificate = myCert;
                  
                  // Set the timestamp & value for the PI tag
                  // Here is where generators need logic to pull mw output from their system
                  TimedValue mWoutput = new TimedValue();
                  mWoutput.Time = DateTime.Now;
                  mWoutput.Value = Convert.ToString(DateTime.Now.Second);     // mWoutput should come from provider
      
                  // insertPIData method requires a TimeSeries array object
                  TimeSeries series = new TimeSeries();
                  series.Path = PATH;
                  TimedValue[] values = { mWoutput };
                  series.TimedValues = values;
                  TimeSeries[] data = { series };             // here is where multiple PI points could be updated
      
                  // use client variable to call InsertPIData method, replacing duplicate values
                  try
                  {
                      client.InsertPIData(data, InsertPIDataDuplicateSwitch.InsertDuplicate);
                  }
                  catch (Exception e)
                  {
                      string error = "Exception occured when calling method: " + e;
                      Console.Write(error);
                  }
      

       

      Do you see anything I'm doing wrong? Why is the certificate not being included with the request?

        • Re: InsertPIData Client Certificate issue
          dng

          Hi Daniel,

           

          In .NET 4/4.5, have you tried to set the certificate using the SetCertificate method instead of setting the properties directly? Looking at the MSDN descriptions, there seems to be a slight discrepancy between the two:

           

          Can you also give me the full error message and/or stack trace?

           

          In addition, do you see the same error in other PI Web Services call?

            • Re: InsertPIData Client Certificate issue
              DSmith1

              I have tried the setCertificate method, that was my initial attempt and it did not work

               

              I will try using a different WebService call - like GetSnapshotData()

                • Re: InsertPIData Client Certificate issue
                  dng

                  Hi Daniel,

                   

                  When you use the SetCertificate method, did you get the same error message?

                  Any success with the GetSnapshotData call?

                  Can you give us the full error message and/or stack trace so we can help identify the issue?

                    • Re: InsertPIData Client Certificate issue
                      Rhys Kirk

                      It could be permissions...if the certificate is not installed locally for the user. Maybe getting the client to skip the validation of the certificate will help (as a test for now)?

                      • Re: InsertPIData Client Certificate issue
                        DSmith1

                        Yes when using the SetCertificate method I get the same error message. When I switch calls (I used GetPISnapshotData) I get the same error message.

                         

                        The code will not send the certificate with it.

                        We used wire shark to monitor traffic and it doesn't go with the request.

                          • Re: InsertPIData Client Certificate issue
                            dng

                            Hi Daniel,

                             

                            In order to allow us to help you troubleshoot the issue, would you mind providing more information?

                            • What version of PI Web Services are you running?
                            • Please provide the content of the web.config file used by PI Web Services (located at %pihome64%\PIPC\PI Web Services\web.config).
                            • Please provide the content of your app.config file used in your .NET applications.
                            • Please provide the full error message and/or stack trace when the issue is encountered.
                              • Re: InsertPIData Client Certificate issue
                                DSmith1

                                PI Web Services is 1.3.0

                                 

                                The web.config file is

                                <configuration>
                                  <configSections>
                                    <section name="PIWebServiceSettings" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" requirePermission="false" />
                                <section name="pidsSettings" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" requirePermission="false" />
                                  </configSections>
                                  <PIWebServiceSettings>
                                    <add key="AllowCalculations" value="true" />
                                    <add key="AllowDataEntry" value="true" />
                                    <add key="FloatPrecision" value="DisplayDigits" />
                                    <add key="UpdatePurgeInterval" value="5" />
                                  </PIWebServiceSettings>
                                <pidsSettings>
                                    <add key="PIinstrumentationConfigFile" value="E:\Program Files\PIPC\PI Web Services\PIInstrumentation.config" />
                                  </pidsSettings>
                                <!--
                                -->
                                  <connectionStrings />
                                  <system.web>
                                    <compilation debug="false" targetFramework="4.0">
                                      <assemblies>
                                        <add assembly="System.Configuration.Install, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
                                        <add assembly="System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
                                        <add assembly="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
                                        <add assembly="OSIsoft.PIDataServices.DataAccess, Culture=neutral, PublicKeyToken=53b77d1d3d7a979b" />
                                        <add assembly="OSIsoft.PIDataServices.Common, Culture=neutral, PublicKeyToken=53b77d1d3d7a979b" />
                                        <add assembly="OSIsoft.PIDataServices.Configuration, Culture=neutral, PublicKeyToken=53b77d1d3d7a979b" />
                                        <add assembly="OSIsoft.PIDataServices.DataService, Culture=neutral, PublicKeyToken=53b77d1d3d7a979b" />
                                        <add assembly="OSIsoft.PIInstrumentation, Culture=neutral, PublicKeyToken=53b77d1d3d7a979b" />
                                        <add assembly="OSIsoft.PIInstrumentation.Listeners, Culture=neutral, PublicKeyToken=53b77d1d3d7a979b" />
                                      </assemblies>
                                    </compilation>
                                    <authentication mode="Windows" />
                                    <identity impersonate="false" />
                                    <customErrors mode="Off" defaultRedirect="GenericErrorPage.htm">
                                      <error statusCode="403" redirect="NoAccess.htm" />
                                      <error statusCode="404" redirect="FileNotFound.htm" />
                                    </customErrors>
                                    <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />
                                  </system.web>
                                  <system.serviceModel>
                                     <bindings>
                                  <basicHttpBinding>
                                    <binding name="basicBinding">
                                      <security mode="Transport">
                                        <transport clientCredentialType="Certificate" />
                                      </security>
                                    </binding>
                                 </basicHttpBinding>
                                 
                                <!--
                                        <mexHttpBinding>
                                  <binding name="mexBinding" />    
                                        </mexHttpBinding>
                                 --> 
                                     </bindings>
                                    <services>
                                      <service behaviorConfiguration="DefaultServiceBehavior"
                                        name="PIWebServices.PIDataService.PITimeSeriesSvcImpl">
                                  
                                  <!--
                                        <endpoint address="mex" binding="mexHttpsBinding" name="mexBasicEndpoint"
                                          contract="IMetadataExchange" />
                                    -->
                                    
                                    
                                        <endpoint binding="basicHttpBinding" bindingConfiguration="basicBinding"
                                          name="BasicEndpoint" bindingNamespace="https://xml.osisoft.com/services/PIDataService"
                                          contract="PIWebService.PIDataService.IPITimeSeries" />
                                      </service>
                                      <service behaviorConfiguration="DefaultServiceBehavior"
                                        name="PIWebServices.PISearchService.PISearchSvcImpl">
                                        <endpoint binding="basicHttpBinding" bindingConfiguration="basicBinding"
                                          name="SearchEndpoint" bindingNamespace="https://xml.osisoft.com/services/PISearchService"
                                          contract="PIWebServices.PISearchService.IPISearch">
                                        </endpoint>
                                  <!--
                                        <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
                                  -->
                                      </service>
                                      <service behaviorConfiguration="DefaultServiceBehavior" name="OSIsoft.PIWebServices.Services.PISoapServiceImpl">
                                        <endpoint binding="basicHttpBinding" bindingConfiguration="basicBinding" name="SoapEndpoint" bindingNamespace="https://xml.osisoft.com/services/PISoapService"
                                          contract="OSIsoft.PIWebServices.Services.IPISoapService">
                                        </endpoint>
                                  
                                  <!--
                                        <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
                                  -->
                                  
                                      </service>
                                    </services>
                                    <behaviors>
                                      <serviceBehaviors>
                                        <behavior name="DefaultServiceBehavior">
                                          <serviceMetadata httpsGetEnabled="true" />  
                                    <serviceDebug includeExceptionDetailInFaults="true" />
                                          <serviceCredentials>
                                
                                            <windowsAuthentication includeWindowsGroups="true" allowAnonymousLogons="true" />
                                            <issuedTokenAuthentication allowUntrustedRsaIssuers="true" />
                                
                                          </serviceCredentials>
                                          <serviceAuthorization principalPermissionMode="None" impersonateCallerForAllOperations="false" />
                                        </behavior>
                                      </serviceBehaviors>
                                    </behaviors>
                                  </system.serviceModel>
                                  <system.webServer>
                                 <defaultDocument>
                                            <files>
                                                <add value="PITimeSeries.svc" />
                                            </files>
                                        </defaultDocument>
                                  </system.webServer>
                                </configuration>
                                

                                 

                                The app.config file is

                                 

                                <?xml version="1.0" encoding="utf-8" ?>
                                <configuration>
                                    <system.serviceModel>
                                        <bindings>
                                            <basicHttpBinding>
                                                <binding name="BasicEndpoint">
                                                    <security mode="Transport">
                                                        <transport clientCredentialType="Certificate" />
                                                    </security>
                                                </binding>
                                            </basicHttpBinding>
                                        </bindings>
                                        <client>
                                            <endpoint address="endpoint"
                                                binding="basicHttpBinding" bindingConfiguration="BasicEndpoint"
                                                contract="PITimeSeriesDev.IPITimeSeries" name="BasicEndpoint" />
                                        </client>
                                    </system.serviceModel>
                                </configuration>
                                

                                 

                                Stack Trace

                                Exception occured when calling method: System.ServiceModel.FaultException: Polic
                                y Falsified
                                Server stack trace:
                                   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRunt
                                ime operation, ProxyRpc& rpc)
                                   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean on
                                eway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan tim
                                eout)
                                   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCall
                                Message methodCall, ProxyOperationRuntime operation)
                                   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
                                Exception rethrown at [0]:
                                   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage req
                                Msg, IMessage retMsg)
                                   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgDa
                                ta, Int32 type)
                                   at PIWebServicesDev.PITimeSeriesDev.IPITimeSeries.InsertPIData(TimeSeries[] e
                                vents, InsertPIDataDuplicateSwitch duplicateSwitch)
                                   at PIWebServicesDev.PITimeSeriesDev.PITimeSeriesClient.InsertPIData(TimeSerie
                                s[] events, InsertPIDataDuplicateSwitch duplicateSwitch) in C:\Users\DSmith1\Doc
                                uments\Visual Studio 2010\Projects\PIWebServicesDev\PIWebServicesDev\Service Ref
                                erences\PITimeSeriesDev\Reference.cs:line 1011
                                   at PIWebServicesDev.Program.Main(String[] args) in C:\Users\DSmith1\Documents
                                \Visual Studio 2010\Projects\PIWebServicesDev\PIWebServicesDev\Program.cs:line 5
                                8
                                
                                  • Re: InsertPIData Client Certificate issue
                                    dng

                                    Hi Daniel,

                                     

                                    Thank you for the provided information. I set up a test system with your current configurations, but the client certificate was successfully sent and data was retrieved. I am therefore going to suggest a series to test in order to establish the baseline functionality of your system.

                                     

                                    • Before we begin, if you disable the requirement for client certificate (in IIS on server, web.config on server, and app.config on client), can you successfully get snapshot values or write values?

                                     

                                    If the above looks good:

                                    • Please upgrade your PI Web Services to version 2012 SP1 (1.3.1.0). This version contains many important bug fixes compared to version 2012 (1.3.0).
                                    • Have you tried to use another client certificate? If not, use another client certificate, or generate a temporary client certificate for testing (information on how to generate a temporary client certificate can be found here: How to: Create and Install Temporary Client Certificates in WCF During Development). What results do you get?
                                    • On a web browser on the client machine, can you successfully navigate to your https PI Web Services endpoint? https://yourwebserver/PIWebServices/PITimeSeries.svc. Make sure to select the same client certificate as the one you are using in your C# code.
                                    • If the above test is successful, is your endpoint address in your app.config file identical to the address you tested above?
                                    • In IIS on your web server, is the SSL settings "Require SSL" and "Client certificates: Require"?

                                     

                                    If all the tests have been successful so far, I encourage you to enable tracing in your application (Debugging SSL/TLS problems in .NET | Tatham Oddie; or How to: Configure Network Tracing). We can then take a look at the log file to see if there are additional information about the error. 

                        • Re: InsertPIData Client Certificate issue
                          DSmith1

                          Found out the issue. IIS was configured to Ignore client certificates. So when generating the WSDL that went in my visual studio app config file it also did not require a certificate.

                           

                          So even though I explicit set the certificate using the SetCertificate method, because the WSDL wasn't expecting the cert the solution wouldn't send it.