From e62787f75093cdbf43863822e4a5da795192fc39 Mon Sep 17 00:00:00 2001 From: dty Date: Wed, 6 Oct 2010 17:23:04 +0000 Subject: [PATCH] [HUDSON-7518] Add an option to allow exclusion of HTTP client information from the crumb calculation. This can be enabled for users who sit behind a proxy that strips this information off, resulting in crumbs varying across requests. git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@35570 71c3de6d-444a-0410-be80-ed276b4c234a --- .../security/csrf/DefaultCrumbIssuer.java | 32 ++++++++++++++++--- .../csrf/DefaultCrumbIssuer/config.jelly | 6 ++++ .../help-excludeClientIPFromCrumb.html | 7 ++++ .../security/csrf/DefaultCrumbIssuerTest.java | 26 +++++++++++---- 4 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 core/src/main/resources/hudson/security/csrf/DefaultCrumbIssuer/config.jelly create mode 100644 core/src/main/resources/hudson/security/csrf/DefaultCrumbIssuer/help-excludeClientIPFromCrumb.html diff --git a/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java b/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java index a7aefba42c..fe11d34839 100644 --- a/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java +++ b/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2008-2009 Yahoo! Inc. + * Copyright (c) 2008-2010 Yahoo! Inc. * All rights reserved. * The copyrights to the contents of this file are licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php) */ @@ -20,6 +20,7 @@ import javax.servlet.http.HttpServletRequest; import net.sf.json.JSONObject; import org.acegisecurity.Authentication; +import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; /** @@ -29,17 +30,36 @@ import org.kohsuke.stapler.StaplerRequest; */ public class DefaultCrumbIssuer extends CrumbIssuer { - private MessageDigest md; + private transient MessageDigest md; + private boolean excludeClientIPFromCrumb; - DefaultCrumbIssuer() { + @DataBoundConstructor + public DefaultCrumbIssuer(boolean excludeClientIPFromCrumb) { try { this.md = MessageDigest.getInstance("MD5"); + this.excludeClientIPFromCrumb = excludeClientIPFromCrumb; } catch (NoSuchAlgorithmException e) { this.md = null; + this.excludeClientIPFromCrumb = false; LOGGER.log(Level.SEVERE, "Can't find MD5", e); } } + public boolean isExcludeClientIPFromCrumb() { + return this.excludeClientIPFromCrumb; + } + + private Object readResolve() { + try { + this.md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + this.md = null; + LOGGER.log(Level.SEVERE, "Can't find MD5", e); + } + + return this; + } + /** * {@inheritDoc} */ @@ -54,7 +74,9 @@ public class DefaultCrumbIssuer extends CrumbIssuer { buffer.append(a.getName()); } buffer.append(';'); - buffer.append(getClientIP(req)); + if (!isExcludeClientIPFromCrumb()) { + buffer.append(getClientIP(req)); + } md.update(buffer.toString().getBytes()); byte[] crumbBytes = md.digest(salt.getBytes()); @@ -116,7 +138,7 @@ public class DefaultCrumbIssuer extends CrumbIssuer { @Override public DefaultCrumbIssuer newInstance(StaplerRequest req, JSONObject formData) throws FormException { - return new DefaultCrumbIssuer(); + return req.bindJSON(DefaultCrumbIssuer.class, formData); } } diff --git a/core/src/main/resources/hudson/security/csrf/DefaultCrumbIssuer/config.jelly b/core/src/main/resources/hudson/security/csrf/DefaultCrumbIssuer/config.jelly new file mode 100644 index 0000000000..9fa86ab4e8 --- /dev/null +++ b/core/src/main/resources/hudson/security/csrf/DefaultCrumbIssuer/config.jelly @@ -0,0 +1,6 @@ + + + + + + diff --git a/core/src/main/resources/hudson/security/csrf/DefaultCrumbIssuer/help-excludeClientIPFromCrumb.html b/core/src/main/resources/hudson/security/csrf/DefaultCrumbIssuer/help-excludeClientIPFromCrumb.html new file mode 100644 index 0000000000..161236990b --- /dev/null +++ b/core/src/main/resources/hudson/security/csrf/DefaultCrumbIssuer/help-excludeClientIPFromCrumb.html @@ -0,0 +1,7 @@ +
+ Some HTTP proxies filter out information that the default crumb issuer uses + to calculate the nonce value. If an HTTP proxy sits between your browser client + and your Hudson server and you receive a 403 response when submitting a form + to Hudson, checking this option may help. Using this option makes the nonce + value easier to forge. +
\ No newline at end of file diff --git a/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java b/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java index 9449c1e3f3..f41a225cb8 100644 --- a/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java +++ b/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java @@ -1,6 +1,7 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. +/** + * Copyright (c) 2008-2010 Yahoo! Inc. + * All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php) */ package hudson.security.csrf; @@ -18,9 +19,7 @@ public class DefaultCrumbIssuerTest extends HudsonTestCase { protected void setUp() throws Exception { super.setUp(); assertNotNull(hudson); - CrumbIssuerDescriptor descriptor = (CrumbIssuerDescriptor)hudson.getDescriptor(DefaultCrumbIssuer.class); - assertNotNull(descriptor); - CrumbIssuer issuer = descriptor.newInstance(null,null); + CrumbIssuer issuer = new DefaultCrumbIssuer(false); assertNotNull(issuer); hudson.setCrumbIssuer(issuer); } @@ -81,4 +80,19 @@ public class DefaultCrumbIssuerTest extends HudsonTestCase { HtmlPage p = wc.goTo("configure"); submit(p.getFormByName("config")); } + + @Bug(7518) + public void testProxyCompatibilityMode() throws Exception { + CrumbIssuer issuer = new DefaultCrumbIssuer(true); + assertNotNull(issuer); + hudson.setCrumbIssuer(issuer); + + WebClient wc = new WebClient(); + wc.addRequestHeader(HEADER_NAME, testData[0]); + HtmlPage p = wc.goTo("configure"); + + wc.removeRequestHeader(HEADER_NAME); + // The crumb should still match if we remove the proxy info + submit(p.getFormByName("config")); + } } -- GitLab