TACTIC Sudo: giving users temporary Admin privileges

Published by tactic on

The TACTIC API is very flexible, allowing you to access almost any of its internal data stored and to execute any command on the system.  However, as of TACTIC 4.7+, there are a number of low level stypes in TACTIC cannot normally be queried by users that are not the “admin” user.  This security restriction is used to protect sensitive data in the database.

An example of this sensitive data is the “login” table which contains all the information about a user.  It is obviously undesirable for an end user to be able to query this table directly.  An end user could in theory, in the Javascript console, use TACTIC’s api to query the “login” table.

var server = TACTIC.get();
var logins = server.query("sthpw/login")

If you do try to execute this with a user that is not “admin”, you will be encounter a permission denied error.  This restriction will even occur in custom python code (such as custom layout python code, triggers or workflow action nodes) on the server.

search = Search("sthpw/login")
sobjects = search.get_sobjects()

However, there are times when this data needs to be access by some part of the system.  In the case of a user, a particular process may need to retrieve a user’s email address.   There is a mechanism that allows a user to be obtain “admin” access for a code block.  This can only be executed in Python code on the server.  Client side code on the Browser or Python API or REST cannot access this level.

from pyasm.security import Sudo
sudo = Sudo()
try:
    search = Search("sthpw/login")
    sobjects = search.get_sobjects()
finally:
    sudo.exit()

The “sudo” call will grant a user temporary “admin” privileges which means that any data in the system can be accessed.  Care must be take as to what code resides within the “try/finally” block.

Because the sudo class maintains a global state and functions called will also occur in sudo mode:

sudo = Sudo()
try:
    function1()
    function2()
    function3()
finally:
    sudo.exit()

All 3 functions will be run under Sudo mode.  Sudo calls can be nested as TACTIC maintains a counter so if function1 also contained a sudo.exit() call, this would not necessarily exit the sudo mode if a calling function all set the sudo mode.

Finally, the sudo state will automatically exit when the “sudo” variable goes out of scope, so sudo.exit() is not always needed, but it does allow you to control exactly when the state is exited.

def my_function(self):
    sudo = Sudo()
    function1()
    function2()
    function3()

On exit of “my_function”, the sudo object will go out of scope and will exit, preventing accidental propagation of unwanted sudo modes.

Because sudo provides complete access to all parts of the system, care must be taken in its use. Best practice suggest putting as little code as possible within a sudo block, limiting as much as possible the amount of code that runs with admin privileges.