From d4651ae86844d0dcc7fb7d602a3d0ee4ce90a3af Mon Sep 17 00:00:00 2001 From: Chamila Adhikarinayake Date: Thu, 30 Mar 2023 17:31:26 +0530 Subject: [PATCH 01/13] Provide external DAO layer plugin --- .../internal/OAuthComponentServiceHolder.java | 41 +++++++++++++++- .../dao/OAuthTokenPersistenceFactory.java | 15 +++++- .../internal/OAuth2ServiceComponent.java | 47 +++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/internal/OAuthComponentServiceHolder.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/internal/OAuthComponentServiceHolder.java index 84f09d1cd7b..a3d9b43e505 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/internal/OAuthComponentServiceHolder.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/internal/OAuthComponentServiceHolder.java @@ -27,6 +27,8 @@ import org.wso2.carbon.identity.oauth.listener.OAuthApplicationMgtListener; import org.wso2.carbon.identity.oauth2.OAuth2ScopeService; import org.wso2.carbon.identity.oauth2.OAuth2Service; +import org.wso2.carbon.identity.oauth2.dao.AccessTokenDAO; +import org.wso2.carbon.identity.oauth2.dao.TokenManagementDAO; import org.wso2.carbon.identity.oauth2.token.handlers.response.AccessTokenResponseHandler; import org.wso2.carbon.identity.oauth2.validators.scope.ScopeValidator; import org.wso2.carbon.identity.organization.management.service.OrganizationUserResidentResolverService; @@ -60,7 +62,8 @@ public class OAuthComponentServiceHolder { private RoleManagementService roleManagementService; private OrganizationUserResidentResolverService organizationUserResidentResolverService; private List accessTokenResponseHandlers = new ArrayList<>(); - + private AccessTokenDAO accessTokenDAOService; + private TokenManagementDAO tokenManagementDAOService; /** * Get the list of scope validator implementations available. @@ -275,4 +278,40 @@ public List getAccessTokenResponseHandlers() { return accessTokenResponseHandlers; } + + /** + * Get AccessTokenDAO instance + * + * @return AccessTokenDAO + */ + public AccessTokenDAO getAccessTokenDAOService() { + return accessTokenDAOService; + } + + /** + * Set AccessTokenDAO instance + * + * @param accessTokenDAOService + */ + public void setAccessTokenDAOService(AccessTokenDAO accessTokenDAOService) { + this.accessTokenDAOService = accessTokenDAOService; + } + + /** + * Get TokenManagementDAO instance + * + * @return + */ + public TokenManagementDAO getTokenManagementDAOService() { + return tokenManagementDAOService; + } + + /** + * Set TokenManagementDAO instance + * + * @param tokenManagementDAOService + */ + public void setTokenManagementDAOService(TokenManagementDAO tokenManagementDAOService) { + this.tokenManagementDAOService = tokenManagementDAOService; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/OAuthTokenPersistenceFactory.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/OAuthTokenPersistenceFactory.java index 8c014854585..c90c4285e63 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/OAuthTokenPersistenceFactory.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/OAuthTokenPersistenceFactory.java @@ -20,6 +20,7 @@ package org.wso2.carbon.identity.oauth2.dao; +import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; import org.wso2.carbon.identity.openidconnect.dao.CacheBackedScopeClaimMappingDAOImpl; import org.wso2.carbon.identity.openidconnect.dao.RequestObjectDAO; import org.wso2.carbon.identity.openidconnect.dao.RequestObjectDAOImpl; @@ -63,8 +64,13 @@ public AuthorizationCodeDAO getAuthorizationCodeDAO() { } public AccessTokenDAO getAccessTokenDAO() { + + AccessTokenDAO accessTokenDAO = OAuthComponentServiceHolder.getInstance().getAccessTokenDAOService(); + if (accessTokenDAO == null) { + return tokenDAO; + } - return tokenDAO; + return accessTokenDAO; } public OAuthScopeDAO getOAuthScopeDAO() { @@ -74,7 +80,12 @@ public OAuthScopeDAO getOAuthScopeDAO() { public TokenManagementDAO getTokenManagementDAO() { - return managementDAO; + TokenManagementDAO tokenManagementDAO = OAuthComponentServiceHolder.getInstance() + .getTokenManagementDAOService(); + if (tokenManagementDAO == null) { + return managementDAO; + } + return tokenManagementDAO; } public RequestObjectDAO getRequestObjectDAO() { 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 fec38c83f8d..4d6c1c264fe 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 @@ -55,7 +55,9 @@ import org.wso2.carbon.identity.oauth2.client.authentication.OAuthClientAuthenticator; import org.wso2.carbon.identity.oauth2.client.authentication.OAuthClientAuthnService; import org.wso2.carbon.identity.oauth2.client.authentication.PublicClientAuthenticator; +import org.wso2.carbon.identity.oauth2.dao.AccessTokenDAO; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; +import org.wso2.carbon.identity.oauth2.dao.TokenManagementDAO; import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthService; import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthServiceImpl; import org.wso2.carbon.identity.oauth2.device.response.DeviceFlowResponseTypeRequestValidator; @@ -651,6 +653,51 @@ protected void unsetOrganizationUserResidentResolverService( OAuth2ServiceComponentHolder.setOrganizationUserResidentResolverService(null); } + @Reference( + name = "access.token.dao.service", + service = AccessTokenDAO.class, + cardinality = ReferenceCardinality.OPTIONAL, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetAccessTokenDAOService" + ) + protected void setAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { + + if (log.isDebugEnabled()) { + log.debug("Adding the Access Token DAO Service : " + accessTokenDAO.getClass().getName()); + } + OAuthComponentServiceHolder.getInstance().setAccessTokenDAOService(accessTokenDAO); + } + + protected void unsetAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { + + if (log.isDebugEnabled()) { + log.debug("Removing the Access Token DAO Service : " + accessTokenDAO.getClass().getName()); + } + OAuthComponentServiceHolder.getInstance().setAccessTokenDAOService(null); + } + + @Reference( + name = "token.management.dao.service", + service = TokenManagementDAO.class, + cardinality = ReferenceCardinality.OPTIONAL, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetTokenMgtDAOService" + ) + protected void setTokenMgtDAOService(TokenManagementDAO tokenMgtDAOService) { + + if (log.isDebugEnabled()) { + log.debug("Adding the Token Mgt DAO Service : " + tokenMgtDAOService.getClass().getName()); + } + OAuthComponentServiceHolder.getInstance().setTokenManagementDAOService(tokenMgtDAOService); + } + + protected void unsetTokenMgtDAOService(TokenManagementDAO tokenManagementDAO) { + + if (log.isDebugEnabled()) { + log.debug("Removing the Token Mgt DAO Service : " + tokenManagementDAO.getClass().getName()); + } + OAuthComponentServiceHolder.getInstance().setTokenManagementDAOService(null); + } private static void loadScopeConfigFile() { List listOIDCScopesClaims = new ArrayList<>(); From 7e62f77a9da7e075b0ff2bd545841344f3ca4d41 Mon Sep 17 00:00:00 2001 From: Chamila Adhikarinayake Date: Sat, 1 Apr 2023 10:12:40 +0530 Subject: [PATCH 02/13] Add interface to refactor RefreshGrantHandler. --- .../DefaultRefreshTokenGrantProcessor.java | 179 ++++++++++++++++++ .../RefreshTokenGrantProcessor.java | 47 +++++ .../internal/OAuth2ServiceComponent.java | 24 +++ .../OAuth2ServiceComponentHolder.java | 14 ++ .../handlers/grant/RefreshGrantHandler.java | 147 +++----------- 5 files changed, 288 insertions(+), 123 deletions(-) create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java new file mode 100644 index 00000000000..23de569c267 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (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.oauth.tokenprocessor; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.base.IdentityConstants; +import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.identity.oauth.common.OAuthConstants; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +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.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.openidconnect.OIDCClaimUtil; + +import java.sql.Timestamp; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +/** + * Default implementation of @RefreshTokenProcessor responsible for handling refresh token persistence logic. + */ + +public class DefaultRefreshTokenGrantProcessor implements RefreshTokenGrantProcessor { + + private static final Log log = LogFactory.getLog(DefaultRefreshTokenGrantProcessor.class); + public static final String PREV_ACCESS_TOKEN = "previousAccessToken"; + public static final int LAST_ACCESS_TOKEN_RETRIEVAL_LIMIT = 10; + + @Override + public RefreshTokenValidationDataDO validateRefreshToken(OAuthTokenReqMessageContext tokenReqMessageContext) + throws IdentityOAuth2Exception { + OAuth2AccessTokenReqDTO tokenReq = tokenReqMessageContext.getOauth2AccessTokenReqDTO(); + RefreshTokenValidationDataDO validationBean = OAuthTokenPersistenceFactory.getInstance().getTokenManagementDAO() + .validateRefreshToken(tokenReq.getClientId(), tokenReq.getRefreshToken()); + validatePersistedAccessToken(validationBean, tokenReq.getClientId()); + return validationBean; + } + + @Override + public void persistNewToken(OAuthTokenReqMessageContext tokenReqMessageContext, AccessTokenDO accessTokenBean, + String userStoreDomain, String clientId) throws IdentityOAuth2Exception { + + RefreshTokenValidationDataDO oldAccessToken = + (RefreshTokenValidationDataDO) tokenReqMessageContext.getProperty(PREV_ACCESS_TOKEN); + if (log.isDebugEnabled()) { + if (IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.ACCESS_TOKEN)) { + log.debug("Previous access token (hashed): " + DigestUtils.sha256Hex(oldAccessToken.getAccessToken())); + } + } + // set the previous access token state to "INACTIVE" and store new access token in single db connection + OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() + .invalidateAndCreateNewAccessToken(oldAccessToken.getTokenId(), + OAuthConstants.TokenStates.TOKEN_STATE_INACTIVE, clientId, + UUID.randomUUID().toString(), accessTokenBean, userStoreDomain, oldAccessToken.getGrantType()); + } + + @Override + public AccessTokenDO createAccessTokenBean(OAuthTokenReqMessageContext tokReqMsgCtx, + OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean, String tokenType) + throws IdentityOAuth2Exception { + + Timestamp timestamp = new Timestamp(new Date().getTime()); + String tokenId = UUID.randomUUID().toString(); + + AccessTokenDO accessTokenDO = new AccessTokenDO(); + accessTokenDO.setConsumerKey(tokenReq.getClientId()); + accessTokenDO.setAuthzUser(tokReqMsgCtx.getAuthorizedUser()); + accessTokenDO.setScope(tokReqMsgCtx.getScope()); + accessTokenDO.setTokenType(tokenType); + accessTokenDO.setTokenState(OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE); + accessTokenDO.setTokenId(tokenId); + accessTokenDO.setGrantType(tokenReq.getGrantType()); + accessTokenDO.setIssuedTime(timestamp); + accessTokenDO.setTokenBinding(tokReqMsgCtx.getTokenBinding()); + + if (OAuth2ServiceComponentHolder.isConsentedTokenColumnEnabled()) { + String previousGrantType = validationBean.getGrantType(); + // Check if the previous grant type is consent refresh token type or not. + if (!StringUtils.equals(OAuthConstants.GrantTypes.REFRESH_TOKEN, previousGrantType)) { + // If the previous grant type is not a refresh token, then check if it's a consent token or not. + if (OIDCClaimUtil.isConsentBasedClaimFilteringApplicable(previousGrantType)) { + accessTokenDO.setIsConsentedToken(true); + } + } else { + /* When previousGrantType == refresh_token, we need to check whether the original grant type + is consented or not. */ + AccessTokenDO accessTokenDOFromTokenIdentifier = OAuth2Util.getAccessTokenDOFromTokenIdentifier( + validationBean.getAccessToken(), false); + accessTokenDO.setIsConsentedToken(accessTokenDOFromTokenIdentifier.isConsentedToken()); + } + + if (accessTokenDO.isConsentedToken()) { + tokReqMsgCtx.setConsentedToken(true); + } + } + + return accessTokenDO; + } + + private boolean validatePersistedAccessToken(RefreshTokenValidationDataDO validationBean, String clientId) + throws IdentityOAuth2Exception { + + if (validationBean.getAccessToken() == null) { + if (log.isDebugEnabled()) { + log.debug("Invalid Refresh Token provided for Client with " + "Client Id : " + clientId); + } + throw new IdentityOAuth2Exception("Persisted access token data not found"); + } + return true; + } + + @Override + public boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean, + String userStoreDomain) throws IdentityOAuth2Exception { + if (log.isDebugEnabled()) { + log.debug("Evaluating refresh token. Token value: " + tokenReq.getRefreshToken() + ", Token state: " + + validationBean.getRefreshTokenState()); + } + if (!OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE.equals(validationBean.getRefreshTokenState())) { + // if refresh token is not in active state, check whether there is an access token + // issued with the same refresh token + List accessTokenBeans = getAccessTokenBeans(tokenReq, validationBean, userStoreDomain); + for (AccessTokenDO token : accessTokenBeans) { + if (tokenReq.getRefreshToken().equals(token.getRefreshToken()) + && (OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE.equals(token.getTokenState()) + || OAuthConstants.TokenStates.TOKEN_STATE_EXPIRED.equals(token.getTokenState()))) { + return true; + } + } + if (log.isDebugEnabled()) { + log.debug("Refresh token: " + tokenReq.getRefreshToken() + " is not the latest"); + } + return false; + } + return true; + } + + private List getAccessTokenBeans(OAuth2AccessTokenReqDTO tokenReq, + RefreshTokenValidationDataDO validationBean, String userStoreDomain) throws IdentityOAuth2Exception { + + List accessTokenBeans = OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() + .getLatestAccessTokens(tokenReq.getClientId(), validationBean.getAuthorizedUser(), userStoreDomain, + OAuth2Util.buildScopeString(validationBean.getScope()), + validationBean.getTokenBindingReference(), true, LAST_ACCESS_TOKEN_RETRIEVAL_LIMIT); + if (accessTokenBeans == null || accessTokenBeans.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("No previous access tokens found. User: " + validationBean.getAuthorizedUser() + ", client: " + + tokenReq.getClientId() + ", scope: " + + OAuth2Util.buildScopeString(validationBean.getScope())); + } + throw new IdentityOAuth2Exception("No previous access tokens found"); + } + return accessTokenBeans; + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java new file mode 100644 index 00000000000..d2ddb30ede9 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (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.oauth.tokenprocessor; + +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.RefreshTokenValidationDataDO; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; + +/** + * + * Intermediate processor for handling refresh token persistence logic. + * + */ + +public interface RefreshTokenGrantProcessor { + + RefreshTokenValidationDataDO validateRefreshToken(OAuthTokenReqMessageContext tokenReqMessageContext) + throws IdentityOAuth2Exception; + + void persistNewToken(OAuthTokenReqMessageContext tokenReqMessageContext, AccessTokenDO accessTokenBean, + String userStoreDomain, String clientId) throws IdentityOAuth2Exception; + + AccessTokenDO createAccessTokenBean(OAuthTokenReqMessageContext tokReqMsgCtx, OAuth2AccessTokenReqDTO tokenReq, + RefreshTokenValidationDataDO validationBean, String tokenType) throws IdentityOAuth2Exception; + + boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean, + String userStoreDomain) throws IdentityOAuth2Exception; + +} 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 4d6c1c264fe..65a6d9f022b 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 @@ -45,6 +45,7 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dto.ScopeDTO; import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; +import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth2.OAuth2ScopeService; import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; @@ -652,6 +653,29 @@ protected void unsetOrganizationUserResidentResolverService( } OAuth2ServiceComponentHolder.setOrganizationUserResidentResolverService(null); } + + @Reference( + name = "refreshtoken.grant.processor", + service = RefreshTokenGrantProcessor.class, + cardinality = ReferenceCardinality.OPTIONAL, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetRefreshTokenGrantProcessor" + ) + protected void setRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refreshTokenGrantProcessor) { + + if (log.isDebugEnabled()) { + log.debug("Setting refresh token grant processor."); + } + OAuth2ServiceComponentHolder.getInstance().setRefreshTokenGrantProcessor(refreshTokenGrantProcessor); + } + + protected void unsetRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refreshTokenGrantProcessor) { + + if (log.isDebugEnabled()) { + log.debug("Unset refresh token grant processor."); + } + OAuth2ServiceComponentHolder.getInstance().setRefreshTokenGrantProcessor(null); + } @Reference( name = "access.token.dao.service", 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 d0c96e5be87..ab0b17b1dec 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 @@ -27,6 +27,8 @@ import org.wso2.carbon.identity.event.services.IdentityEventService; import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl; import org.wso2.carbon.identity.oauth.dto.ScopeDTO; +import org.wso2.carbon.identity.oauth.tokenprocessor.DefaultRefreshTokenGrantProcessor; +import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth2.authz.validators.ResponseTypeRequestValidator; import org.wso2.carbon.identity.oauth2.bean.Scope; import org.wso2.carbon.identity.oauth2.client.authentication.OAuthClientAuthenticator; @@ -76,6 +78,7 @@ public class OAuth2ServiceComponentHolder { private ScopeClaimMappingDAO scopeClaimMappingDAO; private static List jwtRenewWithoutRevokeAllowedGrantTypes = new ArrayList<>(); private static ConsentServerConfigsManagementService consentServerConfigsManagementService; + private RefreshTokenGrantProcessor refreshTokenGrantProcessor; private OAuth2ServiceComponentHolder() { @@ -447,4 +450,15 @@ public static void setConsentServerConfigsManagementService(ConsentServerConfigs OAuth2ServiceComponentHolder.consentServerConfigsManagementService = consentServerConfigsManagementService; } + + public RefreshTokenGrantProcessor getRefreshTokenGrantProcessor() { + if (refreshTokenGrantProcessor == null) { + refreshTokenGrantProcessor = new DefaultRefreshTokenGrantProcessor(); + } + return refreshTokenGrantProcessor; + } + + public void setRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refreshTokenGrantProcessor) { + this.refreshTokenGrantProcessor = refreshTokenGrantProcessor; + } } 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 70d4d66be3c..02e0b205f0d 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 @@ -37,6 +37,7 @@ import org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthClientException; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; +import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.ResponseHeader; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; @@ -50,14 +51,11 @@ 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.openidconnect.OIDCClaimUtil; import java.sql.Timestamp; import java.util.Arrays; -import java.util.Date; import java.util.List; import java.util.Optional; -import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -83,10 +81,9 @@ public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) super.validateGrant(tokReqMsgCtx); OAuth2AccessTokenReqDTO tokenReq = tokReqMsgCtx.getOauth2AccessTokenReqDTO(); - RefreshTokenValidationDataDO validationBean = OAuthTokenPersistenceFactory.getInstance() - .getTokenManagementDAO().validateRefreshToken(tokenReq.getClientId(), tokenReq.getRefreshToken()); + RefreshTokenValidationDataDO validationBean = getRefreshTokenGrantProcessor() + .validateRefreshToken(tokReqMsgCtx); - validatePersistedAccessToken(validationBean, tokenReq.getClientId()); validateRefreshTokenInRequest(tokenReq, validationBean); validateTokenBindingReference(tokenReq, validationBean); @@ -114,7 +111,10 @@ public OAuth2AccessTokenRespDTO issue(OAuthTokenReqMessageContext tokReqMsgCtx) return handleError(OAuth2ErrorCodes.INVALID_GRANT, "Refresh token is expired.", tokenReq); } - AccessTokenDO accessTokenBean = createAccessTokenBean(tokReqMsgCtx, tokenReq, validationBean); + AccessTokenDO accessTokenBean = getRefreshTokenGrantProcessor() + .createAccessTokenBean(tokReqMsgCtx, tokenReq, validationBean, getTokenType()); + // sets accessToken, refreshToken and validity data + setTokenData(accessTokenBean, tokReqMsgCtx, validationBean, tokenReq, accessTokenBean.getIssuedTime()); persistNewToken(tokReqMsgCtx, accessTokenBean, tokenReq.getClientId()); if (log.isDebugEnabled()) { log.debug("Persisted an access token for the refresh token, " + @@ -196,40 +196,13 @@ private boolean validateRefreshTokenInRequest(OAuth2AccessTokenReqDTO tokenReq, throws IdentityOAuth2Exception { validateRefreshTokenStatus(validationBean, tokenReq.getClientId()); - if (isLatestRefreshToken(tokenReq, validationBean)) { + if (getRefreshTokenGrantProcessor().isLatestRefreshToken(tokenReq, + validationBean, getUserStoreDomain(validationBean.getAuthorizedUser()))) { return true; } else { - throw new IdentityOAuth2Exception("Invalid refresh token value in the request"); - } - } - - private boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, - RefreshTokenValidationDataDO validationBean) - throws IdentityOAuth2Exception { - - if (log.isDebugEnabled()) { - log.debug("Evaluating refresh token. Token value: " + tokenReq.getRefreshToken() + ", Token state: " + - validationBean.getRefreshTokenState()); - } - if (!OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE.equals(validationBean.getRefreshTokenState())) { - // if refresh token is not in active state, check whether there is an access token - // issued with the same refresh token - List accessTokenBeans = getAccessTokenBeans(tokenReq, validationBean, - getUserStoreDomain(validationBean.getAuthorizedUser())); - for (AccessTokenDO token : accessTokenBeans) { - if (tokenReq.getRefreshToken().equals(token.getRefreshToken()) - && (OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE.equals(token.getTokenState()) - || OAuthConstants.TokenStates.TOKEN_STATE_EXPIRED.equals(token.getTokenState()))) { - return true; - } - } - if (log.isDebugEnabled()) { - log.debug("Refresh token: " + tokenReq.getRefreshToken() + " is not the latest"); - } removeIfCached(tokenReq, validationBean); - return false; + throw new IdentityOAuth2Exception("Invalid refresh token value in the request"); } - return true; } private void removeIfCached(OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean) @@ -250,25 +223,6 @@ private void removeIfCached(OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValida } } - private List getAccessTokenBeans(OAuth2AccessTokenReqDTO tokenReq, - RefreshTokenValidationDataDO validationBean, - String userStoreDomain) throws IdentityOAuth2Exception { - - List accessTokenBeans = OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() - .getLatestAccessTokens(tokenReq.getClientId(), validationBean.getAuthorizedUser(), userStoreDomain, - OAuth2Util.buildScopeString(validationBean.getScope()), - validationBean.getTokenBindingReference(), true, LAST_ACCESS_TOKEN_RETRIEVAL_LIMIT); - if (accessTokenBeans == null || accessTokenBeans.isEmpty()) { - if (log.isDebugEnabled()) { - log.debug("No previous access tokens found. User: " + validationBean.getAuthorizedUser() + - ", client: " + tokenReq.getClientId() + ", scope: " + - OAuth2Util.buildScopeString(validationBean.getScope())); - } - throw new IdentityOAuth2Exception("No previous access tokens found"); - } - return accessTokenBeans; - } - private boolean validateRefreshTokenStatus(RefreshTokenValidationDataDO validationBean, String clientId) throws IdentityOAuth2Exception { @@ -284,18 +238,6 @@ private boolean validateRefreshTokenStatus(RefreshTokenValidationDataDO validati return true; } - private boolean validatePersistedAccessToken(RefreshTokenValidationDataDO validationBean, String clientId) - throws IdentityOAuth2Exception { - - if (validationBean.getAccessToken() == null) { - if (log.isDebugEnabled()) { - log.debug("Invalid Refresh Token provided for Client with " + - "Client Id : " + clientId); - } - throw new IdentityOAuth2Exception("Persisted access token data not found"); - } - return true; - } private OAuth2AccessTokenRespDTO buildTokenResponse(OAuthTokenReqMessageContext tokReqMsgCtx, AccessTokenDO accessTokenBean) { @@ -328,11 +270,8 @@ private void persistNewToken(OAuthTokenReqMessageContext tokReqMsgCtx, AccessTok log.debug("Previous access token (hashed): " + DigestUtils.sha256Hex(oldAccessToken.getAccessToken())); } } - // set the previous access token state to "INACTIVE" and store new access token in single db connection - OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() - .invalidateAndCreateNewAccessToken(oldAccessToken.getTokenId(), - OAuthConstants.TokenStates.TOKEN_STATE_INACTIVE, clientId, - UUID.randomUUID().toString(), accessTokenBean, userStoreDomain, oldAccessToken.getGrantType()); + getRefreshTokenGrantProcessor().persistNewToken(tokReqMsgCtx, + accessTokenBean, userStoreDomain, clientId); updateCacheIfEnabled(tokReqMsgCtx, accessTokenBean, clientId, oldAccessToken); } @@ -476,8 +415,11 @@ private void clearCache(String clientId, String authorizedUserId, String[] scope OAuthCache.getInstance().clearCacheEntry(oauthCacheKey, tenantDomain); // Remove the old access token from the AccessTokenCache - OAuthCacheKey accessTokenCacheKey = new OAuthCacheKey(accessToken); - OAuthCache.getInstance().clearCacheEntry(accessTokenCacheKey, tenantDomain); + if (accessToken != null) { + OAuthCacheKey accessTokenCacheKey = new OAuthCacheKey(accessToken); + OAuthCache.getInstance().clearCacheEntry(accessTokenCacheKey, tenantDomain); + } + } private boolean isRefreshTokenExpired(RefreshTokenValidationDataDO validationBean) { @@ -559,54 +501,6 @@ private void modifyTokensIfUsernameAssertionEnabled(AccessTokenDO accessTokenDO, } } - private AccessTokenDO createAccessTokenBean(OAuthTokenReqMessageContext tokReqMsgCtx, - OAuth2AccessTokenReqDTO tokenReq, - RefreshTokenValidationDataDO validationBean) - throws IdentityOAuth2Exception { - - Timestamp timestamp = new Timestamp(new Date().getTime()); - String tokenId = UUID.randomUUID().toString(); - - AccessTokenDO accessTokenDO = new AccessTokenDO(); - accessTokenDO.setConsumerKey(tokenReq.getClientId()); - accessTokenDO.setAuthzUser(tokReqMsgCtx.getAuthorizedUser()); - accessTokenDO.setScope(tokReqMsgCtx.getScope()); - accessTokenDO.setTokenType(getTokenType()); - accessTokenDO.setTokenState(OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE); - accessTokenDO.setTokenId(tokenId); - accessTokenDO.setGrantType(tokenReq.getGrantType()); - accessTokenDO.setIssuedTime(timestamp); - accessTokenDO.setTokenBinding(tokReqMsgCtx.getTokenBinding()); - - if (OAuth2ServiceComponentHolder.isConsentedTokenColumnEnabled()) { - String previousGrantType = validationBean.getGrantType(); - // Check if the previous grant type is consent refresh token type or not. - if (!StringUtils.equals(OAuthConstants.GrantTypes.REFRESH_TOKEN, previousGrantType)) { - // If the previous grant type is not a refresh token, then check if it's a consent token or not. - if (OIDCClaimUtil.isConsentBasedClaimFilteringApplicable(previousGrantType)) { - accessTokenDO.setIsConsentedToken(true); - } - } else { - /* When previousGrantType == refresh_token, we need to check whether the original grant type - is consented or not. */ - AccessTokenDO accessTokenDOFromTokenIdentifier = OAuth2Util.getAccessTokenDOFromTokenIdentifier( - validationBean.getAccessToken(), false); - accessTokenDO.setIsConsentedToken(accessTokenDOFromTokenIdentifier.isConsentedToken()); - } - - if (accessTokenDO.isConsentedToken()) { - tokReqMsgCtx.setConsentedToken(true); - } - } - if (tokReqMsgCtx.getOauth2AccessTokenReqDTO().getAccessTokenExtendedAttributes() != null) { - accessTokenDO.setAccessTokenExtendedAttributes( - tokReqMsgCtx.getOauth2AccessTokenReqDTO().getAccessTokenExtendedAttributes()); - } - // sets accessToken, refreshToken and validity data - setTokenData(accessTokenDO, tokReqMsgCtx, validationBean, tokenReq, timestamp); - return accessTokenDO; - } - private long getValidityPeriodInMillis(OAuthTokenReqMessageContext tokReqMsgCtx, OAuthAppDO oAuthAppDO) { long validityPeriodInMillis; @@ -686,6 +580,9 @@ private static void addUserAttributesToCache(AccessTokenDO accessTokenBean, RefreshTokenValidationDataDO oldAccessToken = (RefreshTokenValidationDataDO) msgCtx.getProperty(PREV_ACCESS_TOKEN); + if (oldAccessToken.getAccessToken() == null) { + return; + } AuthorizationGrantCacheKey oldAuthorizationGrantCacheKey = new AuthorizationGrantCacheKey(oldAccessToken .getAccessToken()); if (log.isDebugEnabled()) { @@ -770,4 +667,8 @@ private void validateTokenBindingReference(OAuth2AccessTokenReqDTO tokenReqDTO, throw new IdentityOAuth2Exception("Invalid token binding value is present in the request."); } } + + private RefreshTokenGrantProcessor getRefreshTokenGrantProcessor() { + return OAuth2ServiceComponentHolder.getInstance().getRefreshTokenGrantProcessor(); + } } From 462639af6de46db8485152045207d1afb90dae3a Mon Sep 17 00:00:00 2001 From: Chamila Adhikarinayake Date: Tue, 11 Apr 2023 09:04:44 +0530 Subject: [PATCH 03/13] Check NPE --- .../oauth2/token/handlers/grant/RefreshGrantHandler.java | 8 +++++--- .../openidconnect/DefaultOIDCClaimsCallbackHandler.java | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) 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 02e0b205f0d..712e502da34 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 @@ -296,9 +296,11 @@ private void updateCacheIfEnabled(OAuthTokenReqMessageContext tokReqMsgCtx, Acce OAuthCache.getInstance().clearCacheEntry(oauthCacheKey, accessTokenBean.getAuthzUser().getTenantDomain()); // Remove old access token from the AccessTokenCache - OAuthCacheKey accessTokenCacheKey = new OAuthCacheKey(oldAccessToken.getAccessToken()); - OAuthCache.getInstance().clearCacheEntry(accessTokenCacheKey, - oldAccessToken.getAuthorizedUser().getTenantDomain()); + if (oldAccessToken.getAccessToken() != null) { + OAuthCacheKey accessTokenCacheKey = new OAuthCacheKey(oldAccessToken.getAccessToken()); + OAuthCache.getInstance().clearCacheEntry(accessTokenCacheKey, + oldAccessToken.getAuthorizedUser().getTenantDomain()); + } AccessTokenDO tokenToCache = AccessTokenDO.clone(accessTokenBean); OauthTokenIssuer oauthTokenIssuer; try { diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/DefaultOIDCClaimsCallbackHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/DefaultOIDCClaimsCallbackHandler.java index a21217ddd69..f5ad60b3b77 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/DefaultOIDCClaimsCallbackHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/DefaultOIDCClaimsCallbackHandler.java @@ -686,6 +686,9 @@ private Map getUserClaimsInOidcDialect(Map oidcT */ private boolean isTokenHasCustomUserClaims(RefreshTokenValidationDataDO refreshTokenValidationDataDO) { + if (refreshTokenValidationDataDO.getAccessToken() == null) { + return false; + } AuthorizationGrantCacheKey cacheKey = new AuthorizationGrantCacheKey( refreshTokenValidationDataDO.getAccessToken()); AuthorizationGrantCacheEntry cacheEntry = AuthorizationGrantCache.getInstance() From fec216da9078b7ab2c4ec865e12177847800dbdb Mon Sep 17 00:00:00 2001 From: Chamila Adhikarinayake Date: Mon, 3 Apr 2023 18:03:25 +0530 Subject: [PATCH 04/13] Add abstraction dao layer for token revoke flow. --- .../DefaultOAuth2RevocationProcessor.java | 70 ++++++++++++++++ .../OAuth2RevocationProcessor.java | 82 +++++++++++++++++++ .../carbon/identity/oauth2/OAuth2Service.java | 26 +++--- .../internal/OAuth2ServiceComponent.java | 28 ++++++- .../OAuth2ServiceComponentHolder.java | 14 ++++ 5 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java new file mode 100644 index 00000000000..fce3f42bcb6 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (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.oauth.tokenprocessor; + +import org.apache.commons.lang.StringUtils; +import org.apache.oltu.oauth2.common.message.types.GrantType; +import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; +import org.wso2.carbon.identity.oauth2.dto.OAuthRevocationRequestDTO; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.RefreshTokenValidationDataDO; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; + +/** + * Handles oauth2 token revocation when persistence layer exists. + */ + +public class DefaultOAuth2RevocationProcessor implements OAuth2RevocationProcessor { + + @Override + public void revokeAccessToken(OAuthRevocationRequestDTO revokeRequestDTO, AccessTokenDO accessTokenDO) + throws IdentityOAuth2Exception, UserIdNotFoundException { + OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() + .revokeAccessTokens(new String[] { accessTokenDO.getAccessToken() }); + + } + + @Override + public void revokeRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO, + RefreshTokenValidationDataDO refreshTokenDO) throws IdentityOAuth2Exception { + OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() + .revokeAccessTokens(new String[] { refreshTokenDO.getAccessToken() }); + } + + @Override + public RefreshTokenValidationDataDO getRevocableRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO) + throws IdentityOAuth2Exception { + return OAuthTokenPersistenceFactory.getInstance().getTokenManagementDAO() + .validateRefreshToken(revokeRequestDTO.getConsumerKey(), revokeRequestDTO.getToken()); + } + + @Override + public AccessTokenDO getRevocableAccessToken(OAuthRevocationRequestDTO revokeRequestDTO) + throws IdentityOAuth2Exception { + return OAuth2Util.findAccessToken(revokeRequestDTO.getToken(), true); + } + + @Override + public boolean isRefreshTokenType(OAuthRevocationRequestDTO revokeRequestDTO) { + return StringUtils.equals(GrantType.REFRESH_TOKEN.toString(), revokeRequestDTO.getTokenType()); + } + +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java new file mode 100644 index 00000000000..7fd0aca4ded --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (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.oauth.tokenprocessor; + +import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dto.OAuthRevocationRequestDTO; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.RefreshTokenValidationDataDO; + +/** + * Abstraction layer between OAuth2Service and persistence layer to handle + * revocation logic during token persistence and non-persistence scenarios. + */ + +public interface OAuth2RevocationProcessor { + + /** + * Revoke access token + * + * @param revokeRequestDTO Metadata containing revoke token request. + * @param accessTokenDO + * @throws IdentityOAuth2Exception + * @throws UserIdNotFoundException + */ + public void revokeAccessToken(OAuthRevocationRequestDTO revokeRequestDTO, AccessTokenDO accessTokenDO) + throws IdentityOAuth2Exception, UserIdNotFoundException; + + /** + * Revoke refresh token + * + * @param revokeRequestDTO Metadata containing revoke token request. + * @param refreshTokenDO + * @throws IdentityOAuth2Exception + */ + public void revokeRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO, + RefreshTokenValidationDataDO refreshTokenDO) throws IdentityOAuth2Exception; + + /** + * Validate and return the the refresh token metadata. + * + * @param revokeRequestDTO Metadata containing revoke token request. + * @return RefreshTokenValidationDataDO + * @throws IdentityOAuth2Exception + */ + public RefreshTokenValidationDataDO getRevocableRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO) + throws IdentityOAuth2Exception; + + /** + * Validate and return the the aceess token metadata. + * + * @param revokeRequestDTO Metadata containing revoke token request. + * @param refreshTokenDO + * @throws IdentityOAuth2Exception + */ + + public AccessTokenDO getRevocableAccessToken(OAuthRevocationRequestDTO revokeRequestDTO) + throws IdentityOAuth2Exception; + + /** + * Check whether revoke request is related to access token or revoke token + * @param revokeRequestDTO Metadata containing revoke token request. + * @return boolean whether it is a refresh token request or not + */ + public boolean isRefreshTokenType(OAuthRevocationRequestDTO revokeRequestDTO); +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java index 1a9c4a50593..08da48c148d 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java @@ -37,12 +37,12 @@ import org.wso2.carbon.identity.oauth.dto.OAuthErrorDTO; import org.wso2.carbon.identity.oauth.event.OAuthEventInterceptor; import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; +import org.wso2.carbon.identity.oauth.tokenprocessor.OAuth2RevocationProcessor; import org.wso2.carbon.identity.oauth2.authz.AuthorizationHandlerManager; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.authz.validators.DefaultResponseTypeRequestValidator; import org.wso2.carbon.identity.oauth2.authz.validators.ResponseTypeRequestValidator; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; -import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; @@ -515,13 +515,12 @@ public OAuthRevocationResponseDTO revokeTokenByOAuthClient(OAuthRevocationReques StringUtils.isNotEmpty(revokeRequestDTO.getToken())) { boolean refreshTokenFirst = false; - if (isRefreshTokenType(revokeRequestDTO)) { + if (getRevocationProcessor().isRefreshTokenType(revokeRequestDTO)) { refreshTokenFirst = true; } if (refreshTokenFirst) { - refreshTokenDO = OAuthTokenPersistenceFactory.getInstance().getTokenManagementDAO() - .validateRefreshToken(revokeRequestDTO.getConsumerKey(), revokeRequestDTO.getToken()); + refreshTokenDO = getRevocationProcessor().getRevocableRefreshToken(revokeRequestDTO); if (refreshTokenDO == null || StringUtils.isEmpty(refreshTokenDO.getRefreshTokenState()) || @@ -530,19 +529,16 @@ public OAuthRevocationResponseDTO revokeTokenByOAuthClient(OAuthRevocationReques OAuthConstants.TokenStates.TOKEN_STATE_EXPIRED .equals(refreshTokenDO.getRefreshTokenState()))) { - accessTokenDO = OAuthTokenPersistenceFactory.getInstance() - .getAccessTokenDAO().getAccessToken(revokeRequestDTO.getToken(), true); + accessTokenDO = getRevocationProcessor().getRevocableAccessToken(revokeRequestDTO); refreshTokenDO = null; } } else { - accessTokenDO = OAuth2Util.findAccessToken(revokeRequestDTO.getToken(), true); + accessTokenDO = getRevocationProcessor().getRevocableAccessToken(revokeRequestDTO); if (accessTokenDO == null) { - refreshTokenDO = OAuthTokenPersistenceFactory.getInstance() - .getTokenManagementDAO().validateRefreshToken(revokeRequestDTO.getConsumerKey(), - revokeRequestDTO.getToken()); + refreshTokenDO = getRevocationProcessor().getRevocableRefreshToken(revokeRequestDTO); if (refreshTokenDO == null || StringUtils.isEmpty(refreshTokenDO.getRefreshTokenState()) || @@ -614,8 +610,7 @@ public OAuthRevocationResponseDTO revokeTokenByOAuthClient(OAuthRevocationReques OAuth2Util.buildScopeString(refreshTokenDO.getScope())); OAuthUtil.clearOAuthCache(revokeRequestDTO.getConsumerKey(), refreshTokenDO.getAuthorizedUser()); OAuthUtil.clearOAuthCache(refreshTokenDO.getAccessToken()); - OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() - .revokeAccessTokens(new String[] { refreshTokenDO.getAccessToken() }); + getRevocationProcessor().revokeRefreshToken(revokeRequestDTO, refreshTokenDO); addRevokeResponseHeaders(revokeResponseDTO, refreshTokenDO.getAccessToken(), revokeRequestDTO.getToken(), @@ -661,8 +656,7 @@ public OAuthRevocationResponseDTO revokeTokenByOAuthClient(OAuthRevocationReques String userId = accessTokenDO.getAuthzUser().getUserId(); synchronized ((revokeRequestDTO.getConsumerKey() + ":" + userId + ":" + scope + ":" + tokenBindingReference).intern()) { - OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() - .revokeAccessTokens(new String[]{accessTokenDO.getAccessToken()}); + getRevocationProcessor().revokeAccessToken(revokeRequestDTO, accessTokenDO); } addRevokeResponseHeaders(revokeResponseDTO, revokeRequestDTO.getToken(), @@ -743,6 +737,10 @@ public OAuthRevocationResponseDTO revokeTokenByOAuthClient(OAuthRevocationReques } } + private OAuth2RevocationProcessor getRevocationProcessor() { + return OAuth2ServiceComponentHolder.getInstance().getRevocationProcessor(); + } + private boolean isRefreshTokenType(OAuthRevocationRequestDTO revokeRequestDTO) { return StringUtils.equals(GrantType.REFRESH_TOKEN.toString(), revokeRequestDTO.getTokenType()); } 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 65a6d9f022b..c0d3be195fc 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 @@ -45,6 +45,7 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dto.ScopeDTO; import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; +import org.wso2.carbon.identity.oauth.tokenprocessor.OAuth2RevocationProcessor; import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth2.OAuth2ScopeService; import org.wso2.carbon.identity.oauth2.OAuth2Service; @@ -653,7 +654,7 @@ protected void unsetOrganizationUserResidentResolverService( } OAuth2ServiceComponentHolder.setOrganizationUserResidentResolverService(null); } - + @Reference( name = "refreshtoken.grant.processor", service = RefreshTokenGrantProcessor.class, @@ -722,6 +723,31 @@ protected void unsetTokenMgtDAOService(TokenManagementDAO tokenManagementDAO) { } OAuthComponentServiceHolder.getInstance().setTokenManagementDAOService(null); } + + + @Reference( + name = "oauth2.revocation.processor", + service = OAuth2RevocationProcessor.class, + cardinality = ReferenceCardinality.OPTIONAL, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetOAuth2RevocationProcessor" + ) + protected void setOAuth2RevocationProcessor(OAuth2RevocationProcessor oAuth2RevocationProcessor) { + + if (log.isDebugEnabled()) { + log.debug("Setting Oauth2 revocation processor."); + } + OAuth2ServiceComponentHolder.getInstance().setRevocationProcessor(oAuth2RevocationProcessor); + } + + protected void unsetOAuth2RevocationProcessor(OAuth2RevocationProcessor oAuth2RevocationProcessor) { + + if (log.isDebugEnabled()) { + log.debug("Unset Oauth2 revocation processor."); + } + OAuth2ServiceComponentHolder.setOrganizationUserResidentResolverService(null); + } + private static void loadScopeConfigFile() { List listOIDCScopesClaims = new ArrayList<>(); 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 ab0b17b1dec..6aac59f05b7 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,8 @@ import org.wso2.carbon.identity.oauth.dto.ScopeDTO; import org.wso2.carbon.identity.oauth.tokenprocessor.DefaultRefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; +import org.wso2.carbon.identity.oauth.tokenprocessor.DefaultOAuth2RevocationProcessor; +import org.wso2.carbon.identity.oauth.tokenprocessor.OAuth2RevocationProcessor; import org.wso2.carbon.identity.oauth2.authz.validators.ResponseTypeRequestValidator; import org.wso2.carbon.identity.oauth2.bean.Scope; import org.wso2.carbon.identity.oauth2.client.authentication.OAuthClientAuthenticator; @@ -79,6 +81,7 @@ public class OAuth2ServiceComponentHolder { private static List jwtRenewWithoutRevokeAllowedGrantTypes = new ArrayList<>(); private static ConsentServerConfigsManagementService consentServerConfigsManagementService; private RefreshTokenGrantProcessor refreshTokenGrantProcessor; + private OAuth2RevocationProcessor revocationProcessor; private OAuth2ServiceComponentHolder() { @@ -461,4 +464,15 @@ public RefreshTokenGrantProcessor getRefreshTokenGrantProcessor() { public void setRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refreshTokenGrantProcessor) { this.refreshTokenGrantProcessor = refreshTokenGrantProcessor; } + + public OAuth2RevocationProcessor getRevocationProcessor() { + if (revocationProcessor == null) { + revocationProcessor = new DefaultOAuth2RevocationProcessor(); + } + return revocationProcessor; + } + + public void setRevocationProcessor(OAuth2RevocationProcessor revocationProcessor) { + this.revocationProcessor = revocationProcessor; + } } From 4603d7c6909cdd46dfb7bcf54c618b0f1c4306a5 Mon Sep 17 00:00:00 2001 From: Chamila Adhikarinayake Date: Tue, 11 Apr 2023 09:31:03 +0530 Subject: [PATCH 05/13] Fix NPE --- .../java/org/wso2/carbon/identity/oauth2/OAuth2Service.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java index 08da48c148d..0e356564424 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java @@ -609,7 +609,9 @@ public OAuthRevocationResponseDTO revokeTokenByOAuthClient(OAuthRevocationReques OAuthUtil.clearOAuthCache(revokeRequestDTO.getConsumerKey(), refreshTokenDO.getAuthorizedUser(), OAuth2Util.buildScopeString(refreshTokenDO.getScope())); OAuthUtil.clearOAuthCache(revokeRequestDTO.getConsumerKey(), refreshTokenDO.getAuthorizedUser()); - OAuthUtil.clearOAuthCache(refreshTokenDO.getAccessToken()); + if (refreshTokenDO.getAccessToken() != null) { + OAuthUtil.clearOAuthCache(refreshTokenDO.getAccessToken()); + } getRevocationProcessor().revokeRefreshToken(revokeRequestDTO, refreshTokenDO); addRevokeResponseHeaders(revokeResponseDTO, refreshTokenDO.getAccessToken(), From ad9f77823e9b8db6c194debd4260d59c4147d7be Mon Sep 17 00:00:00 2001 From: dushani Date: Thu, 8 Jun 2023 10:10:07 +0530 Subject: [PATCH 06/13] fix formatting. --- .../oauth2/internal/OAuth2ServiceComponentHolder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 7d6633eb211..b6fdfa83d07 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 @@ -27,10 +27,10 @@ import org.wso2.carbon.identity.event.services.IdentityEventService; import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl; import org.wso2.carbon.identity.oauth.dto.ScopeDTO; -import org.wso2.carbon.identity.oauth.tokenprocessor.DefaultRefreshTokenGrantProcessor; -import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth.tokenprocessor.DefaultOAuth2RevocationProcessor; +import org.wso2.carbon.identity.oauth.tokenprocessor.DefaultRefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth.tokenprocessor.OAuth2RevocationProcessor; +import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth2.authz.validators.ResponseTypeRequestValidator; import org.wso2.carbon.identity.oauth2.bean.Scope; import org.wso2.carbon.identity.oauth2.client.authentication.OAuthClientAuthenticator; From 0f686992579000c33d47c029c5a5bdff156f2d7e Mon Sep 17 00:00:00 2001 From: dushani Date: Thu, 8 Jun 2023 10:13:13 +0530 Subject: [PATCH 07/13] fix licensing. --- .../tokenprocessor/DefaultOAuth2RevocationProcessor.java | 4 ++-- .../tokenprocessor/DefaultRefreshTokenGrantProcessor.java | 4 ++-- .../oauth/tokenprocessor/OAuth2RevocationProcessor.java | 4 ++-- .../oauth/tokenprocessor/RefreshTokenGrantProcessor.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java index fce3f42bcb6..a678356c5c3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (https://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 diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java index 23de569c267..230af034b71 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (https://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 diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java index 7fd0aca4ded..5d244140adf 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (https://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 diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java index d2ddb30ede9..b437fc1930e 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (https://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 From 8b8b2d4964b2a8f4bf9537233c0b392c4a1d9699 Mon Sep 17 00:00:00 2001 From: dushani Date: Thu, 8 Jun 2023 10:28:24 +0530 Subject: [PATCH 08/13] fix formatting. --- .../internal/OAuthComponentServiceHolder.java | 20 ++++--- .../DefaultOAuth2RevocationProcessor.java | 17 +++--- .../DefaultRefreshTokenGrantProcessor.java | 14 +++-- .../OAuth2RevocationProcessor.java | 55 +++++++++---------- .../RefreshTokenGrantProcessor.java | 11 ++-- .../carbon/identity/oauth2/OAuth2Service.java | 1 + .../OAuth2ServiceComponentHolder.java | 24 ++++++++ .../handlers/grant/RefreshGrantHandler.java | 1 + 8 files changed, 86 insertions(+), 57 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/internal/OAuthComponentServiceHolder.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/internal/OAuthComponentServiceHolder.java index a3d9b43e505..46e325afa8d 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/internal/OAuthComponentServiceHolder.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/internal/OAuthComponentServiceHolder.java @@ -280,38 +280,42 @@ public List getAccessTokenResponseHandlers() { } /** - * Get AccessTokenDAO instance + * Get AccessTokenDAO instance. * - * @return AccessTokenDAO + * @return AccessTokenDAO {@link AccessTokenDAO} instance. */ public AccessTokenDAO getAccessTokenDAOService() { + return accessTokenDAOService; } /** - * Set AccessTokenDAO instance + * Set AccessTokenDAO instance. * - * @param accessTokenDAOService + * @param accessTokenDAOService {@link AccessTokenDAO} instance. */ public void setAccessTokenDAOService(AccessTokenDAO accessTokenDAOService) { + this.accessTokenDAOService = accessTokenDAOService; } /** - * Get TokenManagementDAO instance + * Get TokenManagementDAO instance. * - * @return + * @return TokenManagementDAO {@link TokenManagementDAO} instance. */ public TokenManagementDAO getTokenManagementDAOService() { + return tokenManagementDAOService; } /** - * Set TokenManagementDAO instance + * Set TokenManagementDAO instance. * - * @param tokenManagementDAOService + * @param tokenManagementDAOService {@link TokenManagementDAO} instance. */ public void setTokenManagementDAOService(TokenManagementDAO tokenManagementDAOService) { + this.tokenManagementDAOService = tokenManagementDAOService; } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java index a678356c5c3..09956f4e59d 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultOAuth2RevocationProcessor.java @@ -20,7 +20,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.oltu.oauth2.common.message.types.GrantType; -import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; import org.wso2.carbon.identity.oauth2.dto.OAuthRevocationRequestDTO; @@ -31,27 +30,28 @@ /** * Handles oauth2 token revocation when persistence layer exists. */ - public class DefaultOAuth2RevocationProcessor implements OAuth2RevocationProcessor { @Override public void revokeAccessToken(OAuthRevocationRequestDTO revokeRequestDTO, AccessTokenDO accessTokenDO) - throws IdentityOAuth2Exception, UserIdNotFoundException { - OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() - .revokeAccessTokens(new String[] { accessTokenDO.getAccessToken() }); + throws IdentityOAuth2Exception { + OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() + .revokeAccessTokens(new String[]{accessTokenDO.getAccessToken()}); } @Override public void revokeRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO, - RefreshTokenValidationDataDO refreshTokenDO) throws IdentityOAuth2Exception { + RefreshTokenValidationDataDO refreshTokenDO) throws IdentityOAuth2Exception { + OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() - .revokeAccessTokens(new String[] { refreshTokenDO.getAccessToken() }); + .revokeAccessTokens(new String[]{refreshTokenDO.getAccessToken()}); } @Override public RefreshTokenValidationDataDO getRevocableRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO) throws IdentityOAuth2Exception { + return OAuthTokenPersistenceFactory.getInstance().getTokenManagementDAO() .validateRefreshToken(revokeRequestDTO.getConsumerKey(), revokeRequestDTO.getToken()); } @@ -59,12 +59,13 @@ public RefreshTokenValidationDataDO getRevocableRefreshToken(OAuthRevocationRequ @Override public AccessTokenDO getRevocableAccessToken(OAuthRevocationRequestDTO revokeRequestDTO) throws IdentityOAuth2Exception { + return OAuth2Util.findAccessToken(revokeRequestDTO.getToken(), true); } @Override public boolean isRefreshTokenType(OAuthRevocationRequestDTO revokeRequestDTO) { + return StringUtils.equals(GrantType.REFRESH_TOKEN.toString(), revokeRequestDTO.getTokenType()); } - } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java index 230af034b71..01a2a9ced08 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java @@ -43,7 +43,6 @@ /** * Default implementation of @RefreshTokenProcessor responsible for handling refresh token persistence logic. */ - public class DefaultRefreshTokenGrantProcessor implements RefreshTokenGrantProcessor { private static final Log log = LogFactory.getLog(DefaultRefreshTokenGrantProcessor.class); @@ -53,6 +52,7 @@ public class DefaultRefreshTokenGrantProcessor implements RefreshTokenGrantProce @Override public RefreshTokenValidationDataDO validateRefreshToken(OAuthTokenReqMessageContext tokenReqMessageContext) throws IdentityOAuth2Exception { + OAuth2AccessTokenReqDTO tokenReq = tokenReqMessageContext.getOauth2AccessTokenReqDTO(); RefreshTokenValidationDataDO validationBean = OAuthTokenPersistenceFactory.getInstance().getTokenManagementDAO() .validateRefreshToken(tokenReq.getClientId(), tokenReq.getRefreshToken()); @@ -62,7 +62,7 @@ public RefreshTokenValidationDataDO validateRefreshToken(OAuthTokenReqMessageCon @Override public void persistNewToken(OAuthTokenReqMessageContext tokenReqMessageContext, AccessTokenDO accessTokenBean, - String userStoreDomain, String clientId) throws IdentityOAuth2Exception { + String userStoreDomain, String clientId) throws IdentityOAuth2Exception { RefreshTokenValidationDataDO oldAccessToken = (RefreshTokenValidationDataDO) tokenReqMessageContext.getProperty(PREV_ACCESS_TOKEN); @@ -80,7 +80,8 @@ public void persistNewToken(OAuthTokenReqMessageContext tokenReqMessageContext, @Override public AccessTokenDO createAccessTokenBean(OAuthTokenReqMessageContext tokReqMsgCtx, - OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean, String tokenType) + OAuth2AccessTokenReqDTO tokenReq, + RefreshTokenValidationDataDO validationBean, String tokenType) throws IdentityOAuth2Exception { Timestamp timestamp = new Timestamp(new Date().getTime()); @@ -117,7 +118,6 @@ public AccessTokenDO createAccessTokenBean(OAuthTokenReqMessageContext tokReqMsg tokReqMsgCtx.setConsentedToken(true); } } - return accessTokenDO; } @@ -135,7 +135,8 @@ private boolean validatePersistedAccessToken(RefreshTokenValidationDataDO valida @Override public boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean, - String userStoreDomain) throws IdentityOAuth2Exception { + String userStoreDomain) throws IdentityOAuth2Exception { + if (log.isDebugEnabled()) { log.debug("Evaluating refresh token. Token value: " + tokenReq.getRefreshToken() + ", Token state: " + validationBean.getRefreshTokenState()); @@ -160,7 +161,8 @@ public boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTok } private List getAccessTokenBeans(OAuth2AccessTokenReqDTO tokenReq, - RefreshTokenValidationDataDO validationBean, String userStoreDomain) throws IdentityOAuth2Exception { + RefreshTokenValidationDataDO validationBean, String userStoreDomain) + throws IdentityOAuth2Exception { List accessTokenBeans = OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO() .getLatestAccessTokens(tokenReq.getClientId(), validationBean.getAuthorizedUser(), userStoreDomain, diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java index 5d244140adf..ff901cbd47c 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/OAuth2RevocationProcessor.java @@ -28,55 +28,54 @@ * Abstraction layer between OAuth2Service and persistence layer to handle * revocation logic during token persistence and non-persistence scenarios. */ - public interface OAuth2RevocationProcessor { /** - * Revoke access token - * + * Revoke access token. + * * @param revokeRequestDTO Metadata containing revoke token request. - * @param accessTokenDO - * @throws IdentityOAuth2Exception - * @throws UserIdNotFoundException + * @param accessTokenDO {@link AccessTokenDO} instance. + * @throws IdentityOAuth2Exception If an error occurs while revoking the access token. + * @throws UserIdNotFoundException If the user id is not found. */ - public void revokeAccessToken(OAuthRevocationRequestDTO revokeRequestDTO, AccessTokenDO accessTokenDO) + void revokeAccessToken(OAuthRevocationRequestDTO revokeRequestDTO, AccessTokenDO accessTokenDO) throws IdentityOAuth2Exception, UserIdNotFoundException; /** - * Revoke refresh token - * + * Revoke refresh token. + * * @param revokeRequestDTO Metadata containing revoke token request. - * @param refreshTokenDO - * @throws IdentityOAuth2Exception + * @param refreshTokenDO {@link RefreshTokenValidationDataDO} instance. + * @throws IdentityOAuth2Exception If an error occurs while revoking the refresh token. */ - public void revokeRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO, - RefreshTokenValidationDataDO refreshTokenDO) throws IdentityOAuth2Exception; + void revokeRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO, + RefreshTokenValidationDataDO refreshTokenDO) throws IdentityOAuth2Exception; /** - * Validate and return the the refresh token metadata. - * - * @param revokeRequestDTO Metadata containing revoke token request. - * @return RefreshTokenValidationDataDO - * @throws IdentityOAuth2Exception + * Validate and return the refresh token metadata. + * + * @param revokeRequestDTO Metadata containing revoke token request. + * @return RefreshTokenValidationDataDO {@link RefreshTokenValidationDataDO} instance. + * @throws IdentityOAuth2Exception If an error occurs while validating the refresh token. */ - public RefreshTokenValidationDataDO getRevocableRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO) + RefreshTokenValidationDataDO getRevocableRefreshToken(OAuthRevocationRequestDTO revokeRequestDTO) throws IdentityOAuth2Exception; /** - * Validate and return the the aceess token metadata. - * + * Validate and return the access token metadata. + * * @param revokeRequestDTO Metadata containing revoke token request. - * @param refreshTokenDO - * @throws IdentityOAuth2Exception + * @return AccessTokenDO {@link AccessTokenDO} instance. + * @throws IdentityOAuth2Exception If an error occurs while validating the access token. */ - - public AccessTokenDO getRevocableAccessToken(OAuthRevocationRequestDTO revokeRequestDTO) + AccessTokenDO getRevocableAccessToken(OAuthRevocationRequestDTO revokeRequestDTO) throws IdentityOAuth2Exception; - + /** - * Check whether revoke request is related to access token or revoke token + * Check whether revoke request is related to access token or revoke token. + * * @param revokeRequestDTO Metadata containing revoke token request. * @return boolean whether it is a refresh token request or not */ - public boolean isRefreshTokenType(OAuthRevocationRequestDTO revokeRequestDTO); + boolean isRefreshTokenType(OAuthRevocationRequestDTO revokeRequestDTO); } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java index b437fc1930e..f6ad537bfe2 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java @@ -25,23 +25,20 @@ import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; /** - * * Intermediate processor for handling refresh token persistence logic. - * */ - public interface RefreshTokenGrantProcessor { RefreshTokenValidationDataDO validateRefreshToken(OAuthTokenReqMessageContext tokenReqMessageContext) throws IdentityOAuth2Exception; void persistNewToken(OAuthTokenReqMessageContext tokenReqMessageContext, AccessTokenDO accessTokenBean, - String userStoreDomain, String clientId) throws IdentityOAuth2Exception; + String userStoreDomain, String clientId) throws IdentityOAuth2Exception; AccessTokenDO createAccessTokenBean(OAuthTokenReqMessageContext tokReqMsgCtx, OAuth2AccessTokenReqDTO tokenReq, - RefreshTokenValidationDataDO validationBean, String tokenType) throws IdentityOAuth2Exception; + RefreshTokenValidationDataDO validationBean, String tokenType) + throws IdentityOAuth2Exception; boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean, - String userStoreDomain) throws IdentityOAuth2Exception; - + String userStoreDomain) throws IdentityOAuth2Exception; } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java index 0e356564424..dc31bdd82ef 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java @@ -740,6 +740,7 @@ public OAuthRevocationResponseDTO revokeTokenByOAuthClient(OAuthRevocationReques } private OAuth2RevocationProcessor getRevocationProcessor() { + return OAuth2ServiceComponentHolder.getInstance().getRevocationProcessor(); } 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 b6fdfa83d07..cec835f3bb3 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 @@ -463,25 +463,49 @@ public static void setConsentServerConfigsManagementService(ConsentServerConfigs OAuth2ServiceComponentHolder.consentServerConfigsManagementService = consentServerConfigsManagementService; } + /** + * Get Refresh Token Grant Processor. + * + * @return RefreshTokenGrantProcessor Refresh Token Grant Processor. + */ public RefreshTokenGrantProcessor getRefreshTokenGrantProcessor() { + if (refreshTokenGrantProcessor == null) { refreshTokenGrantProcessor = new DefaultRefreshTokenGrantProcessor(); } return refreshTokenGrantProcessor; } + /** + * Set Refresh Token Grant Processor. + * + * @param refreshTokenGrantProcessor Refresh Token Grant Processor. + */ public void setRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refreshTokenGrantProcessor) { + this.refreshTokenGrantProcessor = refreshTokenGrantProcessor; } + /** + * Get Revocation Processor. + * + * @return Revocation Processor. + */ public OAuth2RevocationProcessor getRevocationProcessor() { + if (revocationProcessor == null) { revocationProcessor = new DefaultOAuth2RevocationProcessor(); } return revocationProcessor; } + /** + * Set Revocation Processor. + * + * @param revocationProcessor Revocation Processor. + */ public void setRevocationProcessor(OAuth2RevocationProcessor revocationProcessor) { + this.revocationProcessor = revocationProcessor; } 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 712e502da34..f063ffbe817 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 @@ -671,6 +671,7 @@ private void validateTokenBindingReference(OAuth2AccessTokenReqDTO tokenReqDTO, } private RefreshTokenGrantProcessor getRefreshTokenGrantProcessor() { + return OAuth2ServiceComponentHolder.getInstance().getRefreshTokenGrantProcessor(); } } From a79ee2e471e71fa815a54c003704a15f56970f17 Mon Sep 17 00:00:00 2001 From: dushani Date: Wed, 6 Sep 2023 15:17:44 +0530 Subject: [PATCH 09/13] fix review comments for string concatenation and multi line comments. --- .../DefaultRefreshTokenGrantProcessor.java | 22 ++++++++++--------- .../internal/OAuth2ServiceComponent.java | 9 ++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java index 01a2a9ced08..c0501ad63f3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java @@ -68,7 +68,8 @@ public void persistNewToken(OAuthTokenReqMessageContext tokenReqMessageContext, (RefreshTokenValidationDataDO) tokenReqMessageContext.getProperty(PREV_ACCESS_TOKEN); if (log.isDebugEnabled()) { if (IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.ACCESS_TOKEN)) { - log.debug("Previous access token (hashed): " + DigestUtils.sha256Hex(oldAccessToken.getAccessToken())); + log.debug(String.format("Previous access token (hashed): %s", DigestUtils.sha256Hex( + oldAccessToken.getAccessToken()))); } } // set the previous access token state to "INACTIVE" and store new access token in single db connection @@ -126,7 +127,7 @@ private boolean validatePersistedAccessToken(RefreshTokenValidationDataDO valida if (validationBean.getAccessToken() == null) { if (log.isDebugEnabled()) { - log.debug("Invalid Refresh Token provided for Client with " + "Client Id : " + clientId); + log.debug(String.format("Invalid Refresh Token provided for Client with Client Id : %s", clientId)); } throw new IdentityOAuth2Exception("Persisted access token data not found"); } @@ -138,12 +139,13 @@ public boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTok String userStoreDomain) throws IdentityOAuth2Exception { if (log.isDebugEnabled()) { - log.debug("Evaluating refresh token. Token value: " + tokenReq.getRefreshToken() + ", Token state: " + - validationBean.getRefreshTokenState()); + log.debug(String.format("Evaluating refresh token. Token value: %s, Token state: %s", + tokenReq.getRefreshToken(), validationBean.getRefreshTokenState())); } if (!OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE.equals(validationBean.getRefreshTokenState())) { - // if refresh token is not in active state, check whether there is an access token - // issued with the same refresh token + /* if refresh token is not in active state, check whether there is an access token issued with the same + * refresh token. + */ List accessTokenBeans = getAccessTokenBeans(tokenReq, validationBean, userStoreDomain); for (AccessTokenDO token : accessTokenBeans) { if (tokenReq.getRefreshToken().equals(token.getRefreshToken()) @@ -153,7 +155,7 @@ public boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTok } } if (log.isDebugEnabled()) { - log.debug("Refresh token: " + tokenReq.getRefreshToken() + " is not the latest"); + log.debug(String.format("Refresh token: %s is not the latest", tokenReq.getRefreshToken())); } return false; } @@ -170,9 +172,9 @@ private List getAccessTokenBeans(OAuth2AccessTokenReqDTO tokenReq validationBean.getTokenBindingReference(), true, LAST_ACCESS_TOKEN_RETRIEVAL_LIMIT); if (accessTokenBeans == null || accessTokenBeans.isEmpty()) { if (log.isDebugEnabled()) { - log.debug("No previous access tokens found. User: " + validationBean.getAuthorizedUser() + ", client: " - + tokenReq.getClientId() + ", scope: " - + OAuth2Util.buildScopeString(validationBean.getScope())); + log.debug(String.format("No previous access tokens found. User: %s, client: %s, scope: %s", + validationBean.getAuthorizedUser(), tokenReq.getClientId(), + OAuth2Util.buildScopeString(validationBean.getScope()))); } throw new IdentityOAuth2Exception("No previous access tokens found"); } 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 dd752253bac..a51397acce8 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 @@ -708,7 +708,7 @@ protected void unsetRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refres protected void setAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { if (log.isDebugEnabled()) { - log.debug("Adding the Access Token DAO Service : " + accessTokenDAO.getClass().getName()); + log.debug(String.format("Adding the Access Token DAO Service : %s", accessTokenDAO.getClass().getName())); } OAuthComponentServiceHolder.getInstance().setAccessTokenDAOService(accessTokenDAO); } @@ -716,7 +716,7 @@ protected void setAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { protected void unsetAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { if (log.isDebugEnabled()) { - log.debug("Removing the Access Token DAO Service : " + accessTokenDAO.getClass().getName()); + log.debug(String.format("Removing the Access Token DAO Service : %s", accessTokenDAO.getClass().getName())); } OAuthComponentServiceHolder.getInstance().setAccessTokenDAOService(null); } @@ -731,7 +731,7 @@ protected void unsetAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { protected void setTokenMgtDAOService(TokenManagementDAO tokenMgtDAOService) { if (log.isDebugEnabled()) { - log.debug("Adding the Token Mgt DAO Service : " + tokenMgtDAOService.getClass().getName()); + log.debug(String.format("Adding the Token Mgt DAO Service : %s", tokenMgtDAOService.getClass().getName())); } OAuthComponentServiceHolder.getInstance().setTokenManagementDAOService(tokenMgtDAOService); } @@ -739,7 +739,8 @@ protected void setTokenMgtDAOService(TokenManagementDAO tokenMgtDAOService) { protected void unsetTokenMgtDAOService(TokenManagementDAO tokenManagementDAO) { if (log.isDebugEnabled()) { - log.debug("Removing the Token Mgt DAO Service : " + tokenManagementDAO.getClass().getName()); + log.debug(String.format("Removing the Token Mgt DAO Service : %s", + tokenManagementDAO.getClass().getName())); } OAuthComponentServiceHolder.getInstance().setTokenManagementDAOService(null); } From d3dfa2211975383ff488e13e4313809db84573cf Mon Sep 17 00:00:00 2001 From: dushani Date: Wed, 6 Sep 2023 17:12:46 +0530 Subject: [PATCH 10/13] fix adding missing java doc comments. --- .../RefreshTokenGrantProcessor.java | 35 ++++++++++++++++ .../carbon/identity/oauth2/OAuth2Service.java | 5 +++ .../internal/OAuth2ServiceComponent.java | 40 +++++++++++++++++++ .../handlers/grant/RefreshGrantHandler.java | 5 +++ 4 files changed, 85 insertions(+) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java index f6ad537bfe2..e7362b99138 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/RefreshTokenGrantProcessor.java @@ -29,16 +29,51 @@ */ public interface RefreshTokenGrantProcessor { + /** + * Validate the refresh token. + * + * @param tokenReqMessageContext Token request message context. + * @return Refresh token validation data. + * @throws IdentityOAuth2Exception If an error occurred while validating the refresh token. + */ RefreshTokenValidationDataDO validateRefreshToken(OAuthTokenReqMessageContext tokenReqMessageContext) throws IdentityOAuth2Exception; + /** + * Persist the new access token. + * + * @param tokenReqMessageContext Token request message context. + * @param accessTokenBean Access token data object. + * @param userStoreDomain User store domain. + * @param clientId Client ID. + * @throws IdentityOAuth2Exception If an error occurred while persisting the new access token. + */ void persistNewToken(OAuthTokenReqMessageContext tokenReqMessageContext, AccessTokenDO accessTokenBean, String userStoreDomain, String clientId) throws IdentityOAuth2Exception; + /** + * Create the access token bean. + * + * @param tokReqMsgCtx Token request message context. + * @param tokenReq Token request. + * @param validationBean Refresh token validation data. + * @param tokenType Token type. + * @return Access token data object. + * @throws IdentityOAuth2Exception If an error occurred while creating the access token bean. + */ AccessTokenDO createAccessTokenBean(OAuthTokenReqMessageContext tokReqMsgCtx, OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean, String tokenType) throws IdentityOAuth2Exception; + /** + * Check whether the refresh token is the latest refresh token. + * + * @param tokenReq Token request. + * @param validationBean Refresh token validation data. + * @param userStoreDomain User store domain. + * @return True if the refresh token is the latest refresh token. + * @throws IdentityOAuth2Exception If an error occurred while checking whether the refresh token is the latest + */ boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTokenValidationDataDO validationBean, String userStoreDomain) throws IdentityOAuth2Exception; } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java index dc31bdd82ef..a8453c155ec 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Service.java @@ -739,6 +739,11 @@ public OAuthRevocationResponseDTO revokeTokenByOAuthClient(OAuthRevocationReques } } + /** + * Get the revocation processor. + * + * @return OAuth2RevocationProcessor + */ private OAuth2RevocationProcessor getRevocationProcessor() { return OAuth2ServiceComponentHolder.getInstance().getRevocationProcessor(); 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 a51397acce8..f35189fbf63 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 @@ -675,6 +675,11 @@ protected void unsetOrganizationUserResidentResolverService( OAuth2ServiceComponentHolder.setOrganizationUserResidentResolverService(null); } + /** + * Sets the refresh token grant processor. + * + * @param refreshTokenGrantProcessor RefreshTokenGrantProcessor + */ @Reference( name = "refreshtoken.grant.processor", service = RefreshTokenGrantProcessor.class, @@ -690,6 +695,11 @@ protected void setRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refreshT OAuth2ServiceComponentHolder.getInstance().setRefreshTokenGrantProcessor(refreshTokenGrantProcessor); } + /** + * Unsets the refresh token grant processor. + * + * @param refreshTokenGrantProcessor RefreshTokenGrantProcessor + */ protected void unsetRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refreshTokenGrantProcessor) { if (log.isDebugEnabled()) { @@ -698,6 +708,11 @@ protected void unsetRefreshTokenGrantProcessor(RefreshTokenGrantProcessor refres OAuth2ServiceComponentHolder.getInstance().setRefreshTokenGrantProcessor(null); } + /** + * Sets the access token grant processor. + * + * @param accessTokenDAO AccessTokenDAO + */ @Reference( name = "access.token.dao.service", service = AccessTokenDAO.class, @@ -713,6 +728,11 @@ protected void setAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { OAuthComponentServiceHolder.getInstance().setAccessTokenDAOService(accessTokenDAO); } + /** + * Unsets the access token grant processor. + * + * @param accessTokenDAO AccessTokenDAO + */ protected void unsetAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { if (log.isDebugEnabled()) { @@ -721,6 +741,11 @@ protected void unsetAccessTokenDAOService(AccessTokenDAO accessTokenDAO) { OAuthComponentServiceHolder.getInstance().setAccessTokenDAOService(null); } + /** + * Sets the access token grant processor. + * + * @param tokenMgtDAOService TokenManagementDAO + */ @Reference( name = "token.management.dao.service", service = TokenManagementDAO.class, @@ -736,6 +761,11 @@ protected void setTokenMgtDAOService(TokenManagementDAO tokenMgtDAOService) { OAuthComponentServiceHolder.getInstance().setTokenManagementDAOService(tokenMgtDAOService); } + /** + * Unsets the access token grant processor. + * + * @param tokenManagementDAO TokenManagementDAO + */ protected void unsetTokenMgtDAOService(TokenManagementDAO tokenManagementDAO) { if (log.isDebugEnabled()) { @@ -746,6 +776,11 @@ protected void unsetTokenMgtDAOService(TokenManagementDAO tokenManagementDAO) { } + /** + * Sets the access token grant processor. + * + * @param oAuth2RevocationProcessor OAuth2RevocationProcessor + */ @Reference( name = "oauth2.revocation.processor", service = OAuth2RevocationProcessor.class, @@ -761,6 +796,11 @@ protected void setOAuth2RevocationProcessor(OAuth2RevocationProcessor oAuth2Revo OAuth2ServiceComponentHolder.getInstance().setRevocationProcessor(oAuth2RevocationProcessor); } + /** + * Unsets the access token grant processor. + * + * @param oAuth2RevocationProcessor OAuth2RevocationProcessor + */ protected void unsetOAuth2RevocationProcessor(OAuth2RevocationProcessor oAuth2RevocationProcessor) { if (log.isDebugEnabled()) { 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 f063ffbe817..eaf45b59184 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 @@ -670,6 +670,11 @@ private void validateTokenBindingReference(OAuth2AccessTokenReqDTO tokenReqDTO, } } + /** + * Get the RefreshTokenGrantProcessor. + * + * @return RefreshTokenGrantProcessor + */ private RefreshTokenGrantProcessor getRefreshTokenGrantProcessor() { return OAuth2ServiceComponentHolder.getInstance().getRefreshTokenGrantProcessor(); From ff7a124dc1d0d41040fde1134ad8b524f98a8329 Mon Sep 17 00:00:00 2001 From: dushani Date: Wed, 6 Sep 2023 17:22:10 +0530 Subject: [PATCH 11/13] address review comments on token logging. --- .../DefaultRefreshTokenGrantProcessor.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java index c0501ad63f3..24b9cde838b 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java @@ -139,8 +139,13 @@ public boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTok String userStoreDomain) throws IdentityOAuth2Exception { if (log.isDebugEnabled()) { - log.debug(String.format("Evaluating refresh token. Token value: %s, Token state: %s", - tokenReq.getRefreshToken(), validationBean.getRefreshTokenState())); + if (IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.REFRESH_TOKEN)) { + log.debug(String.format("Evaluating refresh token. Token value(hashed): %s, Token state: %s", + DigestUtils.sha256Hex(tokenReq.getRefreshToken()), validationBean.getRefreshTokenState())); + } else { + log.debug(String.format("Evaluating refresh token. Token state: %s", + validationBean.getRefreshTokenState())); + } } if (!OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE.equals(validationBean.getRefreshTokenState())) { /* if refresh token is not in active state, check whether there is an access token issued with the same From be0223e8df1b84d536c22ea214ef247d84995dcc Mon Sep 17 00:00:00 2001 From: dushani Date: Thu, 7 Sep 2023 11:39:30 +0530 Subject: [PATCH 12/13] fix potential NPEs. --- .../tokenprocessor/DefaultRefreshTokenGrantProcessor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java index 24b9cde838b..f634bd03028 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java @@ -102,7 +102,7 @@ public AccessTokenDO createAccessTokenBean(OAuthTokenReqMessageContext tokReqMsg if (OAuth2ServiceComponentHolder.isConsentedTokenColumnEnabled()) { String previousGrantType = validationBean.getGrantType(); // Check if the previous grant type is consent refresh token type or not. - if (!StringUtils.equals(OAuthConstants.GrantTypes.REFRESH_TOKEN, previousGrantType)) { + if (!OAuthConstants.GrantTypes.REFRESH_TOKEN.equals(previousGrantType)) { // If the previous grant type is not a refresh token, then check if it's a consent token or not. if (OIDCClaimUtil.isConsentBasedClaimFilteringApplicable(previousGrantType)) { accessTokenDO.setIsConsentedToken(true); @@ -153,7 +153,7 @@ public boolean isLatestRefreshToken(OAuth2AccessTokenReqDTO tokenReq, RefreshTok */ List accessTokenBeans = getAccessTokenBeans(tokenReq, validationBean, userStoreDomain); for (AccessTokenDO token : accessTokenBeans) { - if (tokenReq.getRefreshToken().equals(token.getRefreshToken()) + if (tokenReq.getRefreshToken() != null && tokenReq.getRefreshToken().equals(token.getRefreshToken()) && (OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE.equals(token.getTokenState()) || OAuthConstants.TokenStates.TOKEN_STATE_EXPIRED.equals(token.getTokenState()))) { return true; From 8193a441976359681ff25e60ed3062a92e0606cf Mon Sep 17 00:00:00 2001 From: dushani Date: Thu, 7 Sep 2023 11:44:57 +0530 Subject: [PATCH 13/13] remove unused imports. --- .../oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java index f634bd03028..144038132ff 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/tokenprocessor/DefaultRefreshTokenGrantProcessor.java @@ -19,7 +19,6 @@ package org.wso2.carbon.identity.oauth.tokenprocessor; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.base.IdentityConstants;