Demo/Lab: Basic account operations
Prerequisites
Use the target configured in Demo/Lab: Targeting with SQLite example .
Steps
Open
agtsqlitedemo.py
and navigate to the verify Python definition.def verify(cinfo): account = Account(cinfo['acctid']) if account.get(): return ACVerifyFailed if account.passwd != cinfo['oldpw'] or account.enabled != "1": return ACVerifyFailed return ACSuccess
Verify is a simple use case where an account is authenticated against the old password "oldpw". The process of authentication is generally done for us by a target’s API which should check if the accounts password expiry, enabledness, lock status and potentially various other criteria. In our simple use case, we return ACSuccess if the verify operation was successful and ACVerifyFailed otherwise.
Navigate to the reset Python definition.
def reset(cinfo): account = Account(cinfo['acctid']) account.passwd = cinfo['newpw'] account.expiredpw = 0 account.locked = 0 return account.set()
Reset is also a simple use case where an account password is reset with the new password "newpw". As mentioned above, the reset process is generally done for us by the target’s API which should ensure that the password expire, enabledness, lock status and potentially any other criteria is also reset. Although not clear with the above code, if you navigate to the account class "set" definition, you will notice that this example returns ACSuccess if the reset operation was successful, ACInvalidUser if the user does not exist, and ACUnknownError for other failures. If ACUnknownError is used, it is good practice to return an informative error to the caller using agent.error().
Navigate to the disable Python definition.
def disable(cinfo): account = Account(cinfo['acctid']) account.enabled = 0 return account.set()
The enable, disable, unlock, expireacct, and expirepw set the account and password disposition attributes and as such, simply set the account or password to a particular status. They return ACSuccess on success, ACInvalidUser if the user does not exist and ACUnknownError otherwise.
Navigate to the ispwexpired Python definition.
def ispwexpired(cinfo): account = Account(cinfo['acctid']) rc = account.get() if rc: return rc agent.isPwExpired(int(account.expiredpw)) return ACSuccess
The isenabled, islocked, isacctexpired, and ispwexpired get the account and password disposition attributes. Each operation has its own callback to inform the caller of the particular account or password disposition status. These are respectively, agent.isEnabled, agent.isLocked, agent.isAcctExpired and agent.isPwExpired.
Navigate to the create Python definition.
def create(cinfo): account = Account(cinfo['acctid']) rc = account.get() if not rc: agent.stableId(account.id) agent.longId(account.id) agent.shortId(account.shortid) return ACObjectAlreadyExists account.shortid = cinfo['attributes']['shortid']['VALUE'][0] account.fullname = cinfo['attributes']['fullname']['VALUE'][0] account.passwd = cinfo['newpw'] account.email = cinfo['attributes']['email']['VALUE'][0] account.department = cinfo['attributes']['department']['VALUE'][0] rc = account.create() if rc: return rc rc = account.get() if rc: return rc attrs = {} account.listAttributes(attrs) for key, value in attrs.items(): agent.addAccountAttr(key, value) agent.stableId(account.id) agent.longId(account.id) agent.shortId(account.shortid) return ACSuccess
Both the create and update operations are more intricate to develop. Testing the create and update operations requires the configuration of target attributes that are passed into the connector. In the example above, the create operation gets the shortid, fullname, email and department values passed from the caller. This information is contained in the attribute dictionary. These in turn are used to create or update the account attributes on the target.
In more refined connector integrations, the target attributes configured in the product can also define ACTION and SEQUENCE. The ACTION modifier provides the ability to IGNORE, VALUE, COPY or REPLACE a value on create or update. The SEQUENCE modifier provides the ability to order or prioritize the setting and/or updating of attributes during create and update. Generally, simplicity in connector development/integration is a better policy – particularly with respect to custom connectors. Using these attribute modifiers exposes attribute configuration from the UI, at the cost of added connector complexity.
It is important to note on successful creation or update of objects, the primary keys and the modified attribute values must be returned to Bravura Security Fabric to maintain attribute synchronization with the target. The agent.stableId, agent.longId, agent.shortId and agent.addAccountAttr facilitate this.
The create operation returns ACSuccess on success, ACObjectAlreadyExists if the object already exists and ACUnknownError otherwise. And the update operation returns ACSuccess on success, ACInvalidUser if the user does not exist and ACUnknownError otherwise.
Navigate to the delete Python definition.
def delete(cinfo): account = Account(cinfo['acctid']) return account.delete()
The delete, rename and movecontext operations are the last remaining integrations to flush out the account operations for a connector. The delete is fairly self explanatory – it deletes the account object. The rename operation can either rename the shortid or the longid but generally it renames the shortid and if the shortid is a component of the longid, the longid is also renamed. The movecontext operation moves an object from one context to another. The context in most use cases is a relative distinguished name. Because most connectors do not have a context that objects can be contained within, the movecontext in most connectors is unimplemented and not supported.
Because both the rename and movecontext operation potentially act on the shortid and longid, both the agent.longId and agent.shortId callbacks must be called to maintain synchronization with the target.
All these operations return ACSuccess on success, ACInvalidUser if the user does not exist and ACUnknownError otherwise.
Add an operation retry Python definition.
def operationretry(cinfo): # DOC - This is an example of how retrydata can be used to retry an # an operation using idtm. In this sample, the retrydata initial state # is set to 3 and each subsequent run, retrydata is decremented until zero # where success is returned. rc = ACTryAgainLater opinput = cinfo['opinput'] retrydata = '' if 'retrydata' in opinput: retrydata = opinput['retrydata']['VALUE'][0] if not retrydata: agent.retryData("3") agent.retryTime(300) agent.error('WAITING ON AGENT) log.debug('operationretry initial state') elif retrydata == '0': rc = ACSuccess log.debug('operationretry completed') else: retrydataint = int(retrydata) retrydataint -= 1 agent.retryData(str(retrydataint)) agent.retryTime(300) agent.error('WAITING ON AGENT) log.debug('operationretry set to {}'.format(retrydataint)) return rc
Navigate to the create Python definition.
Add the operationretry logic between self.log and "columnclause = ..." such as the following:
self.log() rc = operationretry(cinfo) if rc != ACSuccess: return rc columnclause = "id,shortid,fullname,passwd,expiredpw,enabled,locked,expiredacct" valueclause = "'{0}','{1}','{2}','{3}','0','1','0','0'".format(self.id, self.shortid, self.fullname, self.passwd)
This will add a fake retry look of three attempts for the create operation. The Transaction Monitor Service (
idtm
) is responsible for detecting ACTryAgainLater and retrying until "operationretry" return ACSuccess. When creating the target attributes and profile attributes, the id, shortid, fullname and passwd attributes are mandatory.When creating a new user for the agtsqlitedemo target, the logs will indicate a countdown of three retry attempts with:
operationretry initial state
and then:
operationretry set to 2 operationretry set to 1
and finally:
operationretry completed
The Transaction Monitor Service (
idtm
) will also show a "WAITING ON AGENT" message for the end user.