Details
diff --git a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
index e7661cd..2a4ec62 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
@@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -48,6 +49,7 @@ public class UserRepresentation {
@JsonDeserialize(using = StringListMapDeserializer.class)
protected Map<String, List<String>> attributes;
protected List<CredentialRepresentation> credentials;
+ protected Set<String> disableableCredentialTypes;
protected List<String> requiredActions;
protected List<FederatedIdentityRepresentation> federatedIdentities;
protected List<String> realmRoles;
@@ -254,4 +256,12 @@ public class UserRepresentation {
public void setOrigin(String origin) {
this.origin = origin;
}
+
+ public Set<String> getDisableableCredentialTypes() {
+ return disableableCredentialTypes;
+ }
+
+ public void setDisableableCredentialTypes(Set<String> disableableCredentialTypes) {
+ this.disableableCredentialTypes = disableableCredentialTypes;
+ }
}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 5a18a6e..e35da61 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -189,6 +189,7 @@ public class ModelToRepresentation {
rep.setEnabled(user.isEnabled());
rep.setEmailVerified(user.isEmailVerified());
rep.setTotp(session.userCredentialManager().isConfiguredFor(realm, user, CredentialModel.OTP));
+ rep.setDisableableCredentialTypes(session.userCredentialManager().getDisableableCredentialTypes(realm, user));
rep.setFederationLink(user.getFederationLink());
List<String> reqActions = new ArrayList<String>();
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 f7c8048..06b4ffc 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
@@ -723,40 +723,24 @@ public class UsersResource {
* Disable all credentials for a user of a specific type
*
* @param id
- * @param credentialType
+ * @param credentialTypes
*/
- @Path("{id}/disable-credential-type/{type}")
- @DELETE
- public void disableCredentialType(@PathParam("id") String id, @PathParam("type") String credentialType) {
+ @Path("{id}/disable-credential-types")
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ public void disableCredentialType(@PathParam("id") String id, List<String> credentialTypes) {
auth.requireManage();
UserModel user = session.users().getUserById(id, realm);
if (user == null) {
throw new NotFoundException("User not found");
}
+ if (credentialTypes == null) return;
+ for (String type : credentialTypes) {
+ session.userCredentialManager().disableCredentialType(realm, user, type);
- session.userCredentialManager().disableCredentialType(realm, user, credentialType);
-
- }
-
- /**
- * Credential types that are disablable for this user
- *
- * @param id
- * @return
- */
- @Path("{id}/disableable-credential-types")
- @GET
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- public Set<String> getCredentialTypes(@PathParam("id") String id) {
- auth.requireManage();
-
- UserModel user = session.users().getUserById(id, realm);
- if (user == null) {
- throw new NotFoundException("User not found");
}
- return session.userCredentialManager().getDisableableCredentialTypes(realm, user);
+
}
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 27cb790..b330a3c 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -1206,4 +1206,16 @@ userStorage.cachePolicy.maxLifespan=Max Lifespan
userStorage.cachePolicy.maxLifespan.tooltip=Max lifespan of a user cache entry in milliseconds.
user-origin-link=Storage Origin
+disable=Disable
+disableable-credential-types=Disableable Types
+credentials.disableable.tooltip=List of credential types that you can disable
+disable-credential-types=Disable Credential Types
+credentials.disable.tooltip=Click button to disable selected credential types
+credential-types=Credential Types
+manage-user-password=Manage Password
+disable-credentials=Disable Credentials
+credential-reset-actions=Credential Reset
+
+
+
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index 1e7eb29..03addd9 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -501,7 +501,7 @@ module.controller('UserDetailCtrl', function($scope, realm, user, BruteForceUser
}
});
-module.controller('UserCredentialsCtrl', function($scope, realm, user, RequiredActions, User, UserExecuteActionsEmail, UserCredentials, Notifications, Dialog) {
+module.controller('UserCredentialsCtrl', function($scope, realm, user, $route, RequiredActions, User, UserExecuteActionsEmail, UserCredentials, Notifications, Dialog) {
console.log('UserCredentialsCtrl');
$scope.realm = realm;
@@ -554,18 +554,19 @@ module.controller('UserCredentialsCtrl', function($scope, realm, user, RequiredA
});
};
- $scope.removeTotp = function() {
- Dialog.confirm('Remove totp', 'Are you sure you want to remove the users totp configuration?', function() {
- UserCredentials.removeTotp({ realm: realm.realm, userId: user.id }, { }, function() {
- Notifications.success("The users totp configuration has been removed");
- $scope.user.totp = false;
+ $scope.disableCredentialTypes = function() {
+ Dialog.confirm('Disable credentials', 'Are you sure you want to disable these the users credentials?', function() {
+ UserCredentials.disableCredentialTypes({ realm: realm.realm, userId: user.id }, $scope.disableableCredentialTypes, function() {
+ $route.reload();
+ Notifications.success("Credentials disabled");
}, function() {
- Notifications.error("Failed to remove the users totp configuration");
+ Notifications.error("Failed to disable credentials");
});
});
};
$scope.emailActions = [];
+ $scope.disableableCredentialTypes = [];
$scope.sendExecuteActionsEmail = function() {
if ($scope.changed) {
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/services.js b/themes/src/main/resources/theme/base/admin/resources/js/services.js
index 66ea756..c2e28f5 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -489,6 +489,15 @@ module.factory('UserCredentials', function($resource) {
}
}).update;
+ credentials.disableCredentialTypes = $resource(authUrl + '/admin/realms/:realm/users/:userId/disable-credential-types', {
+ realm : '@realm',
+ userId : '@userId'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ }).update;
+
return credentials;
});
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-credentials.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-credentials.html
index 0f1053c..ccfb203 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-credentials.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-credentials.html
@@ -11,7 +11,8 @@
<input type="password" readonly value="this is not a login form" style="display: none;">
<fieldset class="border-top">
- <div class="form-group">
+ <legend><span class="text">{{:: 'manage-user-password' | translate}}</span></legend>
+ <div class="form-group">
<label class="col-md-2 control-label" for="password">{{:: 'new-password' | translate}} <span class="required" data-ng-show="create">*</span></label>
<div class="col-md-6">
<input class="form-control" type="password" id="password" name="password" data-ng-model="password" required>
@@ -40,35 +41,50 @@
</div>
</fieldset>
- <fieldset class="border-top" data-ng-show="user.totp">
- <div class="form-group" data-ng-show="user.totp">
- <label class="col-md-2 control-label">{{:: 'remove-totp' | translate}}</label>
- <div class="col-sm-5" data-ng-show="user.totp">
- <button class="btn btn-danger" type="submit" data-ng-click="removeTotp()" tooltip-trigger="mouseover mouseout" tooltip="{{:: 'credentials.remove-totp.tooltip' | translate}}" tooltip-placement="right">{{:: 'remove-totp' | translate}}</button>
- </div>
+ <fieldset class="border-top" data-ng-show="user.disableableCredentialTypes && user.disableableCredentialTypes.length > 0">
+ <legend><span class="text">{{:: 'disable-credentials' | translate}}</span></legend>
+ <div class="form-group clearfix">
+ <label class="col-md-2 control-label" for="credentialTypeList">{{:: 'disableable-credential-types' | translate}}</label>
+
+ <div class="col-md-6">
+ <select ui-select2 id="credentialTypeList" ng-model="disableableCredentialTypes" data-placeholder="{{:: 'select-a-type.placeholder' | translate}}" multiple>
+ <option ng-repeat="credType in user.disableableCredentialTypes" value="{{credType}}">{{credType}}</option>
+ </select>
</div>
- </fieldset >
- <fieldset class="border-top" data-ng-show="user.email">
- <div class="form-group clearfix">
- <label class="col-md-2 control-label" for="reqActions">{{:: 'reset-actions' | translate}}</label>
+ <kc-tooltip>{{:: 'credentials.disableable.tooltip' | translate}}</kc-tooltip>
+ </div>
+ <div class="form-group clearfix">
+ <label class="col-md-2 control-label" for="disableCredentialTypes">{{:: 'disable-credential-types' | translate}}</label>
- <div class="col-md-6">
- <select ui-select2 id="reqActions" ng-model="emailActions" data-placeholder="{{:: 'select-an-action.placeholder' | translate}}" multiple>
- <option ng-repeat="action in userReqActionList" value="{{action.alias}}">{{action.name}}</option>
- </select>
- </div>
- <kc-tooltip>{{:: 'credentials.reset-actions.tooltip' | translate}}</kc-tooltip>
+ <div class="col-md-6">
+ <button id="disableCredentialTypes" class="btn btn-default" data-ng-click="disableCredentialTypes()">{{:: 'disable' | translate}}</button>
</div>
- <div class="form-group clearfix">
- <label class="col-md-2 control-label" for="reqActionsEmail">{{:: 'reset-actions-email' | translate}}</label>
+ <kc-tooltip>{{:: 'credentials.disable.tooltip' | translate}}</kc-tooltip>
+ </div>
+ </fieldset>
+
+ <fieldset class="border-top" data-ng-show="user.email">
+ <legend><span class="text">{{:: 'credential-reset-actions' | translate}}</span></legend>
+ <div class="form-group clearfix">
+ <label class="col-md-2 control-label" for="reqActions">{{:: 'reset-actions' | translate}}</label>
- <div class="col-md-6">
- <button id="reqActionsEmail" class="btn btn-default" data-ng-click="sendExecuteActionsEmail()">{{:: 'send-email' | translate}}</button>
- </div>
- <kc-tooltip>{{:: 'credentials.reset-actions-email.tooltip' | translate}}</kc-tooltip>
+ <div class="col-md-6">
+ <select ui-select2 id="reqActions" ng-model="emailActions" data-placeholder="{{:: 'select-an-action.placeholder' | translate}}" multiple>
+ <option ng-repeat="action in userReqActionList" value="{{action.alias}}">{{action.name}}</option>
+ </select>
</div>
- </fieldset>
- </form>
+ <kc-tooltip>{{:: 'credentials.reset-actions.tooltip' | translate}}</kc-tooltip>
+ </div>
+ <div class="form-group clearfix">
+ <label class="col-md-2 control-label" for="reqActionsEmail">{{:: 'reset-actions-email' | translate}}</label>
+
+ <div class="col-md-6">
+ <button id="reqActionsEmail" class="btn btn-default" data-ng-click="sendExecuteActionsEmail()">{{:: 'send-email' | translate}}</button>
+ </div>
+ <kc-tooltip>{{:: 'credentials.reset-actions-email.tooltip' | translate}}</kc-tooltip>
+ </div>
+ </fieldset>
+ </form>
</div>
<kc-menu></kc-menu>