提交 6fb9e91b 编写于 作者: J Jesse Glick 提交者: Oleg Nenashev

[JENKINS-41684] Ensure that PluginManager.dynamicLoad runs as SYSTEM (#2732)

* [FIXED JENKINS-41684] Ensure that PluginManager.dynamicLoad runs as SYSTEM.
Test plugin source:
package test;
import hudson.Plugin;
import jenkins.model.Jenkins;
public class ThePlugin extends Plugin {
    @Override
    public void postInitialize() throws Exception {
        Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
    }
}

* @daniel-beck wants this all reindented.
上级 f8b26a3b
...@@ -819,100 +819,102 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas ...@@ -819,100 +819,102 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
*/ */
@Restricted(NoExternalUse.class) @Restricted(NoExternalUse.class)
public void dynamicLoad(File arc, boolean removeExisting) throws IOException, InterruptedException, RestartRequiredException { public void dynamicLoad(File arc, boolean removeExisting) throws IOException, InterruptedException, RestartRequiredException {
LOGGER.info("Attempting to dynamic load "+arc); try (ACLContext context = ACL.as(ACL.SYSTEM)) {
PluginWrapper p = null; LOGGER.info("Attempting to dynamic load "+arc);
String sn; PluginWrapper p = null;
try { String sn;
sn = strategy.getShortName(arc); try {
} catch (AbstractMethodError x) { sn = strategy.getShortName(arc);
LOGGER.log(WARNING, "JENKINS-12753 fix not active: {0}", x.getMessage()); } catch (AbstractMethodError x) {
p = strategy.createPluginWrapper(arc); LOGGER.log(WARNING, "JENKINS-12753 fix not active: {0}", x.getMessage());
sn = p.getShortName(); p = strategy.createPluginWrapper(arc);
} sn = p.getShortName();
PluginWrapper pw = getPlugin(sn); }
if (pw!=null) { PluginWrapper pw = getPlugin(sn);
if (removeExisting) { // try to load disabled plugins if (pw!=null) {
for (Iterator<PluginWrapper> i = plugins.iterator(); i.hasNext();) { if (removeExisting) { // try to load disabled plugins
pw = i.next(); for (Iterator<PluginWrapper> i = plugins.iterator(); i.hasNext();) {
if(sn.equals(pw.getShortName())) { pw = i.next();
i.remove(); if(sn.equals(pw.getShortName())) {
pw = null; i.remove();
break; pw = null;
break;
}
} }
} else {
throw new RestartRequiredException(Messages._PluginManager_PluginIsAlreadyInstalled_RestartRequired(sn));
} }
} else {
throw new RestartRequiredException(Messages._PluginManager_PluginIsAlreadyInstalled_RestartRequired(sn));
} }
} if (p == null) {
if (p == null) { p = strategy.createPluginWrapper(arc);
p = strategy.createPluginWrapper(arc); }
} if (p.supportsDynamicLoad()== YesNoMaybe.NO)
if (p.supportsDynamicLoad()== YesNoMaybe.NO) throw new RestartRequiredException(Messages._PluginManager_PluginDoesntSupportDynamicLoad_RestartRequired(sn));
throw new RestartRequiredException(Messages._PluginManager_PluginDoesntSupportDynamicLoad_RestartRequired(sn));
// there's no need to do cyclic dependency check, because we are deploying one at a time, // there's no need to do cyclic dependency check, because we are deploying one at a time,
// so existing plugins can't be depending on this newly deployed one. // so existing plugins can't be depending on this newly deployed one.
plugins.add(p); plugins.add(p);
if (p.isActive()) if (p.isActive())
activePlugins.add(p); activePlugins.add(p);
synchronized (((UberClassLoader) uberClassLoader).loaded) { synchronized (((UberClassLoader) uberClassLoader).loaded) {
((UberClassLoader) uberClassLoader).loaded.clear(); ((UberClassLoader) uberClassLoader).loaded.clear();
} }
try {
p.resolvePluginDependencies();
strategy.load(p);
Jenkins.getInstance().refreshExtensions(); try {
p.resolvePluginDependencies();
strategy.load(p);
p.getPlugin().postInitialize(); Jenkins.getInstance().refreshExtensions();
} catch (Exception e) {
failedPlugins.add(new FailedPlugin(sn, e));
activePlugins.remove(p);
plugins.remove(p);
throw new IOException("Failed to install "+ sn +" plugin",e);
}
// run initializers in the added plugin p.getPlugin().postInitialize();
Reactor r = new Reactor(InitMilestone.ordering()); } catch (Exception e) {
final ClassLoader loader = p.classLoader; failedPlugins.add(new FailedPlugin(sn, e));
r.addAll(new InitializerFinder(loader) { activePlugins.remove(p);
@Override plugins.remove(p);
protected boolean filter(Method e) { throw new IOException("Failed to install "+ sn +" plugin",e);
return e.getDeclaringClass().getClassLoader() != loader || super.filter(e);
} }
}.discoverTasks(r));
try {
new InitReactorRunner().run(r);
} catch (ReactorException e) {
throw new IOException("Failed to initialize "+ sn +" plugin",e);
}
// recalculate dependencies of plugins optionally depending the newly deployed one. // run initializers in the added plugin
for (PluginWrapper depender: plugins) { Reactor r = new Reactor(InitMilestone.ordering());
if (depender.equals(p)) { final ClassLoader loader = p.classLoader;
// skip itself. r.addAll(new InitializerFinder(loader) {
continue; @Override
protected boolean filter(Method e) {
return e.getDeclaringClass().getClassLoader() != loader || super.filter(e);
}
}.discoverTasks(r));
try {
new InitReactorRunner().run(r);
} catch (ReactorException e) {
throw new IOException("Failed to initialize "+ sn +" plugin",e);
} }
for (Dependency d: depender.getOptionalDependencies()) {
if (d.shortName.equals(p.getShortName())) { // recalculate dependencies of plugins optionally depending the newly deployed one.
// this plugin depends on the newly loaded one! for (PluginWrapper depender: plugins) {
// recalculate dependencies! if (depender.equals(p)) {
try { // skip itself.
getPluginStrategy().updateDependency(depender, p); continue;
} catch (AbstractMethodError x) { }
LOGGER.log(WARNING, "{0} does not yet implement updateDependency", getPluginStrategy().getClass()); for (Dependency d: depender.getOptionalDependencies()) {
if (d.shortName.equals(p.getShortName())) {
// this plugin depends on the newly loaded one!
// recalculate dependencies!
try {
getPluginStrategy().updateDependency(depender, p);
} catch (AbstractMethodError x) {
LOGGER.log(WARNING, "{0} does not yet implement updateDependency", getPluginStrategy().getClass());
}
break;
} }
break;
} }
} }
}
// Redo who depends on who. // Redo who depends on who.
resolveDependantPlugins(); resolveDependantPlugins();
LOGGER.info("Plugin " + p.getShortName()+":"+p.getVersion() + " dynamically installed"); LOGGER.info("Plugin " + p.getShortName()+":"+p.getVersion() + " dynamically installed");
}
} }
@Restricted(NoExternalUse.class) @Restricted(NoExternalUse.class)
......
...@@ -30,7 +30,10 @@ import hudson.model.Hudson; ...@@ -30,7 +30,10 @@ import hudson.model.Hudson;
import hudson.model.UpdateCenter; import hudson.model.UpdateCenter;
import hudson.model.UpdateCenter.UpdateCenterJob; import hudson.model.UpdateCenter.UpdateCenterJob;
import hudson.model.UpdateSite; import hudson.model.UpdateSite;
import hudson.model.User;
import hudson.scm.SubversionSCM; import hudson.scm.SubversionSCM;
import hudson.security.ACL;
import hudson.security.ACLContext;
import hudson.util.FormValidation; import hudson.util.FormValidation;
import hudson.util.PersistedList; import hudson.util.PersistedList;
import java.io.File; import java.io.File;
...@@ -53,6 +56,7 @@ import org.junit.Test; ...@@ -53,6 +56,7 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.Url; import org.jvnet.hudson.test.Url;
import org.jvnet.hudson.test.recipes.WithPlugin; import org.jvnet.hudson.test.recipes.WithPlugin;
import org.jvnet.hudson.test.recipes.WithPluginManager; import org.jvnet.hudson.test.recipes.WithPluginManager;
...@@ -444,6 +448,16 @@ public class PluginManagerTest { ...@@ -444,6 +448,16 @@ public class PluginManagerTest {
assertTrue(pluginInfo.getString("dependencies") != null); assertTrue(pluginInfo.getString("dependencies") != null);
} }
@Issue("JENKINS-41684")
@Test
public void requireSystemDuringLoad() throws Exception {
r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy());
try (ACLContext context = ACL.as(User.get("underprivileged").impersonate())) {
dynamicLoad("require-system-during-load.hpi");
}
}
private void dynamicLoad(String plugin) throws IOException, InterruptedException, RestartRequiredException { private void dynamicLoad(String plugin) throws IOException, InterruptedException, RestartRequiredException {
PluginManagerUtil.dynamicLoad(plugin, r.jenkins); PluginManagerUtil.dynamicLoad(plugin, r.jenkins);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册