diff --git a/core/src/main/java/hudson/DependencyRunner.java b/core/src/main/java/hudson/DependencyRunner.java index 449c7e0e73df3094c78ecb335088c07093f94bdb..bd4282f8c209bc8012d02ceb2ff16b913725c41b 100644 --- a/core/src/main/java/hudson/DependencyRunner.java +++ b/core/src/main/java/hudson/DependencyRunner.java @@ -36,6 +36,7 @@ import java.util.Collection; import java.util.logging.Logger; import org.acegisecurity.Authentication; +import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; /** @@ -54,9 +55,7 @@ public class DependencyRunner implements Runnable { } public void run() { - Authentication saveAuth = SecurityContextHolder.getContext().getAuthentication(); - SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); - + SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM); try { Set topLevelProjects = new HashSet(); // Get all top-level projects @@ -74,7 +73,7 @@ public class DependencyRunner implements Runnable { runnable.run(p); } } finally { - SecurityContextHolder.getContext().setAuthentication(saveAuth); + SecurityContextHolder.setContext(oldContext); } } diff --git a/core/src/main/java/hudson/model/AsyncAperiodicWork.java b/core/src/main/java/hudson/model/AsyncAperiodicWork.java index fceb25a065d652dcd8cb8e59745afebb752c5960..f46dd33b61d835eec945fec60f76975809d9c3de 100644 --- a/core/src/main/java/hudson/model/AsyncAperiodicWork.java +++ b/core/src/main/java/hudson/model/AsyncAperiodicWork.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.util.logging.Level; import jenkins.model.Jenkins; +import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; /** @@ -70,8 +71,8 @@ public abstract class AsyncAperiodicWork extends AperiodicWork { StreamTaskListener l = createListener(); try { - SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); - + ACL.impersonate(ACL.SYSTEM); + execute(l); } catch (IOException e) { e.printStackTrace(l.fatalError(e.getMessage())); diff --git a/core/src/main/java/hudson/model/AsyncPeriodicWork.java b/core/src/main/java/hudson/model/AsyncPeriodicWork.java index 2c89594643f1e8150913ecb6da1c2d6bc667e31f..52fdb148a1b703e4c44d3036592b824826a4271b 100644 --- a/core/src/main/java/hudson/model/AsyncPeriodicWork.java +++ b/core/src/main/java/hudson/model/AsyncPeriodicWork.java @@ -3,6 +3,7 @@ package hudson.model; import hudson.security.ACL; import hudson.util.StreamTaskListener; import jenkins.model.Jenkins; +import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; import java.io.File; @@ -47,8 +48,8 @@ public abstract class AsyncPeriodicWork extends PeriodicWork { StreamTaskListener l = createListener(); try { - SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); - + ACL.impersonate(ACL.SYSTEM); + execute(l); } catch (IOException e) { e.printStackTrace(l.fatalError(e.getMessage())); diff --git a/core/src/main/java/hudson/model/DependencyGraph.java b/core/src/main/java/hudson/model/DependencyGraph.java index c24ba0f96d0fcd87864f54316e830b70cbc0174c..2b1a7db304266808dba610074d934676d2e3634b 100644 --- a/core/src/main/java/hudson/model/DependencyGraph.java +++ b/core/src/main/java/hudson/model/DependencyGraph.java @@ -84,12 +84,9 @@ public class DependencyGraph implements Comparator { public void build() { // Set full privileges while computing to avoid missing any projects the current user cannot see. // Use setContext (NOT getContext().setAuthentication()) so we don't affect concurrent threads for same HttpSession. - SecurityContext saveCtx = SecurityContextHolder.getContext(); + SecurityContext saveCtx = ACL.impersonate(ACL.SYSTEM); try { this.computationalData = new HashMap, Object>(); - NotSerilizableSecurityContext system = new NotSerilizableSecurityContext(); - system.setAuthentication(ACL.SYSTEM); - SecurityContextHolder.setContext(system); for( AbstractProject p : getAllProjects() ) p.buildDependencyGraph(this); diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index 36cc8bcbdf24a27431833622704290956edb83a2..1815a31db84017a3f8f3db0ab6d6bc5a6caad3ce 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -38,6 +38,7 @@ import hudson.security.ACL; import jenkins.model.InterruptedBuildAction; import jenkins.model.Jenkins; import org.acegisecurity.Authentication; +import org.acegisecurity.context.SecurityContext; import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; @@ -175,7 +176,7 @@ public class Executor extends Thread implements ModelObject { @Override public void run() { // run as the system user. see ACL.SYSTEM for more discussion about why this is somewhat broken - SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); + ACL.impersonate(ACL.SYSTEM); try { finishTime = System.currentTimeMillis(); diff --git a/core/src/main/java/hudson/model/UpdateCenter.java b/core/src/main/java/hudson/model/UpdateCenter.java index 03e95315fc160ebefe33a6a2c7dc9121d9697942..7c3f779d24e6520c48c1327d1617ad462f03d750 100644 --- a/core/src/main/java/hudson/model/UpdateCenter.java +++ b/core/src/main/java/hudson/model/UpdateCenter.java @@ -48,6 +48,7 @@ import hudson.util.XStream2; import jenkins.RestartRequiredException; import jenkins.model.Jenkins; import org.acegisecurity.Authentication; +import org.acegisecurity.context.SecurityContext; import org.apache.commons.io.input.CountingInputStream; import org.apache.commons.io.output.NullOutputStream; import org.jvnet.localizer.Localizable; @@ -1121,13 +1122,14 @@ public class UpdateCenter extends AbstractModelObject implements Saveable { // if this is a bundled plugin, make sure it won't get overwritten PluginWrapper pw = plugin.getInstalled(); - if (pw!=null && pw.isBundled()) + if (pw!=null && pw.isBundled()) { + SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM); try { - SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); pw.doPin(); } finally { - SecurityContextHolder.clearContext(); + SecurityContextHolder.setContext(oldContext); } + } if (dynamicLoad) { try { diff --git a/core/src/main/java/hudson/security/ACL.java b/core/src/main/java/hudson/security/ACL.java index 56fa04c62682be3ff9199b3c914be7a8f2b867a8..1d4e47992e5784e5271730b4765467e80630062e 100644 --- a/core/src/main/java/hudson/security/ACL.java +++ b/core/src/main/java/hudson/security/ACL.java @@ -26,6 +26,8 @@ package hudson.security; import jenkins.model.Jenkins; import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; +import org.acegisecurity.context.SecurityContext; +import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.acls.sid.PrincipalSid; import org.acegisecurity.acls.sid.Sid; @@ -113,4 +115,22 @@ public abstract class ACL { * the user who triggered a build.) */ public static final Authentication SYSTEM = new UsernamePasswordAuthenticationToken("SYSTEM","SYSTEM"); + + /** + * Changes the {@link Authentication} associated with the current thread + * to the specified one, and returns the previous security context. + * + *

+ * When the impersonation is over, be sure to restore the previous authentication + * via {@code SecurityContextHolder.setContext(returnValueFromThisMethod)}. + * + *

+ * We need to create a new {@link SecurityContext} instead of {@link SecurityContext#setAuthentication(Authentication)} + * because the same {@link SecurityContext} object is reused for all the concurrent requests from the same session. + */ + public static SecurityContext impersonate(Authentication auth) { + SecurityContext old = SecurityContextHolder.getContext(); + SecurityContextHolder.setContext(new NotSerilizableSecurityContext(ACL.SYSTEM)); + return old; + } } diff --git a/core/src/main/java/hudson/triggers/SafeTimerTask.java b/core/src/main/java/hudson/triggers/SafeTimerTask.java index a331c4e089bc2bc10e405bfda37b5e8d2710ed2d..49524fbec0b66bbabb07715c033cdd6137cb792c 100644 --- a/core/src/main/java/hudson/triggers/SafeTimerTask.java +++ b/core/src/main/java/hudson/triggers/SafeTimerTask.java @@ -23,6 +23,7 @@ */ package hudson.triggers; +import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; import java.util.Timer; @@ -48,14 +49,13 @@ public abstract class SafeTimerTask extends TimerTask { public final void run() { // background activity gets system credential, // just like executors get it. - SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM); - + SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM); try { doRun(); } catch(Throwable t) { LOGGER.log(Level.SEVERE, "Timer task "+this+" failed",t); } finally { - SecurityContextHolder.clearContext(); + SecurityContextHolder.setContext(oldContext); } } diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index d9a4ef1e93619852847f0913108cc3e9a1662799..111ff4f8fcdfe3d1d3ff69537c4bccbde0639e6d 100755 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -200,6 +200,7 @@ import org.acegisecurity.AcegiSecurityException; import org.acegisecurity.Authentication; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; +import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken; import org.acegisecurity.ui.AbstractProcessingFilter; @@ -702,7 +703,7 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup