You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by th...@apache.org on 2012/02/14 14:44:08 UTC
svn commit: r1243917 - in /cocoon/cocoon3/trunk:
cocoon-shiro-sample/src/main/java/org/apache/cocoon/shiro/sample/rest/LoginUser.java
cocoon-shiro/src/main/java/org/apache/cocoon/shiro/rest/AbstractShiroLogin.java
Author: thorsten
Date: Tue Feb 14 13:44:08 2012
New Revision: 1243917
URL: http://svn.apache.org/viewvc?rev=1243917&view=rev
Log:
COCOON3-89
Reporter:
Ajay Deshwal
Add feature to limit invalid login attempts
Thanks Ajay for your patch
Modified:
cocoon/cocoon3/trunk/cocoon-shiro-sample/src/main/java/org/apache/cocoon/shiro/sample/rest/LoginUser.java
cocoon/cocoon3/trunk/cocoon-shiro/src/main/java/org/apache/cocoon/shiro/rest/AbstractShiroLogin.java
Modified: cocoon/cocoon3/trunk/cocoon-shiro-sample/src/main/java/org/apache/cocoon/shiro/sample/rest/LoginUser.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-shiro-sample/src/main/java/org/apache/cocoon/shiro/sample/rest/LoginUser.java?rev=1243917&r1=1243916&r2=1243917&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-shiro-sample/src/main/java/org/apache/cocoon/shiro/sample/rest/LoginUser.java (original)
+++ cocoon/cocoon3/trunk/cocoon-shiro-sample/src/main/java/org/apache/cocoon/shiro/sample/rest/LoginUser.java Tue Feb 14 13:44:08 2012
@@ -18,8 +18,12 @@
*/
package org.apache.cocoon.shiro.sample.rest;
+import java.net.MalformedURLException;
+import java.util.Map;
import org.apache.cocoon.rest.controller.annotation.RESTController;
+import org.apache.cocoon.rest.controller.response.RestResponse;
+import org.apache.cocoon.rest.controller.response.URLResponse;
import org.apache.cocoon.shiro.rest.AbstractShiroLogin;
@RESTController
@@ -28,8 +32,9 @@ public class LoginUser extends AbstractS
private static final String LOGIN_PAGE = "servlet:/screen/login";
- protected String getLoginPage() {
- return LOGIN_PAGE;
+ protected RestResponse getLoginPage(Map<String, Object> data)
+ throws MalformedURLException {
+ return new URLResponse(LOGIN_PAGE, data);
}
protected String getDefaultTo() {
@@ -37,7 +42,7 @@ public class LoginUser extends AbstractS
}
protected String getErrorLogin() {
- return getLoginPage();
+ return LOGIN_PAGE;
}
}
Modified: cocoon/cocoon3/trunk/cocoon-shiro/src/main/java/org/apache/cocoon/shiro/rest/AbstractShiroLogin.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-shiro/src/main/java/org/apache/cocoon/shiro/rest/AbstractShiroLogin.java?rev=1243917&r1=1243916&r2=1243917&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-shiro/src/main/java/org/apache/cocoon/shiro/rest/AbstractShiroLogin.java (original)
+++ cocoon/cocoon3/trunk/cocoon-shiro/src/main/java/org/apache/cocoon/shiro/rest/AbstractShiroLogin.java Tue Feb 14 13:44:08 2012
@@ -31,6 +31,8 @@ import org.apache.cocoon.rest.controller
import org.apache.cocoon.rest.controller.response.URLResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
@@ -42,12 +44,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RESTController
-public abstract class AbstractShiroLogin implements Post, Get{
-
- protected abstract String getErrorLogin() ;
- protected abstract String getDefaultTo();
- protected abstract String getLoginPage() ;
-
+public abstract class AbstractShiroLogin implements Post, Get {
+
+ protected final String LOGIN_ATTEMPTS_EXCEEDED = "shiroLoginAttemptExceeded";
+
+ protected final String LOGIN_ATTEMPTS_COUNTER = "shiroLoginAttemptCounter";
+
+ private Integer allowedAttempts = 5;
+
@RequestParameter
private String username;
@RequestParameter
@@ -56,7 +60,16 @@ public abstract class AbstractShiroLogin
private boolean rememberMe;
@RequestParameter
protected String to;
- protected static final Logger LOG = LoggerFactory.getLogger(AbstractShiroLogin.class);
+
+ protected static final Logger LOG = LoggerFactory
+ .getLogger(AbstractShiroLogin.class);
+
+ protected abstract String getErrorLogin();
+
+ protected abstract String getDefaultTo();
+
+ protected abstract RestResponse getLoginPage(Map<String, Object> data)
+ throws Exception;
public RestResponse doPost() throws Exception {
// create a UsernamePasswordToken using the
@@ -65,15 +78,35 @@ public abstract class AbstractShiroLogin
password, rememberMe);
Subject subject = SecurityUtils.getSubject();
boolean error = true;
+ Boolean attemptsExceeded = (Boolean) subject.getSession().getAttribute(
+ LOGIN_ATTEMPTS_EXCEEDED);
+ if (attemptsExceeded == null) {
+ attemptsExceeded = false;
+ }
+ boolean invalidCredentials = false;
+ Map<String, Object> errorData = null;
try {
- subject.login(token);
- error = false;
+ errorData = validatePreLogin();
+ if (errorData == null || errorData.isEmpty()) {
+ subject.login(token);
+ error = false;
+ subject.getSession().removeAttribute(LOGIN_ATTEMPTS_EXCEEDED);
+ subject.getSession().removeAttribute(LOGIN_ATTEMPTS_COUNTER);
+ }
+ } catch (ExcessiveAttemptsException eae) {
+ LOG.error(eae.getMessage());
+ attemptsExceeded = true;
} catch (UnknownAccountException ex) {
+ invalidCredentials = true;
LOG.error("UnknownAccountException", ex);
} catch (IncorrectCredentialsException ex) {
+ invalidCredentials = true;
// password provided did not match password found in database
// for the username provided
LOG.error("IncorrectCredentialsException", ex);
+ } catch (AuthenticationException authEx) {
+ invalidCredentials = true;
+ LOG.error("AuthenticationException", authEx);
} catch (Exception e) {
LOG.error("Exception", e);
} finally {
@@ -81,21 +114,73 @@ public abstract class AbstractShiroLogin
}
// clear the information stored in the token
if (error) {
- Map<String, Object> data = new HashMap<String, Object>();
- data.put("error", true);
- data.put("to", getTo());
- return getErrorResponse(data);
+ if (invalidCredentials && !attemptsExceeded) {
+ attemptsExceeded = isAttemptsExceeded(subject);
+ }
+ subject.getSession().setAttribute(LOGIN_ATTEMPTS_EXCEEDED,
+ attemptsExceeded);
+ if (errorData == null) {
+ errorData = new HashMap<String, Object>();
+ }
+ errorData.put("error", true);
+ errorData.put("to", getTo());
+ errorData.put("loginAttemptExceeded", attemptsExceeded);
+ return getErrorResponse(errorData);
} else {
return getSuccessResponse();
}
}
- protected RestResponse getSuccessResponse(){
- return new RedirectResponse(getTo());
+ /**
+ * Checks if login attempts exceeded allowed wrong attempts.
+ *
+ * @param subject
+ * the shiro subject
+ * @return true, if login attempts exceeded
+ */
+ private boolean isAttemptsExceeded(Subject subject) {
+ Integer attemptCount = (Integer) subject.getSession().getAttribute(
+ LOGIN_ATTEMPTS_COUNTER);
+ if (attemptCount == null) {
+ attemptCount = 0;
+ }
+ if (attemptCount >= getAllowedWrongAttempts()) {
+ return true;
+ } else {
+ attemptCount++;
+ }
+ subject.getSession().setAttribute(LOGIN_ATTEMPTS_COUNTER, attemptCount);
+ return false;
+ }
+
+ /**
+ * Gets the number of maximum allowed wrong login attempts.
+ *
+ * @return the allowed wrong attempts count
+ */
+ private Integer getAllowedWrongAttempts() {
+ return allowedAttempts;
+ }
+
+ /**
+ * A validation method that is invoked before initiating login. If this
+ * method returns a non-empty map, then login is skipped and map data is
+ * added to UrlResponse. It can be overridden in extending classes to
+ * perform validations before login like captcha.
+ *
+ * @return the data map that will be passed to error URL Rest response
+ */
+ protected Map<String, Object> validatePreLogin() {
+ return null;
+ }
+
+ protected RestResponse getSuccessResponse() {
+ return new RedirectResponse(getTo());
}
- protected RestResponse getErrorResponse(Map<String, Object> data) throws MalformedURLException{
- return new URLResponse(getErrorLogin(), data);
+ protected RestResponse getErrorResponse(Map<String, Object> data)
+ throws MalformedURLException {
+ return new URLResponse(getErrorLogin(), data);
}
public RestResponse doGet() throws Exception {
@@ -111,7 +196,9 @@ public abstract class AbstractShiroLogin
Map<String, Object> data = new HashMap<String, Object>();
data.put("to", getTo());
data.put("error", false);
- return new URLResponse(getLoginPage(), data);
+ data.put("loginAttemptExceeded",
+ subject.getSession().getAttribute(LOGIN_ATTEMPTS_EXCEEDED));
+ return getLoginPage(data);
}
protected String getTo() {