From d7717f01231869bc228140200cb88c0a6607adf0 Mon Sep 17 00:00:00 2001 From: DilshanSenarath <74205483+DilshanSenarath@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:07:48 +0530 Subject: [PATCH 1/6] add authenticated user validation logic for the refresh grant flow --- .../org.wso2.carbon.identity.oauth/pom.xml | 5 ++ .../config/OAuthServerConfiguration.java | 31 ++++++++ .../internal/OAuth2ServiceComponent.java | 24 +++++++ .../OAuth2ServiceComponentHolder.java | 22 ++++++ .../handlers/grant/RefreshGrantHandler.java | 72 +++++++++++++++++++ pom.xml | 11 +++ 6 files changed, 165 insertions(+) diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 8910c5ee4c7..c8d3e27b784 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -115,6 +115,10 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.event + + org.wso2.carbon.identity.event.handler.accountlock + org.wso2.carbon.identity.handler.event.account.lock + org.wso2.carbon.identity.framework org.wso2.carbon.identity.core @@ -435,6 +439,7 @@ org.wso2.carbon.identity.organization.management.role.management.service.models; version="${carbon.identity.organization.management.version.range}", org.wso2.carbon.identity.organization.management.organization.user.sharing.util;version="${carbon.identity.organization.management.version.range}", org.wso2.carbon.identity.organization.management.organization.user.sharing.models;version="${carbon.identity.organization.management.version.range}", + org.wso2.carbon.identity.handler.event.account.lock.service.*;version="${account.lock.service.imp.pkg.version.range}", org.wso2.carbon.base; version="${carbon.base.imp.pkg.version.range}", org.wso2.carbon.registry.api;version="${carbon.kernel.registry.imp.pkg.version.range}", diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java index 07350987a2c..5072ec576ef 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java @@ -161,6 +161,7 @@ public class OAuthServerConfiguration { private boolean isTokenRenewalPerRequestEnabled = false; private boolean isRefreshTokenRenewalEnabled = true; private boolean isExtendRenewedTokenExpiryTimeEnabled = true; + private boolean isValidateAuthenticatedUserForRefreshGrantEnabled = false; private boolean assertionsUserNameEnabled = false; private boolean accessTokenPartitioningEnabled = false; private boolean redirectToRequestedRedirectUriEnabled = true; @@ -417,6 +418,9 @@ private void buildOAuthServerConfiguration() { // read refresh token renewal config parseRefreshTokenRenewalConfiguration(oauthElem); + // Read the authenticated user validation config for refresh grant. + parseRefreshTokenGrantValidationConfiguration(oauthElem); + // read token persistence processor config parseTokenPersistenceProcessorConfig(oauthElem); @@ -944,6 +948,16 @@ public boolean isExtendRenewedTokenExpiryTimeEnabled() { return isExtendRenewedTokenExpiryTimeEnabled; } + /** + * Check if the authenticated user validation is enabled for refresh token grant flow. + * + * @return Returns true if the config is enabled. + */ + public boolean isValidateAuthenticatedUserForRefreshGrantEnabled() { + + return isValidateAuthenticatedUserForRefreshGrantEnabled; + } + public Map getOauthTokenIssuerMap() { return oauthTokenIssuerMap; } @@ -2231,6 +2245,20 @@ private void parseRefreshTokenRenewalConfiguration(OMElement oauthConfigElem) { } } + private void parseRefreshTokenGrantValidationConfiguration(OMElement oauthConfigElem) { + + OMElement validateAuthenticatedUserForRefreshGrantElem = oauthConfigElem.getFirstChildWithName( + getQNameWithIdentityNS(ConfigElements.VALIDATE_AUTHENTICATED_USER_FOR_REFRESH_GRANT)); + if (validateAuthenticatedUserForRefreshGrantElem != null) { + isValidateAuthenticatedUserForRefreshGrantEnabled = + Boolean.parseBoolean(validateAuthenticatedUserForRefreshGrantElem.getText()); + } + if (log.isDebugEnabled()) { + log.debug("ValidateAuthenticatedUserForRefreshGrant was set to : " + + isValidateAuthenticatedUserForRefreshGrantEnabled); + } + } + private void parseAccessTokenPartitioningConfig(OMElement oauthConfigElem) { OMElement enableAccessTokenPartitioningElem = @@ -3933,6 +3961,9 @@ private class ConfigElements { private static final String ENABLE_CACHE = "EnableOAuthCache"; // Enable/Disable refresh token renewal on each refresh_token grant request private static final String RENEW_REFRESH_TOKEN_FOR_REFRESH_GRANT = "RenewRefreshTokenForRefreshGrant"; + // Enable/Disable Authenticated user validation on refresh_token grant request. + private static final String VALIDATE_AUTHENTICATED_USER_FOR_REFRESH_GRANT = + "ValidateAuthenticatedUserForRefreshGrant"; // Enable/Disable extend the lifetime of the new refresh token private static final String EXTEND_RENEWED_REFRESH_TOKEN_EXPIRY_TIME = "ExtendRenewedRefreshTokenExpiryTime"; // TokenPersistenceProcessor diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.java index 7e4db0f45ff..c1ba6b58ec2 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.java @@ -48,6 +48,7 @@ import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.identity.event.handler.AbstractEventHandler; import org.wso2.carbon.identity.event.services.IdentityEventService; +import org.wso2.carbon.identity.handler.event.account.lock.service.AccountLockService; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.common.token.bindings.TokenBinderInfo; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; @@ -1612,4 +1613,27 @@ protected void unregisterConfigurationManager(ConfigurationManager configuration } OAuth2ServiceComponentHolder.getInstance().setConfigurationManager(null); } + + @Reference( + name = "org.wso2.carbon.identity.handler.event.account.lock.service.AccountLockService", + service = AccountLockService.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetAccountLockService" + ) + protected void setAccountLockService(AccountLockService accountLockService) { + + if (log.isDebugEnabled()) { + log.debug("AccountLockService set in OAuth2ServiceComponent bundle."); + } + OAuth2ServiceComponentHolder.setAccountLockService(accountLockService); + } + + protected void unsetAccountLockService(AccountLockService accountLockService) { + + if (log.isDebugEnabled()) { + log.debug("AccountLockService unset in OAuth2ServiceComponent bundle."); + } + OAuth2ServiceComponentHolder.setAccountLockService(null); + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java index c22e3f9ffdc..1f5f5b0b95a 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java @@ -29,6 +29,7 @@ import org.wso2.carbon.identity.core.SAMLSSOServiceProviderManager; import org.wso2.carbon.identity.core.handler.HandlerComparator; import org.wso2.carbon.identity.event.services.IdentityEventService; +import org.wso2.carbon.identity.handler.event.account.lock.service.AccountLockService; import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl; import org.wso2.carbon.identity.oauth.dto.ScopeDTO; import org.wso2.carbon.identity.oauth.tokenprocessor.DefaultOAuth2RevocationProcessor; @@ -122,6 +123,7 @@ public class OAuth2ServiceComponentHolder { private List impersonationValidators = new ArrayList<>(); private ConfigurationManager configurationManager; + private static AccountLockService accountLockService; private OAuth2ServiceComponentHolder() { @@ -889,4 +891,24 @@ public void setConfigurationManager(ConfigurationManager configurationManager) { this.configurationManager = configurationManager; } + + /** + * Set the account lock service to the OAuth2ServiceComponentHolder. + * + * @param accountLockService Account lock service instance. + */ + public static void setAccountLockService(AccountLockService accountLockService) { + + OAuth2ServiceComponentHolder.accountLockService = accountLockService; + } + + /** + * Retrieve the account lock service. + * + * @return Account lock service instance. + */ + public static AccountLockService getAccountLockService() { + + return OAuth2ServiceComponentHolder.accountLockService; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandler.java index f4d5e3dfa5a..c47bd808f7e 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandler.java @@ -27,10 +27,15 @@ import org.wso2.carbon.identity.action.execution.exception.ActionExecutionException; import org.wso2.carbon.identity.action.execution.model.ActionExecutionStatus; import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.base.IdentityConstants; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.identity.handler.event.account.lock.exception.AccountLockServiceException; +import org.wso2.carbon.identity.handler.event.account.lock.service.AccountLockService; import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCache; import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCacheEntry; import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCacheKey; @@ -52,11 +57,16 @@ import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.model.RefreshTokenValidationDataDO; +import org.wso2.carbon.identity.oauth2.token.AccessTokenIssuer; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuer; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinding; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.FederatedAssociationManager; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.exception.FederatedAssociationManagerException; +import org.wso2.carbon.user.core.UserCoreConstants; +import org.wso2.carbon.user.core.util.UserCoreUtil; import java.sql.Timestamp; import java.util.Arrays; @@ -69,6 +79,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_CHECKING_ACCOUNT_LOCK_STATUS; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_GETTING_USERNAME_ASSOCIATED_WITH_IDP; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.GrantTypes.REFRESH_TOKEN; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenBindings.NONE; import static org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration.JWT_TOKEN_TYPE; @@ -86,6 +98,8 @@ public class RefreshGrantHandler extends AbstractAuthorizationGrantHandler { public static final String DEACTIVATED_ACCESS_TOKEN = "DeactivatedAccessToken"; private static final Log log = LogFactory.getLog(RefreshGrantHandler.class); private boolean isHashDisabled = OAuth2Util.isHashDisabled(); + private static final String ACCOUNT_LOCK_ERROR_MESSAGE = "Account is locked for user %s in tenant %s. Cannot" + + " login until the account is unlocked."; @Override public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) @@ -98,6 +112,7 @@ public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) validateRefreshTokenInRequest(tokenReq, validationBean); validateTokenBindingReference(tokenReq, validationBean); + validateAuthenticatedUser(validationBean, tokReqMsgCtx); if (log.isDebugEnabled()) { log.debug("Refresh token validation successful for Client id : " + tokenReq.getClientId() + @@ -282,6 +297,63 @@ private boolean validateRefreshTokenStatus(RefreshTokenValidationDataDO validati return true; } + private boolean validateAuthenticatedUser(RefreshTokenValidationDataDO validationBean, + OAuthTokenReqMessageContext oAuthTokenReqMessageContext) + throws IdentityOAuth2Exception { + + if (!OAuthServerConfiguration.getInstance().isValidateAuthenticatedUserForRefreshGrantEnabled()) { + return true; + } + + AuthenticatedUser authenticatedUser = validationBean.getAuthorizedUser(); + if (authenticatedUser != null) { + String username = null; + String tenantDomain = null; + + if (authenticatedUser.isFederatedUser()) { + try { + FederatedAssociationManager federatedAssociationManager = + FrameworkUtils.getFederatedAssociationManager(); + OAuthAppDO oAuthAppDO = + (OAuthAppDO) oAuthTokenReqMessageContext.getProperty(AccessTokenIssuer.OAUTH_APP_DO); + String oAuthAppTenantDomain = OAuth2Util.getTenantDomainOfOauthApp(oAuthAppDO); + String associatedLocalUsername = + federatedAssociationManager.getUserForFederatedAssociation(oAuthAppTenantDomain, + authenticatedUser.getFederatedIdPName(), + authenticatedUser.getAuthenticatedSubjectIdentifier()); + if (associatedLocalUsername != null) { + username = associatedLocalUsername; + tenantDomain = oAuthAppTenantDomain; + } + } catch (FederatedAssociationManagerException | FrameworkException e) { + throw new IdentityOAuth2Exception(ERROR_WHILE_GETTING_USERNAME_ASSOCIATED_WITH_IDP.getCode(), + String.format(ERROR_WHILE_GETTING_USERNAME_ASSOCIATED_WITH_IDP.getMessage(), + authenticatedUser.getFederatedIdPName()), e); + } + } else { + username = UserCoreUtil.addDomainToName(authenticatedUser.getUserName(), + authenticatedUser.getUserStoreDomain()); + tenantDomain = authenticatedUser.getTenantDomain(); + } + + if (username != null && tenantDomain != null) { + AccountLockService accountLockService = OAuth2ServiceComponentHolder.getAccountLockService(); + + try { + boolean accountLockStatus = accountLockService.isAccountLocked(username, tenantDomain); + if (accountLockStatus) { + throw new IdentityOAuth2Exception(UserCoreConstants.ErrorCode.USER_IS_LOCKED, + String.format(ACCOUNT_LOCK_ERROR_MESSAGE, username, tenantDomain)); + } + } catch (AccountLockServiceException e) { + throw new IdentityOAuth2Exception(ERROR_WHILE_CHECKING_ACCOUNT_LOCK_STATUS.getCode(), + String.format(ERROR_WHILE_CHECKING_ACCOUNT_LOCK_STATUS.getMessage(), username), e); + } + } + } + + return true; + } private OAuth2AccessTokenRespDTO buildTokenResponse(OAuthTokenReqMessageContext tokReqMsgCtx, AccessTokenDO accessTokenBean) { diff --git a/pom.xml b/pom.xml index c21df78ab3b..7c1f61d6950 100644 --- a/pom.xml +++ b/pom.xml @@ -289,6 +289,13 @@ ${saml.common.util.version} + + + org.wso2.carbon.identity.event.handler.accountlock + org.wso2.carbon.identity.handler.event.account.lock + ${account.lock.service.version} + + com.google.gdata.wso2 @@ -967,6 +974,10 @@ 1.4.0 [1.4.0,1.5.0) + + 1.9.11 + [1.9.11, 2.0.0) + 2.6.0.wso2v1 [2.6.0,3.0.0) From cf9c07528390c2b29bb703caa5b7ff11db1ac0ab Mon Sep 17 00:00:00 2001 From: DilshanSenarath <74205483+DilshanSenarath@users.noreply.github.com> Date: Mon, 14 Oct 2024 01:40:06 +0530 Subject: [PATCH 2/6] add unit tests for refresh grant user validation --- .../org.wso2.carbon.identity.oauth/pom.xml | 6 + .../config/OAuthServerConfigurationTest.java | 7 + .../grant/RefreshGrantHandlerTest.java | 356 ++++++++---------- .../grant/RefreshGrantHandlerTestOld.java | 259 +++++++++++++ .../repository/conf/identity/identity.xml | 2 + 5 files changed, 422 insertions(+), 208 deletions(-) create mode 100644 components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTestOld.java diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index c8d3e27b784..0c6974cdef7 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -552,6 +552,12 @@ + + + org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponent + org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder + + maven-resources-plugin diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfigurationTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfigurationTest.java index 82370a75b2c..e99e8f54d78 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfigurationTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfigurationTest.java @@ -505,6 +505,13 @@ public void testGetSupportedTokenEndpointSigningAlgorithms() { Assert.assertEquals(supportedTokenEndpointSigningAlgorithms.size(), 3); } + @Test + public void testIsValidateAuthenticatedUserForRefreshGrantEnabled() throws Exception { + + Assert.assertTrue(OAuthServerConfiguration.getInstance() + .isValidateAuthenticatedUserForRefreshGrantEnabled()); + } + private String fillURLPlaceholdersForTest(String url) { return url.replace("${carbon.protocol}", "https") diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTest.java index ce88014f3c8..9f089ec907e 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTest.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * 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 @@ -11,249 +11,189 @@ * 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 + * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.identity.oauth2.token.handlers.grant; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; +import org.mockito.MockedStatic; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; -import org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl; -import org.wso2.carbon.identity.application.mgt.internal.ApplicationManagementServiceComponent; -import org.wso2.carbon.identity.application.mgt.internal.ApplicationManagementServiceComponentHolder; -import org.wso2.carbon.identity.common.testng.WithCarbonHome; -import org.wso2.carbon.identity.common.testng.WithH2Database; -import org.wso2.carbon.identity.common.testng.WithRealmService; +import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; +import org.wso2.carbon.identity.handler.event.account.lock.exception.AccountLockServiceException; +import org.wso2.carbon.identity.handler.event.account.lock.service.AccountLockService; import org.wso2.carbon.identity.oauth.common.OAuthConstants; -import org.wso2.carbon.identity.oauth.dao.OAuthAppDAO; -import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; -import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; +import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; +import org.wso2.carbon.identity.oauth.tokenprocessor.DefaultRefreshTokenGrantProcessor; +import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; -import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; -import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.model.RefreshTokenValidationDataDO; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.test.common.testng.utils.MockAuthenticatedUser; -import org.wso2.carbon.identity.testutil.Whitebox; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; -import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE; -import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenStates.TOKEN_STATE_EXPIRED; -import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenStates.TOKEN_STATE_INACTIVE; -import static org.wso2.carbon.identity.oauth.common.OAuthConstants.UNASSIGNED_VALIDITY_PERIOD; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.FederatedAssociationManager; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.exception.FederatedAssociationManagerException; +import org.wso2.carbon.user.core.UserCoreConstants; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_CHECKING_ACCOUNT_LOCK_STATUS; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_GETTING_USERNAME_ASSOCIATED_WITH_IDP; /** - * Test class for RefreshGrantHandler test cases. + * Unit tests for the RefreshGrantHandler class. */ -@WithCarbonHome -@WithRealmService(injectToSingletons = { OAuthComponentServiceHolder.class, - ApplicationManagementServiceComponentHolder.class }) -@WithH2Database(files = { "dbScripts/identity.sql", "dbScripts/insert_consumer_app.sql" }) public class RefreshGrantHandlerTest { - private static final String TEST_USER_ID = "testUser"; - private static final String TEST_USER_DOMAIN = "testDomain"; - private RefreshGrantHandler refreshGrantHandler; - private AuthenticatedUser authenticatedUser; - private String[] scopes; + private RefreshTokenGrantProcessor refreshTokenGrantProcessor; + private OAuthTokenReqMessageContext oAuthTokenReqMessageContext; + private RefreshTokenValidationDataDO refreshTokenValidationDataDO; + private OAuthServerConfiguration oAuthServerConfiguration; + private OAuth2AccessTokenReqDTO oAuth2AccessTokenReqDTO; + private OAuth2ServiceComponentHolder oAuth2ServiceComponentHolder; - @BeforeClass - protected void setUp() throws Exception { - OAuth2ServiceComponentHolder.setApplicationMgtService(ApplicationManagementServiceImpl.getInstance()); - authenticatedUser = new MockAuthenticatedUser(TEST_USER_ID); - authenticatedUser.setUserStoreDomain(TEST_USER_DOMAIN); - scopes = new String[] { "scope1", "scope2" }; + @BeforeMethod + public void init() { + refreshTokenGrantProcessor = mock(DefaultRefreshTokenGrantProcessor.class); + oAuthTokenReqMessageContext = mock(OAuthTokenReqMessageContext.class); + refreshTokenValidationDataDO = mock(RefreshTokenValidationDataDO.class); + oAuthServerConfiguration = mock(OAuthServerConfiguration.class); + oAuth2AccessTokenReqDTO = mock(OAuth2AccessTokenReqDTO.class); + oAuth2ServiceComponentHolder = mock(OAuth2ServiceComponentHolder.class); } - @BeforeMethod - protected void setUpMethod() throws Exception { + @DataProvider(name = "validateGrantWhenUserIsLockedInUserStoreEnd") + public Object[][] validateGrantWhenUserIsLockedInUserStoreEnd() { - ApplicationManagementServiceComponent applicationManagementServiceComponent = - new ApplicationManagementServiceComponent(); - Whitebox.invokeMethod(applicationManagementServiceComponent, "buildFileBasedSPList", null); - } + String userStoreDomain = "user-store-domain"; + String tenantDomain = "tenant-domain"; + String username = "user"; + MockAuthenticatedUser user1 = new MockAuthenticatedUser(username); + user1.setUserStoreDomain(userStoreDomain); + user1.setTenantDomain(tenantDomain); + + MockAuthenticatedUser user2 = new MockAuthenticatedUser(username); - @DataProvider(name = "GetValidateGrantData") - public Object[][] validateGrantData() { + String subjectIdentifier = "subject-identifier"; + String federatedUserId = "federated-user-id"; + String federatedIDPName = "federated-idp"; + MockAuthenticatedUser federatedUser = new MockAuthenticatedUser(federatedUserId); + federatedUser.setAuthenticatedSubjectIdentifier(subjectIdentifier); + federatedUser.setFederatedUser(true); + federatedUser.setFederatedIdPName(federatedIDPName); return new Object[][] { - { "clientId1" }, - { "clientId2" }, - { "clientId2" } + { user1, null, null, false, null, false }, + { user1, null, null, false, null, true }, + { user1, null, null, true, null, true }, + { federatedUser, null, null, false, null, true }, + { federatedUser, user1, null, false, null, true }, + { federatedUser, user1, null, true, null, true }, + { federatedUser, user1, new FederatedAssociationManagerException("test error"), true, null, true }, + { federatedUser, user1, new FrameworkException("test error"), true, null, true }, + { federatedUser, user1, null, true, new AccountLockServiceException("test error"), true }, + { null, null, null, false, null, true }, + { user2, null, null, false, null, true } }; } - @Test(dataProvider = "GetValidateGrantData") - public void testValidateGrant(String clientId) + /** + * Test scenarios for the `validateGrant` method when the user, locked at the user store level, + * attempts to use the refresh grant. + * + * @param user The user attempts to use the refresh grant. + * @param associatedUser Associated local user if the user is federated user. + * @param federatedAssociationManagerException Exception when resolving the local associated user. + * @param isUserLocked Whether the user is locked from user store end. + * @param accountLockServiceException Exception when checking the account lock status. + * @param isValidateAuthenticatedUserForRefreshGrant Whether the `ValidateAuthenticatedUserForRefreshGrant` + * config is enabled in identity.xml. + * @throws Exception Any uncaught exception thrown while running the test case. + */ + @Test(dataProvider = "validateGrantWhenUserIsLockedInUserStoreEnd") + public void testValidateGrantWhenUserIsLockedInUserStoreEnd(AuthenticatedUser user, + AuthenticatedUser associatedUser, + Throwable federatedAssociationManagerException, + boolean isUserLocked, + Throwable accountLockServiceException, + boolean isValidateAuthenticatedUserForRefreshGrant) throws Exception { - OAuthAppDAO oAuthAppDAO = new OAuthAppDAO(); - oAuthAppDAO.removeConsumerApplication(clientId); - - OAuthAppDO oAuthAppDO = new OAuthAppDO(); - oAuthAppDO.setGrantTypes("implicit"); - oAuthAppDO.setOauthConsumerKey(clientId); - oAuthAppDO.setUser(authenticatedUser); - oAuthAppDO.setOauthVersion(OAuthConstants.OAuthVersions.VERSION_2); - - oAuthAppDAO.addOAuthApplication(oAuthAppDO); - - refreshGrantHandler = new RefreshGrantHandler(); - refreshGrantHandler.init(); - - OAuth2AccessTokenReqDTO tokenReqDTO = new OAuth2AccessTokenReqDTO(); - tokenReqDTO.setClientId(clientId); - tokenReqDTO.setRefreshToken("refreshToken1"); - OAuthTokenReqMessageContext tokenReqMessageContext = new OAuthTokenReqMessageContext(tokenReqDTO); - - boolean isValid = refreshGrantHandler.validateGrant(tokenReqMessageContext); - assertTrue(isValid, "Refresh token validation should be successful."); - } - - @DataProvider(name = "validateGrantExceptionData") - public Object[][] validateGrantExceptionData() { - - List accessTokenDOS = new ArrayList<>(); - AccessTokenDO accessTokenDO1 = new AccessTokenDO(); - accessTokenDO1.setTokenState(TOKEN_STATE_ACTIVE); - accessTokenDO1.setRefreshToken("refreshToken1"); - - AccessTokenDO accessTokenDO2 = new AccessTokenDO(); - accessTokenDO2.setTokenState(TOKEN_STATE_EXPIRED); - accessTokenDO2.setRefreshToken("refreshToken2"); - - accessTokenDOS.add(accessTokenDO1); - accessTokenDOS.add(accessTokenDO2); - - return new Object[][] { { "clientId1", "refreshToken1", "accessToken1", TOKEN_STATE_INACTIVE, accessTokenDOS }, - { "clientId1", "refreshToken3", "accessToken1", TOKEN_STATE_EXPIRED, accessTokenDOS }, - { "clientId1", "refreshToken3", "accessToken1", TOKEN_STATE_EXPIRED, null }, - { "clientId1", "refreshToken1", null, null, accessTokenDOS }, }; - } - - @Test(dataProvider = "validateGrantExceptionData", expectedExceptions = IdentityOAuth2Exception.class) - public void testValidateGrantForException(String clientId, String refreshToken, String accessToken, - String tokenState, Object accessTokenObj) throws Exception { - - refreshGrantHandler = new RefreshGrantHandler(); - refreshGrantHandler.init(); - - OAuth2AccessTokenReqDTO tokenReqDTO = new OAuth2AccessTokenReqDTO(); - tokenReqDTO.setClientId(clientId); - tokenReqDTO.setRefreshToken(refreshToken); - OAuthTokenReqMessageContext tokenReqMessageContext = new OAuthTokenReqMessageContext(tokenReqDTO); - - refreshGrantHandler.validateGrant(tokenReqMessageContext); - Assert.fail("Authenticated user cannot be null."); - } - - @Test(dataProvider = "GetTokenIssuerData") - public void testIssue(Long userAccessTokenExpiryTime, Long validityPeriod, String renewRefreshToken, - String clientId) throws Exception { - - OAuthAppDAO oAuthAppDAO = new OAuthAppDAO(); - oAuthAppDAO.removeConsumerApplication(clientId); - OAuthAppDO oAuthAppDO = new OAuthAppDO(); - oAuthAppDO.setUserAccessTokenExpiryTime(userAccessTokenExpiryTime); - oAuthAppDO.setRefreshTokenExpiryTime(userAccessTokenExpiryTime); - oAuthAppDO.setUser(authenticatedUser); - oAuthAppDO.setOauthConsumerKey(clientId); - oAuthAppDO.setOauthVersion(OAuthConstants.OAuthVersions.VERSION_2); - oAuthAppDO.setRenewRefreshTokenEnabled(renewRefreshToken); - oAuthAppDAO.addOAuthApplication(oAuthAppDO); - - refreshGrantHandler = new RefreshGrantHandler(); - refreshGrantHandler.init(); - - OAuth2AccessTokenReqDTO tokenReqDTO = new OAuth2AccessTokenReqDTO(); - tokenReqDTO.setClientId(clientId); - tokenReqDTO.setRefreshToken("refreshToken1"); - tokenReqDTO.setScope(scopes); - - RefreshTokenValidationDataDO oldAccessToken = new RefreshTokenValidationDataDO(); - oldAccessToken.setTokenId("tokenId"); - oldAccessToken.setAccessToken("oldAccessToken"); - - OAuthTokenReqMessageContext tokenReqMessageContext = new OAuthTokenReqMessageContext(tokenReqDTO); - tokenReqMessageContext.addProperty("previousAccessToken", oldAccessToken); - tokenReqMessageContext.setAuthorizedUser(authenticatedUser); - tokenReqMessageContext.setValidityPeriod(validityPeriod); - tokenReqMessageContext.setScope(scopes); + when(refreshTokenGrantProcessor.validateRefreshToken(any())).thenReturn(refreshTokenValidationDataDO); + when(refreshTokenValidationDataDO.getAuthorizedUser()).thenReturn(user); + when(refreshTokenGrantProcessor.isLatestRefreshToken(any(), any(), any())).thenReturn(true); + when(oAuthServerConfiguration.isValidateAuthenticatedUserForRefreshGrantEnabled()).thenReturn( + isValidateAuthenticatedUserForRefreshGrant); + when(oAuth2ServiceComponentHolder.getRefreshTokenGrantProcessor()).thenReturn(refreshTokenGrantProcessor); + when(oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO()).thenReturn(oAuth2AccessTokenReqDTO); + + FederatedAssociationManager federatedAssociationManager = mock(FederatedAssociationManager.class); + if (federatedAssociationManagerException instanceof FederatedAssociationManagerException) { + when(federatedAssociationManager.getUserForFederatedAssociation(anyString(), + eq(user.getFederatedIdPName()), eq(user.getAuthenticatedSubjectIdentifier()))).thenThrow( + federatedAssociationManagerException); + } else if (associatedUser != null) { + when(federatedAssociationManager.getUserForFederatedAssociation(anyString(), + eq(user.getFederatedIdPName()), eq(user.getAuthenticatedSubjectIdentifier()))).thenReturn( + associatedUser.getUserName()); + } - OAuth2AccessTokenRespDTO actual = refreshGrantHandler.issue(tokenReqMessageContext); - assertFalse(actual.isError()); - assertNotNull(actual.getRefreshToken()); - if (Objects.equals(renewRefreshToken, "true") || (renewRefreshToken == null)) { - assertNotEquals("refreshToken1", actual.getRefreshToken()); + AccountLockService accountLockService = mock(AccountLockService.class); + if (accountLockServiceException != null) { + when(accountLockService.isAccountLocked(anyString(), anyString())).thenThrow( + accountLockServiceException); } else { - assertEquals("refreshToken1", actual.getRefreshToken()); + when(accountLockService.isAccountLocked(anyString(), anyString())).thenReturn(isUserLocked); } - } - - @Test(dataProvider = "GetValidateScopeData") - public void validateScope(String[] requestedScopes, String[] grantedScopes, boolean expected, String message) - throws Exception { - - OAuth2AccessTokenReqDTO tokenReqDTO = new OAuth2AccessTokenReqDTO(); - tokenReqDTO.setScope(requestedScopes); - tokenReqDTO.setClientId("clientId1"); - tokenReqDTO.setRefreshToken("refreshToken1"); - tokenReqDTO.setGrantType("refreshTokenGrant"); - OAuthTokenReqMessageContext tokenReqMessageContext = new OAuthTokenReqMessageContext(tokenReqDTO); - tokenReqMessageContext.setScope(grantedScopes); - refreshGrantHandler = new RefreshGrantHandler(); - refreshGrantHandler.init(); - boolean actual = refreshGrantHandler.validateScope(tokenReqMessageContext); - assertEquals(actual, expected, message); - } - - @DataProvider(name = "GetTokenIssuerData") - public Object[][] tokenIssuerData() { - - return new Object[][] { - { 0L, UNASSIGNED_VALIDITY_PERIOD, "true", "clientId1" }, - { 20L, UNASSIGNED_VALIDITY_PERIOD, "true", "clientId2" }, - { 20L, 20L, "true", "clientId3" }, - { 0L, UNASSIGNED_VALIDITY_PERIOD, "true", "clientId4" }, - { 20L, 20L, "false", "clientId5" }, - { 20L, 20L, null, "clientId6" }, - { 20L, 20L, "true", "clientId7" } }; - } - - @DataProvider(name = "GetValidateScopeData") - public Object[][] validateScopeData() { - - String[] requestedScopes = new String[2]; - requestedScopes[0] = "scope1"; - requestedScopes[1] = "scope2"; - - String[] grantedScopes = new String[1]; - grantedScopes[0] = "scope1"; - - String[] grantedScopesWithRequestedScope = new String[1]; - grantedScopesWithRequestedScope[0] = "scope1"; - grantedScopesWithRequestedScope[0] = "scope2"; - - return new Object[][] { { requestedScopes, grantedScopes, false, "scope validation should fail." }, - { requestedScopes, grantedScopesWithRequestedScope, false, "scope validation should fail." }, - { requestedScopes, new String[0], false, "scope validation should fail." }, - { new String[] { "scope_not_granted" }, grantedScopes, false, "scope validation should fail." }, }; + refreshTokenValidationDataDO.setRefreshTokenState(OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE); + try { + try (MockedStatic oAuthServerConfigurationMockedStatic = mockStatic( + OAuthServerConfiguration.class); + MockedStatic oAuth2ServiceComponentHolderMockedStatic = mockStatic( + OAuth2ServiceComponentHolder.class); + MockedStatic frameworkUtilsMockedStatic = mockStatic(FrameworkUtils.class)) { + oAuthServerConfigurationMockedStatic.when(OAuthServerConfiguration::getInstance) + .thenReturn(oAuthServerConfiguration); + oAuth2ServiceComponentHolderMockedStatic.when(OAuth2ServiceComponentHolder::getInstance) + .thenReturn(oAuth2ServiceComponentHolder); + oAuth2ServiceComponentHolderMockedStatic.when(OAuth2ServiceComponentHolder::getAccountLockService) + .thenReturn(accountLockService); + if (federatedAssociationManagerException instanceof FrameworkException) { + frameworkUtilsMockedStatic.when(FrameworkUtils::getFederatedAssociationManager) + .thenThrow(federatedAssociationManagerException); + } else { + frameworkUtilsMockedStatic.when(FrameworkUtils::getFederatedAssociationManager) + .thenReturn(federatedAssociationManager); + } + + RefreshGrantHandler refreshGrantHandler = new RefreshGrantHandler(); + boolean validateResult = refreshGrantHandler.validateGrant(oAuthTokenReqMessageContext); + assertTrue(validateResult); + } + } catch (IdentityOAuth2Exception e) { + if (federatedAssociationManagerException != null) { + assertEquals(ERROR_WHILE_GETTING_USERNAME_ASSOCIATED_WITH_IDP.getCode(), e.getErrorCode()); + } else if (accountLockServiceException != null) { + assertEquals(ERROR_WHILE_CHECKING_ACCOUNT_LOCK_STATUS.getCode(), e.getErrorCode()); + } else if (isUserLocked) { + assertEquals(UserCoreConstants.ErrorCode.USER_IS_LOCKED, e.getErrorCode()); + } else { + fail("Unexpected exception is thrown."); + } + } } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTestOld.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTestOld.java new file mode 100644 index 00000000000..5901248aa87 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTestOld.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.oauth2.token.handlers.grant; + +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl; +import org.wso2.carbon.identity.application.mgt.internal.ApplicationManagementServiceComponent; +import org.wso2.carbon.identity.application.mgt.internal.ApplicationManagementServiceComponentHolder; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.identity.common.testng.WithH2Database; +import org.wso2.carbon.identity.common.testng.WithRealmService; +import org.wso2.carbon.identity.oauth.common.OAuthConstants; +import org.wso2.carbon.identity.oauth.dao.OAuthAppDAO; +import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; +import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO; +import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.RefreshTokenValidationDataDO; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.test.common.testng.utils.MockAuthenticatedUser; +import org.wso2.carbon.identity.testutil.Whitebox; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenStates.TOKEN_STATE_EXPIRED; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenStates.TOKEN_STATE_INACTIVE; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.UNASSIGNED_VALIDITY_PERIOD; + +/** + * Test class for RefreshGrantHandler test cases. + */ +@WithCarbonHome +@WithRealmService(injectToSingletons = { OAuthComponentServiceHolder.class, + ApplicationManagementServiceComponentHolder.class }) +@WithH2Database(files = { "dbScripts/identity.sql", "dbScripts/insert_consumer_app.sql" }) +public class RefreshGrantHandlerTestOld { + + private static final String TEST_USER_ID = "testUser"; + private static final String TEST_USER_DOMAIN = "testDomain"; + private RefreshGrantHandler refreshGrantHandler; + private AuthenticatedUser authenticatedUser; + private String[] scopes; + + @BeforeClass + protected void setUp() throws Exception { + OAuth2ServiceComponentHolder.setApplicationMgtService(ApplicationManagementServiceImpl.getInstance()); + authenticatedUser = new MockAuthenticatedUser(TEST_USER_ID); + authenticatedUser.setUserStoreDomain(TEST_USER_DOMAIN); + scopes = new String[] { "scope1", "scope2" }; + } + + @BeforeMethod + protected void setUpMethod() throws Exception { + + ApplicationManagementServiceComponent applicationManagementServiceComponent = + new ApplicationManagementServiceComponent(); + Whitebox.invokeMethod(applicationManagementServiceComponent, "buildFileBasedSPList", null); + } + + @DataProvider(name = "GetValidateGrantData") + public Object[][] validateGrantData() { + + return new Object[][] { + { "clientId1" }, + { "clientId2" }, + { "clientId2" } + }; + } + + @Test(dataProvider = "GetValidateGrantData") + public void testValidateGrant(String clientId) + throws Exception { + + OAuthAppDAO oAuthAppDAO = new OAuthAppDAO(); + oAuthAppDAO.removeConsumerApplication(clientId); + + OAuthAppDO oAuthAppDO = new OAuthAppDO(); + oAuthAppDO.setGrantTypes("implicit"); + oAuthAppDO.setOauthConsumerKey(clientId); + oAuthAppDO.setUser(authenticatedUser); + oAuthAppDO.setOauthVersion(OAuthConstants.OAuthVersions.VERSION_2); + + oAuthAppDAO.addOAuthApplication(oAuthAppDO); + + refreshGrantHandler = new RefreshGrantHandler(); + refreshGrantHandler.init(); + + OAuth2AccessTokenReqDTO tokenReqDTO = new OAuth2AccessTokenReqDTO(); + tokenReqDTO.setClientId(clientId); + tokenReqDTO.setRefreshToken("refreshToken1"); + OAuthTokenReqMessageContext tokenReqMessageContext = new OAuthTokenReqMessageContext(tokenReqDTO); + + boolean isValid = refreshGrantHandler.validateGrant(tokenReqMessageContext); + assertTrue(isValid, "Refresh token validation should be successful."); + } + + @DataProvider(name = "validateGrantExceptionData") + public Object[][] validateGrantExceptionData() { + + List accessTokenDOS = new ArrayList<>(); + AccessTokenDO accessTokenDO1 = new AccessTokenDO(); + accessTokenDO1.setTokenState(TOKEN_STATE_ACTIVE); + accessTokenDO1.setRefreshToken("refreshToken1"); + + AccessTokenDO accessTokenDO2 = new AccessTokenDO(); + accessTokenDO2.setTokenState(TOKEN_STATE_EXPIRED); + accessTokenDO2.setRefreshToken("refreshToken2"); + + accessTokenDOS.add(accessTokenDO1); + accessTokenDOS.add(accessTokenDO2); + + return new Object[][] { { "clientId1", "refreshToken1", "accessToken1", TOKEN_STATE_INACTIVE, accessTokenDOS }, + { "clientId1", "refreshToken3", "accessToken1", TOKEN_STATE_EXPIRED, accessTokenDOS }, + { "clientId1", "refreshToken3", "accessToken1", TOKEN_STATE_EXPIRED, null }, + { "clientId1", "refreshToken1", null, null, accessTokenDOS }, }; + } + + @Test(dataProvider = "validateGrantExceptionData", expectedExceptions = IdentityOAuth2Exception.class) + public void testValidateGrantForException(String clientId, String refreshToken, String accessToken, + String tokenState, Object accessTokenObj) throws Exception { + + refreshGrantHandler = new RefreshGrantHandler(); + refreshGrantHandler.init(); + + OAuth2AccessTokenReqDTO tokenReqDTO = new OAuth2AccessTokenReqDTO(); + tokenReqDTO.setClientId(clientId); + tokenReqDTO.setRefreshToken(refreshToken); + OAuthTokenReqMessageContext tokenReqMessageContext = new OAuthTokenReqMessageContext(tokenReqDTO); + + refreshGrantHandler.validateGrant(tokenReqMessageContext); + Assert.fail("Authenticated user cannot be null."); + } + + @Test(dataProvider = "GetTokenIssuerData") + public void testIssue(Long userAccessTokenExpiryTime, Long validityPeriod, String renewRefreshToken, + String clientId) throws Exception { + + OAuthAppDAO oAuthAppDAO = new OAuthAppDAO(); + oAuthAppDAO.removeConsumerApplication(clientId); + OAuthAppDO oAuthAppDO = new OAuthAppDO(); + oAuthAppDO.setUserAccessTokenExpiryTime(userAccessTokenExpiryTime); + oAuthAppDO.setRefreshTokenExpiryTime(userAccessTokenExpiryTime); + oAuthAppDO.setUser(authenticatedUser); + oAuthAppDO.setOauthConsumerKey(clientId); + oAuthAppDO.setOauthVersion(OAuthConstants.OAuthVersions.VERSION_2); + oAuthAppDO.setRenewRefreshTokenEnabled(renewRefreshToken); + oAuthAppDAO.addOAuthApplication(oAuthAppDO); + + refreshGrantHandler = new RefreshGrantHandler(); + refreshGrantHandler.init(); + + OAuth2AccessTokenReqDTO tokenReqDTO = new OAuth2AccessTokenReqDTO(); + tokenReqDTO.setClientId(clientId); + tokenReqDTO.setRefreshToken("refreshToken1"); + tokenReqDTO.setScope(scopes); + + RefreshTokenValidationDataDO oldAccessToken = new RefreshTokenValidationDataDO(); + oldAccessToken.setTokenId("tokenId"); + oldAccessToken.setAccessToken("oldAccessToken"); + + OAuthTokenReqMessageContext tokenReqMessageContext = new OAuthTokenReqMessageContext(tokenReqDTO); + tokenReqMessageContext.addProperty("previousAccessToken", oldAccessToken); + tokenReqMessageContext.setAuthorizedUser(authenticatedUser); + tokenReqMessageContext.setValidityPeriod(validityPeriod); + tokenReqMessageContext.setScope(scopes); + + OAuth2AccessTokenRespDTO actual = refreshGrantHandler.issue(tokenReqMessageContext); + assertFalse(actual.isError()); + assertNotNull(actual.getRefreshToken()); + if (Objects.equals(renewRefreshToken, "true") || (renewRefreshToken == null)) { + assertNotEquals("refreshToken1", actual.getRefreshToken()); + } else { + assertEquals("refreshToken1", actual.getRefreshToken()); + } + } + + @Test(dataProvider = "GetValidateScopeData") + public void validateScope(String[] requestedScopes, String[] grantedScopes, boolean expected, String message) + throws Exception { + + OAuth2AccessTokenReqDTO tokenReqDTO = new OAuth2AccessTokenReqDTO(); + tokenReqDTO.setScope(requestedScopes); + tokenReqDTO.setClientId("clientId1"); + tokenReqDTO.setRefreshToken("refreshToken1"); + tokenReqDTO.setGrantType("refreshTokenGrant"); + OAuthTokenReqMessageContext tokenReqMessageContext = new OAuthTokenReqMessageContext(tokenReqDTO); + tokenReqMessageContext.setScope(grantedScopes); + + refreshGrantHandler = new RefreshGrantHandler(); + refreshGrantHandler.init(); + boolean actual = refreshGrantHandler.validateScope(tokenReqMessageContext); + assertEquals(actual, expected, message); + } + + @DataProvider(name = "GetTokenIssuerData") + public Object[][] tokenIssuerData() { + + return new Object[][] { + { 0L, UNASSIGNED_VALIDITY_PERIOD, "true", "clientId1" }, + { 20L, UNASSIGNED_VALIDITY_PERIOD, "true", "clientId2" }, + { 20L, 20L, "true", "clientId3" }, + { 0L, UNASSIGNED_VALIDITY_PERIOD, "true", "clientId4" }, + { 20L, 20L, "false", "clientId5" }, + { 20L, 20L, null, "clientId6" }, + { 20L, 20L, "true", "clientId7" } }; + } + + @DataProvider(name = "GetValidateScopeData") + public Object[][] validateScopeData() { + + String[] requestedScopes = new String[2]; + requestedScopes[0] = "scope1"; + requestedScopes[1] = "scope2"; + + String[] grantedScopes = new String[1]; + grantedScopes[0] = "scope1"; + + String[] grantedScopesWithRequestedScope = new String[1]; + grantedScopesWithRequestedScope[0] = "scope1"; + grantedScopesWithRequestedScope[0] = "scope2"; + + return new Object[][] { { requestedScopes, grantedScopes, false, "scope validation should fail." }, + { requestedScopes, grantedScopesWithRequestedScope, false, "scope validation should fail." }, + { requestedScopes, new String[0], false, "scope validation should fail." }, + { new String[] { "scope_not_granted" }, grantedScopes, false, "scope validation should fail." }, }; + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/test/resources/repository/conf/identity/identity.xml b/components/org.wso2.carbon.identity.oauth/src/test/resources/repository/conf/identity/identity.xml index 8a4742cbbff..113ba6b289d 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/resources/repository/conf/identity/identity.xml +++ b/components/org.wso2.carbon.identity.oauth/src/test/resources/repository/conf/identity/identity.xml @@ -165,6 +165,8 @@ false true + + true org.wso2.carbon.identity.oauth.tokenprocessor.PlainTextPersistenceProcessor From c3ee286957a1c848a384e90db206428537ca0f08 Mon Sep 17 00:00:00 2001 From: DilshanSenarath <74205483+DilshanSenarath@users.noreply.github.com> Date: Mon, 14 Oct 2024 01:43:32 +0530 Subject: [PATCH 3/6] add refresh grant handler test class to the testng.xml --- .../src/test/resources/testng.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml index ca82671d83c..a4849dc6749 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml @@ -110,7 +110,7 @@ - + @@ -182,7 +182,7 @@ - + From a16225f5c38ea86df03add26c388554c6bfd9031 Mon Sep 17 00:00:00 2001 From: DilshanSenarath <74205483+DilshanSenarath@users.noreply.github.com> Date: Mon, 14 Oct 2024 01:59:50 +0530 Subject: [PATCH 4/6] fix the exclude pattern issue --- components/org.wso2.carbon.identity.oauth/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 0c6974cdef7..4fb85fc4419 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -554,8 +554,8 @@ - org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponent - org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder + org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.class + org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.class From 6e5f72362aec0df8e2f727f80941b7a25c47b17f Mon Sep 17 00:00:00 2001 From: DilshanSenarath <74205483+DilshanSenarath@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:37:36 +0530 Subject: [PATCH 5/6] update license headers --- components/org.wso2.carbon.identity.oauth/pom.xml | 2 +- .../identity/oauth/config/OAuthServerConfigurationTest.java | 2 +- .../oauth2/token/handlers/grant/RefreshGrantHandlerTestOld.java | 2 +- .../src/test/resources/repository/conf/identity/identity.xml | 2 +- .../src/test/resources/testng.xml | 2 +- pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 0f2e9fb6854..3a3f49a5df7 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -1,6 +1,6 @@