Skip to content

Commit

Permalink
Enable background threads to impersonate SYSTEM
Browse files Browse the repository at this point in the history
Jenkins plugin listeners and  background threads should normally run as the SYSTEM user.

This commit allows the EventThreads to impersonate ACL.SYSTEM

Addresses regression in [JENKINS-23152]

Change-Id: Ia0f5a223f70497ad44529c390aff0c711e414f67
  • Loading branch information
Scott Hebert committed Feb 6, 2015
1 parent 370bcb4 commit 1740c39
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 19 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -61,7 +61,7 @@
<dependency>
<groupId>com.sonymobile.tools.gerrit</groupId>
<artifactId>gerrit-events</artifactId>
<version>2.4.2</version>
<version>2.6.0</version>
<!-- New source is here: https://github.com/sonyxperiadev/gerrit-events -->
</dependency>
<dependency>
Expand Down
Expand Up @@ -28,29 +28,43 @@

import com.sonymobile.tools.gerrit.gerritevents.GerritHandler;
import com.sonymobile.tools.gerrit.gerritevents.dto.GerritEvent;
import com.sonymobile.tools.gerrit.gerritevents.workers.EventThread;
import com.sonyericsson.hudson.plugins.gerrit.trigger.events.lifecycle.GerritEventLifecycle;

/**
* Specialization of GerritHandler that supports gerrit event's lifecycle.
* @author Hugo Arès &lt;hugo.ares@ericsson.com&gt;
* Specialization of GerritHandler that supports gerrit event's
* lifecycle and takes care of custom EventThread creation.
*
* @author Hugo Arès &lt;hugo.ares@ericsson.com&gt;
*/
public class GerritHandlerLifecycle extends GerritHandler {
public class JenkinsAwareGerritHandler extends GerritHandler {

private static final Logger logger = LoggerFactory.getLogger(GerritHandlerLifecycle.class);
private static final Logger logger = LoggerFactory.getLogger(JenkinsAwareGerritHandler.class);

/**
* Standard Constructor.
*
* @param numberOfWorkerThreads the number of event threads.
* @param numberOfWorkerThreads
* the number of event threads.
*/
public GerritHandlerLifecycle(int numberOfWorkerThreads) {
public JenkinsAwareGerritHandler(int numberOfWorkerThreads) {
super(numberOfWorkerThreads);
}

/**
* Here we override the EventThread creation with
* one that impersonates System.
* @param threadName name of thread.
* @return new EventThread.
*/
@Override
protected EventThread createEventThread(String threadName) {
return new SystemEventThread(this, threadName);
}

@Override
public void notifyListeners(GerritEvent event) {
//Notify lifecycle listeners.
// Notify lifecycle listeners.
if (event instanceof GerritEventLifecycle) {
try {
((GerritEventLifecycle)event).fireTriggerScanStarting();
Expand All @@ -59,10 +73,10 @@ public void notifyListeners(GerritEvent event) {
}
}

//The read deal
// The read deal
super.notifyListeners(event);

////Notify lifecycle listeners.
// //Notify lifecycle listeners.
if (event instanceof GerritEventLifecycle) {
try {
((GerritEventLifecycle)event).fireTriggerScanDone();
Expand Down
Expand Up @@ -474,7 +474,7 @@ public void start() throws Exception {
logger.trace("Loading configs");
load();
GerritSendCommandQueue.initialize(pluginConfig);
gerritEventManager = new GerritHandlerLifecycle(pluginConfig.getNumberOfReceivingWorkerThreads());
gerritEventManager = new JenkinsAwareGerritHandler(pluginConfig.getNumberOfReceivingWorkerThreads());
for (GerritServer s : servers) {
s.start();
}
Expand Down
@@ -0,0 +1,71 @@
/*
* The MIT License
*
* Copyright 2015 Ericsson.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.sonyericsson.hudson.plugins.gerrit.trigger;

import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;

import hudson.security.ACL;

import com.sonymobile.tools.gerrit.gerritevents.workers.Coordinator;
import com.sonymobile.tools.gerrit.gerritevents.workers.EventThread;

/**
* EventThread that impersonates the System user in Jenkins.
* @author scott.hebert@ericsson.com
*
*/
public class SystemEventThread extends EventThread {

/**
* Constructs an Event thread worker with name.
* @param coordinator the master.
* @param name The Thread Name
*/
public SystemEventThread(Coordinator coordinator, String name) {
super(coordinator, name);
}

/**
* Constructs an Event thread worker.
* @param coordinator the master.
*/
public SystemEventThread(Coordinator coordinator) {
super(coordinator);
}

/**
* We perform the impersonation of the System user
* prior to execution.
*/
@Override
public void run() {
SecurityContext old = ACL.impersonate(ACL.SYSTEM);
try {
super.run();
} finally {
SecurityContextHolder.setContext(old);
}
}
}
Expand Up @@ -42,24 +42,24 @@
import com.sonyericsson.hudson.plugins.gerrit.trigger.mock.Setup;

/**
* Tests for {@link GerritHandlerLifecycle}.
* Tests for {@link JenkinsAwareGerritHandler}.
*
* @author Hugo Arès &lt;hugo.ares@ericsson.com&gt;
*/
public class GerritHandlerLifecycleTest {
public class JenkinsAwareGerritHandlerTest {

private GerritHandlerLifecycle gerritHandler;
private JenkinsAwareGerritHandler gerritHandler;

/**
* Creates a GerritHandlerLifecycle.
* Creates a JenkinsAwareGerritHandler.
*/
@Before
public void setUp() {
gerritHandler = new GerritHandlerLifecycle(DEFAULT_NR_OF_RECEIVING_WORKER_THREADS);
gerritHandler = new JenkinsAwareGerritHandler(DEFAULT_NR_OF_RECEIVING_WORKER_THREADS);
}

/**
* Shuts down the GerritHandlerLifecycle.
* Shuts down the JenkinsAwareGerritHandler.
*/
@After
public void shutDown() {
Expand All @@ -70,7 +70,7 @@ public void shutDown() {
}

/**
* Tests that gerritHandleLifecycle Notifies GerritEventListener.
* Tests that JenkinsAwareGerritHandler Notifies GerritEventListener.
*/
@Test
public void shouldNotifyGerritEventListener() {
Expand All @@ -84,7 +84,7 @@ public void shouldNotifyGerritEventListener() {
}

/**
* Tests that gerritHandleLifecycle Notifies GerritEventLifecycleListener.
* Tests that JenkinsAwareGerritHandler Notifies GerritEventLifecycleListener.
*/
@Test
public void shouldNotifyLifecycleListener() {
Expand Down
@@ -0,0 +1,144 @@
/*
* The MIT License
*
* Copyright 2015 Ericsson.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.sonyericsson.hudson.plugins.gerrit.trigger;

import static com.sonymobile.tools.gerrit.gerritevents.mock.SshdServerMock.GERRIT_STREAM_EVENTS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Hudson;
import hudson.model.Result;
import hudson.security.GlobalMatrixAuthorizationStrategy;
import hudson.security.SecurityRealm;

import org.apache.sshd.SshServer;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritCause;
import com.sonyericsson.hudson.plugins.gerrit.trigger.mock.DuplicatesUtil;
import com.sonyericsson.hudson.plugins.gerrit.trigger.mock.Setup;
import com.sonyericsson.hudson.plugins.gerrit.trigger.mock.TestUtils;
import com.sonymobile.tools.gerrit.gerritevents.mock.SshdServerMock;

/**
* Unit test to ensure build can be triggered even if
* security is enabled and only authenticated users can login.
*
* @author Scott Hebert &lt;scott.hebert@ericsson.com&gt;
*/

public class LockedDownGerritEventTest {

/**
* An instance of Jenkins Rule.
*/
// CS IGNORE VisibilityModifier FOR NEXT 2 LINES. REASON: JenkinsRule.
@Rule
public final JenkinsRule j = new JenkinsRule();

private final String gerritServerName = "testServer";
private final String projectName = "testProject";
private final int port = 29418;

private SshdServerMock server;
private SshServer sshd;

/**
* Runs before test method.
*
* @throws Exception throw if so.
*/
@Before
public void setUp() throws Exception {
SshdServerMock.generateKeyPair();
server = new SshdServerMock();
sshd = SshdServerMock.startServer(port, server);
server.returnCommandFor("gerrit ls-projects", SshdServerMock.EofCommandMock.class);
server.returnCommandFor(GERRIT_STREAM_EVENTS, SshdServerMock.CommandMock.class);
server.returnCommandFor("gerrit review.*", SshdServerMock.EofCommandMock.class);
server.returnCommandFor("gerrit version", SshdServerMock.EofCommandMock.class);
}

/**
* Runs after test method.
*
* @throws Exception throw if so.
*/
@After
public void tearDown() throws Exception {
sshd.stop(true);
sshd = null;
}

/**
* Lock down the instance.
* @throws Exception throw if so.
*/
private void lockDown() throws Exception {
SecurityRealm securityRealm = j.createDummySecurityRealm();
j.getInstance().setSecurityRealm(securityRealm);

GlobalMatrixAuthorizationStrategy authorizationStrategy = new GlobalMatrixAuthorizationStrategy();
authorizationStrategy.add(Hudson.READ, "authenticated");
j.getInstance().setAuthorizationStrategy(authorizationStrategy);
}

/**
* Test that a build can still be triggered if only authenticated
* users can login.
*
* Given a secured Jenkins instance
* And a permission scheme that does not provide any permissions to Anonymous
* And a configured Gerrit Server
* And a Gerrit Triggered Job
* When an event triggers a build
* Then the build completes successfully.
*
* @throws Exception throw if so.
*/
@Test
public void testTriggerWithLockedDownInstance() throws Exception {
GerritServer gerritServer = new GerritServer(gerritServerName);
PluginImpl.getInstance().addServer(gerritServer);
gerritServer.start();
FreeStyleProject project = DuplicatesUtil.createGerritTriggeredJob(j, projectName, gerritServerName);

lockDown();

GerritServer gerritServer2 = PluginImpl.getInstance().getServer(gerritServerName);
gerritServer2.triggerEvent(Setup.createPatchsetCreated(gerritServerName));

TestUtils.waitForBuilds(project, 1);

FreeStyleBuild buildOne = project.getLastCompletedBuild();
assertSame(Result.SUCCESS, buildOne.getResult());
assertEquals(1, project.getLastCompletedBuild().getNumber());
assertSame(gerritServerName, buildOne.getCause(GerritCause.class).getEvent().getProvider().getName());
}
}

0 comments on commit 1740c39

Please sign in to comment.