From 54abfb670c9c85096d0502b3ed2b6827eb5386f5 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 15 Apr 2014 11:37:27 -0400 Subject: [PATCH] brute force settings --- .../resources/admin/js/controllers/realm.js | 41 +++++++- .../admin/partials/session-brute-force.html | 96 +++++++++++++++++++ .../idm/RealmRepresentation.java | 57 +++++++++++ .../java/org/keycloak/models/RealmModel.java | 16 +++- .../org/keycloak/models/jpa/RealmAdapter.java | 60 ++++++++++++ .../models/jpa/entities/RealmEntity.java | 57 +++++++++++ .../mongo/keycloak/adapters/RealmAdapter.java | 62 ++++++++++++ .../mongo/keycloak/entities/RealmEntity.java | 62 ++++++++++++ .../managers/BruteForceProtector.java | 75 ++------------- .../managers/ModelToRepresentation.java | 6 ++ .../services/managers/RealmManager.java | 27 +++++- 11 files changed, 490 insertions(+), 69 deletions(-) diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js index 04be1273b1..a08236d7ce 100755 --- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js +++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js @@ -1119,11 +1119,35 @@ module.controller('RealmAuditEventsCtrl', function($scope, RealmAuditEvents, rea $scope.update(); }); -module.controller('RealmBruteForceCtrl', function($scope, Realm, realm, $http, $location, Dialog, Notifications) { +module.controller('RealmBruteForceCtrl', function($scope, Realm, realm, $http, $location, Dialog, Notifications, TimeUnit) { console.log('RealmBruteForceCtrl'); $scope.realm = realm; + $scope.realm.waitIncrementUnit = TimeUnit.autoUnit(realm.waitIncrementSeconds); + $scope.realm.waitIncrement = TimeUnit.toUnit(realm.waitIncrementSeconds, $scope.realm.waitIncrementUnit); + $scope.$watch('realm.waitIncrementUnit', function(to, from) { + $scope.realm.waitIncrement = TimeUnit.convert($scope.realm.waitIncrement, from, to); + }); + + $scope.realm.minimumQuickLoginWaitUnit = TimeUnit.autoUnit(realm.minimumQuickLoginWaitSeconds); + $scope.realm.minimumQuickLoginWait = TimeUnit.toUnit(realm.minimumQuickLoginWaitSeconds, $scope.realm.minimumQuickLoginWaitUnit); + $scope.$watch('realm.minimumQuickLoginWaitUnit', function(to, from) { + $scope.realm.minimumQuickLoginWait = TimeUnit.convert($scope.realm.minimumQuickLoginWait, from, to); + }); + + $scope.realm.maxFailureWaitUnit = TimeUnit.autoUnit(realm.maxFailureWaitSeconds); + $scope.realm.maxFailureWait = TimeUnit.toUnit(realm.maxFailureWaitSeconds, $scope.realm.maxFailureWaitUnit); + $scope.$watch('realm.maxFailureWaitUnit', function(to, from) { + $scope.realm.maxFailureWait = TimeUnit.convert($scope.realm.maxFailureWait, from, to); + }); + + $scope.realm.maxDeltaTimeUnit = TimeUnit.autoUnit(realm.maxDeltaTimeSeconds); + $scope.realm.maxDeltaTime = TimeUnit.toUnit(realm.maxDeltaTimeSeconds, $scope.realm.maxDeltaTimeUnit); + $scope.$watch('realm.maxDeltaTimeUnit', function(to, from) { + $scope.realm.maxDeltaTime = TimeUnit.convert($scope.realm.maxDeltaTime, from, to); + }); + var oldCopy = angular.copy($scope.realm); $scope.changed = false; @@ -1135,6 +1159,20 @@ module.controller('RealmBruteForceCtrl', function($scope, Realm, realm, $http, $ $scope.save = function() { var realmCopy = angular.copy($scope.realm); + delete realmCopy["waitIncrementUnit"]; + delete realmCopy["waitIncrement"]; + delete realmCopy["minimumQuickLoginWaitUnit"]; + delete realmCopy["minimumQuickLoginWait"]; + delete realmCopy["maxFailureWaitUnit"]; + delete realmCopy["maxFailureWait"]; + delete realmCopy["maxDeltaTimeUnit"]; + delete realmCopy["maxDeltaTime"]; + + realmCopy.waitIncrementSeconds = TimeUnit.toSeconds($scope.realm.waitIncrement, $scope.realm.waitIncrementUnit) + realmCopy.minimumQuickLoginWaitSeconds = TimeUnit.toSeconds($scope.realm.minimumQuickLoginWait, $scope.realm.minimumQuickLoginWaitUnit) + realmCopy.maxFailureWaitSeconds = TimeUnit.toSeconds($scope.realm.maxFailureWait, $scope.realm.maxFailureWaitUnit) + realmCopy.maxDeltaTimeSeconds = TimeUnit.toSeconds($scope.realm.maxDeltaTime, $scope.realm.maxDeltaTimeUnit) + $scope.changed = false; Realm.update(realmCopy, function () { $location.url("/realms/" + realm.realm + "/sessions/brute-force"); @@ -1148,3 +1186,4 @@ module.controller('RealmBruteForceCtrl', function($scope, Realm, realm, $http, $ }; }); + diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-brute-force.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-brute-force.html index ae4571284f..a2c7f4704f 100755 --- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-brute-force.html +++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-brute-force.html @@ -20,6 +20,102 @@ +
+ + +
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+ + +
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+
+
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java index 0228a8ba7f..2812fc41d2 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java @@ -28,7 +28,16 @@ public class RealmRepresentation { protected Boolean resetPasswordAllowed; protected Boolean social; protected Boolean updateProfileOnInitialSocialLogin; + //--- brute force settings protected Boolean bruteForceProtected; + protected Integer maxFailureWaitSeconds; + protected Integer minimumQuickLoginWaitSeconds; + protected Integer waitIncrementSeconds; + protected Long quickLoginCheckMilliSeconds; + protected Integer maxDeltaTimeSeconds; + protected Integer failureFactor; + //--- end brute force settings + protected String privateKey; protected String publicKey; protected RolesRepresentation roles; @@ -384,4 +393,52 @@ public class RealmRepresentation { public void setBruteForceProtected(Boolean bruteForceProtected) { this.bruteForceProtected = bruteForceProtected; } + + public Integer getMaxFailureWaitSeconds() { + return maxFailureWaitSeconds; + } + + public void setMaxFailureWaitSeconds(Integer maxFailureWaitSeconds) { + this.maxFailureWaitSeconds = maxFailureWaitSeconds; + } + + public Integer getMinimumQuickLoginWaitSeconds() { + return minimumQuickLoginWaitSeconds; + } + + public void setMinimumQuickLoginWaitSeconds(Integer minimumQuickLoginWaitSeconds) { + this.minimumQuickLoginWaitSeconds = minimumQuickLoginWaitSeconds; + } + + public Integer getWaitIncrementSeconds() { + return waitIncrementSeconds; + } + + public void setWaitIncrementSeconds(Integer waitIncrementSeconds) { + this.waitIncrementSeconds = waitIncrementSeconds; + } + + public Long getQuickLoginCheckMilliSeconds() { + return quickLoginCheckMilliSeconds; + } + + public void setQuickLoginCheckMilliSeconds(Long quickLoginCheckMilliSeconds) { + this.quickLoginCheckMilliSeconds = quickLoginCheckMilliSeconds; + } + + public Integer getMaxDeltaTimeSeconds() { + return maxDeltaTimeSeconds; + } + + public void setMaxDeltaTimeSeconds(Integer maxDeltaTimeSeconds) { + this.maxDeltaTimeSeconds = maxDeltaTimeSeconds; + } + + public Integer getFailureFactor() { + return failureFactor; + } + + public void setFailureFactor(Integer failureFactor) { + this.failureFactor = failureFactor; + } } diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java index 6e2060505f..eda8e30d97 100755 --- a/model/api/src/main/java/org/keycloak/models/RealmModel.java +++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java @@ -33,9 +33,23 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa void setRememberMe(boolean rememberMe); + //--- brute force settings boolean isBruteForceProtected(); - void setBruteForceProtected(boolean value); + int getMaxFailureWaitSeconds(); + void setMaxFailureWaitSeconds(int val); + int getWaitIncrementSeconds(); + void setWaitIncrementSeconds(int val); + int getMinimumQuickLoginWaitSeconds(); + void setMinimumQuickLoginWaitSeconds(int val); + long getQuickLoginCheckMilliSeconds(); + void setQuickLoginCheckMilliSeconds(long val); + int getMaxDeltaTimeSeconds(); + void setMaxDeltaTimeSeconds(int val); + int getFailureFactor(); + void setFailureFactor(int failureFactor); + //--- end brute force settings + boolean isVerifyEmail(); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index fce9a3d9f2..2833c64601 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -136,6 +136,66 @@ public class RealmAdapter implements RealmModel { realm.setBruteForceProtected(value); } + @Override + public int getMaxFailureWaitSeconds() { + return realm.getMaxFailureWaitSeconds(); + } + + @Override + public void setMaxFailureWaitSeconds(int val) { + realm.setMaxFailureWaitSeconds(val); + } + + @Override + public int getWaitIncrementSeconds() { + return realm.getWaitIncrementSeconds(); + } + + @Override + public void setWaitIncrementSeconds(int val) { + realm.setWaitIncrementSeconds(val); + } + + @Override + public long getQuickLoginCheckMilliSeconds() { + return realm.getQuickLoginCheckMilliSeconds(); + } + + @Override + public void setQuickLoginCheckMilliSeconds(long val) { + realm.setQuickLoginCheckMilliSeconds(val); + } + + @Override + public int getMinimumQuickLoginWaitSeconds() { + return realm.getMinimumQuickLoginWaitSeconds(); + } + + @Override + public void setMinimumQuickLoginWaitSeconds(int val) { + realm.setMinimumQuickLoginWaitSeconds(val); + } + + @Override + public int getMaxDeltaTimeSeconds() { + return realm.getMaxDeltaTimeSeconds(); + } + + @Override + public void setMaxDeltaTimeSeconds(int val) { + realm.setMaxDeltaTimeSeconds(val); + } + + @Override + public int getFailureFactor() { + return realm.getFailureFactor(); + } + + @Override + public void setFailureFactor(int failureFactor) { + realm.setFailureFactor(failureFactor); + } + @Override public boolean isVerifyEmail() { return realm.isVerifyEmail(); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java index 6885a7006f..556065f41d 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java @@ -42,7 +42,16 @@ public class RealmEntity { protected boolean resetPasswordAllowed; protected boolean social; protected boolean rememberMe; + //--- brute force settings protected boolean bruteForceProtected; + protected int maxFailureWaitSeconds; + protected int minimumQuickLoginWaitSeconds; + protected int waitIncrementSeconds; + protected long quickLoginCheckMilliSeconds; + protected int maxDeltaTimeSeconds; + protected int failureFactor; + //--- end brute force settings + @Column(name="updateProfileOnInitSocLogin") protected boolean updateProfileOnInitialSocialLogin; @@ -352,6 +361,54 @@ public class RealmEntity { this.bruteForceProtected = bruteForceProtected; } + public int getMaxFailureWaitSeconds() { + return maxFailureWaitSeconds; + } + + public void setMaxFailureWaitSeconds(int maxFailureWaitSeconds) { + this.maxFailureWaitSeconds = maxFailureWaitSeconds; + } + + public int getMinimumQuickLoginWaitSeconds() { + return minimumQuickLoginWaitSeconds; + } + + public void setMinimumQuickLoginWaitSeconds(int minimumQuickLoginWaitSeconds) { + this.minimumQuickLoginWaitSeconds = minimumQuickLoginWaitSeconds; + } + + public int getWaitIncrementSeconds() { + return waitIncrementSeconds; + } + + public void setWaitIncrementSeconds(int waitIncrementSeconds) { + this.waitIncrementSeconds = waitIncrementSeconds; + } + + public long getQuickLoginCheckMilliSeconds() { + return quickLoginCheckMilliSeconds; + } + + public void setQuickLoginCheckMilliSeconds(long quickLoginCheckMilliSeconds) { + this.quickLoginCheckMilliSeconds = quickLoginCheckMilliSeconds; + } + + public int getMaxDeltaTimeSeconds() { + return maxDeltaTimeSeconds; + } + + public void setMaxDeltaTimeSeconds(int maxDeltaTimeSeconds) { + this.maxDeltaTimeSeconds = maxDeltaTimeSeconds; + } + + public int getFailureFactor() { + return failureFactor; + } + + public void setFailureFactor(int failureFactor) { + this.failureFactor = failureFactor; + } + public boolean isAuditEnabled() { return auditEnabled; } diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java index 3fc43f24d4..2052967b53 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java @@ -134,6 +134,68 @@ public class RealmAdapter extends AbstractMongoAdapter implements R realm.setBruteForceProtected(value); } + @Override + public int getMaxFailureWaitSeconds() { + return realm.getMaxFailureWaitSeconds(); + } + + @Override + public void setMaxFailureWaitSeconds(int val) { + realm.setMaxFailureWaitSeconds(val); + } + + @Override + public int getWaitIncrementSeconds() { + return realm.getWaitIncrementSeconds(); + } + + @Override + public void setWaitIncrementSeconds(int val) { + realm.setWaitIncrementSeconds(val); + } + + @Override + public long getQuickLoginCheckMilliSeconds() { + return realm.getQuickLoginCheckMilliSeconds(); + } + + @Override + public void setQuickLoginCheckMilliSeconds(long val) { + realm.setQuickLoginCheckMilliSeconds(val); + } + + @Override + public int getMinimumQuickLoginWaitSeconds() { + return realm.getMinimumQuickLoginWaitSeconds(); + } + + @Override + public void setMinimumQuickLoginWaitSeconds(int val) { + realm.setMinimumQuickLoginWaitSeconds(val); + } + + + @Override + public int getMaxDeltaTimeSeconds() { + return realm.getMaxDeltaTimeSeconds(); + } + + @Override + public void setMaxDeltaTimeSeconds(int val) { + realm.setMaxDeltaTimeSeconds(val); + } + + @Override + public int getFailureFactor() { + return realm.getFailureFactor(); + } + + @Override + public void setFailureFactor(int failureFactor) { + realm.setFailureFactor(failureFactor); + } + + @Override public boolean isVerifyEmail() { return realm.isVerifyEmail(); diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/RealmEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/RealmEntity.java index 6786c9013f..fc0ee56a82 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/RealmEntity.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/RealmEntity.java @@ -32,7 +32,15 @@ public class RealmEntity extends AbstractMongoIdentifiableEntity implements Mong private boolean social; private boolean updateProfileOnInitialSocialLogin; private String passwordPolicy; + //--- brute force settings private boolean bruteForceProtected; + private int maxFailureWaitSeconds; + private int minimumQuickLoginWaitSeconds; + private int waitIncrementSeconds; + private long quickLoginCheckMilliSeconds; + private int maxDeltaTimeSeconds; + private int failureFactor; + //--- end brute force settings private int centralLoginLifespan; private int accessTokenLifespan; @@ -151,6 +159,60 @@ public class RealmEntity extends AbstractMongoIdentifiableEntity implements Mong this.bruteForceProtected = bruteForceProtected; } + @MongoField + public int getMaxFailureWaitSeconds() { + return maxFailureWaitSeconds; + } + + public void setMaxFailureWaitSeconds(int maxFailureWaitSeconds) { + this.maxFailureWaitSeconds = maxFailureWaitSeconds; + } + + @MongoField + public int getMinimumQuickLoginWaitSeconds() { + return minimumQuickLoginWaitSeconds; + } + + public void setMinimumQuickLoginWaitSeconds(int minimumQuickLoginWaitSeconds) { + this.minimumQuickLoginWaitSeconds = minimumQuickLoginWaitSeconds; + } + + @MongoField + public int getWaitIncrementSeconds() { + return waitIncrementSeconds; + } + + public void setWaitIncrementSeconds(int waitIncrementSeconds) { + this.waitIncrementSeconds = waitIncrementSeconds; + } + + @MongoField + public long getQuickLoginCheckMilliSeconds() { + return quickLoginCheckMilliSeconds; + } + + public void setQuickLoginCheckMilliSeconds(long quickLoginCheckMilliSeconds) { + this.quickLoginCheckMilliSeconds = quickLoginCheckMilliSeconds; + } + + @MongoField + public int getMaxDeltaTimeSeconds() { + return maxDeltaTimeSeconds; + } + + public void setMaxDeltaTimeSeconds(int maxDeltaTimeSeconds) { + this.maxDeltaTimeSeconds = maxDeltaTimeSeconds; + } + + @MongoField + public int getFailureFactor() { + return failureFactor; + } + + public void setFailureFactor(int failureFactor) { + this.failureFactor = failureFactor; + } + @MongoField public String getPasswordPolicy() { return passwordPolicy; diff --git a/services/src/main/java/org/keycloak/services/managers/BruteForceProtector.java b/services/src/main/java/org/keycloak/services/managers/BruteForceProtector.java index 8692bf183b..5645c57c04 100755 --- a/services/src/main/java/org/keycloak/services/managers/BruteForceProtector.java +++ b/services/src/main/java/org/keycloak/services/managers/BruteForceProtector.java @@ -23,13 +23,8 @@ import java.util.concurrent.TimeUnit; public class BruteForceProtector implements Runnable { protected static Logger logger = Logger.getLogger(BruteForceProtector.class); - protected int maxFailureWaitSeconds = 900; - protected int minimumQuickLoginWaitSeconds = 60; - protected int waitIncrementSeconds = 60; - protected long quickLoginCheckMilliSeconds = 1000; - protected long maxDeltaTimeMilliSeconds = 60 * 60 * 12 * 1000; // 12 hours - protected int failureFactor = 30; protected volatile boolean run = true; + protected int maxDeltaTimeSeconds = 60 * 60 * 12; // 12 hours protected KeycloakSessionFactory factory; protected CountDownLatch shutdownLatch = new CountDownLatch(1); @@ -83,6 +78,8 @@ public class BruteForceProtector implements Runnable { } public void failure(KeycloakSession session, LoginEvent event) { + RealmModel realm = getRealmModel(session, event); + logFailure(event); UsernameLoginFailureModel user = getUserModel(session, event); if (user == null) return; user.setLastIPFailure(event.ip); @@ -95,19 +92,19 @@ public class BruteForceProtector implements Runnable { user.setLastFailure(currentTime); if (deltaTime > 0) { // if last failure was more than MAX_DELTA clear failures - if (deltaTime > maxDeltaTimeMilliSeconds) { + if (deltaTime > (long)realm.getMaxDeltaTimeSeconds() *1000L) { user.clearFailures(); } } user.incrementFailures(); - int waitSeconds = waitIncrementSeconds * (user.getNumFailures() / failureFactor); + int waitSeconds = realm.getWaitIncrementSeconds() * (user.getNumFailures() / realm.getFailureFactor()); if (waitSeconds == 0) { - if (deltaTime > quickLoginCheckMilliSeconds) { - waitSeconds = minimumQuickLoginWaitSeconds; + if (deltaTime > realm.getQuickLoginCheckMilliSeconds()) { + waitSeconds = realm.getMinimumQuickLoginWaitSeconds(); } } - waitSeconds = Math.min(maxFailureWaitSeconds, waitSeconds); + waitSeconds = Math.min(realm.getMaxFailureWaitSeconds(), waitSeconds); if (waitSeconds > 0) { user.setFailedLoginNotBefore((int) (currentTime / 1000) + waitSeconds); } @@ -153,14 +150,6 @@ public class BruteForceProtector implements Runnable { try { events.add(take); queue.drainTo(events, TRANSACTION_SIZE); - for (LoginEvent event : events) { - if (event instanceof FailedLogin) { - logFailure(event); - } else if (event instanceof SuccessfulLogin) { - logSuccess(event); - } - } - Collections.sort(events); // we sort to avoid deadlock due to ordered updates. Maybe I'm overthinking this. KeycloakSession session = factory.createSession(); try { @@ -203,7 +192,7 @@ public class BruteForceProtector implements Runnable { long delta = 0; if (lastFailure > 0) { delta = System.currentTimeMillis() - lastFailure; - if (delta > maxDeltaTimeMilliSeconds) { + if (delta > (long)maxDeltaTimeSeconds * 1000L) { totalTime = 0; } else { @@ -255,51 +244,5 @@ public class BruteForceProtector implements Runnable { return lastFailure; } - public int getMaxFailureWaitSeconds() { - return maxFailureWaitSeconds; - } - public void setMaxFailureWaitSeconds(int maxFailureWaitSeconds) { - this.maxFailureWaitSeconds = maxFailureWaitSeconds; - } - - public int getMinimumQuickLoginWaitSeconds() { - return minimumQuickLoginWaitSeconds; - } - - public void setMinimumQuickLoginWaitSeconds(int minimumQuickLoginWaitSeconds) { - this.minimumQuickLoginWaitSeconds = minimumQuickLoginWaitSeconds; - } - - public int getWaitIncrementSeconds() { - return waitIncrementSeconds; - } - - public void setWaitIncrementSeconds(int waitIncrementSeconds) { - this.waitIncrementSeconds = waitIncrementSeconds; - } - - public long getQuickLoginCheckMilliSeconds() { - return quickLoginCheckMilliSeconds; - } - - public void setQuickLoginCheckMilliSeconds(long quickLoginCheckMilliSeconds) { - this.quickLoginCheckMilliSeconds = quickLoginCheckMilliSeconds; - } - - public long getMaxDeltaTimeMilliSeconds() { - return maxDeltaTimeMilliSeconds; - } - - public void setMaxDeltaTimeMilliSeconds(long maxDeltaTimeMilliSeconds) { - this.maxDeltaTimeMilliSeconds = maxDeltaTimeMilliSeconds; - } - - public int getFailureFactor() { - return failureFactor; - } - - public void setFailureFactor(int failureFactor) { - this.failureFactor = failureFactor; - } } diff --git a/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java b/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java index 24c09b2016..197046b3ea 100755 --- a/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java +++ b/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java @@ -79,6 +79,12 @@ public class ModelToRepresentation { rep.setRegistrationAllowed(realm.isRegistrationAllowed()); rep.setRememberMe(realm.isRememberMe()); rep.setBruteForceProtected(realm.isBruteForceProtected()); + rep.setMaxFailureWaitSeconds(realm.getMaxFailureWaitSeconds()); + rep.setMinimumQuickLoginWaitSeconds(realm.getMinimumQuickLoginWaitSeconds()); + rep.setWaitIncrementSeconds(realm.getWaitIncrementSeconds()); + rep.setQuickLoginCheckMilliSeconds(realm.getQuickLoginCheckMilliSeconds()); + rep.setMaxDeltaTimeSeconds(realm.getMaxDeltaTimeSeconds()); + rep.setFailureFactor(realm.getFailureFactor()); rep.setVerifyEmail(realm.isVerifyEmail()); rep.setResetPasswordAllowed(realm.isResetPasswordAllowed()); rep.setAccessTokenLifespan(realm.getAccessTokenLifespan()); diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index b710af6cc4..f6e9bebf8e 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -79,7 +79,9 @@ public class RealmManager { if (id == null) id = KeycloakModelUtils.generateId(); RealmModel realm = identitySession.createRealm(id, name); realm.setName(name); - realm.setBruteForceProtected(false); // default settings off for now todo set it on + + // setup defaults + setupRealmDefaults(realm); setupAdminManagement(realm); setupAccountManagement(realm); @@ -89,6 +91,17 @@ public class RealmManager { return realm; } + protected void setupRealmDefaults(RealmModel realm) { + // brute force + realm.setBruteForceProtected(false); // default settings off for now todo set it on + realm.setMaxFailureWaitSeconds(900); + realm.setMinimumQuickLoginWaitSeconds(60); + realm.setWaitIncrementSeconds(60); + realm.setQuickLoginCheckMilliSeconds(1000); + realm.setMaxDeltaTimeSeconds(60 * 60 * 12); // 12 hours + realm.setFailureFactor(30); + } + public boolean removeRealm(RealmModel realm) { boolean removed = identitySession.removeRealm(realm.getId()); @@ -123,6 +136,12 @@ public class RealmManager { if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled()); if (rep.isSocial() != null) realm.setSocial(rep.isSocial()); if (rep.isBruteForceProtected() != null) realm.setBruteForceProtected(rep.isBruteForceProtected()); + if (rep.getMaxFailureWaitSeconds() != null) realm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds()); + if (rep.getMinimumQuickLoginWaitSeconds() != null) realm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds()); + if (rep.getWaitIncrementSeconds() != null) realm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds()); + if (rep.getQuickLoginCheckMilliSeconds() != null) realm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds()); + if (rep.getMaxDeltaTimeSeconds() != null) realm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds()); + if (rep.getFailureFactor() != null) realm.setFailureFactor(rep.getFailureFactor()); if (rep.isRegistrationAllowed() != null) realm.setRegistrationAllowed(rep.isRegistrationAllowed()); if (rep.isRememberMe() != null) realm.setRememberMe(rep.isRememberMe()); if (rep.isVerifyEmail() != null) realm.setVerifyEmail(rep.isVerifyEmail()); @@ -230,6 +249,12 @@ public class RealmManager { if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled()); if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial()); if (rep.isBruteForceProtected() != null) newRealm.setBruteForceProtected(rep.isBruteForceProtected()); + if (rep.getMaxFailureWaitSeconds() != null) newRealm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds()); + if (rep.getMinimumQuickLoginWaitSeconds() != null) newRealm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds()); + if (rep.getWaitIncrementSeconds() != null) newRealm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds()); + if (rep.getQuickLoginCheckMilliSeconds() != null) newRealm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds()); + if (rep.getMaxDeltaTimeSeconds() != null) newRealm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds()); + if (rep.getFailureFactor() != null) newRealm.setFailureFactor(rep.getFailureFactor()); if (rep.getNotBefore() != null) newRealm.setNotBefore(rep.getNotBefore());