Skip to content
Permalink
Browse files

[JENKINS-22949] BuildTrigger & ReverseBuildTrigger should respect Que…

…ueItemAuthenticatorConfiguration (#2881)

* [JENKINS-22949] Simplifying behavior of BuildTrigger & ReverseBuildTrigger to honor QueueItemAuthenticator’s as defined, rather than falling back to anonymous.

* There is no need to impersonate what is already the current thread’s authentication.
  • Loading branch information
jglick authored and oleg-nenashev committed May 19, 2017
1 parent 33afbcc commit 915543dca5399d3ba052219ddfe9c3c061e70726
@@ -64,11 +64,14 @@
import java.util.logging.Logger;

import static hudson.model.queue.Executables.*;
import hudson.security.ACLContext;
import java.util.Collection;
import static java.util.logging.Level.*;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jenkins.model.queue.AsynchronousExecution;
import jenkins.security.QueueItemAuthenticatorConfiguration;
import jenkins.security.QueueItemAuthenticatorDescriptor;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

@@ -398,11 +401,21 @@ public SubTask call() throws Exception {
}
}

ACL.impersonate(workUnit.context.item.authenticate());
setName(getName() + " : executing " + executable.toString());
if (LOGGER.isLoggable(FINE))
LOGGER.log(FINE, getName()+" is now executing "+executable);
queue.execute(executable, task);
Authentication auth = workUnit.context.item.authenticate();
LOGGER.log(FINE, "{0} is now executing {1} as {2}", new Object[] {getName(), executable, auth});
if (LOGGER.isLoggable(FINE) && auth.equals(ACL.SYSTEM)) { // i.e., unspecified
if (QueueItemAuthenticatorDescriptor.all().isEmpty()) {
LOGGER.fine("no QueueItemAuthenticator implementations installed");
} else if (QueueItemAuthenticatorConfiguration.get().getAuthenticators().isEmpty()) {
LOGGER.fine("no QueueItemAuthenticator implementations configured");
} else {
LOGGER.log(FINE, "some QueueItemAuthenticator implementations configured but neglected to authenticate {0}", executable);
}
}
try (ACLContext context = ACL.as(auth)) {
queue.execute(executable, task);
}
} catch (AsynchronousExecution x) {
lock.writeLock().lock();
try {
@@ -63,13 +63,9 @@
import jenkins.model.DependencyDeclarer;
import jenkins.model.Jenkins;
import jenkins.model.ParameterizedJobMixIn;
import jenkins.security.QueueItemAuthenticatorConfiguration;
import jenkins.security.QueueItemAuthenticatorDescriptor;
import jenkins.triggers.ReverseBuildTrigger;
import net.sf.json.JSONObject;
import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.AncestorInPath;
@@ -270,53 +266,24 @@ public int compare(Dependency lhs, Dependency rhs) {
}
});

Authentication auth = Jenkins.getAuthentication(); // from build
if (auth.equals(ACL.SYSTEM)) { // i.e., unspecified
if (QueueItemAuthenticatorDescriptor.all().isEmpty()) {
if (downstreamProjects.isEmpty()) {
return true;
}
logger.println(Messages.BuildTrigger_warning_you_have_no_plugins_providing_ac());
} else if (QueueItemAuthenticatorConfiguration.get().getAuthenticators().isEmpty()) {
if (downstreamProjects.isEmpty()) {
return true;
}
logger.println(Messages.BuildTrigger_warning_access_control_for_builds_in_glo());
} else {
// This warning must be printed even if downstreamProjects is empty.
// Otherwise you could effectively escalate DISCOVER to READ just by trying different project names and checking whether a warning was printed or not.
// If there were an API to determine whether any DependencyDeclarer’s in this project requested downstream project names,
// then we could suppress the warnings in case none did; but if any do, yet Items.fromNameList etc. ignore unknown projects,
// that has to be treated the same as if there really are downstream projects but the anonymous user cannot see them.
// For the above two cases, it is OK to suppress the warning when there are no downstream projects, since running as SYSTEM we would be able to see them anyway.
logger.println(Messages.BuildTrigger_warning_this_build_has_no_associated_aut());
auth = Jenkins.ANONYMOUS;
}
}

for (Dependency dep : downstreamProjects) {
List<Action> buildActions = new ArrayList<Action>();
SecurityContext orig = ACL.impersonate(auth);
try {
if (dep.shouldTriggerBuild(build, listener, buildActions)) {
AbstractProject p = dep.getDownstreamProject();
// Allow shouldTriggerBuild to return false first, in case it is skipping because of a lack of Item.READ/DISCOVER permission:
if (p.isDisabled()) {
logger.println(Messages.BuildTrigger_Disabled(ModelHyperlinkNote.encodeTo(p)));
continue;
}
boolean scheduled = p.scheduleBuild(p.getQuietPeriod(), new UpstreamCause((Run)build), buildActions.toArray(new Action[buildActions.size()]));
if (Jenkins.getInstance().getItemByFullName(p.getFullName()) == p) {
String name = ModelHyperlinkNote.encodeTo(p);
if (scheduled) {
logger.println(Messages.BuildTrigger_Triggering(name));
} else {
logger.println(Messages.BuildTrigger_InQueue(name));
}
} // otherwise upstream users should not know that it happened
if (dep.shouldTriggerBuild(build, listener, buildActions)) {
AbstractProject p = dep.getDownstreamProject();
// Allow shouldTriggerBuild to return false first, in case it is skipping because of a lack of Item.READ/DISCOVER permission:
if (p.isDisabled()) {
logger.println(Messages.BuildTrigger_Disabled(ModelHyperlinkNote.encodeTo(p)));
continue;
}
} finally {
SecurityContextHolder.setContext(orig);
boolean scheduled = p.scheduleBuild(p.getQuietPeriod(), new UpstreamCause((Run)build), buildActions.toArray(new Action[buildActions.size()]));
if (Jenkins.getInstance().getItemByFullName(p.getFullName()) == p) {
String name = ModelHyperlinkNote.encodeTo(p);
if (scheduled) {
logger.println(Messages.BuildTrigger_Triggering(name));
} else {
logger.println(Messages.BuildTrigger_InQueue(name));
}
} // otherwise upstream users should not know that it happened
}
}

@@ -443,9 +410,6 @@ public FormValidation doCheck(@AncestorInPath AbstractProject project, @QueryPar
return FormValidation.error(Messages.BuildTrigger_NotBuildable(projectName));
// check whether the supposed user is expected to be able to build
Authentication auth = Tasks.getAuthenticationOf(project);
if (auth.equals(ACL.SYSTEM) && !QueueItemAuthenticatorConfiguration.get().getAuthenticators().isEmpty()) {
auth = Jenkins.ANONYMOUS; // compare behavior in execute, above
}
if (!item.getACL().hasPermission(auth, Item.BUILD)) {
return FormValidation.error(Messages.BuildTrigger_you_have_no_permission_to_build_(projectName));
}
@@ -65,7 +65,6 @@
import jenkins.model.DependencyDeclarer;
import jenkins.model.Jenkins;
import jenkins.model.ParameterizedJobMixIn;
import jenkins.security.QueueItemAuthenticatorConfiguration;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContext;
@@ -128,9 +127,6 @@ private boolean shouldTrigger(Run upstreamBuild, TaskListener listener) {
Authentication originalAuth = Jenkins.getAuthentication();
Job upstream = upstreamBuild.getParent();
Authentication auth = Tasks.getAuthenticationOf((Queue.Task) job);
if (auth.equals(ACL.SYSTEM) && !QueueItemAuthenticatorConfiguration.get().getAuthenticators().isEmpty()) {
auth = Jenkins.ANONYMOUS; // cf. BuildTrigger
}

SecurityContext orig = ACL.impersonate(auth);
Item authUpstream = null;
@@ -50,9 +50,6 @@ BuildTrigger.NoProjectSpecified=No project specified
BuildTrigger.NotBuildable={0} is not buildable
BuildTrigger.Triggering=Triggering a new build of {0}
BuildTrigger.ok_ancestor_is_null=Ancestor/Context Unknown: the project specified cannot be validated
BuildTrigger.warning_access_control_for_builds_in_glo=Warning: \u2018Access Control for Builds\u2019 in global security configuration is empty, so falling back to legacy behavior of permitting any downstream builds to be triggered
BuildTrigger.warning_this_build_has_no_associated_aut=Warning: this build has no associated authentication, so build permissions may be lacking, and downstream projects which cannot even be seen by an anonymous user will be silently skipped
BuildTrigger.warning_you_have_no_plugins_providing_ac=Warning: you have no plugins providing access control for builds, so falling back to legacy behavior of permitting any downstream builds to be triggered
BuildTrigger.you_have_no_permission_to_build_=You have no permission to build {0}

CommandInterpreter.CommandFailed=command execution failed
@@ -84,4 +81,4 @@ Maven.NoExecutable=Couldn\u2019t find any executable in {0}

Shell.DisplayName=Execute shell
Shell.invalid_exit_code_range=Invalid exit code value: {0}. Check help section
Shell.invalid_exit_code_zero=Exit code zero is ignored and does not make the build unstable
Shell.invalid_exit_code_zero=Exit code zero is ignored and does not make the build unstable
@@ -67,18 +67,6 @@ BuildTrigger.NotBuildable=\
\u201e{0}\u201c \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0437\u0433\u0440\u0430\u0434\u0438
BuildTrigger.Triggering=\
\u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u201e{0}\u201c
BuildTrigger.warning_access_control_for_builds_in_glo=\
\u041f\u0420\u0415\u0414\u0423\u041f\u0420\u0415\u0416\u0414\u0415\u041d\u0418\u0415: \u041f\u043e\u043b\u0435\u0442\u043e \u201e\u041f\u0440\u0430\u0432\u0430 \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f\u0442\u0430\u201c \u0432 \u043e\u0431\u0449\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\
\u0437\u0430 \u0441\u0438\u0433\u0443\u0440\u043d\u043e\u0441\u0442\u0442\u0430 \u043d\u0435 \u0435 \u043f\u043e\u043f\u044a\u043b\u043d\u0435\u043d\u043e. \u0429\u0435 \u0441\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 \u043e\u0441\u0442\u0430\u0440\u044f\u043b\u043e\u0442\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0430\
\u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u0438 \u0437\u0430\u0434\u0430\u0447\u0438, \u0437\u0430\u0432\u0438\u0441\u0435\u0449\u0438 \u043e\u0442 \u0442\u0430\u0437\u0438
BuildTrigger.warning_this_build_has_no_associated_aut=\
\u041f\u0420\u0415\u0414\u0423\u041f\u0420\u0415\u0416\u0414\u0415\u041d\u0418\u0415: \u043b\u0438\u043f\u0441\u0432\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0437\u0430 \u0442\u043e\u0432\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435, \u0437\u0430\u0442\u043e\u0432\u0430 \u0438 \u043f\u0440\u0430\u0432\u0430\u0442\u0430 \u043a\u044a\u043c\
\u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u044f\u043c\u0430 \u0434\u0430 \u0441\u0430 \u043f\u044a\u043b\u043d\u0438. \u0417\u0430\u0432\u0438\u0441\u0435\u0449\u0438\u0442\u0435 \u043e\u0442 \u0442\u043e\u0432\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0438, \u043a\u043e\u0438\u0442\u043e\
\u043d\u0435 \u0441\u0435 \u0432\u0438\u0436\u0434\u0430\u0442 \u043e\u0442 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438, \u0449\u0435 \u0431\u044a\u0434\u0430\u0442 \u043f\u0440\u043e\u043f\u0443\u0441\u043d\u0430\u0442\u0438.
BuildTrigger.warning_you_have_no_plugins_providing_ac=\
\u041f\u0420\u0415\u0414\u0423\u041f\u0420\u0415\u0416\u0414\u0415\u041d\u0418\u0415: \u043b\u0438\u043f\u0441\u0432\u0430\u0442 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438 \u0437\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u043f\u0440\u0430\u0432\u0430 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f. \u0429\u0435\
\u0441\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 \u043e\u0441\u0442\u0430\u0440\u044f\u043b\u043e\u0442\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u0438\
\u0437\u0430\u0434\u0430\u0447\u0438, \u0437\u0430\u0432\u0438\u0441\u0435\u0449\u0438 \u043e\u0442 \u0442\u0430\u0437\u0438
BuildTrigger.you_have_no_permission_to_build_=\
\u041d\u044f\u043c\u0430\u0442\u0435 \u043f\u0440\u0430\u0432\u0430 \u0434\u0430 \u0438\u0437\u0433\u0440\u0430\u0434\u0438\u0442\u0435 \u201e{0}\u201c

@@ -48,9 +48,6 @@ BuildTrigger.NotBuildable={0} kann nicht gebaut werden.
BuildTrigger.Triggering=L\u00F6se einen neuen Build von {0} aus
BuildTrigger.you_have_no_permission_to_build_=Sie haben nicht die Berechtigung, Builds von {0} zu starten.
BuildTrigger.ok_ancestor_is_null=Der angegebene Projektname kann im aktuellen Kontext nicht gepr\u00FCft werden.
BuildTrigger.warning_access_control_for_builds_in_glo=Achtung: Die Zugriffskontrolle von Builds ist in der globalen Sicherheitskonfiguration nicht konfiguriert, daher wird erlaubt, beliebige Downstream-Builds zu starten.
BuildTrigger.warning_you_have_no_plugins_providing_ac=Achtung: Keine Plugins f\u00FCr die Zugriffskontrolle von Builds sind installiert, daher wird erlaubt, beliebige Downstream-Builds zu starten.
BuildTrigger.warning_this_build_has_no_associated_aut=Achtung: Dieser Build hat keine zugeordnete Authentifizierung, daher k\u00F6nnen Berechtigungen fehlen und Downstream-Builds ggf. nicht gestartet werden, wenn anonyme Nutzer auf diese keinen Zugriff haben.

CommandInterpreter.CommandFailed=Befehlsausf\u00FChrung fehlgeschlagen
CommandInterpreter.UnableToDelete=Kann Skriptdatei {0} nicht l\u00F6schen
@@ -78,11 +78,5 @@ JavadocArchiver.NoMatchFound=Nenhum javadoc encontrado {0}: {1}
ArtifactArchiver.SkipBecauseOnlyIfSuccessful=Arquivamento ignorado devido ao t\u00e9rmino do build sem sucesso
# No project specified
BuildTrigger.NoProjectSpecified=Nenhum projeto especificado
# Warning: \u2018Access Control for Builds\u2019 in global security configuration is empty, so falling back to legacy behavior of permitting any downstream builds to be triggered
BuildTrigger.warning_access_control_for_builds_in_glo=Aten\u00e7\u00e3o: o \u2018Controle de acesso para Builds\u2019 nas configura\u00e7\u00f5es de seguran\u00e7a globais est\u00e1 vazio, portanto retornando para o comportamento legado de permitir que quaisquer builds decendentes sejam disparados
# Warning: this build has no associated authentication, so build permissions may be lacking, and downstream projects which cannot even be seen by an anonymous user will be silently skipped
BuildTrigger.warning_this_build_has_no_associated_aut=Aten\u00e7\u00e3o: este build n\u00e3o possui authentica\u00e7\u00e3o associada, portanto permiss\u1ebds de build podem estar faltando, e projetos descendentes que n\u00e3o podem sequer ser vistos por um usu\u00e1rio an\u00f4nimo ser\u00e3o ignorados silenciosamente
# Warning: you have no plugins providing access control for builds, so falling back to legacy behavior of permitting any downstream builds to be triggered
BuildTrigger.warning_you_have_no_plugins_providing_ac=Aten\u00e7\u00e3o: voc\u00ea n\u00e3o possui plugins fornecendo controle de accesso para builds, portanto retornando para o comportamento legado de permitir que quaisquer builds descendentes sejam disparados
# You have no permission to build {0}
BuildTrigger.you_have_no_permission_to_build_=Voc\u00ea n\u00e3o tem permiss\u00e3o para construir {0}

0 comments on commit 915543d

Please sign in to comment.
You can’t perform that action at this time.