Session prop change script has no system.security.logout()?

I'm trying to create my own auto-logout functionality, as our customer wants specific clients to be able to remain logged in under certain usernames.

So I added a custom session prop to act as a trigger to log the user off, however I found that system.security.logout() isn't available in the session prop's on change script scope..? Not sure why this wouldn't have access to this, since it has full awareness of the session?

Error running property change script on session.custom.security.autoLogout.logoutUserTrigger: Traceback (most recent call last): File "function:valueChanged", line 2, in valueChanged AttributeError: 'com.inductiveautomation.ignition.common.script.Imm' object has no attribute 'logout'

I don't really want to have to configure some obscure method using message handlers :frowning:

Edit: Even a Session Event message handler doesn't have the logout function available to it. I'm confused... Aside from adding a message handler to my navigation View which is absurd, I'm not sure how else I can do this?

According to the docs system.security.logout() is Vision specific. You might want to use system.perspective.logout() if you're using Perspective.

2 Likes

In 8.3, the plan is to move a lot of these misleading 'legacy' functions to system.vision for clarity.

4 Likes

Derp, of course! Rookie mistake, thanks guys :slightly_smiling_face:

New problem. Using system.perspective.logout() (or system.perspective.print for that matter) on my session prop change script results in this:

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 2, in valueChanged at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:64) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.logout(PerspectiveScriptingFunctions.java:475) at jdk.internal.reflect.GeneratedMethodAccessor692.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: No perspective page attached to this thread.

at org.python.core.Py.JavaError(Py.java:547)

at org.python.core.Py.JavaError(Py.java:538)

at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)

at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:552)

at org.python.core.PyObject.__call__(PyObject.java:446)

at org.python.core.PyObject.__call__(PyObject.java:450)

at org.python.pycode._pyx2668.valueChanged$1(:2)

at org.python.pycode._pyx2668.call_function()

at org.python.core.PyTableCode.call(PyTableCode.java:173)

at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

at org.python.core.PyFunction.function___call__(PyFunction.java:474)

at org.python.core.PyFunction.__call__(PyFunction.java:469)

at org.python.core.PyFunction.__call__(PyFunction.java:464)

at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:846)

at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:828)

at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runFunction(ProjectScriptLifecycle.java:828)

at com.inductiveautomation.ignition.common.script.ScriptManager$ScriptFunctionImpl.invoke(ScriptManager.java:1009)

at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$AutoRecompilingScriptFunction.invoke(ProjectScriptLifecycle.java:893)

at com.inductiveautomation.perspective.gateway.script.ScriptFunctionHelper.invoke(ScriptFunctionHelper.java:147)

at com.inductiveautomation.perspective.gateway.model.PropertyChangeScript.access$001(PropertyChangeScript.java:30)

at com.inductiveautomation.perspective.gateway.model.PropertyChangeScript$ScriptSequencer.run(PropertyChangeScript.java:156)

at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)

at java.base/java.util.concurrent.FutureTask.run(Unknown Source)

at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at com.inductiveautomation.perspective.gateway.threading.BlockingWork$BlockingWorkRunnable.run(BlockingWork.java:58)

at java.base/java.lang.Thread.run(Unknown Source)

Caused by: org.python.core.PyException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: No perspective page attached to this thread.

... 27 common frames omitted

Caused by: java.lang.IllegalArgumentException: No perspective page attached to this thread.

at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:64)

at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120)

at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47)

at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.logout(PerspectiveScriptingFunctions.java:475)

at jdk.internal.reflect.GeneratedMethodAccessor692.invoke(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.base/java.lang.reflect.Method.invoke(Unknown Source)

at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)

Using this in the change script, I can see a valid session ID is printed, but the logout fails. I'm not sure where to go to from here as I can't get a page id from a session prop :confused: I wouldn't have thought that a page id is even needed, since it's the session that is logged out of, right?

id = self.props.id
print 'Session ID:', id
system.perspective.logout(sessionId = id)

Seems like a pageId is required for the logout function...

You can get pageIds from system.perspective.getSessionInfo(). You might be able to get what you want if you iterate over those and log the user out for each page. Perhaps something similar to this?

sessionId = self.props.id
pageIds = []
	
#Get page IDs
for session in system.perspective.getSessionInfo():
	if session['id'] == sessionId:
		pageIds = session['pageIds']
		break
#Logout each page
for pageId in pageIds:
	system.perspective.logout(sessionId, pageId)
1 Like

Perhaps it's my misunderstanding, but I would have thought that logging in would be scoped to a session, not a page of a session? More a question for IA guys, but thanks for the code

The session doesn't have it's own thread pool - all scripting needs to be supplied a page on which to act. We provide this in many instances behind the scenes by providing access to the page thread for Children of the page (components, View), but we can't do that for session events, Gateway Events, or Tag Change scripts because they obviously have no idea about which page is requesting the script to be executed.

If you invoke system.perspective.logout() from a component, you'll encounter no issue because we've handed the component a thread from the Page's allocated pool to execute the script with, and all of the relevant information is available on that thread.

And so I think the issue isn't that system.perspective.logout() needs the pageId arg because it cares about the page per se, rather, the script eventually gets run on that Page's thread pool, where it has access to the needed information.

You should be able to amend that script slightly and get the same result:

for session in system.perspective.getSessionInfo():
	if session['id'] == sessionId:
        system.perspective.logout(pageId=session['pageIds'][0])
4 Likes