11package com.imsproject.servermanager
22
3+ import kotlinx.coroutines.DelicateCoroutinesApi
4+ import kotlinx.coroutines.GlobalScope
5+ import kotlinx.coroutines.Job
6+ import kotlinx.coroutines.launch
37import org.springframework.context.annotation.Bean
48import org.springframework.context.annotation.Configuration
59import org.springframework.security.authentication.AuthenticationManager
@@ -12,6 +16,9 @@ import org.springframework.security.core.Authentication
1216import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
1317import org.springframework.security.crypto.password.PasswordEncoder
1418import org.springframework.security.web.SecurityFilterChain
19+ import org.springframework.security.web.authentication.WebAuthenticationDetails
20+ import java.util.concurrent.ConcurrentHashMap
21+ import java.util.concurrent.atomic.AtomicInteger
1522
1623@EnableWebSecurity
1724@Configuration
@@ -34,17 +41,45 @@ class SecurityConfig {
3441
3542 private val encoder: PasswordEncoder = BCryptPasswordEncoder ()
3643 private val pass = " \$ 2a\$ 10\$ Ss09W28r0vuNd67EHqcAw.piDzMvPFV4YHK0d0rh2C30O26NYAewG"
44+ private val badAttemptsMap : MutableMap <String , AtomicInteger > = ConcurrentHashMap ()
45+ private val lockedOutAddresses : MutableMap <String , Job > = ConcurrentHashMap ()
3746
3847 override fun authenticate (authentication : Authentication ): Authentication {
39- val userName = authentication.name
40- if (userName.lowercase() != " admin" ) {
41- throw BadCredentialsException (" Bad Credentials" )
48+ val details = authentication.details as WebAuthenticationDetails
49+ val remoteAddress = details.remoteAddress
50+
51+ if (lockedOutAddresses.contains(remoteAddress)) {
52+ throw BadCredentialsException (" Login attempts exceeded, try again later" )
4253 }
43- val password = authentication.credentials.toString()
44- if (encoder.matches(password, pass)) {
45- return UsernamePasswordAuthenticationToken (userName, password, emptyList())
46- } else {
47- throw BadCredentialsException (" Bad Credentials" )
54+
55+ try {
56+ val userName = authentication.name
57+ if (userName.lowercase() != " admin" ) {
58+ badAttemptsMap.computeIfAbsent(remoteAddress) { AtomicInteger (0 ) }.incrementAndGet()
59+ throw BadCredentialsException (" Bad Credentials" )
60+ }
61+ val password = authentication.credentials.toString()
62+ if (encoder.matches(password, pass)) {
63+ badAttemptsMap.remove(remoteAddress)
64+ return UsernamePasswordAuthenticationToken (userName, password, emptyList())
65+ } else {
66+ badAttemptsMap.computeIfAbsent(remoteAddress) { AtomicInteger (0 ) }.incrementAndGet()
67+ throw BadCredentialsException (" Bad Credentials" )
68+ }
69+ } finally {
70+ val attemptsCount = badAttemptsMap[remoteAddress]
71+ if (attemptsCount != null ){
72+ synchronized(attemptsCount) {
73+ if (remoteAddress !in lockedOutAddresses && attemptsCount.get() >= 3 ) {
74+ @OptIn(DelicateCoroutinesApi ::class )
75+ lockedOutAddresses[remoteAddress] = GlobalScope .launch {
76+ kotlinx.coroutines.delay(30 * 1000 )
77+ lockedOutAddresses.remove(remoteAddress)
78+ badAttemptsMap.remove(remoteAddress)
79+ }
80+ }
81+ }
82+ }
4883 }
4984 }
5085 })
0 commit comments