21 Replies Latest reply on Jan 22, 2013 3:34 AM by pcombellick

    Can't get AF-SDK to foward user's credentials to PI server

    jfbeaulieu80

      Hi,

       

      We are building a system that uses PI-AF to feed Silverlight custom controls. We use a Silverlight 5 client, a WCF service, AF-SDK and PI-SDK. The Silverlight client and the WCF Services are hosted on IIS 7.5 (Windows 2008 R2) running on the same machine than the AF server. The PI Server is running on another server (Windows 2008 R2). For the moment, all these servers are part of the same domain drove by ActiveDirectory. Here is representation of our architecture.

       

      2671.Sch_E900_ma-applicatif.jpg

       

       

       

      Because we are using advanced features of the AF SDK, we cannot switch to PI-WebServices.

       

      Ok enough with the introduction. With this architecture, we are experiencing issue getting values from the PI-Server. I looked at the PI Message Log and found the WebService was using his credentials to call the PI-Server (GetValue of a PIPoint using AF-ADK) instead of the client’s credentials.

       

      I’m well aware that it might be a “double hop” kind of issue. But I double checked everything (that I could think of) and it’s still not working.

       

      Here are some observations I made:

       

      -       I made sure to impersonate the caller in the WebService

       

      o   This part is working. The AF current user contains the client credential.

       

      -       I checked at the ImpersonationLevel of the ServiceSecurityContext.Current.Identity and it is Delegation (so it should delegate the user credentials to PI-Server).

       

      -       Kerberos is used by the client to connect to the WebService (Security Audit log event)

       

      o   Settings in ActiveDirectory seems good

       

      o   Settings in IE8 seems good

       

      -       Kerberos is also used by AF-SDK to connect to PI, but with the WebService Credentials

       

      o   I can see that in the PI Message Log and in the PI-Server Security Audit log event.

       

      o   Setting in ActiveDirectory seems good

       

      This is how I try to achieve my task:

       

      First, here is the servicereference.clientconfig

       

      <configuration>
          <system.serviceModel>
              <bindings>
                <basicHttpBinding>
                      <binding name="BasicHttpBinding_IAFService" maxBufferSize="2147483647"
                          maxReceivedMessageSize="2147483647">
                        <security mode="None" />
                      </binding>
                  </basicHttpBinding>
              </bindings>
              <client>

       

                <endpoint address="http://servername:8080/AFWCFService.svc"
                    binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IAFService"
                    contract="AFServiceProxy.IAFService" name="BasicHttpBinding_IAFService"/>

       

              </client>
          </system.serviceModel>
      </configuration>

       

      Second, the Web.config file of the WCF Service

       

       <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
        <appSettings>
          <add key="AFServerName" value="AF_SERVER" />
          <add key="AFDatabaseName" value="AF_DATABASE" />
        </appSettings>

       

        <system.web>
          <compilation debug="true" targetFramework="4.0" />
              <authorization>
                  <deny users="?" />
              </authorization>
          <authentication mode="Windows" />
          <identity impersonate="true" />
        </system.web>
        <system.serviceModel>
          <services>
            <service name="AFWCFServiceLibrary.AFService">
              <endpoint binding="basicHttpBinding" bindingConfiguration="basicHttpSecureBinding" contract="AFWCFServiceLibrary.IAFService">
              </endpoint>
            </service>
          </services>
          <behaviors>
            <serviceBehaviors>
              <behavior>
                <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
                <serviceMetadata httpGetEnabled="true" />
                <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceCredentials>
                  <windowsAuthentication includeWindowsGroups="true" allowAnonymousLogons="false" />
                  <issuedTokenAuthentication allowUntrustedRsaIssuers="true" />
                </serviceCredentials>
                <serviceAuthorization principalPermissionMode="UseWindowsGroups" impersonateCallerForAllOperations="false" />
              </behavior>
            </serviceBehaviors>
          </behaviors>
          <bindings>
            <basicHttpBinding>
              <binding name="basicHttpSecureBinding">
                <security mode="TransportCredentialOnly">
                  <transport clientCredentialType="Windows"/>
                </security>
              </binding>
            </basicHttpBinding>
          </bindings>
          <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
        </system.serviceModel>
       <system.webServer>
          <modules runAllManagedModulesForAllRequests="true" />
        </system.webServer>
       
      </configuration>

       

      Now, here is how impersonation/delegation takes place. 

       

       

       
      [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
      public class AFService: IAFService
      {
           ...
           
           public GetElementsWithAttributesResponse GetElementsWithAttributes(GetElementsWithAttributesRequest req)
           {
                using (WindowsImpersonationContext impersonationContext = ServiceSecurityContext.Current != null ? ((WindowsIdentity)ServiceSecurityContext.Current.WindowsIdentity).Impersonate() : null)
                {
                     ...
      
                     // AFHelper is a Helper class that contains all AF-SDK calls
                     AFHelper afHelper = new AFHelper(ConfigurationManager.AppSettings["AFServerName"],
                                                              ConfigurationManager.AppSettings["AFDatabaseName"])
                     // Add a log to display the current connected AF user
                     log.Info(string.Format(Constants.LogMessage.ConnectedToAFAs, afHelper.GetCurrentConnectedUserName(ConfigurationManager.AppSettings["AFServerName"])));
                     
                     ...
                     // Retreiving AF Values 
                     afValues = attributList.GetValue(req.QueryDate);
                     ...
                }
                
                ...
           }
           
           ....
      }
      

       

       

      At this point, I know that impersonation is working because I can see the current user in AF. I also ran some tests and established I was able to view information available based on security policies I set up in AF. So the client credentials are used here.  But the call to PI seems to use the wcf service credentials. So from here, I suppose delegation is not kicking in. But I can’t figure why.

       

      Last, but not least, here is how I setup my connection to AF. I used the Connect method (with no parameter) from the PISystem object which should pass the impersonated user’s credentials. As I mentioned earlier, this seems to work.

       
      public class AFHelper
      {
      
           public AFHelper(string afServerName, string afDatabaseName)
           {
                _piSystems = new PISystems();
                PISystem thisPISystem;
                if (_piSystems != null)
                {
                     thisPISystem = _piSystems[afServerName];
                     // Use the impersonated user (client credentials)
                     thisPISystem.Connect();
      
                     _db = thisPISystem.Databases[afDatabaseName];
                     _db.Refresh();
                     _afServerName = afServerName;
                }
           }
      }
      

       

       

      So anybody knows why can’t I get AF-SDK to pass user’s credentials to the PI server ?

        • Re: Can't get AF-SDK to foward user's credentials to PI server
          mhamel

          @Jean-François: I have analyzed your two .config files and would like to explain the facts that can be extracted out of them.

           

          1) Your client application configuration file (app.config) is written to use basic HTTP binding which make no use of any security. By default, the basicHttpBinding security mode is None. This default setting means that you do not have authentication and that neither transport nor message security is enabled. By enabling Windows authentication with TransportCredentialOnly, you will get authentication, but no message protection; this is similar to how an ASMX Web service works.

           

          2) Your Web Service configuration file (web.config) is defined to use basic binding with a security mode of TransportCredentialOnly.

           

          3) This section of the .config file indicates that all Anonymous Logon are blocked.
           <authorization>
                <deny users="?" />
           </authorization>

           

          4) This section of the .config file indicates that ASP.NET layer will impersonate the incoming client with the credentials used by the application pool.  
           <authentication mode="Windows" />
           <identity impersonate="true" />

           

          5) This section of the .config file indicates that your WCF Web Service will use Windows Authentication, block Anonymous Logon, allow communication from untrusted issuer of certificates, use Windows Principal to authorize the use of service and impersonate or not the caller for all operations.
          <behavior>         
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceCredentials>
                     <windowsAuthentication includeWindowsGroups="true" allowAnonymousLogons="false" />
                     <issuedTokenAuthentication allowUntrustedRsaIssuers="true" />
                </serviceCredentials>
                <serviceAuthorization principalPermissionMode="UseWindowsGroups" impersonateCallerForAllOperations="false" />
          </behavior>

           

          A few Explanations...

           

          By default, your client WCF application will utilize the Identity impersonation mode if not specified by the app.config file. This means the security token for the user will be sent to IIS. IIS compare the token with the list of authorized users using the white or black list specified in the .config file (<authorization> ... </authorization> part) and the Active Directory (the first available domain controller) to see if the user is member of the domain. Afterward, the process is passed to ASP.NET which will use the Windows authentication mode to validate the security but it will use the identity of the application pool. If the identity is set to Network Service, all calls to your WCF Service will be done under the security token of Network Service. Your WCF Service will call the PI AF (with AF SDK) or the PI Data Archive (with PI SDK) on behalf of Network Service. As your PI AF Server resides on the same machine than the Web Server (IIS), there are strong chances that the security allows the Local System (the machine itself) or Network Service principals to read or write. Although, when a call is made to a GetValue or GetValues method a call is sent to the PI Data Archive from the Production Server with a new security token issued for the identity of the application pool (or Network Service in my example).

           

          Possible Solution

           

          You will need to add an impersonationlevel attribute in the app.config file of your WCF client application that makes use of Delegation as you cross computer boundaries. You will need to change the attribute impersonate to false (<identity impersonate="false" /> ) and the attribute impersonateCallerForAllOperations to true (<serviceAuthorization principalPermissionMode="UseWindowsGroups" impersonateCallerForAllOperations="true" />). You will also need to configure the Production Server to permit delegation inside the domain. Also, if you use Silverlight based application, you will need to add a client access policy at the root of your IIS Server (clientaccesspolicy.xml) that contains the possible restrictions regarding calls from outside the Web Server computer. I have added this link if you’re interested.

           

          I suggest you to take a few readings to understand well the WCF security with this link.

           

          Let me know if that helped you.

            • Re: Can't get AF-SDK to foward user's credentials to PI server
              jfbeaulieu80

              Thanks Mathieu,

               

              I tried the solution you provided, but I still get the same behavior.

               

              1)     My client is a Silverlight application. I have no choice but to use basic HTTP binding. I’ve also seen that in Silverlight 4, TransportCredentialOnly security mode is exactly equivalent to the none security mode. In both modes, Windows credentials are managed by the browser and are not under application’s control. See this link : msdn.microsoft.com/.../dd744835%28v=vs.95%29.aspx

               

              2)     True

               

              3)     Also true. This is to prevent anonymous users to acces to protected shared resources using the credential of the Web Service.

               

              4)     I’m not sure about this one. These lines should indicate that the Service could impersonate the caller, i.e. the service could access resources on behalf of the client. This enables Windows Authentication and ASP.NET Impersonation.

               

              5)     True. Altought in my case, I could set impersonateCallerForAllOperations to true.

               

              I would be very surprised if the WCF application utilizes Identity impersonation mode by defaut. This would represent a security issue as some callers may have higher access level than the service. In most of my reading, it says to turn on impersonation to impersonate the user.

               

              Plus, the behavior obtained differ a bit from your explanations. The AF Server get called with the clients credentials. I logged the current connected user and it’s not Network Service, neither Local System, it’s my client’s credentials. The problem occurs when I try to get value from a point reference. The connection to the PI server is made with my service credentials. I use the GetValues method of the AF-SDK. When I get AF Value (int, double, string) everything works fine. But when I get PI Point reference value it’s not working. So AF-SDK seems to use the right credentials (Impersonation takes place), but does not forward these credentials to the PI-Server. At this point, I really suspect the AF-SDK, but OSIsoft  probably use a similar configuration for  PIWebService and PI Coresight… there should be a solution for this.

                • Re: Can't get AF-SDK to foward user's credentials to PI server
                  jfbeaulieu80

                  Hi,

                   

                  Here are some tests I've done.

                  • I tried to use PI-SDK to get a snapshot value in my WebService. I had the same issue. Credentials used to query the PIServer were my WebService’s credentials and not my user’s (client) credentials.

                   

                   

                  At that point, I was questionning the delegation so I did another test.

                  • I created a folder on the PI-Server (remote). I granted access to it to a specific user (JF, not a member of Administrators). Before calling the PI-SDK, I add a routine to create a file in that folder. Here are the results I got :
                    • I called the WebService using the user JF. The file was created.
                    • I called the WebService using another user (that didn’t have the write access). The file wasn’t create.
                    • I turned off delegation/Impersonation and called the WebService using the user JF to make the WebService use is credentials to create the file. The file wasn’t create.

                   

                   

                   

                   

                   

                   

                   

                   

                  So the delegation seems to work fine. The problem really seems to be with the delegation and PI-SDK combined.

                    • Re: Can't get AF-SDK to foward user's credentials to PI server

                      What is the connection protocol order of PI SDK on your IIS server?

                        • Re: Can't get AF-SDK to foward user's credentials to PI server
                          jfbeaulieu80

                          Hi,

                           

                          Here is the connection protocol order of PI SDK on my IIS Server:

                           

                          1- Windows Security

                           

                          2- PI Trust

                           

                          3- Default User

                           

                          This works fine because I can see the 3 connections attempts in the PI Log Messages. First it says that it can not map the identity of the caller (WebService credentials), second no trust exists for the machine, then pidemo has no access to the point. I would like the first attempt to use my client's credentials instead of my webservice's credentials.

                           

                          Thanls,

                            • Re: Can't get AF-SDK to foward user's credentials to PI server

                              What happens if you don't use AF SDK and just make a direct PI SDK call to the PI Server from your web service?  Is the impersonation to the PI Server still failing?

                               

                              Alternatively, what if you use the AF SDK v2.5?  i.e. no PI SDK but MDA.

                              • Re: Can't get AF-SDK to foward user's credentials to PI server
                                RyanBrown

                                I've had trouble in the past with web services and security.

                                 

                                Out of curiosity ( apologies as you may have already done this ) what happens if we just take out the client machine for the moment. Can you connect and run the application fine from the production server?

                                  • Re: Can't get AF-SDK to foward user's credentials to PI server
                                    jfbeaulieu80

                                    @Rhys

                                     

                                    The impersonation is still failing if I make a direct call to the PI Server using the PI SDK.

                                     

                                    Is there any settings I need to set for STA/MTA ? It would be quite complicated to try the AF SDK 2.5 for now... but I'll keep that in mind.

                                     

                                    @Ryan

                                     

                                    I can't connect either. It is still using the WebService's credentials. But I log a lots of things in my WebService and in that case, I can see that it uses impersonation instead of delegation. Which is good because in that case, there is no "double hop" situation.

                                     

                                    Thanks,

                                      • Re: Can't get AF-SDK to foward user's credentials to PI server
                                        mhamel

                                        @Jean-François: Impersonation must be done inside the WCF layer and not inside the ASP.NET one. If you are impersonating on the ASP.NET layer, the credentials from your application pool will be passed to the WCF layer.

                                         

                                        You can find from WCF Security Fundamentals that the default client impersonation level is set to Identification if it is not configured in your app.config file. You can control impersonation at the client side and prevent WCF services from using client identities to access local resources. Windows credentials have an AllowedImpersonationLevel property that is set to one of the TokenImpersonationLevel options in order to control the impersonation level.

                                         

                                        To explain why it works the way you are setup, your PI AF Server resides on the same machine than your Web Server and does not require a second hop to reach the "service" but your PI Server is. Calls made to AF Data Reference are done by the client connected to PI AF which is the application pool (w3wp.exe process). This process is running with a given user and the call to the PI Server is made with this particular security token. Every call to your PI Server from IIS is considered in the double hop "area". You will need to utilize a user capable of impersonating or delegating. This can be by using Network Service or a domain user account granted the permission to delegate and setup up the computer (Production Server) to allow delegation.

                                         

                                        Can you try use Network Service account for your application pool and configure your Production Server to allow delegation (don't use constrained delegation at this time you can set it at a later time)? Make sure you set the impersonate attribute of identity element is set to false (<identity impersonate="true" />)

                                         

                                        Another option to avoid configuring delegation for your current setup would be to create a PI Trust using Production Server as the network name and w3wp.exe as application name for a given PI Identity. Although, this option prevents you to authorize based on client credentials.

                                         

                                        I can suggest you a nice link that helped me quite a lot to understand. It can easily become chaotic to find our way through this.

                                         

                                        We have something we would like to start soon regarding a white paper on security practices around WCF. We would like to make it a community-driven project, so we can address your concerns, your problems when it comes the time to architecture, configure and test project around WCF.

                                          • Re: Can't get AF-SDK to foward user's credentials to PI server
                                            Gael

                                            Hi Mathieu,

                                             

                                            I am Jean-Francois project manager.

                                             

                                            The option that you proposed by using a PI trust is not corresponding to our needs. Furthermore, this option is not recommended (encouraged) at all by OSIsoft since the new 3.4.380 security mechanism.

                                             

                                            We need delegation (using client credentials) because we want to be able to control PI Points access with OSIsoft integrated security.

                                             

                                            Our architecture (AF Server (with web services), PI Server and Client on 3 different boxes), is a standard setup that has been validated by OSIsoft.

                                             

                                            I would like to know if somebody (and OSIsoft more precisely) has been able to perform PI-SDK calls using delegation and double-hop. Maybe, we are touching an issue and we would like to know. This kind of "mechanism" seems to be something usual and OSIsoft encourages this approach.

                                             

                                            Another question: is-it possible that OSIsoft makes some tests on their side (using the same architecture)? We already have a call opened with the techsupport but we think that both vcampus and techsupport could find a solution.

                                             

                                            I think it will be great to involve the PI-SDK Project Manager or Team development on these posts. They can maybe give us a solution.

                                             

                                            @Rhys

                                             

                                            Thanks for your proposal but AF SDK 2.5 is not officially released so we will not use this approach (and we are not expecting to modify our code at this time). We are not intending to use a prerelease as we all know that other bugs or issues could appear and the support will be not the same.

                                             

                                            Thanks in advance for your inputs