Comment Intégrer JCaptcha au Printemps de Sécurité

Avant de commencer à répondre, je sais qu'il est ReCaptcha qui est plus simple et plus facile, mais je ne peux pas l'utiliser. Le serveur de production n'est pas en ligne. Donc, ici nous allons.

Je suis à l'aide de Spring mvc 3 avec ressort de sécurité sur le Projet maven et weblogic que le serveur web jetty pendant le développement). Je vais être très précis sur ce point.

Avant de voir mes configurations et fichiers, je voudrais vous montrer la liste de mes problèmes:

  • J'ai essayé de ReCaptcha avant JCaptcha avec la même structure de codage, et il fonctionne très bien.
  • enregistreur.debug n'apparaît pas du tout dans CaptchaCaptureFilter classe et/ou CaptchaVerifierFilter classe (alors qu'il apparaît dans ArtajasaAuthenticationProvider classe).
  • Je peux voir l'image captcha, mais quelle que soit la réponse est, elle toujours valide.
  • Avec l'état actuel, il ne fonctionne pas dans la jetée, ni weblogic, mais si je change le filtre personnalisé position de celle-ci, il ne fonctionne que dans la jetée.

    <custom-filter ref="captchaCaptureFilter" position="FIRST"/>
    <custom-filter ref="captchaVerifierFilter" after="FIRST"/>

Merci pour le visionnage et merci de répondre à ma question.
Ci-dessous sont les détails.

Le référentiel pour JCaptcha est celui-ci:

<repository>
        <id>sourceforge-releases</id>
        <name>Sourceforge Releases</name>
        <url>https://oss.sonatype.org/content/repositories/sourceforge-releases</url>
    </repository>

<dependency>
        <groupId>com.octo.captcha</groupId>
        <artifactId>jcaptcha-integration-simple-servlet</artifactId>
        <version>2.0-alpha-1</version>
    </dependency>

Voici la configuration que j'ai faite .des fichiers xml:

web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/applicationContext.xml
        /WEB-INF/spring/spring-security.xml
    </param-value>
</context-param>
 <listener>
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

<servlet>
    <servlet-name>jcaptcha</servlet-name>
    <servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>jcaptcha</servlet-name>
    <url-pattern>/jcaptcha.jpg</url-pattern>
</servlet-mapping>

spring-security.xml

<http auto-config="true" use-expressions="true">
<intercept-url pattern="/resources/**" access="permitAll()" />
<intercept-url pattern="/jcaptcha.jpg" access="permitAll()" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login login-page="/session/login/" default-target-url="/"
authentication-failure-url="/session/loginfailed/" />
<logout logout-success-url="/session/logout/" />
<access-denied-handler error-page="/session/403/" />
<!--JCaptcha Filtering-->
<custom-filter ref="captchaCaptureFilter" before="FORM_LOGIN_FILTER"/>
<custom-filter ref="captchaVerifierFilter" after="FORM_LOGIN_FILTER"/>
<anonymous />
</http>
<!-- For capturing CAPTCHA fields -->
<beans:bean id="captchaCaptureFilter" class="com.util.CaptchaCaptureFilter" />
<!-- For verifying CAPTCHA fields -->
<!-- Private key is assigned by the JCaptcha service -->
<beans:bean id="captchaVerifierFilter" class="com.util.CaptchaVerifierFilter"
p:failureUrl="/session/loginfailed/"
p:captchaCaptureFilter-ref="captchaCaptureFilter"/>
<beans:bean id="customAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="sessionAuthenticationStrategy" ref="sas"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="allowSessionCreation" value="true" />
</beans:bean>
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry"/>
<beans:property name="maximumSessions" value="1" />
</beans:bean>
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
<beans:bean id="userService" class="com.service.mybatis.UserManager" />
<beans:bean id="customAuthenticationProvider" class="com.util.ArtajasaAuthenticationProvider" />
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
<beans:bean id="accessDeniedHandler" class="com.util.ThouShaltNoPass">
<beans:property name="accessDeniedURL" value="/session/403/" />
</beans:bean>

Et ce sont les classes java:

ArtajasaAuthenticationProvider.java

public class ArtajasaAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserService userService;
private Logger logger = LoggerFactory.getLogger(ArtajasaAuthenticationProvider.class);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = String.valueOf(authentication.getPrincipal());
String password = String.valueOf(authentication.getCredentials());
logger.debug("Checking authentication for user {}", username);
if (StringUtils.isBlank(username)
|| StringUtils.isBlank(password)) {
throw new BadCredentialsException("No Username and/or Password Provided.");
} else {
Pengguna user = userService.select(username);
if (user == null) {
throw new BadCredentialsException("Invalid Username and/or Password.");
}
if (user.getPassword().equals(new PasswordUtil().generateHash(password, user.getSalt()))) {
List<GrantedAuthority> authorityList = (List<GrantedAuthority>) userService.getAuthorities(user);
return new UsernamePasswordAuthenticationToken(username, password, authorityList);
} else {
throw new BadCredentialsException("Invalid Username and/or Password.");
}
}
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}

CaptchaCaptureFilter.java

public class CaptchaCaptureFilter extends OncePerRequestFilter {
protected Logger logger = Logger.getLogger(CaptchaCaptureFilter.class);
private String userCaptchaResponse;
private HttpServletRequest request;
@Override
public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
logger.debug("Captcha capture filter");
//Assign values only when user has submitted a Captcha value.
//Without this condition the values will be reset due to redirection
//and CaptchaVerifierFilter will enter an infinite loop
if (req.getParameter("jcaptcha") != null) {
request = req;
userCaptchaResponse = req.getParameter("jcaptcha");
}
logger.debug("userResponse: " + userCaptchaResponse);
//Proceed with the remaining filters
chain.doFilter(req, res);
}
public String getUserCaptchaResponse() {
return userCaptchaResponse;
}
public void setUserCaptchaResponse(String userCaptchaResponse) {
this.userCaptchaResponse = userCaptchaResponse;
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
}

CaptchaVerifierFilter.java

public class CaptchaVerifierFilter extends OncePerRequestFilter {
protected Logger logger = Logger.getLogger(CaptchaVerifierFilter.class);
private String failureUrl;
private CaptchaCaptureFilter captchaCaptureFilter;
//Inspired by log output: AbstractAuthenticationProcessingFilter.java:unsuccessfulAuthentication:320)
//Delegating to authentication failure handlerorg.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@15d4273
private SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
@Override
public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
logger.debug("Captcha verifier filter");
logger.debug("userResponse: " + captchaCaptureFilter.getUserCaptchaResponse());
//Assign values only when user has submitted a Captcha value
if (captchaCaptureFilter.getUserCaptchaResponse() != null) {
//Send HTTP request to validate user's Captcha
boolean captchaPassed = SimpleImageCaptchaServlet.validateResponse(captchaCaptureFilter.getRequest(), captchaCaptureFilter.getUserCaptchaResponse());
//Check if valid
if (!captchaPassed) {
logger.debug("Captcha is invalid!");
//Redirect user to login page
failureHandler.setDefaultFailureUrl(failureUrl);
failureHandler.onAuthenticationFailure(req, res, new BadCredentialsException("Captcha invalid! " + captchaCaptureFilter.getRequest() + " " + captchaCaptureFilter.getUserCaptchaResponse()));
} else {
logger.debug("Captcha is valid!");
}
//Reset Captcha fields after processing
//If this method is skipped, everytime we access a page
//CaptchaVerifierFilter will infinitely send a request to the Google Captcha service!
resetCaptchaFields();
}
//Proceed with the remaining filters
chain.doFilter(req, res);
}
/**
* Reset Captcha fields
*/
public void resetCaptchaFields() {
captchaCaptureFilter.setUserCaptchaResponse(null);
}
public String getFailureUrl() {
return failureUrl;
}
public void setFailureUrl(String failureUrl) {
this.failureUrl = failureUrl;
}
public CaptchaCaptureFilter getCaptchaCaptureFilter() {
return captchaCaptureFilter;
}
public void setCaptchaCaptureFilter(CaptchaCaptureFilter captchaCaptureFilter) {
this.captchaCaptureFilter = captchaCaptureFilter;
}
}

Dernière mais pas moins, de connexion.jsp

<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt' %>
<form id="login" name="f" action="<c:url value='/j_spring_security_check'/>" method="POST">
<div class="container">
<div class="content">
<div class="row">
<div class="login-form">
<h3>Login</h3>
<br />
<fieldset>
<div class="clearfix">
username: ecr
<input type="text" name='j_username' value='<c:if test="${not empty param.login_error}"><c:out value="${SPRING_SECURITY_LAST_USERNAME}"/></c:if>' placeholder="[email protected]">
</div>
<div class="clearfix">
password: ecr123
<input type="password" name='j_password' placeholder="password">
</div>
<div class="clearfix">
<img src="../../jcaptcha.jpg" />
<br />
<input type="text" name="jcaptcha" placeholder="masukkan captcha" />
</div>
<br />
<button class="btn btn-primary" type="submit"><i class="icon-lock"></i> Sign in</button>
</fieldset>
</div>
</div>
</div>
<br />
<c:if test="${not empty error}">
<div class="alert alert-error">
<button type="button" class="close" data-dismiss="alert"><i class="icon-remove"></i></button>
Login Failed, try again.<br />
<c:out value="${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message}"/>
</div>
</c:if>
</div>

OriginalL'auteur Salingga | 2012-10-12