mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-07 09:06:03 +00:00
Merge pull request #155 from jieryn/JENKINS-9915
[FIXED JENKINS-9915] Make captcha support optional; remove LGPL jcaptcha
This commit is contained in:
commit
8007d83fc9
10 files changed
+192
-75
No files matched your search
@@ -55,6 +55,9 @@ Upcoming changes</a>
|
||||
<!-- Record your changes in the trunk here. -->
|
||||
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
|
||||
<ul class=image>
|
||||
<li class=rfe>
|
||||
Make captcha support optional; remove LGPL jcaptcha
|
||||
(<a href="http://issues.jenkins-ci.org/browse/JENKINS-9915">issue 9915</a>)
|
||||
<li class=bug>
|
||||
Validate new view name relative to current context
|
||||
<li class=bug>
|
||||
|
||||
@@ -703,49 +703,6 @@ THE SOFTWARE.
|
||||
<artifactId>memory-monitor</artifactId>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.octo.captcha</groupId>
|
||||
<artifactId>jcaptcha-all</artifactId>
|
||||
<version>1.0-RC6</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>quartz</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>xerces</groupId>
|
||||
<artifactId>xercesImpl</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>xerces</groupId>
|
||||
<artifactId>xmlParserAPIs</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>concurrent</groupId>
|
||||
<artifactId>concurrent</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency><!-- StAX implementation. See HUDSON-2547. -->
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>wstx-asl</artifactId>
|
||||
|
||||
@@ -34,6 +34,7 @@ import hudson.security.AccessControlled;
|
||||
import hudson.security.AuthorizationStrategy;
|
||||
import hudson.security.Permission;
|
||||
import hudson.security.SecurityRealm;
|
||||
import hudson.security.captcha.CaptchaSupport;
|
||||
import hudson.security.csrf.CrumbIssuer;
|
||||
import hudson.slaves.Cloud;
|
||||
import hudson.slaves.ComputerLauncher;
|
||||
@@ -687,6 +688,10 @@ public class Functions {
|
||||
return ParameterDefinition.all();
|
||||
}
|
||||
|
||||
public static List<Descriptor<CaptchaSupport>> getCaptchaSupportDescriptors() {
|
||||
return CaptchaSupport.all();
|
||||
}
|
||||
|
||||
public static List<Descriptor<ViewsTabBar>> getViewsTabBarDescriptors() {
|
||||
return ViewsTabBar.all();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import hudson.model.User;
|
||||
import hudson.model.UserProperty;
|
||||
import hudson.model.UserPropertyDescriptor;
|
||||
import hudson.security.FederatedLoginService.FederatedIdentity;
|
||||
import hudson.security.captcha.CaptchaSupport;
|
||||
import hudson.tasks.Mailer;
|
||||
import hudson.util.PluginServletFilter;
|
||||
import hudson.util.Protector;
|
||||
@@ -92,9 +93,21 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
|
||||
*/
|
||||
private final boolean disableSignup;
|
||||
|
||||
@DataBoundConstructor
|
||||
/**
|
||||
* If true, captcha will be enabled.
|
||||
*/
|
||||
private final boolean enableCaptcha;
|
||||
|
||||
@Deprecated
|
||||
public HudsonPrivateSecurityRealm(boolean allowsSignup) {
|
||||
this(allowsSignup, false, (CaptchaSupport) null);
|
||||
}
|
||||
|
||||
@DataBoundConstructor
|
||||
public HudsonPrivateSecurityRealm(boolean allowsSignup, boolean enableCaptcha, CaptchaSupport captchaSupport) {
|
||||
this.disableSignup = !allowsSignup;
|
||||
this.enableCaptcha = enableCaptcha;
|
||||
setCaptchaSupport(captchaSupport);
|
||||
if(!allowsSignup && !hasSomeUser()) {
|
||||
// if Hudson is newly set up with the security realm and there's no user account created yet,
|
||||
// insert a filter that asks the user to create one
|
||||
@@ -111,6 +124,15 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
|
||||
return !disableSignup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if captcha is enabled on user signup.
|
||||
*
|
||||
* @return true if captcha is enabled on signup.
|
||||
*/
|
||||
public boolean isEnableCaptcha() {
|
||||
return enableCaptcha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes if this Hudson has some user accounts configured.
|
||||
*
|
||||
@@ -194,7 +216,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
|
||||
throw HttpResponses.error(SC_UNAUTHORIZED,new Exception("User sign up is prohibited"));
|
||||
|
||||
boolean firstUser = !hasSomeUser();
|
||||
User u = createAccount(req, rsp, true, formView);
|
||||
User u = createAccount(req, rsp, enableCaptcha, formView);
|
||||
if(u!=null) {
|
||||
if(firstUser)
|
||||
tryToMakeAdmin(u); // the first user should be admin, or else there's a risk of lock out
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
*/
|
||||
package hudson.security;
|
||||
|
||||
import com.octo.captcha.service.CaptchaServiceException;
|
||||
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
|
||||
import com.octo.captcha.service.image.ImageCaptchaService;
|
||||
import groovy.lang.Binding;
|
||||
import hudson.ExtensionPoint;
|
||||
import hudson.DescriptorExtensionList;
|
||||
@@ -35,6 +32,7 @@ import hudson.model.AbstractDescribableImpl;
|
||||
import hudson.model.Descriptor;
|
||||
import jenkins.model.Jenkins;
|
||||
import hudson.security.FederatedLoginService.FederatedIdentity;
|
||||
import hudson.security.captcha.CaptchaSupport;
|
||||
import hudson.util.DescriptorList;
|
||||
import hudson.util.PluginServletFilter;
|
||||
import hudson.util.spring.BeanBuilder;
|
||||
@@ -57,13 +55,13 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.Cookie;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -127,6 +125,11 @@ import java.util.logging.Logger;
|
||||
* @see PluginServletFilter
|
||||
*/
|
||||
public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityRealm> implements ExtensionPoint {
|
||||
/**
|
||||
* Captcha Support to be used with this SecurityRealm for User Signup
|
||||
*/
|
||||
private CaptchaSupport captchaSupport;
|
||||
|
||||
/**
|
||||
* Creates fully-configured {@link AuthenticationManager} that performs authentication
|
||||
* against the user realm. The implementation hides how such authentication manager
|
||||
@@ -236,6 +239,18 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal
|
||||
return req.getContextPath()+"/";
|
||||
}
|
||||
|
||||
public CaptchaSupport getCaptchaSupport() {
|
||||
return captchaSupport;
|
||||
}
|
||||
|
||||
public void setCaptchaSupport(CaptchaSupport captchaSupport) {
|
||||
this.captchaSupport = captchaSupport;
|
||||
}
|
||||
|
||||
public List<Descriptor<CaptchaSupport>> getCaptchaSupportDescriptors() {
|
||||
return CaptchaSupport.all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the logout processing.
|
||||
*
|
||||
@@ -324,35 +339,29 @@ public abstract class SecurityRealm extends AbstractDescribableImpl<SecurityReal
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DefaultManageableImageCaptchaService} holder to defer initialization.
|
||||
*/
|
||||
public static final class CaptchaService {
|
||||
public static ImageCaptchaService INSTANCE = new DefaultManageableImageCaptchaService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a captcha image.
|
||||
*/
|
||||
public final void doCaptcha(StaplerRequest req, StaplerResponse rsp) throws IOException {
|
||||
String id = req.getSession().getId();
|
||||
rsp.setContentType("image/png");
|
||||
rsp.addHeader("Cache-Control","no-cache");
|
||||
ImageIO.write( CaptchaService.INSTANCE.getImageChallengeForID(id), "PNG", rsp.getOutputStream() );
|
||||
if (captchaSupport != null) {
|
||||
String id = req.getSession().getId();
|
||||
rsp.setContentType("image/png");
|
||||
rsp.addHeader("Cache-Control", "no-cache");
|
||||
captchaSupport.generateImage(id, rsp.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the captcha.
|
||||
*/
|
||||
protected final boolean validateCaptcha(String text) {
|
||||
try {
|
||||
if (captchaSupport != null) {
|
||||
String id = Stapler.getCurrentRequest().getSession().getId();
|
||||
Boolean b = CaptchaService.INSTANCE.validateResponseForID(id, text);
|
||||
return b!=null && b;
|
||||
} catch (CaptchaServiceException e) {
|
||||
LOGGER.log(Level.INFO, "Captcha validation had a problem",e);
|
||||
return false;
|
||||
return captchaSupport.validateCaptcha(id, text);
|
||||
}
|
||||
|
||||
// If no Captcha Support then bogus validation always returns true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2011, Winston.Prakash@oracle.com
|
||||
*
|
||||
* 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 hudson.security.captcha;
|
||||
|
||||
|
||||
import hudson.DescriptorExtensionList;
|
||||
import hudson.ExtensionPoint;
|
||||
import hudson.model.AbstractDescribableImpl;
|
||||
import hudson.model.Descriptor;
|
||||
import hudson.model.Hudson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
|
||||
/**
|
||||
* Extension point for adding Captcha Support to User Registration Page {@link CaptchaSupport}.
|
||||
*
|
||||
* <p>
|
||||
* This object can have an optional <tt>config.jelly</tt> to configure the Captcha Support
|
||||
* <p>
|
||||
* A default constructor is needed to create CaptchaSupport in
|
||||
* the default configuration.
|
||||
*
|
||||
* @author Winston Prakash
|
||||
* @since 1.416
|
||||
* @see CaptchaSupportDescriptor
|
||||
*/
|
||||
public abstract class CaptchaSupport extends AbstractDescribableImpl<CaptchaSupport> implements ExtensionPoint {
|
||||
/**
|
||||
* Returns all the registered {@link CaptchaSupport} descriptors.
|
||||
*/
|
||||
public static DescriptorExtensionList<CaptchaSupport, Descriptor<CaptchaSupport>> all() {
|
||||
return Hudson.getInstance().<CaptchaSupport, Descriptor<CaptchaSupport>>getDescriptorList(CaptchaSupport.class);
|
||||
}
|
||||
|
||||
abstract public boolean validateCaptcha(String id, String text);
|
||||
|
||||
abstract public void generateImage(String id, OutputStream ios) throws IOException;
|
||||
|
||||
public CaptchaSupportDescriptor getDescriptor() {
|
||||
return (CaptchaSupportDescriptor)super.getDescriptor();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2011, Winston.Prakash@oracle.com
|
||||
*
|
||||
* 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 hudson.security.captcha;
|
||||
|
||||
import hudson.model.Descriptor;
|
||||
|
||||
/**
|
||||
* {@link Descriptor} for {@link CaptchaSupport}.
|
||||
*
|
||||
* @author Winston Prakash
|
||||
* @since 1.416
|
||||
*/
|
||||
public abstract class CaptchaSupportDescriptor extends Descriptor<CaptchaSupport> {
|
||||
// so far nothing different from plain Descriptor
|
||||
// but it may prove useful for future expansion
|
||||
}
|
||||
@@ -23,9 +23,25 @@ THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<f:entry title="" help="/help/security/private-realm/allow-signup.html">
|
||||
<f:checkbox name="privateRealm.allowsSignup" checked="${h.defaultToTrue(instance.allowsSignup())}"
|
||||
title="${%Allow users to sign up}"/>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson"
|
||||
xmlns:f="/lib/form">
|
||||
<f:entry title="" help="/help/security/private-realm/allow-signup.html">
|
||||
<f:checkbox name="privateRealm.allowsSignup" checked="${h.defaultToTrue(instance.allowsSignup())}" title="${%Allow users to sign up}" />
|
||||
</f:entry>
|
||||
</j:jelly>
|
||||
<j:if test="${size(h.captchaSupportDescriptors) gt 0}">
|
||||
<f:entry>
|
||||
<f:checkbox name="privateRealm.enableCaptcha" checked="${h.defaultToTrue(instance.isEnableCaptcha())}"
|
||||
title="${%Enable captcha on sign up}" />
|
||||
</f:entry>
|
||||
<f:dropdownList name="privateRealm.captchaSupport" title="${%Captcha Support}">
|
||||
<!-- Loop through available Captcha Support Descriptors -->
|
||||
<j:forEach var="descriptor" items="${h.captchaSupportDescriptors}" varStatus="loop">
|
||||
<f:dropdownListBlock title="${descriptor.displayName}" value="${loop.index}"
|
||||
selected="${descriptor==instance.captchaSupport.descriptor}" staplerClass="${descriptor.clazz.name}">
|
||||
<!-- Include config.jelly for this Captcha Support -->
|
||||
<st:include page="${descriptor.configPage}" from="${descriptor}" optional="true" />
|
||||
</f:dropdownListBlock>
|
||||
</j:forEach>
|
||||
</f:dropdownList>
|
||||
</j:if>
|
||||
</j:jelly>
|
||||
@@ -27,5 +27,5 @@ THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<local:_entryForm host="${app}" title="${%Sign up}" action="createAccount" captcha="${true}" xmlns:local="/hudson/security/HudsonPrivateSecurityRealm" />
|
||||
</j:jelly>
|
||||
<local:_entryForm host="${app}" title="${%Sign up}" action="createAccount" captcha="${it.isEnableCaptcha()}" xmlns:local="/hudson/security/HudsonPrivateSecurityRealm" />
|
||||
</j:jelly>
|
||||
@@ -2,7 +2,10 @@
|
||||
By default, Jenkins allows users to create accounts by themselves, via the "sign up" link on the top right shoulder of the page.
|
||||
But if you'd like to prevent random users from creating accounts, and instead tightly control how user accounts are created,
|
||||
uncheck this box.
|
||||
|
||||
<p>
|
||||
When this checkbox is unchecked, someone with the administrator role would have to create accounts.
|
||||
</div>
|
||||
<p>
|
||||
By default, Jenkins does not use captcha verification if the user creates an account by themself.
|
||||
If you'd like to enable captcha verification, install a captcha support plugin, e.g. the Jenkins
|
||||
<a href="https://wiki.jenkins-ci.org/display/JENKINS/JCaptcha+Plugin">JCaptcha Plugin</a>.
|
||||
</div>
|
||||
Reference in new issue
Block a user