I have a client that is on the same computer as the gateway. I need to know if that client is logged in with a certain role in order to for them to be able to start a process. The process is started with physical push button through a PLC tag. The people at the facility this is at like to log in on their computers at their desks and don’t always log off so I need to filter them. I also need to filter designer on the computer in question.
So, I need to grab the IP address of a client that is also the gateway, check if its not in designer and check the role of the user logged on. That will then flip an OPC bit to tell the PLC that the user has the permissions to hit the start button. Has anyone done something like this?
It looks like GetSessionInfo is what I need but I am not the best python programmer around and don’t really know how to navigate the table to filter the information I need. I am looking further into this now.
Ahh. Yes you are right. I am using vision so that wouldn’t work. Here is where I am currently.
I created a client tag with the following expression:
If ({[System]Client/Network/IPAddress} == “192.168.0.250” && {[System]Client/User/RolesString} == “Administrator”,1,0)
I then created a value change script to write it to an OPC tag
if (currentValue == 1):
system.tag.write(“OPCtag”, 1)
else:
system.tag.write(“OPCtag”, 0)
I put a multistate indicator on the screen just to see the value on my HMI and I am getting a bad evaluation overlay. I don’t see anything wrong with the expression but I could be wrong.
I did it all piece by piece also and no matter what I put into the client tag expression it throws a fit.
The roles string could potentially contain Administrator and other roles, so you really need to search for the role within the string, e.g. if(indexof({[System]Client/User/RolesString}, "Administrator")>0, 1, 0)
Note: this may not always work, depending on the role you're looking for (other roles may contain the string you're looking for, in this case however it's probably unlikely)
Remember that you have multiple instances of these client tags on your other clients, all running the same change event script. These will all be writing to this OPC tag as well, potentially overwriting any "1" written by your special client.
It doesn't sound like a very robust or secure way to do this. Consider maybe using a button on SCADA with privileges set to enable it on logon/IP address, which enables the OPC tag for a time period.
I didn’t think about the overwriting. That tears this whole thing down. I would run into the same problem though with the button. It would rely on a client tag writing to the OPC tag with the IP address/login
I would split this requirement into two separate indicators, one for determining whether a client is running on the gateway or not, the other checking the required role.
I would implement the first requirement with a client startup script that interrogates the local network interfaces and checks for the mac IDs of the gateway (those could be hard-coded into the script). And then writes the result to a boolean tag like [Client]RunningInGateway. Such script only runs in a client, so designers would be excluded by default. (Note, a designer could just toggle that boolean to get around this, but you can't really stop anyone with designer privileges from going around your security.) This script might help you:
I would implement the latter requirement as a boolean custom property, IsPrivileged perhaps, on the window containing the restricted pushbuttons, bound to the hasRole() expression function.
The pushbuttons in question would have the expression {[Client]RunningInGateway} && {Root Container.IsPrivileged} bound to their enable property.
@pturmel Agree with you, but for the second part, I believe the OP is talking about physical push-buttons, not scada push buttons. Hence why I think there needs to be some sort of enable button on scada set by a user with privilege and from the correct client teeminal
Sorry, missed that. I would adjust the approach to include a client timer event script that repeatedly evaluates the current role and sends a heartbeat message to the gateway to maintain the physical enable. Then have a gateway timer event that regularly checks the timestamp of the last heartbeat and kills the physical enable if it expires.
I ended up getting it to work using my original solution:
sessions = system.util.getSessionInfo()
for sess in sessions:
if not sess["isDesigner"]:
user = system.user.getUser("default",sess["username"])
address = sess["address"]
for role in system.user.getRoles("default"):
if address == "comp name":
if role == "Administrator":
system.tag.write("JparsonsTest/Start", 1)
break
else:
system.tag.write("JparsonsTest/Start", 0)
Thank you all for your inputs. This has taught me a lot more about python and ignition for the future!
Edit: Just kidding. I just tested it fully and it didn’t work. Back to square one.
sessions = system.util.getSessionInfo()
for sess in sessions:
if not sess["isDesigner"]:
try:
user = system.user.getUser("default",sess["username"])
except:
user = system.user.getUser("AD database",sess["username"])
address = sess["address"]
if address == "jparsons-vm":
user.getRoles()
for role in user.getRoles():
if role == "Administrator":
system.tag.write("JparsonsTest/Strt", 1)
else:
system.tag.write("JparsonsTest/Strt", 0)
if address == "jparsons-vm":
if "Administrator" in user.getRoles():
system.tag.write("JparsonsTest/Strt", 1)
else:
system.tag.write("JparsonsTest/Strt", 0)
If you had multiple cases that could make the condition true, you can use:
if any(role in user.getRoles() for role in ("Administrator", "Supervisor")):
or you can use all(...) in place of any to match all of the roles.