diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/persistence/model/User.java b/spring-security-login-and-registration/src/main/java/org/baeldung/persistence/model/User.java index 5aac7f50a9..4fc2d57f5b 100644 --- a/spring-security-login-and-registration/src/main/java/org/baeldung/persistence/model/User.java +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/persistence/model/User.java @@ -2,6 +2,7 @@ package org.baeldung.persistence.model; import java.util.Collection; +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @@ -23,6 +24,7 @@ public class User { private String email; + @Column(length = 60) private String password; private boolean enabled; diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/security/AuthenticationFailureListener.java b/spring-security-login-and-registration/src/main/java/org/baeldung/security/AuthenticationFailureListener.java new file mode 100644 index 0000000000..3f1702defe --- /dev/null +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/security/AuthenticationFailureListener.java @@ -0,0 +1,19 @@ +package org.baeldung.security; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.stereotype.Component; + +@Component +public class AuthenticationFailureListener implements ApplicationListener { + + @Autowired + private LoginAttemptService loginAttemptService; + + public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent e) { + WebAuthenticationDetails auth = (WebAuthenticationDetails) e.getAuthentication().getDetails(); + loginAttemptService.loginFailed(auth.getRemoteAddress()); + } +} \ No newline at end of file diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/security/AuthenticationSuccessEventListener.java b/spring-security-login-and-registration/src/main/java/org/baeldung/security/AuthenticationSuccessEventListener.java new file mode 100644 index 0000000000..dff78ac0db --- /dev/null +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/security/AuthenticationSuccessEventListener.java @@ -0,0 +1,19 @@ +package org.baeldung.security; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.stereotype.Component; + +@Component +public class AuthenticationSuccessEventListener implements ApplicationListener { + + @Autowired + private LoginAttemptService loginAttemptService; + + public void onApplicationEvent(AuthenticationSuccessEvent e) { + WebAuthenticationDetails auth = (WebAuthenticationDetails) e.getAuthentication().getDetails(); + loginAttemptService.loginSucceeded(auth.getRemoteAddress()); + } +} diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/security/LoginAttemptService.java b/spring-security-login-and-registration/src/main/java/org/baeldung/security/LoginAttemptService.java new file mode 100644 index 0000000000..d03b50932a --- /dev/null +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/security/LoginAttemptService.java @@ -0,0 +1,49 @@ +package org.baeldung.security; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.springframework.stereotype.Service; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +@Service +public class LoginAttemptService { + + private final int MAX_ATTEMPT = 10; + private LoadingCache attemptsCache; + + public LoginAttemptService() { + super(); + attemptsCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.DAYS).build(new CacheLoader() { + public Integer load(String key) { + return 0; + } + }); + } + + public void loginSucceeded(String key) { + attemptsCache.invalidate(key); + } + + public void loginFailed(String key) { + int attempts = 0; + try { + attempts = attemptsCache.get(key); + } catch (ExecutionException e) { + attempts = 0; + } + attempts++; + attemptsCache.put(key, attempts); + } + + public boolean isBlocked(String key) { + try { + return attemptsCache.get(key) >= MAX_ATTEMPT; + } catch (ExecutionException e) { + return false; + } + } +} diff --git a/spring-security-login-and-registration/src/main/java/org/baeldung/security/MyUserDetailsService.java b/spring-security-login-and-registration/src/main/java/org/baeldung/security/MyUserDetailsService.java index 3fa12d0aed..0de7fadd46 100644 --- a/spring-security-login-and-registration/src/main/java/org/baeldung/security/MyUserDetailsService.java +++ b/spring-security-login-and-registration/src/main/java/org/baeldung/security/MyUserDetailsService.java @@ -5,6 +5,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import javax.servlet.http.HttpServletRequest; + import org.baeldung.persistence.dao.RoleRepository; import org.baeldung.persistence.dao.UserRepository; import org.baeldung.persistence.model.Privilege; @@ -34,6 +36,12 @@ public class MyUserDetailsService implements UserDetailsService { @Autowired private RoleRepository roleRepository; + @Autowired + private LoginAttemptService loginAttemptService; + + @Autowired + private HttpServletRequest request; + public MyUserDetailsService() { super(); } @@ -42,6 +50,11 @@ public class MyUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(final String email) throws UsernameNotFoundException { + String ip = request.getRemoteAddr(); + if (loginAttemptService.isBlocked(ip)) { + throw new RuntimeException("blocked"); + } + try { final User user = userRepository.findByEmail(email); if (user == null) { diff --git a/spring-security-login-and-registration/src/main/resources/messages_en.properties b/spring-security-login-and-registration/src/main/resources/messages_en.properties index 801042878b..cc70a9004d 100644 --- a/spring-security-login-and-registration/src/main/resources/messages_en.properties +++ b/spring-security-login-and-registration/src/main/resources/messages_en.properties @@ -58,4 +58,5 @@ message.resendToken=We will send you a message with a new registration token to message.forgetPassword=Forget Password message.resetPassword=Reset Password message.updatePassword=Update Password -message.userNotFound=User Not Found \ No newline at end of file +message.userNotFound=User Not Found +auth.message.blocked=This ip is blocked for 24 hours \ No newline at end of file diff --git a/spring-security-login-and-registration/src/main/resources/messages_es_ES.properties b/spring-security-login-and-registration/src/main/resources/messages_es_ES.properties index 20d0d0332d..f4667dba0a 100644 --- a/spring-security-login-and-registration/src/main/resources/messages_es_ES.properties +++ b/spring-security-login-and-registration/src/main/resources/messages_es_ES.properties @@ -58,4 +58,5 @@ message.resendToken=Le enviaremos un mensaje con un nuevo token de registro en s message.forgetPassword=Olvide la contraseņa message.resetPassword=Restablecer contraseņa message.updatePassword=Actualizar contraseņa -message.userNotFound=Usuario no encontrado \ No newline at end of file +message.userNotFound=Usuario no encontrado +auth.message.blocked=Esta IP se bloquea durante 24 horas \ No newline at end of file diff --git a/spring-security-login-and-registration/src/main/webapp/WEB-INF/view/login.jsp b/spring-security-login-and-registration/src/main/webapp/WEB-INF/view/login.jsp index 21cb940524..a251094ec9 100644 --- a/spring-security-login-and-registration/src/main/webapp/WEB-INF/view/login.jsp +++ b/spring-security-login-and-registration/src/main/webapp/WEB-INF/view/login.jsp @@ -21,6 +21,12 @@ + +
+ +
+
diff --git a/spring-security-login-and-registration/src/main/webapp/WEB-INF/web.xml b/spring-security-login-and-registration/src/main/webapp/WEB-INF/web.xml index 41f9c310a1..ed3d1b3ce7 100644 --- a/spring-security-login-and-registration/src/main/webapp/WEB-INF/web.xml +++ b/spring-security-login-and-registration/src/main/webapp/WEB-INF/web.xml @@ -16,7 +16,11 @@ org.springframework.web.context.ContextLoaderListener - + + + org.springframework.web.context.request.RequestContextListener + + mvc org.springframework.web.servlet.DispatcherServlet