keycloak-service
クラス | 公開メンバ関数 | 静的公開変数類 | 限定公開メンバ関数 | 限定公開変数類 | 非公開メンバ関数 | 静的非公開変数類 | 全メンバ一覧
org.keycloak.services.managers.DefaultBruteForceProtector クラス
org.keycloak.services.managers.DefaultBruteForceProtector の継承関係図
Inheritance graph
org.keycloak.services.managers.DefaultBruteForceProtector 連携図
Collaboration graph

クラス

class  FailedLogin
 
class  LoginEvent
 
class  ShutdownEvent
 
class  SuccessfulLogin
 

公開メンバ関数

 DefaultBruteForceProtector (KeycloakSessionFactory factory)
 
void failure (KeycloakSession session, LoginEvent event)
 
void start ()
 
void shutdown ()
 
void run ()
 
void failedLogin (RealmModel realm, UserModel user, ClientConnection clientConnection)
 
void successfulLogin (final RealmModel realm, final UserModel user, final ClientConnection clientConnection)
 
boolean isTemporarilyDisabled (KeycloakSession session, RealmModel realm, UserModel user)
 
void close ()
 

静的公開変数類

static final int TRANSACTION_SIZE = 20
 

限定公開メンバ関数

UserLoginFailureModel getUserModel (KeycloakSession session, LoginEvent event)
 
RealmModel getRealmModel (KeycloakSession session, LoginEvent event)
 
void logFailure (LoginEvent event)
 

限定公開変数類

volatile boolean run = true
 
int maxDeltaTimeSeconds = 60 * 60 * 12
 
KeycloakSessionFactory factory
 
CountDownLatch shutdownLatch = new CountDownLatch(1)
 
volatile long failures
 
volatile long lastFailure
 
volatile long totalTime
 
LinkedBlockingQueue< LoginEventqueue = new LinkedBlockingQueue<LoginEvent>()
 

非公開メンバ関数

void success (KeycloakSession session, LoginEvent event)
 

静的非公開変数類

static final Logger logger = Logger.getLogger(DefaultBruteForceProtector.class)
 

詳解

A single thread will log failures. This is so that we can avoid concurrent writes as we want an accurate failure count

著者
Bill Burke
バージョン
Revision
1

構築子と解体子

◆ DefaultBruteForceProtector()

org.keycloak.services.managers.DefaultBruteForceProtector.DefaultBruteForceProtector ( KeycloakSessionFactory  factory)
inline
96  {
97  this.factory = factory;
98  }
KeycloakSessionFactory factory
Definition: DefaultBruteForceProtector.java:47

関数詳解

◆ close()

void org.keycloak.services.managers.DefaultBruteForceProtector.close ( )
inline
321  {
322 
323  }

◆ failedLogin()

void org.keycloak.services.managers.DefaultBruteForceProtector.failedLogin ( RealmModel  realm,
UserModel  user,
ClientConnection  clientConnection 
)
inline
279  {
280  try {
281  FailedLogin event = new FailedLogin(realm.getId(), user.getId(), clientConnection.getRemoteAddr());
282  queue.offer(event);
283  // wait a minimum of seconds for type to process so that a hacker
284  // cannot flood with failed logins and overwhelm the queue and not have notBefore updated to block next requests
285  // todo failure HTTP responses should be queued via async HTTP
286  event.latch.await(5, TimeUnit.SECONDS);
287  } catch (InterruptedException e) {
288  }
289  logger.trace("sent failure event");
290  }
static final Logger logger
Definition: DefaultBruteForceProtector.java:43
LinkedBlockingQueue< LoginEvent > queue
Definition: DefaultBruteForceProtector.java:54

◆ failure()

void org.keycloak.services.managers.DefaultBruteForceProtector.failure ( KeycloakSession  session,
LoginEvent  event 
)
inline
100  {
101  logger.debug("failure");
102  RealmModel realm = getRealmModel(session, event);
103  logFailure(event);
104 
105  String userId = event.userId;
106  UserModel user = session.users().getUserById(userId, realm);
107  if (user == null) {
108  return;
109  }
110 
111  UserLoginFailureModel userLoginFailure = getUserModel(session, event);
112  if (userLoginFailure == null) {
113  userLoginFailure = session.sessions().addUserLoginFailure(realm, userId);
114  }
115  userLoginFailure.setLastIPFailure(event.ip);
116  long currentTime = Time.currentTimeMillis();
117  long last = userLoginFailure.getLastFailure();
118  long deltaTime = 0;
119  if (last > 0) {
120  deltaTime = currentTime - last;
121  }
122  userLoginFailure.setLastFailure(currentTime);
123 
124  if(realm.isPermanentLockout()) {
125  userLoginFailure.incrementFailures();
126  logger.debugv("new num failures: {0}", userLoginFailure.getNumFailures());
127 
128  if(userLoginFailure.getNumFailures() == realm.getFailureFactor()) {
129  logger.debugv("user {0} locked permanently due to too many login attempts", user.getUsername());
130  user.setEnabled(false);
131  return;
132  }
133 
134  if (last > 0 && deltaTime < realm.getQuickLoginCheckMilliSeconds()) {
135  logger.debugv("quick login, set min wait seconds");
136  int waitSeconds = realm.getMinimumQuickLoginWaitSeconds();
137  int notBefore = (int) (currentTime / 1000) + waitSeconds;
138  logger.debugv("set notBefore: {0}", notBefore);
139  userLoginFailure.setFailedLoginNotBefore(notBefore);
140  }
141  return;
142  }
143 
144  if (deltaTime > 0) {
145  // if last failure was more than MAX_DELTA clear failures
146  if (deltaTime > (long) realm.getMaxDeltaTimeSeconds() * 1000L) {
147  userLoginFailure.clearFailures();
148  }
149  }
150  userLoginFailure.incrementFailures();
151  logger.debugv("new num failures: {0}", userLoginFailure.getNumFailures());
152 
153  int waitSeconds = realm.getWaitIncrementSeconds() * (userLoginFailure.getNumFailures() / realm.getFailureFactor());
154  logger.debugv("waitSeconds: {0}", waitSeconds);
155  logger.debugv("deltaTime: {0}", deltaTime);
156 
157  if (waitSeconds == 0) {
158  if (last > 0 && deltaTime < realm.getQuickLoginCheckMilliSeconds()) {
159  logger.debugv("quick login, set min wait seconds");
160  waitSeconds = realm.getMinimumQuickLoginWaitSeconds();
161  }
162  }
163  if (waitSeconds > 0) {
164  waitSeconds = Math.min(realm.getMaxFailureWaitSeconds(), waitSeconds);
165  int notBefore = (int) (currentTime / 1000) + waitSeconds;
166  logger.debugv("set notBefore: {0}", notBefore);
167  userLoginFailure.setFailedLoginNotBefore(notBefore);
168  }
169  }
RealmModel getRealmModel(KeycloakSession session, LoginEvent event)
Definition: DefaultBruteForceProtector.java:180
static final Logger logger
Definition: DefaultBruteForceProtector.java:43
void logFailure(LoginEvent event)
Definition: DefaultBruteForceProtector.java:263
UserLoginFailureModel getUserModel(KeycloakSession session, LoginEvent event)
Definition: DefaultBruteForceProtector.java:172

◆ getRealmModel()

RealmModel org.keycloak.services.managers.DefaultBruteForceProtector.getRealmModel ( KeycloakSession  session,
LoginEvent  event 
)
inlineprotected
180  {
181  RealmModel realm = session.realms().getRealm(event.realmId);
182  if (realm == null) return null;
183  return realm;
184  }

◆ getUserModel()

UserLoginFailureModel org.keycloak.services.managers.DefaultBruteForceProtector.getUserModel ( KeycloakSession  session,
LoginEvent  event 
)
inlineprotected
172  {
173  RealmModel realm = getRealmModel(session, event);
174  if (realm == null) return null;
175  UserLoginFailureModel user = session.sessions().getUserLoginFailure(realm, event.userId);
176  if (user == null) return null;
177  return user;
178  }
RealmModel getRealmModel(KeycloakSession session, LoginEvent event)
Definition: DefaultBruteForceProtector.java:180

◆ isTemporarilyDisabled()

boolean org.keycloak.services.managers.DefaultBruteForceProtector.isTemporarilyDisabled ( KeycloakSession  session,
RealmModel  realm,
UserModel  user 
)
inline
305  {
306  UserLoginFailureModel failure = session.sessions().getUserLoginFailure(realm, user.getId());
307 
308  if (failure != null) {
309  int currTime = (int) (Time.currentTimeMillis() / 1000);
310  int failedLoginNotBefore = failure.getFailedLoginNotBefore();
311  if (currTime < failedLoginNotBefore) {
312  logger.debugv("Current: {0} notBefore: {1}", currTime, failedLoginNotBefore);
313  return true;
314  }
315  }
316 
317 
318  return false;
319  }
void failure(KeycloakSession session, LoginEvent event)
Definition: DefaultBruteForceProtector.java:100
static final Logger logger
Definition: DefaultBruteForceProtector.java:43

◆ logFailure()

void org.keycloak.services.managers.DefaultBruteForceProtector.logFailure ( LoginEvent  event)
inlineprotected
263  {
264  ServicesLogger.LOGGER.loginFailure(event.userId, event.ip);
265  failures++;
266  long delta = 0;
267  if (lastFailure > 0) {
268  delta = Time.currentTimeMillis() - lastFailure;
269  if (delta > (long)maxDeltaTimeSeconds * 1000L) {
270  totalTime = 0;
271 
272  } else {
273  totalTime += delta;
274  }
275  }
276  }
volatile long lastFailure
Definition: DefaultBruteForceProtector.java:51
int maxDeltaTimeSeconds
Definition: DefaultBruteForceProtector.java:46
volatile long failures
Definition: DefaultBruteForceProtector.java:50
volatile long totalTime
Definition: DefaultBruteForceProtector.java:52

◆ run()

void org.keycloak.services.managers.DefaultBruteForceProtector.run ( )
inline
200  {
201  final ArrayList<LoginEvent> events = new ArrayList<LoginEvent>(TRANSACTION_SIZE + 1);
202  try {
203  while (run) {
204  try {
205  LoginEvent take = queue.poll(2, TimeUnit.SECONDS);
206  if (take == null) {
207  continue;
208  }
209  try {
210  events.add(take);
211  queue.drainTo(events, TRANSACTION_SIZE);
212  Collections.sort(events); // we sort to avoid deadlock due to ordered updates. Maybe I'm overthinking this.
213  KeycloakSession session = factory.create();
214  session.getTransactionManager().begin();
215  try {
216  for (LoginEvent event : events) {
217  if (event instanceof FailedLogin) {
218  failure(session, event);
219  } else if (event instanceof SuccessfulLogin) {
220  success(session, event);
221  } else if (event instanceof ShutdownEvent) {
222  run = false;
223  }
224  }
225  session.getTransactionManager().commit();
226  } catch (Exception e) {
227  session.getTransactionManager().rollback();
228  throw e;
229  } finally {
230  for (LoginEvent event : events) {
231  if (event instanceof FailedLogin) {
232  ((FailedLogin) event).latch.countDown();
233  } else if (event instanceof SuccessfulLogin) {
234  ((SuccessfulLogin) event).latch.countDown();
235  }
236  }
237  events.clear();
238  session.close();
239  }
240  } catch (Exception e) {
241  ServicesLogger.LOGGER.failedProcessingType(e);
242  }
243  } catch (InterruptedException e) {
244  break;
245  }
246  }
247  } finally {
248  shutdownLatch.countDown();
249  }
250  }
static final int TRANSACTION_SIZE
Definition: DefaultBruteForceProtector.java:55
void failure(KeycloakSession session, LoginEvent event)
Definition: DefaultBruteForceProtector.java:100
void success(KeycloakSession session, LoginEvent event)
Definition: DefaultBruteForceProtector.java:252
LinkedBlockingQueue< LoginEvent > queue
Definition: DefaultBruteForceProtector.java:54
void run()
Definition: DefaultBruteForceProtector.java:200
KeycloakSessionFactory factory
Definition: DefaultBruteForceProtector.java:47
CountDownLatch shutdownLatch
Definition: DefaultBruteForceProtector.java:48

◆ shutdown()

void org.keycloak.services.managers.DefaultBruteForceProtector.shutdown ( )
inline
190  {
191  run = false;
192  try {
193  queue.offer(new ShutdownEvent());
194  shutdownLatch.await(10, TimeUnit.SECONDS);
195  } catch (InterruptedException e) {
196  throw new RuntimeException(e);
197  }
198  }
LinkedBlockingQueue< LoginEvent > queue
Definition: DefaultBruteForceProtector.java:54
void run()
Definition: DefaultBruteForceProtector.java:200
CountDownLatch shutdownLatch
Definition: DefaultBruteForceProtector.java:48

◆ start()

void org.keycloak.services.managers.DefaultBruteForceProtector.start ( )
inline
186  {
187  new Thread(this, "Brute Force Protector").start();
188  }

◆ success()

void org.keycloak.services.managers.DefaultBruteForceProtector.success ( KeycloakSession  session,
LoginEvent  event 
)
inlineprivate
252  {
253  String userId = event.userId;
254  UserModel model = session.users().getUserById(userId, getRealmModel(session, event));
255 
256  UserLoginFailureModel user = getUserModel(session, event);
257  if(user == null) return;
258 
259  logger.debugv("user {0} successfully logged in, clearing all failures", model.getUsername());
260  user.clearFailures();
261  }
RealmModel getRealmModel(KeycloakSession session, LoginEvent event)
Definition: DefaultBruteForceProtector.java:180
static final Logger logger
Definition: DefaultBruteForceProtector.java:43
UserLoginFailureModel getUserModel(KeycloakSession session, LoginEvent event)
Definition: DefaultBruteForceProtector.java:172

◆ successfulLogin()

void org.keycloak.services.managers.DefaultBruteForceProtector.successfulLogin ( final RealmModel  realm,
final UserModel  user,
final ClientConnection  clientConnection 
)
inline
293  {
294  try {
295  SuccessfulLogin event = new SuccessfulLogin(realm.getId(), user.getId(), clientConnection.getRemoteAddr());
296  queue.offer(event);
297 
298  event.latch.await(5, TimeUnit.SECONDS);
299  } catch (InterruptedException e) {
300  }
301  logger.trace("sent success event");
302  }
static final Logger logger
Definition: DefaultBruteForceProtector.java:43
LinkedBlockingQueue< LoginEvent > queue
Definition: DefaultBruteForceProtector.java:54

メンバ詳解

◆ factory

KeycloakSessionFactory org.keycloak.services.managers.DefaultBruteForceProtector.factory
protected

◆ failures

volatile long org.keycloak.services.managers.DefaultBruteForceProtector.failures
protected

◆ lastFailure

volatile long org.keycloak.services.managers.DefaultBruteForceProtector.lastFailure
protected

◆ logger

final Logger org.keycloak.services.managers.DefaultBruteForceProtector.logger = Logger.getLogger(DefaultBruteForceProtector.class)
staticprivate

◆ maxDeltaTimeSeconds

int org.keycloak.services.managers.DefaultBruteForceProtector.maxDeltaTimeSeconds = 60 * 60 * 12
protected

◆ queue

LinkedBlockingQueue<LoginEvent> org.keycloak.services.managers.DefaultBruteForceProtector.queue = new LinkedBlockingQueue<LoginEvent>()
protected

◆ run

volatile boolean org.keycloak.services.managers.DefaultBruteForceProtector.run = true
protected

◆ shutdownLatch

CountDownLatch org.keycloak.services.managers.DefaultBruteForceProtector.shutdownLatch = new CountDownLatch(1)
protected

◆ totalTime

volatile long org.keycloak.services.managers.DefaultBruteForceProtector.totalTime
protected

◆ TRANSACTION_SIZE

final int org.keycloak.services.managers.DefaultBruteForceProtector.TRANSACTION_SIZE = 20
static

このクラス詳解は次のファイルから抽出されました: