diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionStrategy.java b/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionStrategy.java
index bd66bea40c..ace8ef51c9 100644
--- a/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionStrategy.java
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionStrategy.java
@@ -16,27 +16,48 @@
*/
package org.keycloak.representations.idm.authorization;
+import java.util.Map;
+import java.util.Objects;
+import org.keycloak.util.EnumWithStableIndex;
+
/**
* The decision strategy dictates how the policies associated with a given policy are evaluated and how a final decision
* is obtained.
*
* @author Pedro Igor
*/
-public enum DecisionStrategy {
+public enum DecisionStrategy implements EnumWithStableIndex {
/**
* Defines that at least one policy must evaluate to a positive decision in order to the overall decision be also positive.
*/
- AFFIRMATIVE,
+ AFFIRMATIVE(0),
/**
* Defines that all policies must evaluate to a positive decision in order to the overall decision be also positive.
*/
- UNANIMOUS,
+ UNANIMOUS(1),
/**
* Defines that the number of positive decisions must be greater than the number of negative decisions. If the number of positive and negative is the same,
* the final decision will be negative.
*/
- CONSENSUS
+ CONSENSUS(2);
+
+ private final int stableIndex;
+ private static final Map BY_ID = EnumWithStableIndex.getReverseIndex(values());
+
+ private DecisionStrategy(int stableIndex) {
+ Objects.requireNonNull(stableIndex);
+ this.stableIndex = stableIndex;
+ }
+
+ @Override
+ public int getStableIndex() {
+ return stableIndex;
+ }
+
+ public static DecisionStrategy valueOfInteger(Integer id) {
+ return id == null ? null : BY_ID.get(id);
+ }
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/Logic.java b/core/src/main/java/org/keycloak/representations/idm/authorization/Logic.java
index 70c382e952..e66b147b84 100644
--- a/core/src/main/java/org/keycloak/representations/idm/authorization/Logic.java
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/Logic.java
@@ -16,21 +16,42 @@
*/
package org.keycloak.representations.idm.authorization;
+import java.util.Map;
+import java.util.Objects;
+import org.keycloak.util.EnumWithStableIndex;
+
/**
* The decision strategy dictates how the policies associated with a given policy are evaluated and how a final decision
* is obtained.
*
* @author Pedro Igor
*/
-public enum Logic {
+public enum Logic implements EnumWithStableIndex {
/**
* Defines that this policy follows a positive logic. In other words, the final decision is the policy outcome.
*/
- POSITIVE,
+ POSITIVE(0),
/**
* Defines that this policy uses a logical negation. In other words, the final decision would be a negative of the policy outcome.
*/
- NEGATIVE,
+ NEGATIVE(1);
+
+ private final int stableIndex;
+ private static final Map BY_ID = EnumWithStableIndex.getReverseIndex(values());
+
+ private Logic(int stableIndex) {
+ Objects.requireNonNull(stableIndex);
+ this.stableIndex = stableIndex;
+ }
+
+ @Override
+ public int getStableIndex() {
+ return stableIndex;
+ }
+
+ public static Logic valueOfInteger(Integer id) {
+ return id == null ? null : BY_ID.get(id);
+ }
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEnforcementMode.java b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEnforcementMode.java
index 4d1eef67ed..ee303b4554 100644
--- a/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEnforcementMode.java
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEnforcementMode.java
@@ -16,25 +16,46 @@
*/
package org.keycloak.representations.idm.authorization;
+import java.util.Map;
+import java.util.Objects;
+import org.keycloak.util.EnumWithStableIndex;
+
/**
* The policy enforcement mode dictates how authorization requests are handled by the server.
*
* @author Pedro Igor
*/
-public enum PolicyEnforcementMode {
+public enum PolicyEnforcementMode implements EnumWithStableIndex {
/**
* Requests are denied by default even when there is no policy associated with a given resource.
*/
- ENFORCING,
+ ENFORCING(0),
/**
* Requests are allowed even when there is no policy associated with a given resource.
*/
- PERMISSIVE,
+ PERMISSIVE(1),
/**
* Completely disables the evaluation of policies and allow access to any resource.
*/
- DISABLED
+ DISABLED(2);
+
+ private final int stableIndex;
+ private static final Map BY_ID = EnumWithStableIndex.getReverseIndex(values());
+
+ private PolicyEnforcementMode(int stableIndex) {
+ Objects.requireNonNull(stableIndex);
+ this.stableIndex = stableIndex;
+ }
+
+ @Override
+ public int getStableIndex() {
+ return stableIndex;
+ }
+
+ public static PolicyEnforcementMode valueOfInteger(Integer id) {
+ return id == null ? null : BY_ID.get(id);
+ }
}
diff --git a/core/src/main/java/org/keycloak/util/EnumWithStableIndex.java b/core/src/main/java/org/keycloak/util/EnumWithStableIndex.java
new file mode 100644
index 0000000000..f3b14a5d73
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/EnumWithStableIndex.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.util;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Classes implementing this interface guarantee that for each instance of this class,
+ * there exists an mutually unique integer which is stable in time, and identifies
+ * always the same instance of this class.
+ * The index might be used for persistence, hence the index of a particular item
+ * cannot be changed.
+ * This is mostly usable for @{code enum}s.
+ */
+public interface EnumWithStableIndex {
+ /**
+ * @return Unique numeric index which is stable in time and identifies an instance.
+ * Reusing the same index for two distinct entries of the same class is forbidden even
+ * if they cannot exist at the same time (e.g. one is deleted before other is introduced).
+ */
+ public int getStableIndex();
+
+ public static Map getReverseIndex(E[] values) {
+ return Stream.of(values).collect(Collectors.toMap(EnumWithStableIndex::getStableIndex, Function.identity()));
+ }
+}
diff --git a/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/hibernate/jsonb/JsonbType.java b/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/hibernate/jsonb/JsonbType.java
index 98681bc4c4..c970b6d1a4 100644
--- a/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/hibernate/jsonb/JsonbType.java
+++ b/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/hibernate/jsonb/JsonbType.java
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
@@ -77,8 +78,7 @@ import org.keycloak.models.map.realm.entity.MapRequiredCredentialEntity;
import org.keycloak.models.map.realm.entity.MapRequiredCredentialEntityImpl;
import org.keycloak.models.map.realm.entity.MapWebAuthnPolicyEntity;
import org.keycloak.models.map.realm.entity.MapWebAuthnPolicyEntityImpl;
-
-import static org.keycloak.models.map.storage.jpa.hibernate.jsonb.JpaEntityMigration.MIGRATIONS;
+import org.keycloak.util.EnumWithStableIndex;
public class JsonbType extends AbstractSingleColumnStandardBasicType