Skip to content

Commit b460b3d

Browse files
Add LIST value type for rule evaluation
1 parent bcf3476 commit b460b3d

File tree

4 files changed

+112
-1
lines changed

4 files changed

+112
-1
lines changed

components/rule-mgt/org.wso2.carbon.identity.rule.evaluation/src/main/java/org/wso2/carbon/identity/rule/evaluation/api/model/FieldValue.java

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
package org.wso2.carbon.identity.rule.evaluation.api.model;
2020

21+
import java.util.List;
22+
2123
/**
2224
* Field value model.
2325
* This class represents a field value in the context that is utilized at rule evaluation.
@@ -53,6 +55,13 @@ public FieldValue(String name, Number value) {
5355
this.value = Double.valueOf(value.toString());
5456
}
5557

58+
public FieldValue(String name, List<String> value) {
59+
60+
this.name = name;
61+
this.valueType = ValueType.LIST;
62+
this.value = value;
63+
}
64+
5665
public String getName() {
5766

5867
return name;

components/rule-mgt/org.wso2.carbon.identity.rule.evaluation/src/main/java/org/wso2/carbon/identity/rule/evaluation/api/model/ValueType.java

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class ValueType {
3030
public static final ValueType NUMBER = new ValueType("NUMBER");
3131
public static final ValueType BOOLEAN = new ValueType("BOOLEAN");
3232
public static final ReferenceValueType REFERENCE = new ReferenceValueType("REFERENCE");
33+
public static final ValueType LIST = new ValueType("LIST");
3334

3435
public static ReferenceValueType createReferenceType(String referenceAttribute) {
3536

components/rule-mgt/org.wso2.carbon.identity.rule.evaluation/src/main/java/org/wso2/carbon/identity/rule/evaluation/internal/service/impl/RuleEvaluator.java

+45
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
import org.wso2.carbon.identity.rule.management.api.model.ORCombinedRule;
2929
import org.wso2.carbon.identity.rule.management.api.model.Rule;
3030

31+
import java.util.List;
3132
import java.util.Map;
3233

3334
import static org.wso2.carbon.identity.rule.evaluation.api.model.ValueType.BOOLEAN;
35+
import static org.wso2.carbon.identity.rule.evaluation.api.model.ValueType.LIST;
3436
import static org.wso2.carbon.identity.rule.evaluation.api.model.ValueType.NUMBER;
3537
import static org.wso2.carbon.identity.rule.evaluation.api.model.ValueType.REFERENCE;
3638
import static org.wso2.carbon.identity.rule.evaluation.api.model.ValueType.STRING;
@@ -45,6 +47,11 @@ public class RuleEvaluator {
4547

4648
private final OperatorRegistry operatorRegistry;
4749

50+
// Operators
51+
private static final String EQUALS = "equals";
52+
private static final String NOT_EQUALS = "notEquals";
53+
private static final String CONTAINS = "contains";
54+
4855
public RuleEvaluator(OperatorRegistry operatorRegistry) {
4956

5057
this.operatorRegistry = operatorRegistry;
@@ -106,8 +113,46 @@ private boolean evaluateExpression(Expression expression, Map<String, FieldValue
106113
return operator.apply(fieldValue.getValue(), Double.parseDouble(expression.getValue().getFieldValue()));
107114
} else if (fieldValue.getValueType().equals(REFERENCE)) {
108115
return operator.apply(fieldValue.getValue(), expression.getValue().getFieldValue());
116+
} else if (fieldValue.getValueType().equals(LIST)) {
117+
return applyOperatorForList(operator, fieldValue.getValue(), expression.getValue().getFieldValue());
109118
}
110119

111120
throw new IllegalStateException("Unsupported value type: " + fieldValue.getValueType());
112121
}
122+
123+
private boolean applyOperatorForList(Operator operator, Object fieldValue, Object expressionValue) {
124+
125+
if (!isListString(fieldValue)) {
126+
throw new IllegalStateException("Expected a List of Strings for field value, but found: "
127+
+ fieldValue.getClass().getName());
128+
}
129+
130+
if (operator.getName().equals(EQUALS) || operator.getName().equals(CONTAINS)) {
131+
for (String value : (List<String>) fieldValue) {
132+
if (operator.apply(value, expressionValue)) {
133+
return true;
134+
}
135+
}
136+
return false;
137+
} else if (operator.getName().equals(NOT_EQUALS)) {
138+
for (String value : (List<String>) fieldValue) {
139+
if (!operator.apply(value, expressionValue)) {
140+
return false;
141+
}
142+
}
143+
return true;
144+
}
145+
146+
throw new IllegalStateException("Unsupported operator: " + operator.getName() + " for LIST value type");
147+
}
148+
149+
private boolean isListString(Object fieldValue) {
150+
151+
if (fieldValue instanceof List<?>) {
152+
List<?> list = (List<?>) fieldValue;
153+
return list.stream().allMatch(element -> element instanceof String);
154+
}
155+
156+
return false;
157+
}
113158
}

components/rule-mgt/org.wso2.carbon.identity.rule.evaluation/src/test/java/org/wso2/carbon/identity/rule/evaluation/core/RuleEvaluatorTest.java

+57-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,13 @@ public Object[][] ruleEvaluationDataProvider() throws Exception {
122122
{createRuleWithTwoANDExpressionsAndOneORExpressionUsingReferenceAndNumberValueTypes(),
123123
createEvaluationData("testapp3", 4), true},
124124
{createRuleWithANDExpressionUsingStringValueTypesAndContainsOperator(),
125-
createEvaluationData("[email protected]"), true}
125+
createEvaluationData("[email protected]"), true},
126+
{createRuleWithTwoANDExpressionsUsingListValueTypes(),
127+
createEvaluationData(Arrays.asList("http://wso2.org/claims/givenname",
128+
"http://wso2.org/claims/country")), true},
129+
{createRuleWithOneORExpressionUsingListValueTypes(),
130+
createEvaluationData(Arrays.asList("http://wso2.org/claims/givenname",
131+
"http://wso2.org/claims/dob")), false}
126132
};
127133
}
128134

@@ -223,6 +229,37 @@ private Rule createRuleWithTwoANDExpressionsAndOneORExpressionUsingReferenceAndN
223229
return ruleBuilder.build();
224230
}
225231

232+
private Rule createRuleWithTwoANDExpressionsUsingListValueTypes() throws Exception {
233+
234+
RuleBuilder ruleBuilder = RuleBuilder.create(FlowType.PRE_ISSUE_ACCESS_TOKEN, "tenant1");
235+
236+
Expression expression1 = new Expression.Builder().field("claim").operator("equals")
237+
.value(new Value(Value.Type.REFERENCE, "http://wso2.org/claims/country")).build();
238+
Expression expression2 = new Expression.Builder().field("claim").operator("notEquals")
239+
.value(new Value(Value.Type.REFERENCE, "http://wso2.org/claims/dob")).build();
240+
ruleBuilder.addAndExpression(expression1);
241+
ruleBuilder.addAndExpression(expression2);
242+
243+
return ruleBuilder.build();
244+
}
245+
246+
private Rule createRuleWithOneORExpressionUsingListValueTypes() throws Exception {
247+
248+
RuleBuilder ruleBuilder = RuleBuilder.create(FlowType.PRE_ISSUE_ACCESS_TOKEN, "tenant1");
249+
250+
Expression expression1 = new Expression.Builder().field("claim").operator("equals")
251+
.value(new Value(Value.Type.REFERENCE, "http://wso2.org/claims/country")).build();
252+
ruleBuilder.addAndExpression(expression1);
253+
254+
ruleBuilder.addOrCondition();
255+
256+
Expression expression2 = new Expression.Builder().field("claim").operator("notEquals")
257+
.value(new Value(Value.Type.REFERENCE, "http://wso2.org/claims/givenname")).build();
258+
ruleBuilder.addAndExpression(expression2);
259+
260+
return ruleBuilder.build();
261+
}
262+
226263
private Map<String, FieldValue> createEvaluationData(String applicationValue, String grantTypeValue) {
227264

228265
Map<String, FieldValue> evaluationData = new HashMap<>();
@@ -254,6 +291,13 @@ private Map<String, FieldValue> createEvaluationData(String emailValue) {
254291
return evaluationData;
255292
}
256293

294+
private Map<String, FieldValue> createEvaluationData(List<String> claims) {
295+
296+
Map<String, FieldValue> evaluationData = new HashMap<>();
297+
evaluationData.put("claim", new FieldValue("claim", claims));
298+
return evaluationData;
299+
}
300+
257301
private List<FieldDefinition> getMockedFieldDefinitions() {
258302

259303
List<FieldDefinition> fieldDefinitionList = new ArrayList<>();
@@ -298,6 +342,18 @@ private List<FieldDefinition> getMockedFieldDefinitions() {
298342
new FieldDefinition(emailField, Collections.singletonList(new Operator("contains", "contains")),
299343
emailValue));
300344

345+
Field claimField = new Field("claim", "claim");
346+
List<Operator> operatorsForClaim = Arrays.asList(new Operator("equals", "equals"),
347+
new Operator("notEquals", "not equals"));
348+
List<Link> linksForClaim = Arrays.asList(new Link("/claim-dialects/local/claims?exclude-hidden-claims=true",
349+
"GET", "values"));
350+
org.wso2.carbon.identity.rule.metadata.api.model.Value
351+
claimValue = new OptionsReferenceValue.Builder().valueReferenceAttribute("uri")
352+
.valueDisplayAttribute("name").valueType(
353+
org.wso2.carbon.identity.rule.metadata.api.model.Value.ValueType.REFERENCE)
354+
.links(linksForClaim).build();
355+
fieldDefinitionList.add(new FieldDefinition(claimField, operatorsForClaim, claimValue));
356+
301357
return fieldDefinitionList;
302358
}
303359
}

0 commit comments

Comments
 (0)