keycloak-memoizeit
Merge pull request #1361 from ssilvert/KEYCLOAK-1083-unlock-user-account KEYCLOAK-1083: …
Changes
model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java 6(+6 -0)
model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UsernameLoginFailureAdapter.java 2(+1 -1)
model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UsernameLoginFailureEntity.java 7(+7 -0)
model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/UsernameLoginFailureAdapter.java 2(+1 -1)
model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/UsernameLoginFailureEntity.java 7(+7 -0)
model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/UsernameLoginFailureAdapter.java 2(+1 -1)
Details
diff --git a/model/api/src/main/java/org/keycloak/models/entities/UsernameLoginFailureEntity.java b/model/api/src/main/java/org/keycloak/models/entities/UsernameLoginFailureEntity.java
index e25e717..e6123f3 100644
--- a/model/api/src/main/java/org/keycloak/models/entities/UsernameLoginFailureEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/UsernameLoginFailureEntity.java
@@ -60,4 +60,11 @@ public class UsernameLoginFailureEntity extends AbstractIdentifiableEntity {
public void setRealmId(String realmId) {
this.realmId = realmId;
}
+
+ public void clearFailures() {
+ this.numFailures = 0;
+ this.lastFailure = 0;
+ this.lastIPFailure = null;
+ this.failedLoginNotBefore = 0;
+ }
}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
index 8bb05e7..b330c2e 100644
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
@@ -62,4 +62,10 @@ public class LoginFailureEntity implements Serializable {
this.lastIPFailure = lastIPFailure;
}
+ public void clearFailures() {
+ this.failedLoginNotBefore = 0;
+ this.numFailures = 0;
+ this.lastFailure = 0;
+ this.lastIPFailure = null;
+ }
}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UsernameLoginFailureAdapter.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UsernameLoginFailureAdapter.java
index fed8f28..c478a0f 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UsernameLoginFailureAdapter.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UsernameLoginFailureAdapter.java
@@ -51,7 +51,7 @@ public class UsernameLoginFailureAdapter implements UsernameLoginFailureModel {
@Override
public void clearFailures() {
- entity.setNumFailures(0);
+ entity.clearFailures();
update();
}
diff --git a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UsernameLoginFailureEntity.java b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UsernameLoginFailureEntity.java
index c62e474..d03f597 100755
--- a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UsernameLoginFailureEntity.java
+++ b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/entities/UsernameLoginFailureEntity.java
@@ -91,6 +91,13 @@ public class UsernameLoginFailureEntity {
this.realmId = realmId;
}
+ public void clearFailures() {
+ setFailedLoginNotBefore(0);
+ setLastFailure(0);
+ setLastIPFailure(null);
+ setNumFailures(0);
+ }
+
public static class Key implements Serializable {
private String realmId;
diff --git a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/UsernameLoginFailureAdapter.java b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/UsernameLoginFailureAdapter.java
index b5852bb..9293648 100755
--- a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/UsernameLoginFailureAdapter.java
+++ b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/UsernameLoginFailureAdapter.java
@@ -43,7 +43,7 @@ public class UsernameLoginFailureAdapter implements UsernameLoginFailureModel
@Override
public void clearFailures() {
- user.setNumFailures(0);
+ user.clearFailures();
}
@Override
diff --git a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/UsernameLoginFailureEntity.java b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/UsernameLoginFailureEntity.java
index b1788d2..32cf981 100644
--- a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/UsernameLoginFailureEntity.java
+++ b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/entities/UsernameLoginFailureEntity.java
@@ -62,4 +62,11 @@ public class UsernameLoginFailureEntity {
this.lastIpFailure = lastIpFailure;
}
+ public void clearFailures() {
+ this.failedLoginNotBefore = new AtomicInteger();
+ this.lastFailure = new AtomicLong();
+ this.lastIpFailure = new AtomicReference<String>();
+ this.numFailures = new AtomicInteger();
+ }
+
}
diff --git a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/UsernameLoginFailureAdapter.java b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/UsernameLoginFailureAdapter.java
index 03dc558..e47a643 100644
--- a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/UsernameLoginFailureAdapter.java
+++ b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/UsernameLoginFailureAdapter.java
@@ -45,7 +45,7 @@ public class UsernameLoginFailureAdapter implements UsernameLoginFailureModel {
@Override
public void clearFailures() {
- entity.getNumFailures().set(0);
+ entity.clearFailures();
}
@Override
diff --git a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/UsernameLoginFailureAdapter.java b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/UsernameLoginFailureAdapter.java
index 7d28125..251d26e 100755
--- a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/UsernameLoginFailureAdapter.java
+++ b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/UsernameLoginFailureAdapter.java
@@ -50,7 +50,7 @@ public class UsernameLoginFailureAdapter extends AbstractMongoAdapter<MongoUser
@Override
public void clearFailures() {
- user.setNumFailures(0);
+ user.clearFailures();
updateMongoEntity();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 55d97b0..c00fb11 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -68,6 +68,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.services.managers.BruteForceProtector;
/**
* Base resource for managing users
@@ -81,9 +83,9 @@ public class UsersResource {
protected RealmModel realm;
private RealmAuth auth;
-
+
private AdminEventBuilder adminEvent;
-
+
@Context
protected ClientConnection clientConnection;
@@ -96,6 +98,9 @@ public class UsersResource {
@Context
protected HttpHeaders headers;
+ @Context
+ protected BruteForceProtector protector;
+
public UsersResource(RealmModel realm, RealmAuth auth, TokenManager tokenManager, AdminEventBuilder adminEvent) {
this.auth = auth;
this.realm = realm;
@@ -131,6 +136,13 @@ public class UsersResource {
attrsToRemove = Collections.emptySet();
}
+ if (rep.isEnabled()) {
+ UsernameLoginFailureModel failureModel = session.sessions().getUserLoginFailure(realm, rep.getUsername());
+ if (failureModel != null) {
+ failureModel.clearFailures();
+ }
+ }
+
updateUserFromRep(user, rep, attrsToRemove);
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
@@ -169,13 +181,13 @@ public class UsersResource {
UserModel user = session.users().addUser(realm, rep.getUsername());
Set<String> emptySet = Collections.emptySet();
updateUserFromRep(user, rep, emptySet);
-
+
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, user.getId()).representation(rep).success();
-
+
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
-
+
return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getId()).build()).build();
} catch (ModelDuplicateException e) {
if (session.getTransaction().isActive()) {
@@ -237,7 +249,7 @@ public class UsersResource {
if (user == null) {
throw new NotFoundException("User not found");
}
-
+
UserRepresentation rep = ModelToRepresentation.toRepresentation(user);
if (realm.isIdentityFederationEnabled()) {
@@ -251,6 +263,10 @@ public class UsersResource {
}
}
+ if ((protector != null) && protector.isTemporarilyDisabled(session, realm, rep.getUsername())) {
+ rep.setEnabled(false);
+ }
+
return rep;
}
@@ -689,7 +705,7 @@ public class UsersResource {
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo, role.getId()).representation(roles).success();
}
}
-
+
}
@Path("{id}/role-mappings/clients/{client}")
@@ -703,7 +719,7 @@ public class UsersResource {
if (client == null) {
throw new NotFoundException("Client not found");
}
-
+
return new UserClientRoleMappingsResource(uriInfo, realm, auth, user, clientModel, adminEvent);
}
@@ -737,7 +753,7 @@ public class UsersResource {
throw new BadRequestException("Can't reset password as account is read only");
}
if (pass.isTemporary()) user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
-
+
adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
}