From 1d94649b96648d27413c319958a3759c074b0fc3 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Tue, 29 Apr 2014 12:03:09 +0100 Subject: [PATCH] Ensure application and client names are unique within realm --- .../resources/partials/oauth-client-list.html | 2 +- .../models/jpa/JpaKeycloakTransaction.java | 7 +- .../models/jpa/OAuthClientAdapter.java | 1 + .../jpa/PersistenceExceptionConverter.java | 20 +++-- .../jpa/entities/ApplicationEntity.java | 14 +--- .../models/jpa/entities/ClientEntity.java | 20 ++++- .../jpa/entities/OAuthClientEntity.java | 25 ------- .../models/jpa/entities/RealmEntity.java | 2 +- .../keycloak/entities/ApplicationEntity.java | 2 + .../keycloak/entities/OAuthClientEntity.java | 2 + .../org/keycloak/model/test/AdapterTest.java | 75 +++++++++++++++++-- .../services/managers/RealmManager.java | 6 +- .../resources/admin/ApplicationResource.java | 12 ++- .../resources/admin/ApplicationsResource.java | 10 ++- .../resources/admin/OAuthClientResource.java | 12 ++- .../resources/admin/OAuthClientsResource.java | 10 ++- .../resources/admin/RealmAdminResource.java | 12 ++- 17 files changed, 162 insertions(+), 70 deletions(-) diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-list.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-list.html index c477f14ce6..cf9f9850d8 100755 --- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-list.html +++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-list.html @@ -22,7 +22,7 @@
- Add Application + Add Client
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java index 6e7f3f38cf..a300b0f7e7 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java @@ -3,6 +3,7 @@ package org.keycloak.models.jpa; import org.keycloak.models.KeycloakTransaction; import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; /** * @author Bill Burke @@ -23,7 +24,11 @@ public class JpaKeycloakTransaction implements KeycloakTransaction { @Override public void commit() { - em.getTransaction().commit(); + try { + em.getTransaction().commit(); + } catch (PersistenceException e) { + throw PersistenceExceptionConverter.convert(e.getCause()); + } } @Override diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java index 1ae4a3dd31..48d0e4f8ce 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java @@ -21,5 +21,6 @@ public class OAuthClientAdapter extends ClientAdapter implements OAuthClientMode @Override public void setClientId(String id) { entity.setName(id); + } } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/PersistenceExceptionConverter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/PersistenceExceptionConverter.java index 712f1e7c0b..dfa5053822 100644 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/PersistenceExceptionConverter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/PersistenceExceptionConverter.java @@ -6,6 +6,7 @@ import org.keycloak.models.ModelDuplicateException; import javax.persistence.EntityExistsException; import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -31,14 +32,17 @@ public class PersistenceExceptionConverter implements InvocationHandler { try { return method.invoke(em, args); } catch (InvocationTargetException e) { - Throwable c = e.getCause(); - if (c.getCause() != null && c.getCause() instanceof ConstraintViolationException) { - throw new ModelDuplicateException(c); - } if (c instanceof EntityExistsException) { - throw new ModelDuplicateException(c); - } else { - throw new ModelException(c); - } + throw convert(e.getCause()); + } + } + + public static ModelException convert(Throwable t) { + if (t.getCause() != null && t.getCause() instanceof ConstraintViolationException) { + throw new ModelDuplicateException(t); + } if (t instanceof EntityExistsException) { + throw new ModelDuplicateException(t); + } else { + throw new ModelException(t); } } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java index ffafaa5044..adcae87145 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java @@ -7,10 +7,13 @@ import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -30,9 +33,6 @@ public class ApplicationEntity extends ClientEntity { private String managementUrl; private boolean bearerOnly; - @ManyToOne() - private RealmEntity realm; - @OneToMany(fetch = FetchType.EAGER, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "application") Collection roles = new ArrayList(); @@ -80,14 +80,6 @@ public class ApplicationEntity extends ClientEntity { this.defaultRoles = defaultRoles; } - public RealmEntity getRealm() { - return realm; - } - - public void setRealm(RealmEntity realm) { - this.realm = realm; - } - public boolean isBearerOnly() { return bearerOnly; } 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 b365ee0f5d..07295532b8 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 @@ -4,6 +4,7 @@ import org.hibernate.annotations.GenericGenerator; import javax.persistence.CascadeType; import javax.persistence.CollectionTable; +import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; @@ -11,8 +12,11 @@ import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; import java.util.HashSet; import java.util.Set; @@ -21,12 +25,14 @@ import java.util.Set; * @version $Revision: 1 $ */ @Entity -@Inheritance(strategy = InheritanceType.JOINED) -public class ClientEntity { +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"realm", "name"})}) +public abstract class ClientEntity { @Id @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") @GeneratedValue(generator = "keycloak_generator") private String id; + @Column(name = "name") private String name; private boolean enabled; private String secret; @@ -34,6 +40,9 @@ public class ClientEntity { private int notBefore; private boolean publicClient; + @ManyToOne + @JoinColumn(name = "realm") + protected RealmEntity realm; @ElementCollection @CollectionTable @@ -42,6 +51,13 @@ public class ClientEntity { @CollectionTable protected Set redirectUris = new HashSet(); + public RealmEntity getRealm() { + return realm; + } + + public void setRealm(RealmEntity realm) { + this.realm = realm; + } public String getId() { return id; diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java index ff69530170..2a570244a9 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java @@ -1,20 +1,8 @@ package org.keycloak.models.jpa.entities; -import javax.persistence.CollectionTable; -import javax.persistence.ElementCollection; import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.ManyToOne; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; -import javax.persistence.OneToOne; - -import org.hibernate.annotations.GenericGenerator; - -import java.util.HashSet; -import java.util.Set; /** * @author Bill Burke @@ -27,17 +15,4 @@ import java.util.Set; }) @Entity public class OAuthClientEntity extends ClientEntity { - - @ManyToOne() - private RealmEntity realm; - - public RealmEntity getRealm() { - return realm; - } - - public void setRealm(RealmEntity realm) { - this.realm = realm; - } - - } 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 7d4b5a91ce..ba662f42d1 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 @@ -83,7 +83,7 @@ public class RealmEntity { @JoinTable(name="AuthProviders") List authenticationProviders = new ArrayList(); - @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") + @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true) Collection applications = new ArrayList(); @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/ApplicationEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/ApplicationEntity.java index be086d9997..c98842e91b 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/ApplicationEntity.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/ApplicationEntity.java @@ -7,12 +7,14 @@ import com.mongodb.DBObject; import com.mongodb.QueryBuilder; import org.keycloak.models.mongo.api.MongoCollection; import org.keycloak.models.mongo.api.MongoField; +import org.keycloak.models.mongo.api.MongoIndex; import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext; /** * @author Marek Posolda */ @MongoCollection(collectionName = "applications") +@MongoIndex(name = "name-within-realm", fields = { "realmId", "name" }, unique = true) public class ApplicationEntity extends ClientEntity { private boolean surrogateAuthRequired; diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/OAuthClientEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/OAuthClientEntity.java index 7c6ea588f3..0ca8045c3b 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/OAuthClientEntity.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/OAuthClientEntity.java @@ -1,6 +1,7 @@ package org.keycloak.models.mongo.keycloak.entities; import org.keycloak.models.mongo.api.MongoCollection; +import org.keycloak.models.mongo.api.MongoIndex; import java.util.List; @@ -8,6 +9,7 @@ import java.util.List; * @author Marek Posolda */ @MongoCollection(collectionName = "oauthClients") +@MongoIndex(name = "name-within-realm", fields = { "realmId", "name" }, unique = true) public class OAuthClientEntity extends ClientEntity { } diff --git a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java index 625e959d11..a6c23151d4 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java @@ -218,9 +218,9 @@ public class AdapterTest extends AbstractModelTest { realmModel.addScopeMapping(app, realmRole); - Assert.assertTrue(identitySession.removeRealm(realmModel.getId())); - Assert.assertFalse(identitySession.removeRealm(realmModel.getId())); - Assert.assertNull(identitySession.getRealm(realmModel.getId())); + Assert.assertTrue(realmManager.removeRealm(realmModel)); + Assert.assertFalse(realmManager.removeRealm(realmModel)); + Assert.assertNull(realmManager.getRealm(realmModel.getId())); } @@ -522,17 +522,80 @@ public class AdapterTest extends AbstractModelTest { commit(true); // Ty to rename realm to duplicate name - realmModel = realmManager.createRealm("JUGGLER2"); + realmManager.createRealm("JUGGLER2"); + commit(); + try { + realmManager.getRealmByName("JUGGLER2").setName("JUGGLER"); + commit(); + Assert.fail("Expected exception"); + } catch (ModelDuplicateException e) { + } + + identitySession.close(); + identitySession = factory.createSession(); + identitySession.getTransaction().begin(); + } + + @Test + public void testAppNameCollisions() throws Exception { + realmManager.createRealm("JUGGLER1").addApplication("app1"); + realmManager.createRealm("JUGGLER2").addApplication("app1"); + commit(); - realmModel = realmManager.getRealmByName("JUGGLER2"); + // Try to create app with duplicate name try { - realmModel.setName("JUGGLER"); + realmManager.getRealmByName("JUGGLER1").addApplication("app1"); commit(); Assert.fail("Expected exception"); } catch (ModelDuplicateException e) { } commit(true); + + // Ty to rename app to duplicate name + realmManager.getRealmByName("JUGGLER1").addApplication("app2"); + commit(); + try { + realmManager.getRealmByName("JUGGLER1").getApplicationByName("app2").setName("app1"); + commit(); + Assert.fail("Expected exception"); + } catch (ModelDuplicateException e) { + } + + identitySession.close(); + identitySession = factory.createSession(); + identitySession.getTransaction().begin(); + } + + @Test + public void testClientNameCollisions() throws Exception { + realmManager.createRealm("JUGGLER1").addOAuthClient("client1"); + realmManager.createRealm("JUGGLER2").addOAuthClient("client1"); + + commit(); + + // Try to create app with duplicate name + try { + realmManager.getRealmByName("JUGGLER1").addOAuthClient("client1"); + commit(); + Assert.fail("Expected exception"); + } catch (ModelDuplicateException e) { + } + commit(true); + + // Ty to rename app to duplicate name + realmManager.getRealmByName("JUGGLER1").addOAuthClient("client2"); + commit(); + try { + realmManager.getRealmByName("JUGGLER1").getOAuthClient("client2").setClientId("client1"); + commit(); + Assert.fail("Expected exception"); + } catch (ModelDuplicateException e) { + } + + identitySession.close(); + identitySession = factory.createSession(); + identitySession.getTransaction().begin(); } } 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 4f7b9e076b..ff76a99da0 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -104,9 +104,9 @@ public class RealmManager { public boolean removeRealm(RealmModel realm) { boolean removed = identitySession.removeRealm(realm.getId()); - - getKeycloakAdminstrationRealm().removeApplication(realm.getAdminApp().getId()); - + if (removed) { + getKeycloakAdminstrationRealm().removeApplication(realm.getAdminApp().getId()); + } return removed; } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java index 0fb20a9493..8878c6bfa5 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java @@ -5,6 +5,7 @@ import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.models.ApplicationModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; @@ -17,6 +18,7 @@ import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.resources.KeycloakApplication; +import org.keycloak.services.resources.flows.Flows; import org.keycloak.util.JsonSerialization; import javax.ws.rs.Consumes; @@ -32,6 +34,7 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.Application; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.util.HashMap; @@ -74,11 +77,16 @@ public class ApplicationResource { @PUT @Consumes(MediaType.APPLICATION_JSON) - public void update(final ApplicationRepresentation rep) { + public Response update(final ApplicationRepresentation rep) { auth.requireManage(); ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session)); - applicationManager.updateApplication(rep, application); + try { + applicationManager.updateApplication(rep, application); + return Response.noContent().build(); + } catch (ModelDuplicateException e) { + return Flows.errors().exists("Application " + rep.getName() + " already exists"); + } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java index ec236cf585..d3e954397a 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java @@ -6,6 +6,7 @@ import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.models.ApplicationModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.RealmModel; import org.keycloak.representations.idm.ApplicationRepresentation; import org.keycloak.services.managers.ApplicationManager; @@ -72,12 +73,13 @@ public class ApplicationsResource { public Response createApplication(final @Context UriInfo uriInfo, final ApplicationRepresentation rep) { auth.requireManage(); - if (realm.getApplicationNameMap().containsKey(rep.getName())) { + ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session)); + try { + ApplicationModel applicationModel = resourceManager.createApplication(realm, rep); + return Response.created(uriInfo.getAbsolutePathBuilder().path(applicationModel.getName()).build()).build(); + } catch (ModelDuplicateException e) { return Flows.errors().exists("Application " + rep.getName() + " already exists"); } - ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session)); - ApplicationModel applicationModel = resourceManager.createApplication(realm, rep); - return Response.created(uriInfo.getAbsolutePathBuilder().path(applicationModel.getName()).build()).build(); } @Path("{app-name}") diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java index eb72e63091..5b07018c26 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java @@ -4,6 +4,7 @@ import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.OAuthClientModel; import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; @@ -12,6 +13,7 @@ import org.keycloak.representations.idm.OAuthClientRepresentation; import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.OAuthClientManager; import org.keycloak.services.resources.KeycloakApplication; +import org.keycloak.services.resources.flows.Flows; import org.keycloak.util.JsonSerialization; import javax.ws.rs.Consumes; @@ -24,6 +26,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Application; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.io.IOException; @@ -64,11 +67,16 @@ public class OAuthClientResource { @PUT @Consumes(MediaType.APPLICATION_JSON) - public void update(final OAuthClientRepresentation rep) { + public Response update(final OAuthClientRepresentation rep) { auth.requireManage(); OAuthClientManager manager = new OAuthClientManager(realm); - manager.update(rep, oauthClient); + try { + manager.update(rep, oauthClient); + return Response.noContent().build(); + } catch (ModelDuplicateException e) { + return Flows.errors().exists("Client " + rep.getName() + " already exists"); + } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java index 3fdcd16691..f940c931c2 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java @@ -5,10 +5,12 @@ import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.OAuthClientModel; import org.keycloak.models.RealmModel; import org.keycloak.representations.idm.OAuthClientRepresentation; import org.keycloak.services.managers.OAuthClientManager; +import org.keycloak.services.resources.flows.Flows; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -74,8 +76,12 @@ public class OAuthClientsResource { auth.requireManage(); OAuthClientManager resourceManager = new OAuthClientManager(realm); - OAuthClientModel oauth = resourceManager.create(rep); - return Response.created(uriInfo.getAbsolutePathBuilder().path(oauth.getId()).build()).build(); + try { + OAuthClientModel oauth = resourceManager.create(rep); + return Response.created(uriInfo.getAbsolutePathBuilder().path(oauth.getId()).build()).build(); + } catch (ModelDuplicateException e) { + return Flows.errors().exists("Client " + rep.getName() + " already exists"); + } } @Path("{id}") diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java index 2e564371d7..7ec8c169a9 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -9,6 +9,7 @@ import org.keycloak.audit.Event; import org.keycloak.audit.EventQuery; import org.keycloak.models.ApplicationModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.RealmModel; import org.keycloak.representations.adapters.action.SessionStats; import org.keycloak.representations.idm.RealmAuditRepresentation; @@ -18,10 +19,12 @@ import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.managers.TokenManager; +import org.keycloak.services.resources.flows.Flows; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -94,11 +97,16 @@ public class RealmAdminResource { @PUT @Consumes("application/json") - public void updateRealm(final RealmRepresentation rep) { + public Response updateRealm(final RealmRepresentation rep) { auth.requireManage(); logger.debug("updating realm: " + realm.getName()); - new RealmManager(session).updateRealm(rep, realm); + try { + new RealmManager(session).updateRealm(rep, realm); + return Response.noContent().build(); + } catch (ModelDuplicateException e) { + return Flows.errors().exists("Realm " + rep.getRealm() + " already exists"); + } } @DELETE