It has come up a few times on PI Square and whilst working with clients that it would be great to be able to secure a ProcessBook display to a limited set of users, rather than it be public and freely available to everyone.

 

Your first port of call should be to deny the user access to the data by securing the PI Points in the PI Data Archive and the AF Elements in the PI AF Server. A good security model should provide that level of protection. However, what if you had something drawn on the display itself that you didn't want to share, or you had users with access to the data but you want to keep the audience to a display limited? You do not have that ability in PI Coresight's current state for which OSIsoft have an enhancement request to address this: https://techsupport.osisoft.com/Troubleshooting/Enhancements/82110

 

What if you don't want to wait for that, is there an option? Well yes, hence this blog post.

I have had some R&D into URL authorisation in IIS and some other potential tricks to achieve this but none of them really worked, unlike what I'll show you below. We need OSIsoft to implement this security feature at the Controller level of PI Coresight, likely with AuthoriseAttribute.

 

We will be adding a few lines of javascript to a PI Coresight file so usual warnings about backing up the file and do so at your own risk. This is an example of how you can enhance PI Coresight to secure your ProcessBook displays.

 

The display security mapping file.

For this example let's keep it extremely simple and make a basic json file that will list the display Ids (or names) that we want to be "restricted" to certain users. The assumption for this example is that we are using Windows Authentication only and we're not bothered about the domain of the user...that could come later if you wanted to enhance it yourself.

 

So I am going to want a display Id and a list of allowed users...

{"Displays": [
  {
    "Id": "123",
    "AllowedUsers": [ { "Name": "User0" }, { "Name": "User1" }, { "Name": "User2" } ]
  },
  {
    "Id": "234",
    "AllowedUsers": [ { "Name": "User3" } ]
  },
  {
    "Id": "345",
    "AllowedUsers": [ { "Name": "User4" } ]
  }
]} 

 

Simple enough. Let's call the file "restrictedDisplays.json" and place it into the root of the PI Coresight folder structure on the web server.

The idea here is going to be that as a new ProcessBook display is opened then we'll check with the file if the display is classed as restricted (by its existence in the file), and if so which users have access to it. If your names not on the list then you ain't getting in...said the club bouncer to me on many an occasion during my youth.

For now I am treating a restricted display as a deviation from the norm, so all other displays are still treated as public. It will keep the size of the file down, but may depend on the size of your PI Coresight instance. Either way this is now our display ACL.

 

The need for a timer.

I had a very quick attempt to get something working without a timer but alas a timer seems to be the best approach given my time limited research into this topic.

Basically we are going to add some javascript to the main PI Coresight page that loads the view for a ProcessBook display. This is loaded once and re-used so I didn't see a clear path to reliably call some javascript each time a new display was navigated to...this is a similar approach to what I have used in Project Coresight Candy. To ensure the timer runs quick enough to redirect an unauthorised user then I'm going to use something like 500ms. Of course this approach isn't fool proof but will help secure the displays for the majority of users, there will always be people (like me) that will look for ways round such features.

 

~/Views/Home/_PBDisplay.cshtml

Back up the file.

We will just add a script block to this file that is going to create a timer, inside the timer we'll look for a change in display (only a ProcessBook display), get the display Id, check our display ACL file, then authorize or deny the user. By denying the user we will just redirect back to the PI Coresight home page for now.

 

In _PBDisplay.cshtml find where the body is being defined:

@section Body {

 

And add the following javascript (after reading through the code explanation that follows):

<script type="text/javascript">
    var lastURL = '';
    
    setInterval(function(){
    
    if (window.location.href.toString().toLowerCase() != lastURL)
    {
        lastURL = window.location.href.toString().toLowerCase();
        if (lastURL.indexOf('/pbdisplays/') > 1)
        {
            var userName = "@HttpContext.Current.User.Identity.Name.Split(new char[] {'\\'})[1]";
            var displayNameOrNumber = lastURL.split('/pbdisplays/')[1];
            if (displayNameOrNumber.indexOf('?') > 0) displayNameOrNumber = displayNameOrNumber.split('?')[0]
            var userAllowed = true;


            $.getJSON('http://webserver/Coresight/RestrictedDisplays.json', function (data) {
                $.each(data, function (displaysContainer, displays) {
                    $.each(displays, function (display, displayDetails) {
                        if (displayDetails.Id == displayNameOrNumber) {
                            userAllowed = false;
                            $.each(displayDetails.AllowedUsers, function (a, b) {
                                if (userName.toLowerCase() == b.Name.toLowerCase()) {
                                    userAllowed = true;
                                    return false;
                                }
                            });
                            return false;
                        }
                    });
                });
                if (!userAllowed) window.location.href = 'http://webserver/Coresight/';
            });
        }
    }
    }, 500);
    </script>

 

In a nutshell we are doing the following:

  • Creating a timer with a 500ms interval.
  • Keeping track of the URL to detect a change in display.
  • Making sure the display now being shown is a ProcessBook display.
  • Getting the display id or name from the URL.
  • Fetching the display ACL json.
  • Parsing the ACL to see if the display being viewed is classed as restricted.
  • If restricted then check if the user (we get the username via Razor...neat eh!) is explicitly permitted to view the display.
  • If permitted then do nothing.
  • If denied then redirect to the PI Coresight homepage.

 

There is a 500ms potential for someone to scrape the html of the display...but someone would have to be really determined to get at the display to do that so I can live with the 500ms timer.

 

After some very brief testing this seems to work like a charm! I can easily modify the json to permit users to restricted displays or restrict existing displays as I wish.

 

You could modify this to redirect to a specific page where a user can request access to the display, or something similar. You could perform a check on AD group membership, or look to filter the list of all display thumbnails on the overview page of ProcessBook displays. However, I think this demonstrates the concept for the purpose of this blog post.

 

And of course this is a stop gap until the functionality comes as part of PI Coresight out of the box.

 

Enjoy!