A site upgrade is scheduled for 7/21 at 9 PM ET — please refresh your browser if needed.
Join this online group to communicate across IBM product users and experts by sharing advice and best practices with peers and staying up to date regarding product enhancements.
When you set out to define a permissions model for IBM UrbanCode Deploy (now IBM DevOps Deploy) it’s often a requirement to document the model for discussions/approvals…
While UCD provides tools to build and maintain the permissions model it doesn’t give you a ‘single view’ that can be used in workshops and other forums to discuss the operation of the model and the specifics of what permissions are granted to each role.
Often as part of the process of adopting UCD, it is seen as desirable to have the model presented in a documented form for sign-off and also for discussions around future change. It can also be needed for training purposes so that each role in the organization clearly knows what their responsibilities are.
It would also help if there was an easy way to spot anomalies where a permission isn’t granted to any role. This might be an oversight or perhaps intentional, but it would help if these were easy to spot and justify.
UCD has over 160 permissions at the time of writing spread across 18 different categories or object classes. This also changes over time as UCD evolves and more permissions are added / old ones changed in their scope.
So, wouldn’t it be handy if you could just develop the permissions model in UCD itself and then extract what you had set up for documentation and discussion purposes? That way you would only have one place to maintain the model and, in keeping with general best practices, only have a single source of truth – UCD itself!!
What I’m presenting here is a small groovy script that will do just that for you. It will enumerate all the permissions in UCD across the 18 different object classes and include variations in permissions for each resource role or ‘Type’, against all of the UCD roles that you have defined. The output is a tab-separated list which can be easily imported into a spreadsheet for analysis.
The script will also warn you if there are any permissions in your model that aren’t assigned to any role-resource role combination meaning that the UCD operation it represents cannot be performed by anyone.
The tool is executed via a shell script and you will need a copy of the uDeployRestClient.jar file in the same directory. You can find this jar in any of the UCD plugins that provide services to automate UCD itself.
You will also need to setup the environment variables JAVA_HOME pointing at your JRE and also GROOVY_HOME pointing at a groovy installation. (UCD agents have one of these in their opt sub-directory.)
The script takes three parameters, -user, -password and -weburl. You should redirect standard output to a file to receive the extracted permissions information which you will later import into a spreadsheet.
./extractPermissions.sh -user admin -password admin -weburl https://localhost:8443 > permissons.out
The application title and any other information is presented on standard error. This includes a warning about permissions assigned to no role. The following is an example output. In my case, I’ve upgraded a UCD server with a version that has new permissions that have yet to be assigned to any role.
UCD Role Permissions Extractor V3.0 December 2020 The permission 'Create External Approvals' of Class 'External Approval' was not assigned to any role The permission 'Delete' of Class 'External Approval' was not assigned to any role The permission 'Edit Basic Settings' of Class 'External Approval' was not assigned to any role The permission 'Manage Properties' of Class 'External Approval' was not assigned to any role The permission 'Manage Teams' of Class 'External Approval' was not assigned to any role The permission 'Manage Maintenance Mode' of Class 'Server Configuration' was not assigned to any role The permission 'Manage Tags' of Class 'Server Configuration' was not assigned to any role The permission 'Configuration Tab' of Class 'Web UI' was not assigned to any role Extract Complete
This is the kind of thing you would see once you import the output into a spreadsheet. Being able to generate this automatically represents a significant saving in time and improvement in accuracy not to speak of saving a lot of hair!!!
So this is the shell script to invoke the script in a nice friendly manner
#!/bin/sh if [ -n "$GROOVY_HOME" ]; then # change the dir to the root of the client directory SHELL_NAME="$0" SHELL_PATH=`dirname "${SHELL_NAME}"` if [ "." = "$SHELL_PATH" ] then SHELL_PATH=`pwd` fi groovycmd="$GROOVY_HOME/bin/groovy" jarfile="$SHELL_PATH/uDeployRestClient.jar" if [ -r "$jarfile" ]; then "$groovycmd" -cp "$jarfile" extractPermissions.groovy "$@" else echo "Didn't find $jarfile in directory ${SHELL_PATH}" exit 1 fi else echo You must have GROOVY_HOME set in your environment to use the extractPermissions tool. exit 1 fi
Finally, the most important bit, the script itself
import java.net.URI; import java.util.LinkedHashMap; import com.urbancode.ud.client.UDRestClient; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONObject; import org.codehaus.jettison.json.JSONException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.impl.client.DefaultHttpClient; userid=""; password=""; weburl=""; System.err << "UCD Role Permissions Extractor V3.0 December 2020\n" public class extensionsClient extends UDRestClient { public extensionsClient(final URI url, final String clientUser, final String clientPassword) { super(url, clientUser, clientPassword); } public extensionsClient(final URI url, final String clientUser, final String clientPassword, final boolean trustAllCerts) { super(url, clientUser, clientPassword, trustAllCerts); } public extensionsClient(final URI url, final DefaultHttpClient client) { super(url, client); } // fetch the action mappings for a given role. This maps permissions to roles including user defined types JSONArray getSecurityRoleActionMappings(final String roleID) { String uri = this.url.toString() + "/security/role/${roleID}/actionMappings"; final HttpGet method = new HttpGet(uri); final CloseableHttpResponse response = invokeMethod((HttpRequestBase)method); final String body = this.getBody(response) ; return new JSONArray(body); } JSONArray getSecurityRoles() { String uri = this.url.toString() + "/security/role"; final HttpGet method = new HttpGet(uri); final CloseableHttpResponse response = invokeMethod((HttpRequestBase)method); final String body = this.getBody(response) ; return new JSONArray(body); } JSONArray getSecurityClassPermissions(final String resourceClass) { String uri = this.url.toString() + "/security/resourceType/${resourceClass}/actions"; final HttpGet method = new HttpGet(uri); final CloseableHttpResponse response = invokeMethod((HttpRequestBase)method); final String body = this.getBody(response) ; return new JSONArray(body); } JSONArray getResourceRolesforClass(final String resourceClass) { String uri = this.url.toString() + "/security/resourceType/${resourceClass}/resourceRoles"; final HttpGet method = new HttpGet(uri); final CloseableHttpResponse response = invokeMethod((HttpRequestBase)method); final String body = this.getBody(response) ; return new JSONArray(body); } JSONArray getSecurityResourceTypes() { String uri = this.url.toString() + "/security/resourceType"; final HttpGet method = new HttpGet(uri); final CloseableHttpResponse response = invokeMethod((HttpRequestBase)method); final String body = this.getBody(response) ; return new JSONArray(body); } } ParseCommandLine(this.args); myClient = new extensionsClient( new URI(weburl), userid , password, true); // Permissions Extraction // OK, lets start the exercise by getting the list of role permissions classifications eg, agent, agent pool, application and so on. // Map contains the permission classification and its ID LinkedHashMap <String, String> Role_Class_Info = getNameAndID(myClient.getSecurityResourceTypes()); Role_Class_Info.sort{it} // Now build a map of the roles and ID's LinkedHashMap <String, String> Role_Info = getNameAndID(myClient.getSecurityRoles()); // print static part of column header line print "Permission Category\tPermission Name\tPermission Description\tResource Role" NumRoles=Role_Class_Info.size(); // Output the names of all the roles Role_Info.each {print "\t" + it.key }; // Terminate column headings line println ""; // Now get the permissions map for all of the roles against each role there is a JSON array of permissions LinkedHashMap<String, JSONArray> RoleMaps = getRoleMaps(Role_Info); // Now process each of the role permission classifications Role_Class_Info.each { // Get values for loop EncodedClassName = it.key.replace(' ', '%20'); CLASS_NAME = it.key; CLASS_ID = it.value; // Get the permissions details for each permission in the class category JSONArray ClassPermissions = myClient.getSecurityClassPermissions(EncodedClassName); // get the names of the resourcetypes available for the category // So we will end up with lists of all of the types for each permission category and also the IDs of those JSONArray resourceRoles = myClient.getResourceRolesforClass(EncodedClassName); // see if there are any additional to the standard type RESOURCE_ROLE_NAMES= ["standard"]; RESOURCE_ROLE_IDS = ["NA"]; if ( resourceRoles.length() > 0 ) { for (int i= 0 ; i< resourceRoles.length() ; ++i) { JSONObject propObject = (JSONObject)resourceRoles.get(i); RESOURCE_ROLE_NAMES = RESOURCE_ROLE_NAMES << propObject.get("name"); RESOURCE_ROLE_IDS = RESOURCE_ROLE_IDS << propObject.get("id"); } } lastPermID="" lastPermName="" permCount=0 // Now iterate over each permission/type combination and find out what roles have it for (int i = 0; i < ClassPermissions.length(); ++i) { final JSONObject propObject = (JSONObject)ClassPermissions.get(i); PERM_NAME = propObject.get("name"); PERM_ID = propObject.get("id"); PERM_DESC = propObject.get("description"); for (int j=0; j<RESOURCE_ROLE_NAMES.size(); ++j) { // Print the static data for each permission print "${CLASS_NAME}\t${PERM_NAME}\t${PERM_DESC}\t"+RESOURCE_ROLE_NAMES[j] // Check to see if a permissions wasn't assigned to any role if ( lastPermID != PERM_ID) { if (lastPermID != "") if ( permCount == 0 ) System.err << " The permission \'${lastPermName}\' of Class \'${CLASS_NAME}\' was not assigned to any role\n" lastPermID= PERM_ID lastPermName = PERM_NAME permCount=0 } // Add the assigned permission information to the output line Role_Info.each { ROLE = it.key; JSONArray MapForRole = RoleMaps[ROLE]; assigned = searchJSONArrayforKey(MapForRole, PERM_ID, RESOURCE_ROLE_NAMES[j]); if (assigned.contains("X")) permCount++ print assigned } println ""; } } } System.err << "Extract Complete\n" // This method searches the action map for a role looking to see if the role has the permission we're interested in // It returns either an 'X' for present or blank for missing String searchJSONArrayforKey (JSONArray actionsMap, String id , String resourceRole) { // Search the JSON array given for an oject containing the specific value of a given key for ( int i = 0 ; i < actionsMap.length(); ++i) { JSONObject obj = actionsMap.get(i); try { if ( resourceRole == "standard" ) if ( obj.find {it.action.id == id} != null ) return "\tX"; else if (obj.find {it.resourceRole.name == resourceRole} != null ) return "\tX"; } catch (Exception JSONException) { } } return "\t"; } // This method parses the command options to extract connection details void ParseCommandLine(args) { def idx=0 def arg="" while ( idx < args.size()) { arg = args[idx].toLowerCase(); switch (arg) { case "-user": case "--user": userid=args[++idx]; break; case "-password": case "--password": password=args[++idx]; break; case "-weburl": case "--weburl": weburl=args[++idx]; break; default: System.err << "Unexpected argument ${arg}\n"; System.err << "Expected command line -user <ucdd admin username> -passsword <password for admin user> -weburl https://<host>:<port> \n" System.exit(1); } idx++; } } LinkedHashMap<String, String> getNameAndID(JSONArray roleInfo) throws IOException, JSONException { final Map<String, String> result = new LinkedHashMap<String, String>(); for (int i = 0; i < roleInfo.length(); ++i) { final JSONObject propObject = (JSONObject)roleInfo.get(i); result.put((String)propObject.get("name"), (String)propObject.get("id")); } return result; } LinkedHashMap<String, JSONArray> getRoleMaps(LinkedHashMap <String, String> RoleInfo ) { final Map<String, JSONArray> result = new LinkedHashMap<String, JSONArray>(); RoleInfo.each { result.put((String)it.key, (JSONArray) myClient.getSecurityRoleActionMappings(it.value)); } return result; }
I hope you find this script useful and that it saves you some time (and hair!).
#UrbanCodeDeploy#10minutetip
Copy