All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almworks.jira.structure.api.permissions.PermissionSubject Maven / Gradle / Ivy

The newest version!
package com.almworks.jira.structure.api.permissions;

import com.almworks.jira.structure.api.settings.StructureConfiguration;
import com.almworks.jira.structure.api.util.*;
import com.atlassian.crowd.embedded.api.Group;
import com.atlassian.jira.project.Project;
import com.atlassian.jira.project.ProjectManager;
import com.atlassian.jira.security.roles.ProjectRoleManager;
import com.atlassian.jira.user.ApplicationUser;
import com.fasterxml.jackson.annotation.*;
import org.jetbrains.annotations.Nullable;

import javax.xml.bind.annotation.*;
import java.io.Serializable;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;

import static org.apache.commons.lang3.StringUtils.removeStart;

/**
 * 

PermissionSubject is an abstraction used to specify which users a particular permission * is applicable to. All possible sub-classes of PermissionSubject are listed in this class, and other implementation are not * supported because Structure needs to serialize and deserialize permission subjects.

* * @see PermissionSubject.JiraUser * @see PermissionSubject.JiraGroup * @see PermissionSubject.ProjectRole * @see PermissionSubject.Anyone * @see Structure Permissions (Structure Documentation) * @author Igor Sereda */ @XmlRootElement @XmlSeeAlso({PermissionSubject.Anyone.class, PermissionSubject.JiraUser.class, PermissionSubject.JiraGroup.class, PermissionSubject.ProjectRole.class}) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = PermissionSubject.Anyone.class, name = "anyone"), @JsonSubTypes.Type(value = PermissionSubject.JiraUser.class, name = "user"), @JsonSubTypes.Type(value = PermissionSubject.JiraGroup.class, name = "group"), @JsonSubTypes.Type(value = PermissionSubject.ProjectRole.class, name = "project.role") }) public abstract class PermissionSubject implements Cloneable { public abstract boolean matches(@Nullable ApplicationUser user); /** * @return a string representation of this permission subject * @see #fromEncodedString */ public abstract String toEncodedString(); /** * Creates a PermissionSubject based on the string representation. Null parameter yields null result. * Use this method only if user keys were used to encode user permissions. * * @param s string representation of the PermissionSubject * @return decoded PermissionSubject, or null if s was null or an empty string. * @throws ParseException if s was not null neither empty, but the code failed to decipher the string * @see #fromEncodedString(String, boolean) */ @Nullable public static PermissionSubject fromEncodedString(@Nullable String s) throws ParseException { return fromEncodedString(s, false); } /** * Creates a PermissionSubject based on the string representation. Null parameter yields null result. * * @param s string representation of the PermissionSubject * @param usersAsUserNames true if user names were used to encode user permissions (Structure version was less than 2.3), * false if user keys were used instead. * @return decoded PermissionSubject, or null if s was null or an empty string. * @throws ParseException if s was not null neither empty, but the code failed to decipher the string */ @Nullable public static PermissionSubject fromEncodedString(@Nullable String s, boolean usersAsUserNames) throws ParseException { if (s == null || s.length() == 0) return null; String p = removeStart(s, "anyone"); if (!p.equals(s)) return new Anyone(); p = removeStart(s, "user:"); if (!p.equals(s)) { if (usersAsUserNames) p = StructureUtil.migrateUserNameToUserKey(p); return new JiraUser(p); } p = removeStart(s, "group:"); if (!p.equals(s)) return new JiraGroup(p); p = removeStart(s, "role:"); if (!p.equals(s)) { int k = p.indexOf(':'); if (k < 0) return null; try { long project = Long.parseLong(p.substring(0, k)); long role = Long.parseLong(p.substring(k + 1)); return new ProjectRole(project, role); } catch (NumberFormatException e) { throw new ParseException(s, 0); } } throw new ParseException(s, 0); } /** * @return a clone of this subject */ @SuppressWarnings( {"CloneDoesntDeclareCloneNotSupportedException"}) public PermissionSubject clone() { // must be overridden - but defining here to get rid of CloneNotSupportedException try { return (PermissionSubject) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(e); } } public String toString() { return toEncodedString(); } /** * Calls an appropriate visitor method, passing this PermissionSubject and the carry parameter. * @return the result of the call * @since 7.2.0 (Structure 2.0) */ @Nullable public abstract T visit(Visitor visitor, @Nullable T carry); /** * Represents "anyone", a subject that would match all users, even anonymous. */ @XmlRootElement public static class Anyone extends PermissionSubject implements Serializable { public Anyone() { } public boolean matches(ApplicationUser user) { return true; } public String toEncodedString() { return "anyone"; } public boolean equals(Object obj) { return obj instanceof Anyone; } @Override public T visit(Visitor visitor, T carry) { return visitor.onAnyone(this, carry); } public int hashCode() { return Anyone.class.hashCode(); } } @Nullable public static PermissionSubject clone(@Nullable PermissionSubject owner) { return owner == null ? null : owner.clone(); } /** *

Represents a specific user in JIRA, matching only that user.

* *

A user is identified by the user key, introduced in JIRA 6. This is different from structure-api 7.x, which * used user name as the ID. As a result, serialized permission subjects from JIRA 5.x may not correctly * deserialize with this new version of the API - migration is needed. See {@link StructureUtil#migrateUserNameToUserKey(String)}.

*/ @XmlRootElement(name = "user") @XmlType(name = "user") public static class JiraUser extends PermissionSubject { @Nullable private String myUserKey; public JiraUser() { } public JiraUser(@Nullable String userKey) { myUserKey = userKey; } public JiraUser(@Nullable ApplicationUser user) { myUserKey = JiraUsers.getKeyFor(user); } @Nullable @XmlTransient @JsonIgnore public String getUserName() { return StructureUtil.getUserNameByKey(myUserKey); } @Nullable @XmlAttribute(name = "name") @JsonProperty("name") public String getUserKey() { return myUserKey; } public void setUserName(@Nullable String userName) { ApplicationUser user = StructureUtil.getApplicationUserByName(userName); myUserKey = StructureUtil.getUserKey(user); } public void setUserKey(@Nullable String userKey) { myUserKey = userKey; } public boolean matches(ApplicationUser user) { return myUserKey == null ? user == null : myUserKey.equals(JiraUsers.getKeyFor(user)); } public String toEncodedString() { return "user:" + myUserKey; } @Override public T visit(Visitor visitor, T carry) { return visitor.onUser(this, carry); } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; JiraUser jiraUser = (JiraUser) o; if (myUserKey != null ? !myUserKey.equals(jiraUser.myUserKey) : jiraUser.myUserKey != null) return false; return true; } public int hashCode() { return myUserKey != null ? myUserKey.hashCode() : 0; } } /** * Represents a specific group in JIRA, matching only the users that belong to that group. */ @XmlRootElement(name = "group") @XmlType(name = "group") public static class JiraGroup extends PermissionSubject { @Nullable private String myGroupName; public JiraGroup() { } public JiraGroup(@Nullable String groupName) { myGroupName = groupName; } public JiraGroup(@Nullable Group group) { myGroupName = group == null ? null : group.getName(); } @Nullable @XmlAttribute(name = "name") @JsonProperty("name") public String getGroupName() { return myGroupName; } public void setGroupName(@Nullable String groupName) { myGroupName = groupName; } public boolean matches(ApplicationUser user) { if (myGroupName == null || user == null) { return false; } return JiraComponents.getGroupManager().isUserInGroup(user, myGroupName); } public String toEncodedString() { return "group:" + myGroupName; } @Override public T visit(Visitor visitor, T carry) { return visitor.onGroup(this, carry); } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; JiraGroup jiraGroup = (JiraGroup) o; if (myGroupName != null ? !myGroupName.equals(jiraGroup.myGroupName) : jiraGroup.myGroupName != null) return false; return true; } public int hashCode() { return myGroupName != null ? myGroupName.hashCode() : 0; } } /** * Represents a specific project role in a specific project, matching the users that belong to that project role * in that project. */ @XmlRootElement(name = "role") @XmlType(name = "role") public static class ProjectRole extends PermissionSubject { private long myProjectId; private long myRoleId; public ProjectRole() { } public ProjectRole(long projectId, long roleId) { myProjectId = projectId; myRoleId = roleId; } @XmlAttribute @JsonProperty("project") public long getProjectId() { return myProjectId; } public void setProjectId(long projectId) { myProjectId = projectId; } @XmlAttribute @JsonProperty("role") public long getRoleId() { return myRoleId; } public void setRoleId(long roleId) { myRoleId = roleId; } public boolean matches(ApplicationUser user) { if (myRoleId == 0) { return false; } ProjectRoleManager rm = JiraComponents.getComponentOfType(ProjectRoleManager.class); com.atlassian.jira.security.roles.ProjectRole role = rm.getProjectRole(myRoleId); if (role == null) { return false; } List projects; if (myProjectId == 0) { StructureConfiguration configuration = JiraComponents.getOSGiComponentInstanceOfType(StructureConfiguration.class); if (configuration == null) { return false; } projects = configuration.getCurrentlyEnabledProjects(); } else { ProjectManager pm = JiraComponents.getProjectManager(); Project project = pm.getProjectObj(myProjectId); projects = project == null ? Collections.emptyList() : Collections.singletonList(project); } for (Project project : projects) { if (rm.isUserInProjectRole(user, role, project)) { return true; } } return false; } public String toEncodedString() { return "role:" + myProjectId + ":" + myRoleId; } @Override public T visit(Visitor visitor, T carry) { return visitor.onProjectRole(this, carry); } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ProjectRole that = (ProjectRole) o; if (myProjectId != that.myProjectId) return false; if (myRoleId != that.myRoleId) return false; return true; } public int hashCode() { int result = (int) (myProjectId ^ (myProjectId >>> 32)); result = 31 * result + (int) (myRoleId ^ (myRoleId >>> 32)); return result; } } /** * Used to visit specific subtypes of {@link PermissionSubject}. * * @param arbitrary type used to pass a value in and out of visitor (carry). Use {@link Visitor.NoCarry} if you * don't need it. */ public interface Visitor { T onAnyone(Anyone anyone, T carry); T onUser(JiraUser user, T carry); T onGroup(JiraGroup group, T carry); T onProjectRole(ProjectRole projectRole, T carry); public static abstract class NoCarry implements Visitor { public abstract void onAnyone(Anyone anyone); public abstract void onUser(JiraUser user); public abstract void onGroup(JiraGroup group); public abstract void onProjectRole(ProjectRole projectRole); @Override public Void onAnyone(Anyone anyone, Void carry) { onAnyone(anyone); return carry; } @Override public Void onUser(JiraUser user, Void carry) { onUser(user); return carry; } @Override public Void onGroup(JiraGroup group, Void carry) { onGroup(group); return carry; } @Override public Void onProjectRole(ProjectRole projectRole, Void carry) { onProjectRole(projectRole); return carry; } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy