Some notes on user management

I tested the new user management and found some little issues:

  • When tyring to delete a profile that is in use somewhere, the error message is not real helpful:

  • When soft failover is used in an AD/Internal Auth Profile, and a user logs in the client with a failover account, the UserManagement component shows the users from the failover profile but the roles from the main profile.
    It also allows editing of users from the failover profiles. Trying to add those users to one of the listed roles results in an exception of course.

Here the failover profile is the internal default profile.

ERROR [UserManagementPanel-AWT-EventQueue-0] Error saving user.
java.util.concurrent.ExecutionException: com.inductiveautomation.ignition.client.gateway_interface.GatewayException: java.lang.Long cannot be cast to java.lang.String
	at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
	at java.util.concurrent.FutureTask.get(Unknown Source)
	at com.jidesoft.utils.SwingWorker.get(Unknown Source)
	at com.inductiveautomation.factorypmi.application.components.UserManagementPanel$UserEdit$SaveTask.done(UserManagementPanel.java:1011)
	at com.jidesoft.utils.SwingWorker$5.run(Unknown Source)
	at com.jidesoft.utils.SwingWorker$DoSubmitAccumulativeRunnable.run(Unknown Source)
	at com.jidesoft.utils.AccumulativeRunnable.run(Unknown Source)
	at com.jidesoft.utils.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(Unknown Source)
	at javax.swing.Timer.fireActionPerformed(Unknown Source)
	at javax.swing.Timer$DoPostEvent.run(Unknown Source)
	at java.awt.event.InvocationEvent.dispatch(Unknown Source)
	at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.awt.EventQueue.access$000(Unknown Source)
	at java.awt.EventQueue$1.run(Unknown Source)
	at java.awt.EventQueue$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: com.inductiveautomation.ignition.client.gateway_interface.GatewayException: java.lang.Long cannot be cast to java.lang.String
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.newGatewayException(GatewayInterface.java:313)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:287)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:244)
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.invoke(GatewayInterface.java:797)
	at com.inductiveautomation.factorypmi.application.components.UserManagementPanel$UserEdit$SaveTask.doInBackground(UserManagementPanel.java:998)
	at com.inductiveautomation.factorypmi.application.components.managementpanel.AbstractManagerPanel$GatewayInvokeWorker.doInBackground(AbstractManagerPanel.java:129)
	at com.inductiveautomation.factorypmi.application.components.managementpanel.AbstractManagerPanel$GatewayInvokeWorker.doInBackground(AbstractManagerPanel.java:125)
	at com.jidesoft.utils.SwingWorker$1.call(Unknown Source)
	at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
	at java.util.concurrent.FutureTask.run(Unknown Source)
	at com.jidesoft.utils.SwingWorker.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
	at com.inductiveautomation.ignition.gateway.authentication.impl.ADInternalHybridUserSource.findUserInternalId(ADInternalHybridUserSource.java:95)
	at com.inductiveautomation.ignition.gateway.authentication.impl.ADInternalHybridUserSource.alterUser(ADInternalHybridUserSource.java:109)
	at com.inductiveautomation.ignition.gateway.authentication.UserSourceWrapper.alterUser(UserSourceWrapper.java:183)
	at com.inductiveautomation.ignition.gateway.servlets.gateway.functions.Users.alterUser(Users.java:280)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(null)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(null)
	at java.lang.reflect.Method.invoke(null)
	at com.inductiveautomation.ignition.gateway.servlets.gateway.AbstractGatewayFunction.invoke(AbstractGatewayFunction.java:176)
	at com.inductiveautomation.ignition.gateway.servlets.Gateway.doPost(Gateway.java:377)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at com.inductiveautomation.ignition.gateway.bootstrap.MapServlet.service(MapServlet.java:85)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(null)
  • There is also a potential concurrency problem. If two users add a role with the same name at the same time, the role is added twice to the database (Ok, this will not happen so often).

Interesting. I suggest setting the user managament panel’s user source property explicitly if you’re using failover profiles.

This works, unless the main profile becomes unavailabe. In this case, the user management shows the users from the fallback profile, even if the user source is explicitely set.

Side not: The property is called 'User Profile' in the component, maybe it should be renamed to 'User Source' for consistency.