8 Replies Latest reply on Sep 21, 2017 7:45 PM by jturow

    Problem with PI Web API authentication using HTML files (i.e. no web server)

    gavin.strack

      Hi,

       

      I have encountered a problem with trying to get authentication working.

       

      To start with, I am developing my web app on the same machine that hosts the AF server and PI Web API.  To attempt to diagnose the problem, I am using the CORS Testing app from the training video.

      When I attempt to use basic authentication, I get:

      Which is similar to the error expected when a request from a domain not listed in the CorsOrigins attribute.  When I look into the request header, the Origin header is like this:

      Since the request is from the same machine, I don't see how CORS is even relevant, but if the browser is getting this response, who am I to argue.

       

      So I tried adding "null", "http://localhost", "https://localhost" to the CorsOrigins attribute but I still get this error.

       

      In the browser, my "URL" is  "file:///C:/User/....etc....etc.../cors_app.html".  I noticed that all the PI Web API tutorials appear to be using a locally hosted webserver (i.e. URL = http://localhost:12343).  Before I go an install WAMP or figure out how to use IIS, is there something simple I can do to get this working.  My web apps work fine when I don't use authentication.

        • Re: Problem with PI Web API authentication using HTML files (i.e. no web server)
          gavin.strack

          OK - so after investigating several sources, it appears that one cannot use CORS authentication running from a file. (e.g. Browser URL = ///file:c.....). So I have to run my app from a web server to allow for the Origin header to be anything but null.

           

          So I have a Python simple HTTP server running on my client machine at http://localhost:8899.  This is working with my browser displaying the contents of my app directory with a URL of http://localhost:8899.

           

          I can also use Fiddler to authenticate from my client machine and get the JSON response from the getdatabases controller, so I know my client, PI Web API and connectivity between them are all good.

           

          I have set up the PI Web API configuration to allow http://localhost:8899 on my CorsOrigin attribute

           

          When I run the CORS Testing app from the video tutorial in Chrome, via the simple HTTP server, the Origin header is now populated with http://localhost:8899

          However, I still get a CORS error.

          This is my code:

          <!DOCTYPE html>

          <html>

          <head>

            <title>PI Web API CORS Testing</title>

            <meta charset="utf-8"" />

            <script type="text/javascript" src="piwebapp/js/jquery-2.1.4.min.js"></script>

          </head>

          <body>

            <p>Click to get the list of AF Databases for the AF server AUSGRAAF1.</p>

            <button id="getDB">Get Databases</button>

            <ul></ul>

           

            <script>

            $(document).ready(function() {

            $('#getDB').click(function () {

            $.ajax({

            url: "https://ausgraaf1.gfau.gfiroot.local/piwebapi/assetservers/S0Ex4T6OMfdUmRTss388yhhAQVVTR1JBQUYx/assetdatabases",

            beforeSend: function (xhr) {

            xhr.setRequestHeader('Authorization', 'Basic <deleted encoded string>');

            },

            success: function (data) {

            for (i = 0; i < data.Items.length; i++){

            $('ul').append('<li>' + data.Items[i].Name + '</li>');

            }

            },

            error: function(xhr) {

            console.log(xhr.responseText);

            }

            });

            });

            });

            </script>

          </body>

           

          The "undefined" error on line 29 corresponds to the the code [ console.log(xhr.responseText); ] in the error: function.

           

          Can anyone explain to me why in the seven hells this code doesn't work?

          So far I've had nothing but an exercise in frustration.

            • Re: Problem with PI Web API authentication using HTML files (i.e. no web server)
              OmicronPi

              Hi Gavin-

               

              I'm not an ajax expert, but it appears to me you may be missing some properties.

               

              This is what my function says:

                    function setAFValue(type, pathName, jsonObj) {
                          $.ajax({
                              type: type,
                              xhrFields: {
                                  withCredentials: true
                              },
                              dataType: "json",
                              jasonp: false,
                              contentType: "application/json",
                              data: jsonObj,
                              async: false,
                              crossDomain: true,

                              url: pathName.webPath,
                              beforeSend: function (xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa("USERNAME:PASSWORD")); },
                              success: function (jsonData) {
                                  console.log("Data: " + data + "\nStatus: " + status);
                                  alert("Data: " + data + "\nStatus: " + status);
                              },
                              error: function (request, textStatus, errorThrown) {
                                  console.log(request.responseText);
                                  console.log(textStatus);
                                  console.log(errorThrown);
                              }
                          });
                      }

               

              This is how I call it:

               

                              if (pathName.webPath.indexOf("streams") != -1) {
                                  var jsonObj = '{ "Timestamp": "2016-02-23T16:41:00.9734802Z", "Value": ' + v + '}';
                                  setAFValue('POST', pathName, jsonObj);
                              } else {
                                  var jsonObj = '{ "Timestamp": "*", "Value": ' + v + ', "UnitsAbbreviation": "", "Good": true, "Questionable": false, "Substituted": false }';
                                  setAFValue('PUT', pathName, jsonObj);
                              }

               

              Eric

               

              • Re: Problem with PI Web API authentication using HTML files (i.e. no web server)
                OmicronPi

                Gavin-

                 

                I didn't look at the screen captures before.

                 

                Have you tried putting just the http://localhost:8899 in the CorsOrigins?  (I'm thinking that all listed domains must start with http://)

                 

                Eric

                • Re: Problem with PI Web API authentication using HTML files (i.e. no web server)
                  gavin.strack

                  Thanks for the info Eric.  I tried the additional arguments you provided but unfortunately I still encountered the same error.

                   

                  After a bit more research I was finally able to get the StreetView application working, although it does have some limitations.  In summary, I had to do the following:

                   

                  - run a simple HTTP server to run the app.  I chose the Python SimpleHTTPServer for this.

                  - open Chrome using the --args --disable-web-security parameter

                  - run the application on the AF Server host.

                   

                  When I tried to run the app on the remote client machine, I found that not all the Javascript functionality worked.  Specifically, the start/stop buttons were not being enabled/disables and event frame were not being created.  Copying the code to the AF server and running it from there allowed the app to work perfectly.

                   

                  Here is a screenshot of the event frame and data being updated in PI from my app.

                   

                   

                  Overall, I have spent several days trying to overcome web security/accessiblity issues, which are largely uncovered and/or inadequately documented in any of the PI Web API tutorials or documentation. The vast majority of the helpful information has been on StackOverflow, GitHub and other sources. This has been time I could have been spent writing my new app for the course.

                   

                  As the net result of this experience is a somewhat tarnished opinion of PI Web API (despite my excitement of its functionality and possible use cases), I would recommend that OSIsoft develop a much more detailed and explanatory guide in setting up this product on a more realistic environment. If it looks nice and easy in the video tutorial, and its a week-long nightmare of frustration and angst for the customer on their system, there is a problem. Whilst I have been able to get the app functional, there is no way I would consider this for a production system.  There are too many workarounds and props for my liking, which is disappointing.

                   

                  And to preempt the response of "it's your security policies that are causing the problems, not the product", I would counter with the fact that we have a robust architecture and industry standard security policy.  If the product doesnt work with the industry standard, we don't change the industry to fit the product, we change the product to fit the industry.

                  • Re: Problem with PI Web API authentication using HTML files (i.e. no web server)
                    jturow

                    I know this is an old post, but I ran into the same problem today while attempting to access the PI Web API.  I kept getting blocked by CORS even though "CorsOrigins" was set properly in the PI Web API Configuration. I was being blocked because I passed a custom header in the http request.  By default, CORS doesn't allow any headers to be sent (even the "Authorization" header that is necessary for basic auth!)

                     

                    Adding my custom headers to the "CorsHeaders" attribute fixed the issue.  You could also set "CorsHeaders" to * to allow all incoming headers.