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() {
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.