提交 8aafca03 编写于 作者: J Jesse Glick

Merge branch 'security' into security-rc

Conflicts:
	core/src/main/java/hudson/model/AbstractItem.java
	core/src/main/java/hudson/security/ACL.java
	test/src/test/groovy/hudson/model/AbstractProjectTest.groovy
......@@ -43,6 +43,7 @@ import hudson.util.AlternativeUiTextProvider.Message;
import hudson.util.AtomicFileWriter;
import hudson.util.IOUtils;
import jenkins.model.Jenkins;
import org.acegisecurity.Authentication;
import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.types.FileSet;
import org.kohsuke.stapler.WebMethod;
......@@ -210,7 +211,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
* Not all the Items need to support this operation, but if you decide to do so,
* you can use this method.
*/
protected void renameTo(String newName) throws IOException {
protected void renameTo(final String newName) throws IOException {
// always synchronize from bigger objects first
final ItemGroup parent = getParent();
synchronized (parent) {
......@@ -223,13 +224,28 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
if (this.name.equals(newName))
return;
Item existing = parent.getItem(newName);
if (existing != null && existing!=this)
// the look up is case insensitive, so we need "existing!=this"
// to allow people to rename "Foo" to "foo", for example.
// see http://www.nabble.com/error-on-renaming-project-tt18061629.html
throw new IllegalArgumentException("Job " + newName
+ " already exists");
// the test to see if the project already exists or not needs to be done in escalated privilege
// to avoid overwriting
ACL.impersonate(ACL.SYSTEM,new Callable<Void,IOException>() {
final Authentication user = Jenkins.getAuthentication();
@Override
public Void call() throws IOException {
Item existing = parent.getItem(newName);
if (existing != null && existing!=AbstractItem.this) {
if (existing.getACL().hasPermission(user,Item.DISCOVER))
// the look up is case insensitive, so we need "existing!=this"
// to allow people to rename "Foo" to "foo", for example.
// see http://www.nabble.com/error-on-renaming-project-tt18061629.html
throw new IllegalArgumentException("Job " + newName + " already exists");
else {
// can't think of any real way to hide this, but at least the error message could be vague.
throw new IOException("Unable to rename to " + newName);
}
}
return null;
}
});
String oldName = this.name;
String oldFullName = getFullName();
......@@ -634,7 +650,13 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
}
// try to reflect the changes by reloading
new XmlFile(Items.XSTREAM, out.getTemporaryFile()).unmarshal(this);
Object o = new XmlFile(Items.XSTREAM, out.getTemporaryFile()).unmarshal(this);
if (o!=this) {
// ensure that we've got the same job type. extending this code to support updating
// to different job type requires destroying & creating a new job type
throw new IOException("Expecting "+this.getClass()+" but got "+o.getClass()+" instead");
}
Items.whileUpdatingByXml(new Callable<Void,IOException>() {
@Override public Void call() throws IOException {
onLoad(getParent(), getRootDir().getName());
......
......@@ -28,6 +28,8 @@ import hudson.remoting.PingThread;
import hudson.remoting.Channel.Mode;
import hudson.util.ChunkedOutputStream;
import hudson.util.ChunkedInputStream;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -151,10 +153,12 @@ abstract public class FullDuplexHttpChannel {
/**
* Set to true if the servlet container doesn't support chunked encoding.
*/
@Restricted(NoExternalUse.class)
public static boolean DIY_CHUNKING = Boolean.getBoolean("hudson.diyChunking");
/**
* Controls the time out of waiting for the 2nd HTTP request to arrive.
*/
private static long CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(15);
@Restricted(NoExternalUse.class)
public static long CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(15);
}
......@@ -24,6 +24,7 @@
package hudson.security;
import javax.annotation.Nonnull;
import hudson.remoting.Callable;
import jenkins.security.NonSerializableSecurityContext;
import jenkins.model.Jenkins;
import org.acegisecurity.AccessDeniedException;
......@@ -146,4 +147,19 @@ public abstract class ACL {
}
}
/**
* Safer variant of {@link #impersonate(Authentication)} that does not require a finally-block.
* @param auth authentication, such as {@link #SYSTEM}
* @param body an action to run with this alternate authentication in effect
* @since TODO
*/
public static <V,T extends Exception> V impersonate(Authentication auth, Callable<V,T> body) throws T {
SecurityContext old = impersonate(auth);
try {
return body.call();
} finally {
SecurityContextHolder.setContext(old);
}
}
}
......@@ -14,7 +14,6 @@ import javax.mail.internet.InternetAddress;
import javax.servlet.ServletContext;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
......@@ -108,9 +107,14 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration {
*/
private void updateSecureSessionFlag() {
try {
boolean v = fixNull(jenkinsUrl).startsWith("https");
ServletContext context = Jenkins.getInstance().servletContext;
Method m = context.getClass().getMethod("getSessionCookieConfig");
Method m;
try {
m = context.getClass().getMethod("getSessionCookieConfig");
} catch (NoSuchMethodException x) { // 3.0+
LOGGER.log(Level.FINE, "Failed to set secure cookie flag", x);
return;
}
Object sessionCookieConfig = m.invoke(context);
// not exposing session cookie to JavaScript to mitigate damage caused by XSS
......@@ -119,9 +123,10 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration {
setHttpOnly.invoke(sessionCookieConfig,true);
Method setSecure = scc.getMethod("setSecure",boolean.class);
boolean v = fixNull(jenkinsUrl).startsWith("https");
setSecure.invoke(sessionCookieConfig,v);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to set secure cookie flag. Maybe running on Servlet 2.5 and younger?", e);
LOGGER.log(Level.WARNING, "Failed to set secure cookie flag", e);
}
}
......
......@@ -33,6 +33,10 @@ import hudson.tasks.BuildStepMonitor;
import hudson.tasks.BuildTrigger
import hudson.tasks.Publisher
import hudson.tasks.Recorder;
import com.gargoylesoftware.htmlunit.html.HtmlPage
import hudson.maven.MavenModuleSet;
import hudson.security.*;
import hudson.tasks.BuildTrigger;
import hudson.tasks.Shell;
import hudson.scm.NullSCM;
import hudson.scm.SCM
......@@ -49,7 +53,7 @@ import hudson.util.StreamTaskListener;
import hudson.util.OneShotEvent
import jenkins.model.Jenkins;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.context.SecurityContextHolder
import org.jvnet.hudson.test.HudsonTestCase
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.MemoryAssert
......@@ -524,4 +528,70 @@ public class AbstractProjectTest extends HudsonTestCase {
done.signal()
}
public void testRenameToPrivileged() {
def secret = jenkins.createProject(FreeStyleProject.class,"secret");
def regular = jenkins.createProject(FreeStyleProject.class,"regular")
jenkins.securityRealm = createDummySecurityRealm();
def auth = new ProjectMatrixAuthorizationStrategy();
jenkins.authorizationStrategy = auth;
auth.add(Jenkins.ADMINISTER, "alice");
auth.add(Jenkins.READ, "bob");
// bob the regular user can only see regular jobs
regular.addProperty(new AuthorizationMatrixProperty([(Job.READ) : ["bob"] as Set]));
def wc = createWebClient()
wc.login("bob")
wc.executeOnServer {
assert jenkins.getItem("secret")==null;
try {
regular.renameTo("secret")
fail("rename as an overwrite should have failed");
} catch (Exception e) {
// expected rename to fail in some non-descriptive generic way
e.printStackTrace()
}
}
// those two jobs should still be there
assert jenkins.getItem("regular")!=null;
assert jenkins.getItem("secret")!=null;
}
/**
* Trying to POST to config.xml by a different job type should fail.
*/
public void testConfigDotXmlSubmissionToDifferentType() {
jenkins.crumbIssuer = null
def p = createFreeStyleProject()
HttpURLConnection con = postConfigDotXml(p, "<maven2-moduleset />")
// this should fail with a type mismatch error
// the error message should report both what was submitted and what was expected
assert con.responseCode == 500
def msg = con.errorStream.text
println msg
assert msg.contains(FreeStyleProject.class.name)
assert msg.contains(MavenModuleSet.class.name)
// control. this should work
con = postConfigDotXml(p, "<project />")
assert con.responseCode == 200
}
private HttpURLConnection postConfigDotXml(FreeStyleProject p, String xml) {
HttpURLConnection con = new URL(getURL(), "job/${p.name}/config.xml").openConnection()
con.requestMethod = "POST"
con.setRequestProperty("Content-Type", "application/xml")
con.doOutput = true
con.outputStream.withStream { s ->
s.write(xml.bytes)
}
return con
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册