/jira-project/jira-components/jira-core/src/main/java/com/atlassian/jira/security/WorkflowBasedPermissionManager.java
Java | 261 lines | 188 code | 28 blank | 45 comment | 41 complexity | 095b67ae02bbcecdd6048e81aeb9e2d4 MD5 | raw file
Possible License(s): Apache-2.0
- package com.atlassian.jira.security;
- import com.atlassian.jira.component.ComponentAccessor;
- import com.atlassian.jira.config.SubTaskManager;
- import com.atlassian.jira.issue.Issue;
- import com.atlassian.jira.issue.status.Status;
- import com.atlassian.jira.permission.PermissionContext;
- import com.atlassian.jira.permission.PermissionContextFactory;
- import com.atlassian.jira.permission.WorkflowPermission;
- import com.atlassian.jira.permission.WorkflowPermissionFactory;
- import com.atlassian.jira.project.Project;
- import com.atlassian.jira.security.plugin.ProjectPermissionKey;
- import com.atlassian.jira.security.plugin.ProjectPermissionTypesManager;
- import com.atlassian.jira.user.ApplicationUser;
- import com.opensymphony.workflow.loader.ActionDescriptor;
- import org.ofbiz.core.entity.GenericValue;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import javax.annotation.Nonnull;
- import javax.annotation.Nullable;
- import java.util.List;
- import static com.atlassian.jira.permission.LegacyProjectPermissionKeyMapping.getKey;
- /**
- * Permission manager which allows workflow permissions to be further restricted for each workflow step, in the workflow XML descriptor.
- * For instance, if the workflow contains a step:
- * <pre>
- * <step id="1" name="Open">
- * <meta name="jira.status.id">1</meta>
- * <meta name="jira.permission.comment.group">acme-bizusers</meta>
- * <meta name="jira.permission.comment.user">qa</meta>
- * <meta name="jira.permission.edit.group.1">jira-developers</meta>
- * <meta name="jira.permission.edit.group.2">jira-editors</meta>
- * <meta name="jira.permission.edit.projectrole">10001</meta>
- * </pre>
- * then only members of the acme-bizusers group and user 'qa' will be able to comment on open issues, and only members of
- * 'jira-developers' and 'jira-editors' groups or members of the project role with id '10001' will be able to edit issues.
- * Assuming, of course, these users already have the relevant permission in the permission scheme.<p>
- * Meta attributes can also modify subtasks' permissions. For example if the 'Bug' workflow's Open step has:
- * <pre>
- * <meta name="jira.permission.subtasks.edit.group">jira-qa</meta>
- * </pre>
- * Then subtasks of Bugs will only be editable by 'jira-qa' members, when their parent is in the Open state.<p>
- * The format is 'jira.permission.[subtasks.]{permission}.{type}[.suffix]', where:
- * <ul>
- * <li>{permission} is a short name specified in {@link Permissions}
- * <li>{type} is a type (group, user, assignee, reporter, lead, userCF, projectrole)
- * of permission granted, or <tt>denied</tt> to deny the permission.
- * <li><tt>subtasks.</tt>, if specified, indicates that the permission
- * applies to the subtasks of issues in this step.
- * <p>
- * <b>Important:</b>Workflow permissions can only <i>restrict</i>
- * permissions set in the permission scheme, not grant permissions.
- *
- * @see com.atlassian.jira.permission.WorkflowBasedPermissionSchemeManager
- */
- public class WorkflowBasedPermissionManager extends DefaultPermissionManager {
- private static final Logger log = LoggerFactory.getLogger(WorkflowBasedPermissionManager.class);
- private final WorkflowPermissionFactory workflowPermissionFactory;
- private final PermissionContextFactory permissionContextFactory;
- public WorkflowBasedPermissionManager(final WorkflowPermissionFactory workflowPermissionFactory,
- final PermissionContextFactory permissionContextFactory,
- final ProjectPermissionTypesManager projectPermissionTypesManager,
- final ProjectPermissionOverrideDescriptorCache projectPermissionOverrideDescriptorCache) {
- super(projectPermissionTypesManager, projectPermissionOverrideDescriptorCache);
- this.workflowPermissionFactory = workflowPermissionFactory;
- this.permissionContextFactory = permissionContextFactory;
- }
- @Override
- public boolean hasPermission(final int permissionsId, final Issue issue, final ApplicationUser user) {
- final boolean permSchemeAllows = super.hasPermission(permissionsId, issue, user);
- return workflowPermissionCheck(permSchemeAllows, permissionsId, issue, user);
- }
- @Override
- public boolean hasPermission(@Nonnull final ProjectPermissionKey permissionsKey, @Nonnull final Issue issue, final ApplicationUser user) {
- final boolean permSchemeAllows = super.hasPermission(permissionsKey, issue, user);
- return workflowPermissionCheck(permSchemeAllows, permissionsKey, issue, user);
- }
- @Override
- public boolean hasPermission(@Nonnull final ProjectPermissionKey permissionKey, @Nonnull final Issue issue, @Nullable final ApplicationUser user, @Nullable final ActionDescriptor actionDescriptor) {
- // Check for permission ignoring workflow/status
- final boolean permSchemeAllows = super.hasPermission(permissionKey, issue, user);
- // Now see if the new status will change permissions
- return workflowPermissionCheck(permSchemeAllows, permissionKey, issue, user, actionDescriptor);
- }
- @Override
- public boolean hasPermission(@Nonnull final ProjectPermissionKey permissionKey, @Nonnull final Issue issue, @Nullable final ApplicationUser user, @Nonnull final Status status) {
- // Check for permission ignoring workflow/status
- final boolean permSchemeAllows = super.hasPermission(permissionKey, issue, user);
- // Now see if the new status will change permissions
- return workflowPermissionCheck(permSchemeAllows, permissionKey, issue, user, status);
- }
- @Override
- public boolean hasPermission(final int permissionsId, final Project project, final ApplicationUser user) {
- final boolean permSchemeAllows = super.hasPermission(permissionsId, project, user);
- return workflowPermissionCheck(permSchemeAllows, permissionsId, project.getGenericValue(), user);
- }
- @Override
- public boolean hasPermission(@Nonnull final ProjectPermissionKey permissionsKey, @Nonnull final Project project, @Nullable final ApplicationUser user) {
- final boolean permSchemeAllows = super.hasPermission(permissionsKey, project, user);
- return workflowPermissionCheck(permSchemeAllows, permissionsKey, getIssueOrNull(project.getGenericValue()), user);
- }
- @Override
- public boolean hasPermission(final int permissionsId, final Project project, final ApplicationUser user, final boolean issueCreation) {
- final boolean permSchemeAllows = super.hasPermission(permissionsId, project, user, issueCreation);
- return workflowPermissionCheck(permSchemeAllows, permissionsId, project.getGenericValue(), user);
- }
- @Override
- public boolean hasPermission(@Nonnull final ProjectPermissionKey permissionsKey, @Nonnull final Project project, final ApplicationUser user, final boolean issueCreation) {
- final boolean permSchemeAllows = super.hasPermission(permissionsKey, project, user, issueCreation);
- return workflowPermissionCheck(permSchemeAllows, permissionsKey, getIssueOrNull(project.getGenericValue()), user);
- }
- private boolean workflowPermissionCheck(final boolean permissionSchemeAllows, final int permissionId, final GenericValue entity, final ApplicationUser user) {
- ProjectPermissionKey permissionKey = getKey(permissionId);
- return workflowPermissionCheck(permissionSchemeAllows, permissionKey, getIssueOrNull(entity), user);
- }
- private boolean workflowPermissionCheck(final boolean permissionSchemeAllows, final int permissionId, final Issue issue, final ApplicationUser user) {
- final ProjectPermissionKey permissionKey = getKey(permissionId);
- return workflowPermissionCheck(permissionSchemeAllows, permissionKey, issue, user);
- }
- private boolean workflowPermissionCheck(final boolean permissionSchemeAllows, final ProjectPermissionKey permissionKey, final Issue issue, final ApplicationUser user) {
- return workflowPermissionCheck(permissionSchemeAllows, permissionKey, issue, user, (ActionDescriptor) null);
- }
- private boolean workflowPermissionCheck(final boolean permissionSchemeAllows, final ProjectPermissionKey permissionKey,
- final Issue issue, final ApplicationUser user, @Nonnull final Status status) {
- if (permissionKey == null) {
- return permissionSchemeAllows;
- }
- if (permissionSchemeAllows) {
- if (issue != null) {
- return workflowPermissionCheck(permissionSchemeAllows, permissionKey, issue, user,
- permissionContextFactory.getPermissionContext(issue, status));
- } else {
- if (log.isDebugEnabled()) {
- log.debug(permissionKey.permissionKey() + " permission granted by permission scheme");
- }
- return true;
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug(permissionKey.permissionKey() + " permission denied by permission scheme");
- }
- return false;
- }
- }
- private boolean workflowPermissionCheck(final boolean permissionSchemeAllows, final ProjectPermissionKey permissionKey,
- final Issue issue, final ApplicationUser user, @Nullable final ActionDescriptor actionDescriptor) {
- if (permissionKey == null) {
- return permissionSchemeAllows;
- }
- if (permissionSchemeAllows) {
- if (issue != null) {
- return workflowPermissionCheck(permissionSchemeAllows, permissionKey, issue, user,
- permissionContextFactory.getPermissionContext(issue, actionDescriptor));
- } else {
- if (log.isDebugEnabled()) {
- log.debug(permissionKey.permissionKey() + " permission granted by permission scheme");
- }
- return true;
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug(permissionKey.permissionKey() + " permission denied by permission scheme");
- }
- return false;
- }
- }
- private boolean workflowPermissionCheck(final boolean permissionSchemeAllows, final ProjectPermissionKey permissionKey,
- final Issue issue, final ApplicationUser user, @Nonnull final PermissionContext permissionContext) {
- if (permissionKey == null) {
- return permissionSchemeAllows;
- }
- if (permissionSchemeAllows) {
- if (issue != null) {
- final List<WorkflowPermission> workflowPerms = workflowPermissionFactory.getWorkflowPermissions(
- permissionContext, permissionKey, false);
- // add parent workflow permissions if issue is a sub-task
- addParentPermissionsIfSubTask(workflowPerms, issue, permissionKey);
- if (!workflowPerms.isEmpty()) {
- for (final WorkflowPermission permission : workflowPerms) {
- if (permission.allows(permissionKey, issue, user)) {
- if (log.isInfoEnabled()) {
- log.info(permissionKey.permissionKey() + " granted by permission scheme and " + permission);
- }
- return true;
- }
- if (log.isInfoEnabled()) {
- log.info("\t" + permissionKey.permissionKey() + " not granted by " + permission);
- }
- }
- if (log.isInfoEnabled()) {
- log.info(permissionKey.permissionKey() + " granted by permission scheme but DENIED by workflow");
- }
- return false;
- } else {
- if (log.isDebugEnabled()) {
- log.debug(permissionKey.permissionKey() + " granted by permission scheme");
- }
- return true;
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug(permissionKey.permissionKey() + " permission granted by permission scheme");
- }
- return true;
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug(permissionKey.permissionKey() + " permission denied by permission scheme");
- }
- return false;
- }
- }
- private Issue getIssueOrNull(final GenericValue entity) {
- if (entity != null && "Issue".equals(entity.getEntityName())) {
- return ComponentAccessor.getIssueFactory().getIssue(entity);
- }
- return null;
- }
- /**
- * Adds parent's workflow permissions if sub-tasks are enabled and the given issue is a sub-task
- *
- * @param workflowPerms list of workflow permissions to add parent's into
- * @param issue issue to check for being a sub-task
- * @param permissionId permission id
- */
- private void addParentPermissionsIfSubTask(final List<WorkflowPermission> workflowPerms, final Issue issue, final ProjectPermissionKey permissionId) {
- final SubTaskManager subTaskManager = ComponentAccessor.getSubTaskManager();
- final Issue parent = issue.getParentObject();
- if (subTaskManager.isSubTasksEnabled() && (parent != null)) {
- final PermissionContext parentPermissionContext = permissionContextFactory.getPermissionContext(parent);
- workflowPerms.addAll(workflowPermissionFactory.getWorkflowPermissions(parentPermissionContext, permissionId, true));
- }
- }
- }