Setting Access Control Permissions for Work Items


This is the second post in the series around very fine grained access control permissions for work items and RTC SCM versionables. It explains how to set the access control permissions for work items.

See the problem description in the first post of the series

Related posts

The posts in this series are:

  1. Manage Access Control Permissions for Work Items and Versionables
  2. Setting Access Control Permissions for Work Items – this post
  3. Setting Access Control Permissions for SCM Versionables
  4. Setting Attributes for SCM Versionables

License

The post contains published code, so our lawyers reminded me to state that the code in this post is derived from examples from Jazz.net as well as the RTC SDK. The usage of code from that example source code is governed by this license. Therefore this code is governed by this license. I found a section relevant to source code at the and of the license. Please also remember, as stated in the disclaimer, that this code comes with the usual lack of promise or guarantee. Enjoy!

Just Starting With Extending RTC?

If you just get started with extending Rational Team Concert, or create API based automation, start with the post Learning To Fly: Getting Started with the RTC Java API’s and follow the linked resources.

You should be able to use the following code in this environment and get your own automation or extension working.

Compatibility

This code has been used with RTC 5.0.2 and is prepared to be used with RTC 6.0.x with no changes and it is pretty safe to assume, that the code will work with newer versions of RTC.

The code in this post uses common libraries/services that are available in the Plain Java Client, Eclipse client and Jazz Eclipse server API. If client or server API is used, this is stated.

Work Item Access Control Code

Now that we have all the rules and pieces together as explained in this post, lets have a look at the work item access control. Again, note, that work items can only have access groups and project areas set for access control in manual mode as shown in the image below.

WorkItemAccessContextSelection

To set the access context for work items, the interface IWorkItem provides the method

IWorkItem.setContextId(UUID contextId);

It should also be possible to set the internal attribute with the ID “contextId” also available as constant

IWorkItem.CONTEXT_ID_PROPERTY

in the IWorkItem interface.

Working With the UUID Representing the Access Context

How to find the objects we are interested in, is explained in this post.

To be able to set the access control context for work items, it is necessary to understand how to access the value that represents the access context of a process area (project or team area) or access group.

The common API provides this method to access the access context of an item:

com.ibm.team.repository.common.IAuditableHandle.getItemId()

This interface implements (through a number of intermediate interfaces) the interface IItemHandle, which defines the method getItemId() for all items. So strictly speaking the method is available as

com.ibm.team.repository.common.IItemHandle.getItemId()

This means, the access context can be accessed already from the item handle e.g. in case only a handle such as IProcessAreaHandle, IProjectAreaHandle, ITeamAreaHandle, IAccessGroupHandle or IContributorHanlde is available.

It is also available at all resolved IItems such as IProcessArea, IProjectArea, ITeamArea, IAccessGroup or IContributor as all these interfaces implement IItemHandle. In fact it is available on all IItems. Example code:

IProcessAreaHandle paHandle = ..... get the handle
IProcessArea pa = ..... resolve the handle

// These values are the same
UUID paHandleContext1 = paHandle.getItemID(); 
UUID paHandleContext2 = pa.getItemID();

Note, that all items in RTC have an itemID like the one above and can be uniquely be identified by it. Other itemID’s are just not used as access context.

The return value is of the type

com.ibm.team.repository.common.UUID

The UUID is an object that uniquely identifies an item in the repository and can be used to recreate the item as well. The string representation shows up in several places, for example in OSLC links. To get the string representation use

com.ibm.team.repository.common.UUID.getUuidValue()

If it is necessary to recreate an UUID from the string representation as an example named contextIDString, use the method

UUID.valueOf(contextIDString)

This recreates the UUID of the object if the string is a valid string representation of a UUID.

This way, you have the choice to use the UUID or its string representation to set the access context of RTC work items.

Setting the WorkItem Access Context

Given the UUID provided by a project area or access group, it is possible to set the access context of a work item.

Although all the code to retrieve the access context is common code, the code to set the work items context differs on client and server.

In the Client API, use a WorkItemOperation like the code below.

/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2015. All Rights Reserved. 
 *
 * Note to U.S. Government Users Restricted Rights:  Use, duplication or 
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *******************************************************************************/
package com.ibm.js.access.control.client;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.repository.common.UUID;
import com.ibm.team.workitem.client.WorkItemOperation;
import com.ibm.team.workitem.client.WorkItemWorkingCopy;
import com.ibm.team.workitem.common.model.IWorkItem;
import com.ibm.team.workitem.common.model.ItemProfile;

/**
 * WorkItem Operation to set the access context for the work item. This is
 * client code only.
 * 
 */
public class SetAccessControlOperation extends WorkItemOperation {

	private UUID fAccessContext;

	public SetAccessControlOperation(UUID accessContext,
			ItemProfile loadProfile) {
		super("Set Access Context", loadProfile);
		fAccessContext = accessContext;
	}

	@Override
	protected void execute(WorkItemWorkingCopy workingCopy,
			IProgressMonitor monitor) throws TeamRepositoryException {
		workingCopy.getWorkItem().setContextId(fAccessContext);
	}
}

The operation can be called like this:

	SetAccessControlOperation operation = new SetAccessControlOperation(
		UUID.valueOf(context), IWorkItem.FULL_PROFILE);
	operation.run(workItem, monitor);

Because the WorkItemOperation is not available in the server API, a save has to be performed manually like below.

	// Set the work item visibility
	// Get the full state of the parent work item so we can edit it
	// and avoid stale data exceptions
	// Get the required service interfaces
	IWorkItemServer wiServer = getService(IWorkItemServer.class);
	IWorkItem fullItem = (IWorkItem) wiServer
			.getAuditableCommon()
			.resolveAuditable(workItem, IWorkItem.FULL_PROFILE, monitor)
			.getWorkingCopy();

	// Set the context of the work item
	fullItem.setContextId(UUID.valueOf(context));

	// Save the work item
	HashSet additionalParams = new HashSet();
	additionalParams.add("WORK_ITEM_CONTEXT_CHANGE");

	IStatus status = wiServer.saveWorkItem3(fullItem, null, null,
			additionalParams);
	if (!status.isOK()) {
		String parameter[] = new String[1];
			parameter[0] = Integer.toString(fullItem.getId());

		String description = NLS.bind(
				"Failed to save work item ''{0}''.", parameter);
		IReportInfo info = collector.createInfo(
				"WORK_ITEM_CONTEXT_CHANGE"
				+ ": Error running the participant.",
				description);
		info.setSeverity(IProcessReport.ERROR);
		collector.addInfo(info);
		return;
	}

Please note, if this is performed in a participant/follow up action, it is important to send an additional save parameter like “WORK_ITEM_CONTEXT_CHANGE”. This protects the participants from causing a recursion ultimately crashing the server. The participant can protect itself to run again for the save it just performed by testing for the additional save parameter. If the parameter is detected, the participant knows it caused the save and should exit to prevent the recursion.

Please also note, that in some cases you might have a WorkItemWorkingCopy, instead of an IWorkItem. In these cases use a cast or the method getWorkItem() on the working copy to get the IWorkItem item to be able to set the context.

The examples above uses the string version of the UUID, however, it would have been possible to get the UUID directly from the IItem.

Getting the WorkItem Access Context

It is possible to get the access context of a work item, if the work item is accessible for read, by using IWorkItem.getContextId(). The resulting UUID can be used to get the related item.

Summary

This post explains how to set read access control for work items. The next post will explain the details around setting access control for SCM versionables.

Advertisements

Manage Access Control Permissions for Work Items and Versionables


A customer requires very fine grained access control to work items and versionable objects such as files in the SCM system. In addition the customer had the requirement to be able to set attributes on elements in the SCM system.

I knew that it can be set for work items and kind of how to because I had briefly looked at it in the A RTC WorkItem Command Line Version 3.0. But I was not completely sure about the rules and how to access the SCM part and the attributes in SCM.

Since the customer needed this urgently I looked at what the rules are and what can be done.

The content is way too big for just one post, so this is going to be a series. The first post explains the rules around access control permissions and some basic API’s around finding the objects that can be used to provide the access control context.

Related posts

The posts in this series are:

  1. Manage Access Control Permissions for Work Items and Versionables – this post
  2. Setting Access Control Permissions for Work Items
  3. Setting Access Control Permissions for SCM Versionables
  4. Setting Attributes for SCM Versionables

Also see

Controlling access to source control artifacts in Rational Team Concert

License and Download

The post contains published code, so our lawyers reminded me to state that the code in this post is derived from examples from Jazz.net as well as the RTC SDK. The usage of code from that example source code is governed by this license. Therefore this code is governed by this license. I found a section relevant to source code at the and of the license. Please also remember, as stated in the disclaimer, that this code comes with the usual lack of promise or guarantee. Enjoy!

Just Starting With Extending RTC?

If you just get started with extending Rational Team Concert, or create API based automation, start with the post Learning To Fly: Getting Started with the RTC Java API’s and follow the linked resources.

You should be able to use the following code in this environment and get your own automation or extension working.

Compatibility

This code has been used with RTC 5.0.2 and is prepared to be used with RTC 6.0.x with no changes and it is pretty safe to assume, that the code will work with newer versions of RTC.

The code in this post uses common libraries/services that are available in the Plain Java Client, Eclipse client and Jazz Eclipse server API. If client or server API is used, this is stated.

Problem Description

The first question was, if it was possible to set the permission to access

  1. Work Items
  2. Items in the SCM system such as versionables

The second question was, if it was possible to set the attributes introduced in RTC 5.0 that can be specified and set using the API. The documentation only mentioned the SCM command line.

The third question was, how team areas and access groups can be created automatically.

The forth question was, what exactly the rules are:

  1. Can this be done in the server?
  2. Can this be done in the client?
  3. Can this be done in a command line tool or from another application?
  4. What permissions are required and what are the rules in the different contexts?

Solution Approach

The approach that we chose was to try to implement a minimal demonstrator to demonstrate the capabilities and prove them as a proof of concept. this demonstrator was also intended to serve as a platform to find the rules.

Learning

Here is what we learned creating the demonstrator.

The Rules – Work Items

Work Items have an attribute called “Restricted Access” that can be used to control access to them. There are basically the following modes available for work items that can be used.

  1. Access control using access control of the project area
  2. Restricted access by category
  3. Restricted access by setting the restricted access attribute

Option 1: Only the users that have access to the context set for the project area can access these items. This can be set to everyone basically exposing the work items to everyone. Other options a re project area membership and access control list etc. The rules here are very clear.

Option 2: It is possible to set RTC in a project area to automatically determine access permissions based on the category (filed against) of the work item. This sets the restricted access to the project area or team area associated to the category. Only members of the team area (and members of sub team areas of the team area associated to the category) have access to the work items which are restricted by category. It is worth noting, that a user being associated to the project area can not look into the work items filed against teams, if these limit access, it is quite the opposite.

Option 3: Use a special editor presentation to set the restricted access attribute manually to a project area or an access group. this could potentially be supported by automation.

The most important learning for option 3 is, that it is only possible to set the restricted access attribute to a project area or an access group this way. It is not possible to set the access context to a team area. If the context is set to a team area, it automatically picks up the containing project area. This also holds for automation.

See this help topic on how to set up the work items to allow setting the restricted access.

The Rules – Versionables

Prior to RTC 6.0.1, which has just been released, it is only possible to set read access control to the default (which is controlled by the component) project areas, team areas (called process areas if the distinction is unimportant) and a single user.

If access control is set to a team area, any member of that team area and its sub team areas have access. Note that this is different from option 2 for work items. If access control is set to a project area, any member who has access to the project area has access to the item.

RTC 6.0.1 introduces the capability to set access control to an access group. Only members of this access group have access to the item. This seems to be the best option by far, especially since access groups can contain project areas and team areas which adds their members to the access group.

Please note, that access control applies to the whole item and its history.

JazzAdmin Repository Role

Users with the JazzAdmin repository role have access to any work item or SCM controlled item, regardless of the access control setting. Users with this role (and sufficient licenses) can access all data.

Project Area Administrators

Administrators of a team or project area and don’t have the JazzAdmin repository role can not access items that have access control set to a context they don’t have access to.

General Rules

Users can only set the access context of work items or items in the SCM system to an access context that preserves their access permission. It is not possible to find or select an access group, process area the user has no access to/is member of or a different user and set the access context to it. This would remove the read permissions and is prevented.

Users with the JazzAdmin role and sufficient licenses however can do this, because they don’t loose read access.

General Rules For Automation

All automation can only perform the operations that are permitted to the user that is used to run the automation. This especially means that automation running in the context of a user with JazzAdmin repository role and the required licenses can perform all operations. The user context available in an automation depends on the automation.

  1. Follow up actions (participants) run in the context of the user that is performing the operation on the client or the server. They are especially not elevated run in a JazzAdmin repository role, if the user that performs the operation does not have this role. It is also not possible to use a different users or services to elevate the permissions.
  2. Preconditions (advisors) must not change the triggering elements. Otherwise the same rules apply as described in follow up actions.
  3. Asynchronous tasks or services in RTC are run with JazzAdmin permissions and can use the IImpersonationService to change the operation to a different user context.
  4. Plain Java Client Library or other client based automation run in the context of the user that was used to log into the system.

In the context of this post, 1 means, that it is not possible to set access control in such an operation that would remove read access from the user that performs the operation. If you require rules where this could be necessary, it would be necessary to run in a administrative context such as an Asynchronous task or in a client application with JazzAdmin repository role.

Finding ProcessAreas, Access Groups and Contributors

How to find the access context information needed using the Java API?

Finding ProcessAreas

There are many ways to find ProcessAreas (project areas and team areas) using the API, the simplest one assumes an java.net.URI constructed from a string based name path of the process area separated by ‘/’.

Lets assume a project area named TestProject1 and a team area within the project are named TestTeam1 and a sub team area underneath TestTeam1 named TestSubTeam1.

The URI for the project area could be constructed from the string “TestProject1”. The URI for TestTeam1 could be constructed from the string “TestProject1/TestTeam1”. Similar the URI for TestSubTeam1 could be constructed from the string “TestProject1/TestTeam1/TestSubTeam1”.

Process area names could contain spaces. Spaces are not allowed in URI’s, therefore they need to be replaced by the encoding character string “%20”.

To construct an java.net.URI from a string value use the following code.

String namePath = "TestProject1/TestTeam1/TestSubTeam1";
URI anURI = URI.create(URI.create(namePath.replaceAll(" ", "%20")))

The service to find the process area by its URI is provided by the interface IAuditableCommon. This interface class, as its name implies, is a common interface that is available in the RTC Plain Java API, as well as the RTC Eclipse client and Eclipse server SDK. This allows to use this API call in any possible context, either by

IAuditableCommon auditableCommon = (IAuditableCommon) teamRepository
	.getClientLibrary(IAuditableCommon.class);

in Plain Java and client SDK based code, or using

IAuditableCommon auditableCommon = getService(IAuditableCommon.class);

in the server extensions that all extend AbstractService (or in case of SCM server extensions AbstractScmService, which extends AbstractService).

For code that already retrieved the common Service IWorkItemCommon, for example to find work items, IAuditableCommon is available using the call

IAuditableCommon auditableCommon = workItemCommon.getAuditableCommon();

So the following code would retrieve the access context for the team area “/TestTeam1/TestSubTeam1” nested in the team area “TestTeam1” in the project area “TestProject1”

String namePath = "TestProject1/TestTeam1/TestSubTeam1";
IProcessArea area = auditableCommon.findProcessAreaByURI(URI.create(namePath.replaceAll(" ", "%20")), null, monitor);
UUID context = area.getItemId();

Note, for work items only a project area is a valid context. Setting the context above will result in the project area containing the process area to be set. Alternatively use

UUID context = area.getProjectArea().getItemId();

for work items and document the fact to save the time to figure it out the hard way during testing (like I did).

Finding the Public Access Context

Work items can also be set to public read access. The constant com.ibm.team.repository.common.IContext.PUBLIC is available for that.

UUID publicContext = IContext.PUBLIC.getUuidValue();

provides with the public access context.

Finding Access Groups

Access Groups are managed in the administration pages of the RTC application. It is possible to create, modify and delete access groups. The image below shows this section.

Access Group ManagementAccess Groups are also accessible using the IAuditableCommon common interface that was already used in the section above.

To get all access groups use this code:

IAccessGroup[] groups;
groups = auditableCommon.getAccessGroups(null, Integer.MAX_VALUE,
	monitor);

This returns all access groups up to a maximal number that is passed to the method.

It is possible to pass a filter to select only access groups with specific name pattern like below.

IAccessGroup[] groups;
groups = auditableCommon.getAccessGroups("My*", Integer.MAX_VALUE,
	monitor);

The access groups can be iterated like below to compare the name or do something similar.

for (IAccessGroup group : groups) {
// Compare the value to the access group name.
	if (group.getName().equalsIgnoreCase(value)) {
		return group;
	}
}

Similar to the process areas above, there is also a public access group which can be obtained like this:

return auditableCommon.getAccessGroupForGroupContextId(
	IContext.PUBLIC, monitor);

Finding Contributors

Finding contributors is different in the client and the server. There is no common API available.

In the client API the IContributorManager can be used for example using the following methods.

IContributorManager contributorManager= teamRepository.contributorManager();
// Find a user by the users ID returns a handle
IContributorHandle contributorHandle = contributorManager
	.fetchContributorByUserId(attributeValue, monitor);

// Get all users, returns a list of full IContributor items
List contributors = contManager.fetchAllContributors(monitor);

In the server API the IContributorService is available and provides the following method.

IContributorService contributorService = getService(IContributorService.class);
contributorService.fetchContributorByUserId(userId);

I was not able to locate a way to search for all users like in the client API. The server API usually gets a user passed and there is no need to find all users.

Summary

This post explains the rules around read access control for work items and RTC SCM versionables and some basic API’s around finding the objects that can be used to provide the access control context. The next post will explain the details around setting access control for work items.