Skip to content

Commit

Permalink
Merge pull request #2684 from malithie/rule-evaluation
Browse files Browse the repository at this point in the history
Implement rule evaluation data provider for pre issue access token flow.
  • Loading branch information
malithie authored Jan 23, 2025
2 parents a5c1cd5 + 1444af2 commit 12a36db
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 6 deletions.
8 changes: 8 additions & 0 deletions components/org.wso2.carbon.identity.oauth/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.action.execution</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.rule.evaluation</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.event</artifactId>
Expand Down Expand Up @@ -431,6 +435,10 @@
org.wso2.carbon.identity.application.common.*;version="${carbon.identity.framework.imp.pkg.version.range}",
org.wso2.carbon.identity.application.authentication.framework.*;version="${carbon.identity.framework.imp.pkg.version.range}",
org.wso2.carbon.identity.user.store.configuration.*;version="${carbon.identity.framework.imp.pkg.version.range}",
org.wso2.carbon.identity.rule.evaluation.model; version="${carbon.identity.framework.imp.pkg.version.range}",
org.wso2.carbon.identity.rule.evaluation.exception; version="${carbon.identity.framework.imp.pkg.version.range}",
org.wso2.carbon.identity.rule.evaluation.provider; version="${carbon.identity.framework.imp.pkg.version.range}",

org.wso2.carbon.identity.oauth.common.token.bindings.*;version="${identity.inbound.auth.oauth.imp.pkg.version.range}",
org.wso2.carbon.identity.oauth.common.*;version="${identity.inbound.auth.oauth.imp.pkg.version.range}",
org.wso2.carbon.identity.saml.common.util.*; version="${saml.common.util.version.range}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* under the License.
*/

package org.wso2.carbon.identity.oauth.action;
package org.wso2.carbon.identity.oauth.action.execution;

import com.nimbusds.jwt.JWTClaimsSet;
import org.apache.commons.logging.Log;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* under the License.
*/

package org.wso2.carbon.identity.oauth.action;
package org.wso2.carbon.identity.oauth.action.execution;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you 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.wso2.carbon.identity.oauth.action.rule;

import org.wso2.carbon.identity.application.common.model.ServiceProvider;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.identity.rule.evaluation.exception.RuleEvaluationDataProviderException;
import org.wso2.carbon.identity.rule.evaluation.model.Field;
import org.wso2.carbon.identity.rule.evaluation.model.FieldValue;
import org.wso2.carbon.identity.rule.evaluation.model.FlowContext;
import org.wso2.carbon.identity.rule.evaluation.model.FlowType;
import org.wso2.carbon.identity.rule.evaluation.model.RuleEvaluationContext;
import org.wso2.carbon.identity.rule.evaluation.model.ValueType;
import org.wso2.carbon.identity.rule.evaluation.provider.RuleEvaluationDataProvider;

import java.util.ArrayList;
import java.util.List;

/**
* Rule evaluation data provider for pre issue access token flow.
* This class provides the data required for rule evaluation in pre issue access token flow.
*/
public class PreIssueAccessTokenRuleEvaluationDataProvider implements RuleEvaluationDataProvider {

private enum RuleField {
APPLICATION("application"),
GRANT_TYPE("grantType");

final String fieldName;

RuleField(String fieldName) {

this.fieldName = fieldName;
}

public String getFieldName() {

return fieldName;
}

public static RuleField valueOfFieldName(String fieldName) throws RuleEvaluationDataProviderException {

for (RuleField ruleField : RuleField.values()) {
if (ruleField.getFieldName().equals(fieldName)) {
return ruleField;
}
}

throw new RuleEvaluationDataProviderException("Unsupported field: " + fieldName);
}
}

@Override
public FlowType getSupportedFlowType() {

return FlowType.PRE_ISSUE_ACCESS_TOKEN;
}

@Override
public List<FieldValue> getEvaluationData(RuleEvaluationContext ruleEvaluationContext,
FlowContext flowContext, String tenantDomain)
throws RuleEvaluationDataProviderException {

OAuthTokenReqMessageContext tokenMessageContext =
(OAuthTokenReqMessageContext) flowContext.getContextData().get("tokenMessageContext");

OAuth2AccessTokenReqDTO tokenReqDTO = tokenMessageContext.getOauth2AccessTokenReqDTO();
List<FieldValue> fieldValueList = new ArrayList<>();

for (Field field : ruleEvaluationContext.getFields()) {
switch (RuleField.valueOfFieldName(field.getName())) {
case APPLICATION:
addApplicationFieldValue(fieldValueList, field, tokenReqDTO);
break;
case GRANT_TYPE:
fieldValueList.add(new FieldValue(field.getName(), tokenReqDTO.getGrantType(), ValueType.STRING));
break;
default:
throw new RuleEvaluationDataProviderException("Unsupported field: " + field.getName());
}
}

return fieldValueList;
}

private void addApplicationFieldValue(List<FieldValue> fieldValueList, Field field,
OAuth2AccessTokenReqDTO tokenReqDTO)
throws RuleEvaluationDataProviderException {

try {
ServiceProvider application =
OAuth2Util.getServiceProvider(tokenReqDTO.getClientId(), tokenReqDTO.getTenantDomain());
if (application != null) {
fieldValueList.add(
new FieldValue(field.getName(), application.getApplicationResourceId(), ValueType.REFERENCE));
}
} catch (IdentityOAuth2Exception e) {
throw new RuleEvaluationDataProviderException("Error retrieving service provider", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@
import org.wso2.carbon.identity.event.handler.AbstractEventHandler;
import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl;
import org.wso2.carbon.identity.oauth.OauthInboundAuthConfigHandler;
import org.wso2.carbon.identity.oauth.action.PreIssueAccessTokenRequestBuilder;
import org.wso2.carbon.identity.oauth.action.PreIssueAccessTokenResponseProcessor;
import org.wso2.carbon.identity.oauth.action.execution.PreIssueAccessTokenRequestBuilder;
import org.wso2.carbon.identity.oauth.action.execution.PreIssueAccessTokenResponseProcessor;
import org.wso2.carbon.identity.oauth.action.rule.PreIssueAccessTokenRuleEvaluationDataProvider;
import org.wso2.carbon.identity.oauth.cache.OAuthCache;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;
import org.wso2.carbon.identity.oauth.common.token.bindings.TokenBinderInfo;
Expand All @@ -58,6 +59,7 @@
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationUserResidentResolverService;
import org.wso2.carbon.identity.role.mgt.core.RoleManagementService;
import org.wso2.carbon.identity.rule.evaluation.provider.RuleEvaluationDataProvider;
import org.wso2.carbon.idp.mgt.IdpManager;
import org.wso2.carbon.user.core.listener.UserOperationEventListener;
import org.wso2.carbon.user.core.service.RealmService;
Expand Down Expand Up @@ -118,6 +120,7 @@ protected void activate(ComponentContext context) {
authProtocolApplicationService, null);

registerActionRequestBuilderAndResponseProcessor(context);
registerRuleEvaluationDataProvider(context);
// Note : DO NOT add any activation related code below this point,
// to make sure the server doesn't start up if any activation failures occur

Expand All @@ -140,6 +143,13 @@ private void registerActionRequestBuilderAndResponseProcessor(ComponentContext c
null);
}

private void registerRuleEvaluationDataProvider(ComponentContext context) {

context.getBundleContext()
.registerService(RuleEvaluationDataProvider.class, new PreIssueAccessTokenRuleEvaluationDataProvider(),
null);
}

protected void deactivate(ComponentContext context) {

if (serviceRegistration != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* under the License.
*/

package org.wso2.carbon.identity.oauth.action;
package org.wso2.carbon.identity.oauth.action.execution;

import org.apache.commons.codec.binary.Base64;
import org.mockito.MockedStatic;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you 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.wso2.carbon.identity.oauth.action.rule;

import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.wso2.carbon.identity.application.common.model.ServiceProvider;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.identity.rule.evaluation.exception.RuleEvaluationDataProviderException;
import org.wso2.carbon.identity.rule.evaluation.model.Field;
import org.wso2.carbon.identity.rule.evaluation.model.FieldValue;
import org.wso2.carbon.identity.rule.evaluation.model.FlowContext;
import org.wso2.carbon.identity.rule.evaluation.model.FlowType;
import org.wso2.carbon.identity.rule.evaluation.model.RuleEvaluationContext;
import org.wso2.carbon.identity.rule.evaluation.model.ValueType;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;

public class PreIssueAccessTokenRuleEvaluationDataProviderTest {

@InjectMocks
private PreIssueAccessTokenRuleEvaluationDataProvider provider;
@Mock
private OAuthTokenReqMessageContext tokenMessageContext;
@Mock
private OAuth2AccessTokenReqDTO tokenReqDTO;
@Mock
private FlowContext flowContext;
@Mock
private RuleEvaluationContext ruleEvaluationContext;
@Mock
private ServiceProvider serviceProvider;
private MockedStatic<OAuth2Util> oAuth2UtilMockedStatic;

@BeforeMethod
public void setUp() {

MockitoAnnotations.openMocks(this);
when(flowContext.getContextData()).thenReturn(
Collections.singletonMap("tokenMessageContext", tokenMessageContext));
when(tokenMessageContext.getOauth2AccessTokenReqDTO()).thenReturn(tokenReqDTO);

oAuth2UtilMockedStatic = mockStatic(OAuth2Util.class);
}

@AfterMethod
public void tearDown() {

oAuth2UtilMockedStatic.close();
}

@Test
public void testGetSupportedFlowType() {

assertEquals(provider.getSupportedFlowType(), FlowType.PRE_ISSUE_ACCESS_TOKEN);
}

@Test
public void testGetEvaluationDataWithValidFields() throws Exception {

Field applicationField = new Field("application", ValueType.REFERENCE);
Field grantTypeField = new Field("grantType", ValueType.STRING);
when(ruleEvaluationContext.getFields()).thenReturn(Arrays.asList(applicationField, grantTypeField));

when(tokenReqDTO.getClientId()).thenReturn("clientId");
when(tokenReqDTO.getTenantDomain()).thenReturn("tenantDomain");
when(tokenReqDTO.getGrantType()).thenReturn("authorization_code");

when(OAuth2Util.getServiceProvider(anyString(), anyString())).thenReturn(serviceProvider);
when(serviceProvider.getApplicationResourceId()).thenReturn("testapp");

List<FieldValue> fieldValues = provider.getEvaluationData(ruleEvaluationContext, flowContext, null);

assertEquals(fieldValues.size(), 2);
assertEquals(fieldValues.get(0).getName(), "application");
assertEquals(fieldValues.get(0).getValue(), "testapp");
assertEquals(fieldValues.get(1).getName(), "grantType");
assertEquals(fieldValues.get(1).getValue(), "authorization_code");
}

@Test(expectedExceptions = RuleEvaluationDataProviderException.class, expectedExceptionsMessageRegExp =
"Unsupported field: unsupported")
public void testGetEvaluationDataWithUnsupportedField() throws Exception {

Field unsupportedField = new Field("unsupported", ValueType.STRING);
when(ruleEvaluationContext.getFields()).thenReturn(Collections.singletonList(unsupportedField));

provider.getEvaluationData(ruleEvaluationContext, flowContext, null);
}

@Test(expectedExceptions = RuleEvaluationDataProviderException.class)
public void testGetEvaluationDataWhenRetrievingServiceProviderFails() throws Exception {

Field applicationField = new Field("application", ValueType.REFERENCE);
when(ruleEvaluationContext.getFields()).thenReturn(Collections.singletonList(applicationField));

when(tokenReqDTO.getClientId()).thenReturn("clientId");
when(tokenReqDTO.getTenantDomain()).thenReturn("tenantDomain");

when(OAuth2Util.getServiceProvider(anyString(), anyString())).thenThrow(new IdentityOAuth2Exception("Error"));

provider.getEvaluationData(ruleEvaluationContext, flowContext, "tenantDomain");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@
<class name="org.wso2.carbon.identity.oauth2.rar.token.IntrospectionRARDataProviderTest"/>
<class name="org.wso2.carbon.identity.oauth2.rar.token.JWTAccessTokenRARClaimProviderTest"/>
<class name="org.wso2.carbon.identity.oauth2.rar.validator.DefaultAuthorizationDetailsValidatorTest"/>
<class name="org.wso2.carbon.identity.oauth.action.execution.PreIssueAccessTokenRequestBuilderTest"/>
<class name="org.wso2.carbon.identity.oauth.action.rule.PreIssueAccessTokenRuleEvaluationDataProviderTest"/>
</classes>
</test>
</suite>
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,11 @@
<artifactId>org.wso2.carbon.identity.action.execution</artifactId>
<version>${carbon.identity.framework.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.rule.evaluation</artifactId>
<version>${carbon.identity.framework.version}</version>
</dependency>

<!--SAML Common Util dependency-->
<dependency>
Expand Down Expand Up @@ -962,7 +967,7 @@
<carbon.kernel.registry.imp.pkg.version.range>[1.0.1, 2.0.0)</carbon.kernel.registry.imp.pkg.version.range>

<!-- Carbon Identity Framework version -->
<carbon.identity.framework.version>7.7.90</carbon.identity.framework.version>
<carbon.identity.framework.version>7.7.112</carbon.identity.framework.version>
<carbon.identity.framework.imp.pkg.version.range>[5.25.234, 8.0.0)
</carbon.identity.framework.imp.pkg.version.range>
<identity.oauth.xacml.version.range>[2.0.0, 3.0.0)</identity.oauth.xacml.version.range>
Expand Down

0 comments on commit 12a36db

Please sign in to comment.