Adding missing database constraints for clients in JPA map storage.

This should ensure consistency for the store even in the event of concurrent creation of clients by multiple callers.

Closes #9610
This commit is contained in:
Alexander Schwartz 2022-01-19 12:18:53 +01:00 committed by Hynek Mlnařík
parent b53c5d5eee
commit e2ac7b38f4
3 changed files with 16 additions and 6 deletions

View file

@ -36,6 +36,7 @@ import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
@ -48,11 +49,16 @@ import org.keycloak.models.map.storage.jpa.hibernate.jsonb.JsonbType;
/**
* There are some fields marked by {@code @Column(insertable = false, updatable = false)}.
* Those fields are automatically generated by database from json field,
* Those fields are automatically generated by database from json field,
* therefore marked as non-insertable and non-updatable to instruct hibernate.
*/
@Entity
@Table(name = "client")
@Table(name = "client",
uniqueConstraints = {
@UniqueConstraint(
columnNames = {"realmId", "clientId"}
)
})
@TypeDefs({@TypeDef(name = "jsonb", typeClass = JsonbType.class)})
public class JpaClientEntity extends AbstractClientEntity implements Serializable {

View file

@ -44,7 +44,7 @@ limitations under the License.
<createIndex tableName="client" indexName="client_entityVersion">
<column name="entityversion"/>
</createIndex>
<createIndex tableName="client" indexName="client_realmId_clientId">
<createIndex tableName="client" indexName="client_realmId_clientId" unique="true">
<column name="realmid"/>
<column name="clientid"/>
</createIndex>

View file

@ -139,15 +139,19 @@ public class MapClientProvider implements ClientProvider {
public ClientModel addClient(RealmModel realm, String id, String clientId) {
LOG.tracef("addClient(%s, %s, %s)%s", realm, id, clientId, getShortStackTrace());
if (id != null && tx.read(id) != null) {
throw new ModelDuplicateException("Client with same id exists: " + id);
}
if (clientId != null && getClientByClientId(realm, clientId) != null) {
throw new ModelDuplicateException("Client with same clientId in realm " + realm.getName() + " exists: " + clientId);
}
MapClientEntity entity = new MapClientEntityImpl();
entity.setId(id);
entity.setRealmId(realm.getId());
entity.setClientId(clientId);
entity.setEnabled(true);
entity.setStandardFlowEnabled(true);
if (id != null && tx.read(id) != null) {
throw new ModelDuplicateException("Client exists: " + id);
}
entity = tx.create(entity);
if (clientId == null) {
clientId = entity.getId();