Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/jenkinsci/ownership-plugin
Browse files Browse the repository at this point in the history
…into folder-specific-security

# Conflicts:
#	src/main/java/com/synopsys/arc/jenkins/plugins/ownership/util/AbstractOwnershipHelper.java
#	src/main/java/org/jenkinsci/plugins/ownership/model/folders/FolderOwnershipHelper.java
  • Loading branch information
SofteqDG committed Jun 18, 2018
2 parents 67df14b + 2be2bd8 commit e1c0abf
Show file tree
Hide file tree
Showing 13 changed files with 411 additions and 36 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
@@ -1,6 +1,17 @@
Changelog
-----

### 0.12.1

Release date: Apr 30, 2018

* [JENKINS-49744](https://issues.jenkins-ci.org/browse/JENKINS-49744) -
Users with `Manage Ownership` permissions were unable to change Foler ownership from CLI/REST API without `Jenkins/Administer` persiossion.
* [JENKINS-50807](https://issues.jenkins-ci.org/browse/JENKINS-50807) -
Add missing implementations for [OwnershipHelperLocator](https://jenkins.io/doc/developer/extensions/ownership/#ownershiphelperlocator)
extension point.
Now the API can be used to retrieve ownership info for any object.

### 0.12.0

Release date: Feb 26, 2018
Expand Down
7 changes: 4 additions & 3 deletions pom.xml
Expand Up @@ -3,16 +3,16 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>2.37</version>
<version>3.5</version>
</parent>

<groupId>com.synopsys.jenkinsci</groupId>
<artifactId>ownership</artifactId>
<version>0.12.1-SNAPSHOT</version>
<version>0.12.2-SNAPSHOT</version>
<name>Job and Node ownership plugin</name>
<packaging>hpi</packaging>
<description>Provides explicit ownership of jobs and nodes</description>
<url>https://wiki.jenkins-ci.org/display/JENKINS/Ownership+Plugin</url>
<url>https://wiki.jenkins.io/display/JENKINS/Ownership+Plugin</url>

<licenses>
<license>
Expand All @@ -27,6 +27,7 @@
<java.level>7</java.level>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<workflow.version>1.14</workflow.version>
<findbugs.effort>Max</findbugs.effort>
</properties>

<developers>
Expand Down
Expand Up @@ -23,16 +23,14 @@
*/
package com.synopsys.arc.jenkins.plugins.ownership;

import com.synopsys.arc.jenkins.plugins.ownership.jobs.JobOwnerJobProperty;
import com.synopsys.arc.jenkins.plugins.ownership.util.AbstractOwnershipHelper;
import com.synopsys.arc.jenkins.plugins.ownership.util.IdStrategyComparator;
import com.synopsys.arc.jenkins.plugins.ownership.util.OwnershipDescriptionHelper;
import com.synopsys.arc.jenkins.plugins.ownership.nodes.OwnerNodeProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Util;
import hudson.model.Computer;
import hudson.model.Descriptor;
import hudson.model.Job;
import hudson.model.Node;
import hudson.model.ModelObject;
import hudson.model.User;
import hudson.security.ACL;
import hudson.security.AccessControlled;
Expand All @@ -44,13 +42,16 @@
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.jenkinsci.plugins.ownership.model.OwnershipHelperLocator;
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
Expand All @@ -62,6 +63,9 @@
* @since 0.0.3
*/
public class OwnershipDescription implements Serializable {

private static final Logger LOGGER = Logger.getLogger(OwnershipDescription.class.getName());

/**
* Disabled description, which means that ownership is disabled
*/
Expand Down Expand Up @@ -392,41 +396,45 @@ private void checkUnsecuredConfiguration() throws ObjectStreamException {
StaplerRequest request = Stapler.getCurrentRequest();
if (request != null) {
AccessControlled context = request.findAncestorObject(AccessControlled.class);
if (context instanceof Job) {
Job<?, ?> job = (Job)context;
JobOwnerJobProperty existing = job.getProperty(JobOwnerJobProperty.class);
if (existing == null || !Objects.equals(existing.getOwnership(), this)) {
throwIfMissingPermission(job, OwnershipPlugin.MANAGE_ITEMS_OWNERSHIP);
}
return;
} else if (context instanceof Computer) {
Node node = ((Computer)context).getNode();
if (node != null) {
OwnerNodeProperty existing = node.getNodeProperties().get(OwnerNodeProperty.class);
if (existing == null || !Objects.equals(existing.getOwnership(), this)) {
throwIfMissingPermission(node, OwnershipPlugin.MANAGE_SLAVES_OWNERSHIP);
if (context != null) {
final AbstractOwnershipHelper<AccessControlled> helper = OwnershipHelperLocator.locate(context);
if (helper != null) {
final OwnershipDescription d = helper.getOwnershipDescription(context);
if (!helper.hasLocallyDefinedOwnership(context) || !Objects.equals(d, this)) {
throwIfMissingPermission(context, helper.getRequiredPermission());
}
return;
} else {
LOGGER.log(Level.WARNING, "Cannot locate OwnershipHelperClass for object {0}. " +
"Jenkins.ADMINISTER permissions will be required to change ownership", context);
}
} else if (context instanceof Node) {
Node node = ((Node)context);
OwnerNodeProperty existing = node.getNodeProperties().get(OwnerNodeProperty.class);
if (existing == null || !Objects.equals(existing.getOwnership(), this)) {
throwIfMissingPermission(node, OwnershipPlugin.MANAGE_SLAVES_OWNERSHIP);
}
return;
} else {
//TODO: maybe it should rejected, because there is no use-cases for it so far AFAIK
LOGGER.log(Level.WARNING, "Ownership Description is used outside the object context. " +
"Jenkins.ADMINISTER permissions will be required to change ownership");
}
}
// We don't know what object this OwnershipDescription belongs to, so we require Overall/Administer permissions.
// CLI commands always use this check.
throwIfMissingPermission(Jenkins.getActiveInstance(), Jenkins.ADMINISTER);
}

private void throwIfMissingPermission(AccessControlled context, Permission permission) throws ObjectStreamException {
private void throwIfMissingPermission(@Nonnull AccessControlled context, Permission permission) throws ObjectStreamException {
try {
context.checkPermission(permission);
} catch (AccessDeniedException e) {
throw new InvalidObjectException(e.getMessage());
final String name;
if (context instanceof ModelObject) {
name = ((ModelObject)context).getDisplayName();
} else {
name = context.toString();
}

InvalidObjectException ex = new InvalidObjectException(
String.format("Cannot modify permissions of %s of type %s: %s", name,
context.getClass(), e.getMessage()));
ex.addSuppressed(e);
throw ex;
}
}

Expand Down
Expand Up @@ -43,9 +43,13 @@
import java.util.Collection;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import hudson.security.Permission;
import org.jenkinsci.plugins.ownership.model.OwnershipHelperLocator;
import org.jenkinsci.plugins.ownership.model.OwnershipInfo;
import org.jenkinsci.plugins.ownership.model.jobs.JobOwnershipDescriptionSource;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
* Helper for Jobs Ownership.
Expand Down Expand Up @@ -95,6 +99,16 @@ public static boolean isUserExists(@Nonnull String userIdOrFullName) {
return getOwnershipInfo(job).getDescription();
}

@Override
public Permission getRequiredPermission() {
return OwnershipPlugin.MANAGE_ITEMS_OWNERSHIP;
}

@Override
public boolean hasLocallyDefinedOwnership(@Nonnull Job<?, ?> job) {
return getOwnerProperty(job) != null;
}

@Override
public OwnershipInfo getOwnershipInfo(Job<?, ?> job) {
JobOwnerJobProperty prop = getOwnerProperty(job);
Expand Down Expand Up @@ -199,6 +213,7 @@ public String getItemURL(Job<?, ?> item) {
}

@Extension
@Restricted(NoExternalUse.class)
public static class LocatorImpl extends OwnershipHelperLocator<Job<?,?>> {

@Override
Expand Down
Expand Up @@ -24,7 +24,9 @@
package com.synopsys.arc.jenkins.plugins.ownership.nodes;

import com.synopsys.arc.jenkins.plugins.ownership.OwnershipDescription;
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipPlugin;
import com.synopsys.arc.jenkins.plugins.ownership.util.AbstractOwnershipHelper;
import hudson.Extension;
import hudson.model.Computer;
import hudson.model.Node;
import hudson.model.User;
Expand All @@ -33,7 +35,12 @@
import java.util.Collections;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import hudson.security.Permission;
import org.jenkinsci.plugins.ownership.model.OwnershipHelperLocator;
import org.jenkinsci.plugins.ownership.model.OwnershipInfo;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
* Provides ownership helper for {@link Computer}.
Expand Down Expand Up @@ -83,6 +90,21 @@ public static void setOwnership(@Nonnull Computer computer,
NodeOwnerHelper.setOwnership(node, descr);
}

@Override
public Permission getRequiredPermission() {
return OwnershipPlugin.MANAGE_SLAVES_OWNERSHIP;
}

@Override
public boolean hasLocallyDefinedOwnership(@Nonnull Computer computer) {
Node node = computer.getNode();
if (node == null) {
// Node is not defined => permission is detached
return false;
}
return NodeOwnerHelper.Instance.hasLocallyDefinedOwnership(node);
}

@Override
public String getItemTypeName(Computer item) {
return "computer";
Expand All @@ -98,4 +120,17 @@ public String getItemURL(Computer item) {
//TODO: Absolute URL
return item.getUrl();
}

@Extension
@Restricted(NoExternalUse.class)
public static class LocatorImpl extends OwnershipHelperLocator<Computer> {

@Override
public AbstractOwnershipHelper<Computer> findHelper(Object item) {
if (item instanceof Computer) {
return INSTANCE;
}
return null;
}
}
}
Expand Up @@ -29,16 +29,23 @@
import com.synopsys.arc.jenkins.plugins.ownership.util.UserCollectionFilter;
import com.synopsys.arc.jenkins.plugins.ownership.util.userFilters.AccessRightsFilter;
import com.synopsys.arc.jenkins.plugins.ownership.util.userFilters.IUserFilter;
import hudson.Extension;
import hudson.model.Computer;
import hudson.model.Job;
import hudson.model.Node;
import hudson.model.User;

import java.io.IOException;
import java.util.Collection;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import hudson.security.Permission;
import org.jenkinsci.plugins.ownership.model.OwnershipHelperLocator;
import org.jenkinsci.plugins.ownership.model.OwnershipInfo;
import org.jenkinsci.plugins.ownership.model.nodes.NodeOwnershipDescriptionSource;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
* Provides helper for Node owner.
Expand Down Expand Up @@ -83,7 +90,17 @@ public OwnershipInfo getOwnershipInfo(Node item) {
return prop != null ? new OwnershipInfo(OwnershipDescription.DISABLED_DESCR,
new NodeOwnershipDescriptionSource(item)) : OwnershipInfo.DISABLED_INFO;
}


@Override
public Permission getRequiredPermission() {
return OwnershipPlugin.MANAGE_SLAVES_OWNERSHIP;
}

@Override
public boolean hasLocallyDefinedOwnership(@Nonnull Node node) {
return getOwnerProperty(node) != null;
}

@Override
public Collection<User> getPossibleOwners(Node item) {
if (OwnershipPlugin.getInstance().isRequiresConfigureRights()) {
Expand Down Expand Up @@ -126,4 +143,17 @@ public String getItemURL(Node item) {
Computer c = item.toComputer();
return c != null ? ComputerOwnerHelper.INSTANCE.getItemURL(c) : null;
}

@Extension
@Restricted(NoExternalUse.class)
public static class LocatorImpl extends OwnershipHelperLocator<Node> {

@Override
public AbstractOwnershipHelper<Node> findHelper(Object item) {
if (item instanceof Node) {
return Instance;
}
return null;
}
}
}
Expand Up @@ -27,14 +27,21 @@
import com.synopsys.arc.jenkins.plugins.ownership.OwnershipPlugin;
import com.synopsys.arc.jenkins.plugins.ownership.util.AbstractOwnershipHelper;
import com.synopsys.arc.jenkins.plugins.ownership.util.UserCollectionFilter;
import hudson.Extension;
import hudson.model.Job;
import hudson.model.Node;
import hudson.model.User;
import hudson.security.Permission;
import hudson.slaves.NodeProperty;
import java.util.Collection;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import org.jenkinsci.plugins.ownership.model.OwnershipHelperLocator;
import org.jenkinsci.plugins.ownership.model.OwnershipInfo;
import org.jenkinsci.plugins.ownership.model.nodes.NodeOwnershipDescriptionSource;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
* Provides helper for Node owner
Expand Down Expand Up @@ -94,6 +101,17 @@ public Collection<User> getPossibleOwners(NodeProperty item) {
return null;
}

@Override
public Permission getRequiredPermission() {
return OwnershipPlugin.MANAGE_SLAVES_OWNERSHIP;
}

@Override
public boolean hasLocallyDefinedOwnership(@Nonnull NodeProperty item) {
// Self-defined
return true;
}

@Override
public String getItemTypeName(NodeProperty item) {
return NodeOwnerHelper.ITEM_TYPE_NAME;
Expand All @@ -109,5 +127,18 @@ public String getItemDisplayName(NodeProperty item) {
public String getItemURL(NodeProperty item) {
Node node = getNode(item);
return node != null ? NodeOwnerHelper.Instance.getItemURL(node) : null;
}
}

@Extension
@Restricted(NoExternalUse.class)
public static class LocatorImpl extends OwnershipHelperLocator<NodeProperty> {

@Override
public AbstractOwnershipHelper<NodeProperty> findHelper(Object item) {
if (item instanceof NodeProperty) {
return Instance;
}
return null;
}
}
}

0 comments on commit e1c0abf

Please sign in to comment.