Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement rule evaluation data provider for pre issue access token flow. #2684

Merged
merged 3 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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");
malithie marked this conversation as resolved.
Show resolved Hide resolved

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
Loading