keycloak-uncached
Merge pull request #1737 from thomasdarimont/issue/KEYCLOAK-1918 KEYCLOAK-1918 …
Changes
forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties 3(+2 -1)
forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties 3(+2 -1)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html 7(+7 -0)
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java 12(+12 -0)
Details
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.6.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.6.0.xml
index a782f76..7c5de94 100644
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.6.0.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.6.0.xml
@@ -10,6 +10,7 @@
 
         <addColumn tableName="CLIENT">
             <column name="ROOT_URL" type="VARCHAR(255)"/>
+            <column name="DESCRIPTION" type="VARCHAR(255)"/>
         </addColumn>
 
         <createTable tableName="OFFLINE_USER_SESSION">
                diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
index 7ad8c6e..0999505 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
@@ -11,6 +11,7 @@ public class ClientRepresentation {
     protected String id;
     protected String clientId;
     protected String name;
+    protected String description;
     protected String rootUrl;
     protected String adminUrl;
     protected String baseUrl;
@@ -51,6 +52,14 @@ public class ClientRepresentation {
         this.name = name;
     }
 
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
     public String getClientId() {
         return clientId;
     }
                diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties
index 10549e1..87640e0 100644
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_de.properties
@@ -160,7 +160,7 @@ select-file=de Select file
 view-details=de View details
 clear-import=de Clear import
 client-id.tooltip=de Specifies ID referenced in URI and tokens. For example 'my-client'
-client.name.tooltip=de Specifies display name of the client. For example 'My Client'. Supports keys for localized values as well. For example: ${my_client}
+client.name.tooltip=de Specifies display name of the client. For example 'My Client'. Supports keys for localized values as well. For example\: ${my_client}
 client.enabled.tooltip=de Disabled clients cannot initiate a login or have obtain access tokens.
 consent-required=de Consent Required
 consent-required.tooltip=de If enabled users have to consent to client access.
@@ -460,3 +460,4 @@ realm=de Realm
 identity-provider-mappers=de Identity Provider Mappers
 create-identity-provider-mapper=de Create Identity Provider Mapper
 add-identity-provider-mapper=de Add Identity Provider Mapper
+client.description.tooltip=de Specifies description of the client. For example 'My Client for TimeSheets'. Supports keys for localized values as well. For example\: ${my_client_description}
                diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index d5193e7..3e653db 100644
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -160,7 +160,7 @@ select-file=Select file
 view-details=View details
 clear-import=Clear import
 client-id.tooltip=Specifies ID referenced in URI and tokens. For example 'my-client'
-client.name.tooltip=Specifies display name of the client. For example 'My Client'. Supports keys for localized values as well. For example: ${my_client}
+client.name.tooltip=Specifies display name of the client. For example 'My Client'. Supports keys for localized values as well. For example\: ${my_client}
 client.enabled.tooltip=Disabled clients cannot initiate a login or have obtain access tokens.
 consent-required=Consent Required
 consent-required.tooltip=If enabled users have to consent to client access.
@@ -458,3 +458,4 @@ realm=Realm
 identity-provider-mappers=Identity Provider Mappers
 create-identity-provider-mapper=Create Identity Provider Mapper
 add-identity-provider-mapper=Add Identity Provider Mapper
+client.description.tooltip=Specifies description of the client. For example 'My Client for TimeSheets'. Supports keys for localized values as well. For example\: ${my_client_description}
                diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
index 5d2b2dd..443cbe9 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
@@ -38,6 +38,13 @@
                 </div>
                 <kc-tooltip>{{:: 'client.name.tooltip' | translate}}</kc-tooltip>
             </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="client.description">
+                </div>
+                <kc-tooltip>{{:: 'client.description.tooltip' | translate}}</kc-tooltip>
+            </div>
             <div class="form-group clearfix block">
                 <label class="col-md-2 control-label" for="enabled">{{:: 'enabled' | translate}}</label>
                 <div class="col-sm-6">
                diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index ee4317c..8753f45 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -28,6 +28,10 @@ public interface ClientModel extends RoleContainerModel {
 
     void setName(String name);
 
+    String getDescription();
+
+    void setDescription(String description);
+
     boolean isEnabled();
 
     void setEnabled(boolean enabled);
                diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
index 4c742ab..aa4f725 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
@@ -12,6 +12,7 @@ public class ClientEntity extends AbstractIdentifiableEntity {
 
     private String clientId;
     private String name;
+    private String description;
     private String realmId;
     private boolean enabled;
     private String clientAuthenticatorType;
@@ -61,6 +62,10 @@ public class ClientEntity extends AbstractIdentifiableEntity {
         this.name = name;
     }
 
+    public String getDescription() { return description; }
+
+    public void setDescription(String description) { this.description = description; }
+
     public boolean isEnabled() {
         return enabled;
     }
                diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 96b47cb..03e88a8 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -299,6 +299,7 @@ public class ModelToRepresentation {
         rep.setId(clientModel.getId());
         rep.setClientId(clientModel.getClientId());
         rep.setName(clientModel.getName());
+        rep.setDescription(clientModel.getDescription());
         rep.setEnabled(clientModel.isEnabled());
         rep.setAdminUrl(clientModel.getManagementUrl());
         rep.setPublicClient(clientModel.isPublicClient());
                diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 62933a0..839e149 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -692,6 +692,7 @@ public class RepresentationToModel {
 
         ClientModel client = resourceRep.getId()!=null ? realm.addClient(resourceRep.getId(), resourceRep.getClientId()) : realm.addClient(resourceRep.getClientId());
         if (resourceRep.getName() != null) client.setName(resourceRep.getName());
+        if(resourceRep.getDescription() != null) client.setDescription(resourceRep.getDescription());
         if (resourceRep.isEnabled() != null) client.setEnabled(resourceRep.isEnabled());
         client.setManagementUrl(resourceRep.getAdminUrl());
         if (resourceRep.isSurrogateAuthRequired() != null)
@@ -793,6 +794,7 @@ public class RepresentationToModel {
     public static void updateClient(ClientRepresentation rep, ClientModel resource) {
         if (rep.getClientId() != null) resource.setClientId(rep.getClientId());
         if (rep.getName() != null) resource.setName(rep.getName());
+        if (rep.getDescription() != null) resource.setDescription(rep.getDescription());
         if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled());
         if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly());
         if (rep.isConsentRequired() != null) resource.setConsentRequired(rep.isConsentRequired());
                diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
index 1ddc364..81e60ee 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
@@ -79,6 +79,12 @@ public class ClientAdapter implements ClientModel {
     }
 
     @Override
+    public String getDescription() { return entity.getDescription(); }
+
+    @Override
+    public void setDescription(String description) { entity.setDescription(description); }
+
+    @Override
     public Set<String> getWebOrigins() {
         Set<String> result = new HashSet<String>();
         if (entity.getWebOrigins() != null) {
                diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
index e181978..477c5d6 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
@@ -322,6 +322,18 @@ public class ClientAdapter implements ClientModel {
     }
 
     @Override
+    public String getDescription() {
+        if (updated != null) return updated.getDescription();
+        return cached.getDescription();
+    }
+
+    @Override
+    public void setDescription(String description) {
+        getDelegateForUpdate();
+        updated.setDescription(description);
+    }
+
+    @Override
     public boolean isSurrogateAuthRequired() {
         if (updated != null) return updated.isSurrogateAuthRequired();
         return cached.isSurrogateAuthRequired();
                diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
index 3015acf..2d58222 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -25,6 +25,7 @@ public class CachedClient implements Serializable {
     private String id;
     private String clientId;
     private String name;
+    private String description;
     private String realm;
     private Set<String> redirectUris = new HashSet<String>();
     private boolean enabled;
@@ -58,6 +59,7 @@ public class CachedClient implements Serializable {
         secret = model.getSecret();
         clientId = model.getClientId();
         name = model.getName();
+        description = model.getDescription();
         this.realm = realm.getId();
         enabled = model.isEnabled();
         protocol = model.getProtocol();
@@ -103,6 +105,10 @@ public class CachedClient implements Serializable {
         return name;
     }
 
+    public String getDescription() { return description; }
+
+    public void setDescription(String description) { this.description = description; }
+
     public String getRealm() {
         return realm;
     }
                diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index 1e0c21e..3baddd1 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -66,6 +66,12 @@ public class ClientAdapter implements ClientModel {
     }
 
     @Override
+    public String getDescription() { return entity.getDescription(); }
+
+    @Override
+    public void setDescription(String description) { entity.setDescription(description); }
+
+    @Override
     public boolean isEnabled() {
         return entity.isEnabled();
     }
                diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
index b0a30cd..f26f651 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
@@ -34,6 +34,8 @@ public class ClientEntity {
     private String id;
     @Column(name = "NAME")
     private String name;
+    @Column(name = "DESCRIPTION")
+    private String description;
     @Column(name = "CLIENT_ID")
     private String clientId;
     @Column(name="ENABLED")
@@ -143,6 +145,14 @@ public class ClientEntity {
         this.name = name;
     }
 
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
     public boolean isEnabled() {
         return enabled;
     }
                diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index 4e1b4fa..e99f142 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -71,6 +71,15 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
     }
 
     @Override
+    public String getDescription() { return getMongoEntity().getDescription(); }
+
+    @Override
+    public void setDescription(String description) {
+        getMongoEntity().setDescription(description);
+        updateMongoEntity();
+    }
+
+    @Override
     public void setClientId(String clientId) {
         getMongoEntity().setClientId(clientId);
         updateMongoEntity();
                diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
index e780dbf..5c80bca 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
@@ -73,6 +73,7 @@ public class ClientsResource {
                 ClientRepresentation client = new ClientRepresentation();
                 client.setId(clientModel.getId());
                 client.setClientId(clientModel.getClientId());
+                client.setDescription(clientModel.getDescription());
                 rep.add(client);
             }
         }
                diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index 2097175..cf2df9d 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -48,6 +48,7 @@ public class ClientTest extends AbstractClientTest {
     private String createClient() {
         ClientRepresentation rep = new ClientRepresentation();
         rep.setClientId("my-app");
+        rep.setDescription("my-app description");
         rep.setEnabled(true);
         Response response = realm.clients().create(rep);
         response.close();
@@ -79,6 +80,19 @@ public class ClientTest extends AbstractClientTest {
         assertTrue(rep.isEnabled());
     }
 
+    /**
+     * See <a href="https://issues.jboss.org/browse/KEYCLOAK-1918">KEYCLOAK-1918</a>
+     */
+    @Test
+    public void getClientDescription() {
+
+        String id = createClient();
+
+        ClientRepresentation rep = realm.clients().get(id).toRepresentation();
+        assertEquals(id, rep.getId());
+        assertEquals("my-app description", rep.getDescription());
+    }
+
     @Test
     public void getClientSessions() throws Exception {
         OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
                diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
index eff25e3..bb47ebe 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ClientModelTest.java
@@ -32,6 +32,7 @@ public class ClientModelTest extends AbstractModelTest {
         realm = realmManager.createRealm("original");
         client = realm.addClient("application");
         client.setName("Application");
+        client.setDescription("Description");
         client.setBaseUrl("http://base");
         client.setManagementUrl("http://management");
         client.setClientId("app-name");
@@ -87,6 +88,7 @@ public class ClientModelTest extends AbstractModelTest {
     public static void assertEquals(ClientModel expected, ClientModel actual) {
         Assert.assertEquals(expected.getClientId(), actual.getClientId());
         Assert.assertEquals(expected.getName(), actual.getName());
+        Assert.assertEquals(expected.getDescription(), actual.getDescription());
         Assert.assertEquals(expected.getBaseUrl(), actual.getBaseUrl());
         Assert.assertEquals(expected.getManagementUrl(), actual.getManagementUrl());
         Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());