Feature Request: SecurityRequestError Structure Standardization
Closed this issue · 1 comments
Is your feature request related to a problem? Please describe.
When you run into "error" xml returned from IRRSMO00, there are effectively two kinds of structures:
Structure 1 is the case we based SecurityResultError on, RACF returns with a non-zero RC and the following XML:
<?xml version="1.0" encoding="IBM-1047"?>
<securityresult xmlns="http://www.ibm.com/systems/zos/saf/IRRSMO00Result1">
<user name="TESTBOY" operation="set" requestid="UserRequest">
<info>Definition exists. Add command skipped due to precheck option</info>
<command>
<safreturncode>8</safreturncode>
<returncode>16</returncode>
<reasoncode>8</reasoncode>
<image>ALTUSER TESTBOY OMVS (UID (STRING))</image>
<message>IKJ56701I MISSING OMVS UID+</message>
<message>IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS</message>
<message>IKJ56716I EXTRANEOUS INFORMATION WAS IGNORED: STRING</message>
</command>
</user>
<returncode>4</returncode>
<reasoncode>0</reasoncode>
</securityresult>
Structure 2 is the case where IRRSMO00 itself is returning an error to the user as XML:
<?xml version="1.0" encoding="IBM-1047"?>
<securityresult xmlns="http://www.ibm.com/systems/zos/saf/IRRSMO00Result1">
<user name="TESTBOY" operation="set" requestid="UserRequest">
<error>
<errorfunction>10</errorfunction>
<errorcode>2000</errorcode>
<errorreason>76</errorreason>
<errormessage>Data may not be specified for a boolean field.</errormessage>
<erroroffset>216</erroroffset>
<textinerror>STRING</textinerror>
</error>
</user>
<returncode>2000</returncode>
<reasoncode>76</reasoncode>
</securityresult>
Because the internal XML structure is so different, the SecurityRequestError is very different. Our documented sample of:
from pyracf import UserAdmin
from pyracf import SecurityRequestError
user_admin = UserAdmin()
try:
user_admin.alter("squidwrd", traits={"base:password": "passwordtoolong"})
except SecurityRequestError as e:
return_code = e.result["securityResult"]["user"]["returnCode"]
reason_code = e.result["securityResult"]["user"]["reasonCode"]
messages = "\n".join(e.result["securityResult"]["user"]["commands"][0]["messages"])
print(f"Return Code: {return_code}")
print(f"Reason Code: {reason_code}")
print(f"Messages:\n\n{messages}")
would not work because there is no commands dictionary and no 'messages', just all sorts of error tags.
Describe the solution you'd like
We should make one structure conform to the other at least when added under the SecurityRequestError object so that errors thrown either by SMO or RACF can be handled by users without having to change their exception handling logic.
Describe alternatives you've considered
We could also split these into two entirely separate error objects to be handled differently, but that could still leave users with complications.
Additional context
The SMO errors also have some nice fields like erroroffset
and textinerror
. It would be nice to incorporate these into the SecurityRequestError in some way so that end users could quickly access that information to correct user error.
Resolved in #57