From d6e64a2c5e2e98db0146000c255f709f83e31b3a Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Thu, 11 Jun 2015 15:32:03 -0400 Subject: [PATCH] KEYCLOAK-1083: Provide a way for admin to unlock user account --- .../entities/UsernameLoginFailureEntity.java | 7 ++++ .../UsernameLoginFailureAdapter.java | 2 +- .../entities/LoginFailureEntity.java | 6 ++++ .../jpa/UsernameLoginFailureAdapter.java | 2 +- .../entities/UsernameLoginFailureEntity.java | 7 ++++ .../mem/UsernameLoginFailureAdapter.java | 2 +- .../entities/UsernameLoginFailureEntity.java | 7 ++++ .../mongo/UsernameLoginFailureAdapter.java | 2 +- .../resources/admin/UsersResource.java | 34 ++++++++++++++----- 9 files changed, 56 insertions(+), 13 deletions(-) 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 e25e717408..e6123f3249 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/UsernameLoginFailureAdapter.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UsernameLoginFailureAdapter.java index fed8f2865a..c478a0fa11 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-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 8bb05e7239..b330c2ecbc 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-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 b5852bb3f8..929364876b 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-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 c62e4745c0..d03f597650 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-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 03dc558540..e47a643df8 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-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 b1788d2e68..32cf9815c5 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(); + this.numFailures = new AtomicInteger(); + } + } 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 7d28125875..251d26e538 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 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(); }