From c8d568e5fae03a37e16a0de383cb48fe771fc0c0 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Tue, 2 Jul 2024 16:18:54 +0530 Subject: [PATCH 01/28] accept and persist authorization_details of authorize request - Accept 'authorization_details' field in the authorization request. - Persist code and consent authorization details in the database. - Add support for oauth.rar and oauth.rar.common modules. - Read custom implementations of AuthorizationDetailsProvider from SPI. - Display rich authorization details in the consent UI. --- .../pom.xml | 5 + .../endpoint/authz/OAuth2AuthzEndpoint.java | 101 +++++- .../oauth/endpoint/util/EndpointUtil.java | 8 + .../authz/OAuth2AuthzEndpointTest.java | 10 + .../pom.xml | 60 ++++ .../common/dao/AuthorizationDetailsDAO.java | 69 ++++ .../dao/AuthorizationDetailsDAOImpl.java | 189 +++++++++++ .../oauth2/rar/common/dao/SQLQueries.java | 68 ++++ .../dto/AuthorizationDetailsCodeDTO.java | 22 ++ .../dto/AuthorizationDetailsConsentDTO.java | 38 +++ .../common/dto/AuthorizationDetailsDTO.java | 53 ++++ .../rar/common/model/AuthorizationDetail.java | 298 ++++++++++++++++++ .../common/model/AuthorizationDetails.java | 126 ++++++++ .../util/AuthorizationDetailsCommonUtils.java | 149 +++++++++ .../util/AuthorizationDetailsConstants.java | 37 +++ .../pom.xml | 108 +++++++ .../rar/AuthorizationDetailsService.java | 278 ++++++++++++++++ .../rar/AuthorizationDetailsValidator.java | 171 ++++++++++ .../core/AuthorizationDetailsProvider.java | 108 +++++++ .../AuthorizationDetailsProviderFactory.java | 133 ++++++++ ...thorizationDetailsProcessingException.java | 30 ++ .../RARAccessTokenResponseHandler.java | 61 ++++ .../AuthorizationDetailsDataHolder.java | 94 ++++++ .../AuthorizationDetailsServiceComponent.java | 69 ++++ .../model/AuthorizationDetailsContext.java | 98 ++++++ .../oauth2/rar/model/ValidationResult.java | 134 ++++++++ .../rar/util/AuthorizationDetailsUtils.java | 56 ++++ .../org.wso2.carbon.identity.oauth/pom.xml | 5 + ...tityOAuth2AuthorizationDetailsService.java | 134 ++++++++ .../authz/AuthorizationHandlerManager.java | 2 +- .../authz/OAuthAuthzReqMessageContext.java | 25 ++ .../handlers/AbstractResponseTypeHandler.java | 3 + .../handlers/CodeResponseTypeHandler.java | 2 + .../dao/OAuthTokenPersistenceFactory.java | 17 + .../oauth2/model/OAuth2Parameters.java | 25 ++ pom.xml | 18 ++ 36 files changed, 2802 insertions(+), 2 deletions(-) create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/pom.xml create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAO.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAOImpl.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/SQLQueries.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsCodeDTO.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsConsentDTO.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsDTO.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetail.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetails.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsCommonUtils.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsConstants.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/pom.xml create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsValidator.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProvider.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/handler/RARAccessTokenResponseHandler.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsDataHolder.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsServiceComponent.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/ValidationResult.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/IdentityOAuth2AuthorizationDetailsService.java diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index 82b7cdb973..564cacdef7 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -176,6 +176,11 @@ jackson-core provided + + org.wso2.carbon.identity.inbound.auth.oauth2 + org.wso2.carbon.identity.oauth.rar + provided + diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java index af69213459..47f2f21f5b 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java @@ -119,6 +119,7 @@ import org.wso2.carbon.identity.oauth2.IdentityOAuth2UnauthorizedScopeException; import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.RequestObjectException; +import org.wso2.carbon.identity.oauth2.authz.AuthorizationHandlerManager; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthService; @@ -134,6 +135,12 @@ import org.wso2.carbon.identity.oauth2.model.FederatedTokenDO; import org.wso2.carbon.identity.oauth2.model.HttpRequestHeaderHandler; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsValidator; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.responsemode.provider.AuthorizationResponseDTO; import org.wso2.carbon.identity.oauth2.responsemode.provider.ResponseModeProvider; import org.wso2.carbon.identity.oauth2.scopeservice.ScopeMetadataService; @@ -280,6 +287,9 @@ public class OAuth2AuthzEndpoint { private static ScopeMetadataService scopeMetadataService; private static DeviceAuthService deviceAuthService; + + private static AuthorizationDetailsService authorizationDetailsService; + private static final String AUTH_SERVICE_RESPONSE = "authServiceResponse"; private static final String IS_API_BASED_AUTH_HANDLED = "isApiBasedAuthHandled"; private static final ApiAuthnHandler API_AUTHN_HANDLER = new ApiAuthnHandler(); @@ -304,6 +314,16 @@ public static void setScopeMetadataService(ScopeMetadataService scopeMetadataSer OAuth2AuthzEndpoint.scopeMetadataService = scopeMetadataService; } + public static AuthorizationDetailsService getAuthorizationDetailsService() { + + return authorizationDetailsService; + } + + public static void setAuthorizationDetailsService(AuthorizationDetailsService authorizationDetailsService) { + + OAuth2AuthzEndpoint.authorizationDetailsService = authorizationDetailsService; + } + private static Class oAuthAuthzRequestClass; @GET @@ -1697,10 +1717,18 @@ private void storeUserConsent(OAuthMessage oAuthMessage, String consent) throws if (approvedAlways) { OpenIDConnectUserRPStore.getInstance().putUserRPToStore(loggedInUser, applicationName, true, clientId); + final AuthorizationDetails userConsentedAuthorizationDetails = + authorizationDetailsService.getUserConsentedAuthorizationDetails( + oAuthMessage.getRequest().getParameterMap(), oauth2Params); + if (hasPromptContainsConsent(oauth2Params)) { EndpointUtil.storeOAuthScopeConsent(loggedInUser, oauth2Params, true); + authorizationDetailsService.storeOrReplaceUserConsentedAuthorizationDetails(loggedInUser, + clientId, oauth2Params, userConsentedAuthorizationDetails); } else { EndpointUtil.storeOAuthScopeConsent(loggedInUser, oauth2Params, false); + authorizationDetailsService.storeUserConsentedAuthorizationDetails(loggedInUser, + clientId, oauth2Params, userConsentedAuthorizationDetails); } } } @@ -2577,6 +2605,12 @@ private String populateOauthParameters(OAuth2Parameters params, OAuthMessage oAu params.setEssentialClaims(oauthRequest.getParam(CLAIMS)); } + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(oauthRequest)) { + final String authorizationDetailsJson = oauthRequest + .getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS); + params.setAuthorizationDetails(new AuthorizationDetails(authorizationDetailsJson)); + } + handleMaxAgeParameter(oauthRequest, params); Object isMtls = oAuthMessage.getRequest().getAttribute(OAuthConstants.IS_MTLS_REQUEST); @@ -2980,6 +3014,22 @@ private String doUserAuthorization(OAuthMessage oAuthMessage, String sessionData return handleAuthorizationFailureBeforeConsent(oAuthMessage, oauth2Params, authorizeRespDTO); } + try { + validateAuthorizationDetailsBeforeConsent(oAuthMessage, oauth2Params, authzReqDTO); + } catch (AuthorizationDetailsProcessingException e) { + log.debug("Error occurred while validating authorization details. Caused by, ", e); + + authorizationResponseDTO.setError(HttpServletResponse.SC_FOUND, + AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_MSG, + AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_CODE); + + OAuth2AuthorizeRespDTO oAuth2AuthorizeRespDTO = new OAuth2AuthorizeRespDTO(); + oAuth2AuthorizeRespDTO.setErrorMsg(AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_MSG); + oAuth2AuthorizeRespDTO.setErrorCode(AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_CODE); + oAuth2AuthorizeRespDTO.setCallbackURI(authzReqDTO.getCallbackUrl()); + return handleAuthorizationFailureBeforeConsent(oAuthMessage, oauth2Params, oAuth2AuthorizeRespDTO); + } + boolean hasUserApproved = isUserAlreadyApproved(oauth2Params, authenticatedUser); if (hasPromptContainsConsent(oauth2Params)) { @@ -3673,7 +3723,8 @@ private boolean isUserAlreadyApproved(OAuth2Parameters oauth2Params, Authenticat throws OAuthSystemException { try { - return EndpointUtil.isUserAlreadyConsentedForOAuthScopes(user, oauth2Params); + return EndpointUtil.isUserAlreadyConsentedForOAuthScopes(user, oauth2Params) && + authorizationDetailsService.isUserAlreadyConsentedForAuthorizationDetails(user, oauth2Params); } catch (IdentityOAuth2ScopeException | IdentityOAuthAdminException e) { throw new OAuthSystemException("Error occurred while checking user has already approved the consent " + "required OAuth scopes.", e); @@ -4746,4 +4797,52 @@ private Response handleUnsupportedGrantForApiBasedAuth() { new AuthServiceClientException(AuthServiceConstants.ErrorMessage.ERROR_INVALID_AUTH_REQUEST.code(), "App native authentication is only supported with code response type."), log); } + + /** + * Validates the authorization details in the provided OAuth message before user consent. + * + *

This method checks if the request is a rich authorization request. If it is, it + * retrieves and validates the authorization details, updating the parameters and context + * accordingly. If any validation errors occur, it logs the issue and throws an appropriate + * exception.

+ * + * @param oAuthMessage The {@link OAuthMessage} containing the authorization request details. + * @param oAuth2Parameters The {@link OAuth2Parameters} object holding the parameters of the OAuth request. + * @param oAuth2AuthorizeReqDTO The {@link OAuth2AuthorizeReqDTO} object containing the authorization request. + * @throws OAuthSystemException If there is an error during the validation process. + * @throws AuthorizationDetailsProcessingException If there is an error processing the authorization details. + */ + private void validateAuthorizationDetailsBeforeConsent(final OAuthMessage oAuthMessage, + final OAuth2Parameters oAuth2Parameters, + final OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO) + throws OAuthSystemException, AuthorizationDetailsProcessingException { + + if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuth2Parameters)) { + log.debug("Authorization request is not a rich authorization request. Skipping validation."); + return; + } + + try { + final OAuthAppDO oAuthAppDO = AuthorizationHandlerManager.getInstance() + .getAppInformation(oAuth2AuthorizeReqDTO); + // Validate the authorization details + final AuthorizationDetails validatedAuthorizationDetails = new AuthorizationDetailsValidator() + .getValidatedAuthorizationDetails(oAuth2Parameters, oAuthAppDO, oAuth2AuthorizeReqDTO.getUser()); + + if (log.isDebugEnabled()) { + log.debug("Authorization details validated successfully for user: " + + oAuth2AuthorizeReqDTO.getUser().getLoggableMaskedUserId()); + } + // update oAuth2Parameters with validated authorization details + oAuth2Parameters.setAuthorizationDetails(validatedAuthorizationDetails); + + // Update the authorization message context with validated authorization details + OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext = + oAuthMessage.getSessionDataCacheEntry().getAuthzReqMsgCtx(); + oAuthAuthzReqMessageContext.setAuthorizationDetails(validatedAuthorizationDetails); + } catch (IdentityOAuth2Exception | InvalidOAuthClientException e) { + log.error("Error occurred while validating authorization details. Caused by, ", e); + throw new OAuthSystemException("Error occurred while validating requested authorization details", e); + } + } } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java index 616870d296..4129b752b7 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java @@ -103,6 +103,8 @@ import org.wso2.carbon.identity.oauth2.model.CarbonOAuthAuthzRequest; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.model.OAuth2ScopeConsentResponse; +import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.scopeservice.OAuth2Resource; import org.wso2.carbon.identity.oauth2.scopeservice.ScopeMetadataService; import org.wso2.carbon.identity.oauth2.util.AuthzUtil; @@ -868,6 +870,12 @@ public static String getUserConsentURL(OAuth2Parameters params, String loggedInU (consentRequiredScopes, UTF_8) + "&" + OAuthConstants.SESSION_DATA_KEY_CONSENT + "=" + URLEncoder.encode(sessionDataKeyConsent, UTF_8) + "&" + "&spQueryParams=" + queryString; + // Append authorization details to consent page url + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(params)) { + consentPageUrl = consentPageUrl + "&" + AuthorizationDetailsConstants.AUTHORIZATION_DETAILS + "=" + + URLEncoder.encode(params.getAuthorizationDetails().toJsonString(), UTF_8); + } + // Append scope metadata to additionalQueryParams. String scopeMetadataQueryParam = getScopeMetadataQueryParam(params.getConsentRequiredScopes(), params.getTenantDomain()); diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpointTest.java index 3448987379..9f990810f4 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpointTest.java @@ -112,6 +112,7 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2ClientValidationResponseDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; import org.wso2.carbon.identity.oauth2.responsemode.provider.ResponseModeProvider; import org.wso2.carbon.identity.oauth2.responsemode.provider.impl.DefaultResponseModeProvider; import org.wso2.carbon.identity.oauth2.responsemode.provider.impl.FormPostResponseModeProvider; @@ -284,6 +285,9 @@ public class OAuth2AuthzEndpointTest extends TestOAuthEndpointBase { @Mock private CentralLogMgtServiceComponentHolder centralLogMgtServiceComponentHolderMock; + @Mock + private AuthorizationDetailsService authorizationDetailsService; + private static final String ERROR_PAGE_URL = "https://localhost:9443/authenticationendpoint/oauth2_error.do"; private static final String LOGIN_PAGE_URL = "https://localhost:9443/authenticationendpoint/login.do"; private static final String USER_CONSENT_URL = @@ -803,6 +807,10 @@ public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, bo when(oAuth2ScopeService.hasUserProvidedConsentForAllRequestedScopes( anyString(), isNull(), anyInt(), anyList())).thenReturn(true); + when(authorizationDetailsService.isUserAlreadyConsentedForAuthorizationDetails( + any(AuthenticatedUser.class), any(OAuth2Parameters.class))).thenReturn(true); + OAuth2AuthzEndpoint.setAuthorizationDetailsService(authorizationDetailsService); + mockServiceURLBuilder(serviceURLBuilder); setSupportedResponseModes(); Response response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); @@ -1644,6 +1652,8 @@ public void testHandleUserConsent(boolean isRespDTONull, String consent, boolean OAuthAuthzReqMessageContext authzReqMsgCtx = new OAuthAuthzReqMessageContext(authorizeReqDTO); when(consentCacheEntry.getAuthzReqMsgCtx()).thenReturn(authzReqMsgCtx); + OAuth2AuthzEndpoint.setAuthorizationDetailsService(authorizationDetailsService); + Response response; try { setSupportedResponseModes(); diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/pom.xml b/components/org.wso2.carbon.identity.oauth.rar.common/pom.xml new file mode 100644 index 0000000000..1ac995d59f --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/pom.xml @@ -0,0 +1,60 @@ + + + org.wso2.carbon.identity.inbound.auth.oauth2 + identity-inbound-auth-oauth + 7.0.107-SNAPSHOT + ../../pom.xml + + + 4.0.0 + org.wso2.carbon.identity.oauth.rar.common + jar + WSO2 Carbon - Rich Authorization Requests Common + http://wso2.org + + + UTF-8 + + + + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.core + provided + + + + com.fasterxml.jackson.core + jackson-databind + provided + + + + junit + junit + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + + + + com.github.spotbugs + spotbugs-maven-plugin + + High + 2048 + + + + + + diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAO.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAO.java new file mode 100644 index 0000000000..a21b68b4d7 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAO.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.common.dao; + +import org.wso2.carbon.identity.oauth2.rar.common.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; + +import java.sql.SQLException; +import java.util.List; +import java.util.Set; + +/** + * Provides methods to interact with the database to manage authorization details. + */ +public interface AuthorizationDetailsDAO { + + /** + * Adds authorization details against a given OAuth2 code. + * + * @param authorizationCodeID The ID of the authorization code. + * @param authorizationDetails The authorization details to store. + * @param tenantId The tenant ID. + * @return An array of positive integers indicating the number of rows affected for each batch operation, + * or negative integers if any of the batch operations fail. + * @throws SQLException If a database access error occurs. + */ + int[] addOAuth2CodeAuthorizationDetails(String authorizationCodeID, AuthorizationDetails authorizationDetails, + int tenantId) throws SQLException; + + /** + * Adds user consented authorization details. + * + * @param authorizationDetailsConsentDTOs List of user consented authorization details DTOs. + * {@link AuthorizationDetailsConsentDTO } + * @return An array of positive integers indicating the number of rows affected for each batch operation, + * or negative integers if any of the batch operations fail. + * @throws SQLException If a database access error occurs. + */ + int[] addUserConsentedAuthorizationDetails(List authorizationDetailsConsentDTOs) + throws SQLException; + + int deleteUserConsentedAuthorizationDetails(String consentId, int tenantId) + throws SQLException; + + // add a todo and mention to move this to consent module + String getConsentIdByUserIdAndAppId(String userId, String appId, int tenantId) throws SQLException; + + Set getUserConsentedAuthorizationDetails(String consentId, int tenantId) + throws SQLException; + + int[] updateUserConsentedAuthorizationDetails(List authorizationDetailsConsentDTOs) + throws SQLException; +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAOImpl.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAOImpl.java new file mode 100644 index 0000000000..839f23c464 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAOImpl.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.common.dao; + +import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; +import org.wso2.carbon.identity.oauth2.rar.common.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Implementation of {@link AuthorizationDetailsDAO}. + * This class provides methods to add authorization details to the database. + */ +public class AuthorizationDetailsDAOImpl implements AuthorizationDetailsDAO { + + /** + * Stores authorization details against the provided OAuth2 authorization code. + * + * @param authorizationCodeID The ID of the authorization code. + * @param authorizationDetails The details to be added. + * @param tenantId The tenant ID. + * @return An array of positive integers indicating the number of rows affected for each batch operation, + * or negative integers if any of the batch operations fail. + * @throws SQLException If a database access error occurs. + */ + @Override + public int[] addOAuth2CodeAuthorizationDetails(final String authorizationCodeID, + final AuthorizationDetails authorizationDetails, + final int tenantId) throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS)) { + + for (AuthorizationDetail authorizationDetail : authorizationDetails.getDetails()) { + ps.setString(1, authorizationCodeID); + ps.setString(2, authorizationDetail.getType()); + ps.setInt(3, tenantId); + ps.setString(4, authorizationDetail.toJsonString()); + ps.setInt(5, tenantId); + ps.addBatch(); + } + return ps.executeBatch(); + } + } + + /** + * Stores user consented authorization details. + * + * @param authorizationDetailsConsentDTOs The user consented authorization details DTOs + * @return An array of positive integers indicating the number of rows affected for each batch operation, + * or negative integers if any of the batch operations fail. + * @throws SQLException If a database access error occurs. + */ + @Override + public int[] addUserConsentedAuthorizationDetails( + final List authorizationDetailsConsentDTOs) throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + + for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { + ps.setString(1, consentDTO.getConsentId()); + ps.setString(2, consentDTO.getAuthorizationDetail().getType()); + ps.setInt(3, consentDTO.getTenantId()); + ps.setString(4, consentDTO.getAuthorizationDetail().toJsonString()); + ps.setBoolean(5, consentDTO.isConsentActive()); + ps.setInt(6, consentDTO.getTenantId()); + ps.addBatch(); + } + return ps.executeBatch(); + } + } + + @Override + public int[] updateUserConsentedAuthorizationDetails( + final List authorizationDetailsConsentDTOs) throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + + for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { + ps.setString(1, consentDTO.getAuthorizationDetail().toJsonString()); + ps.setBoolean(2, consentDTO.isConsentActive()); + ps.setString(3, consentDTO.getConsentId()); + ps.setInt(4, consentDTO.getTenantId()); + ps.addBatch(); + } + return ps.executeBatch(); + } + } + + @Override + public int deleteUserConsentedAuthorizationDetails(final String consentId, final int tenantId) + throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.DELETE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + + ps.setString(1, consentId); + ps.setInt(2, tenantId); + return ps.executeUpdate(); + } + } + + @Override + public Set getUserConsentedAuthorizationDetails(final String consentId, + final int tenantId) + throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + + ps.setString(1, consentId); + ps.setInt(2, tenantId); + try (ResultSet rs = ps.executeQuery()) { + + final Set authorizationDetailsConsentDTOs = new HashSet<>(); + while (rs.next()) { + final String id = rs.getString(1); + final int typeId = rs.getInt(2); + final String authorizationDetail = rs.getString(3); + final boolean isConsentActive = rs.getBoolean(4); + + authorizationDetailsConsentDTOs.add(new AuthorizationDetailsConsentDTO(id, consentId, typeId, + authorizationDetail, isConsentActive, tenantId)); + } + return authorizationDetailsConsentDTOs; + } + } + } + + /** + * Retrieves the first consent ID for a given user ID and application ID. + * + * @param userId The ID of the user. + * @param appId The ID of the application. + * @param tenantId The tenant ID. + * @return The first consent ID found, or null if no consent ID is found. + * @throws SQLException If a database access error occurs. + */ + @Override + public String getConsentIdByUserIdAndAppId(final String userId, final String appId, final int tenantId) + throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.GET_IDN_OAUTH2_USER_CONSENT_CONSENT_ID)) { + + ps.setString(1, userId); + ps.setString(2, appId); + ps.setInt(3, tenantId); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return rs.getString(1); + } + } + } + return null; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/SQLQueries.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/SQLQueries.java new file mode 100644 index 0000000000..79faa31c9e --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/SQLQueries.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.common.dao; + +/** + * The {@code SQLQueries} class contains SQL query constants used for performing + * database operations related to OAuth2 Rich Authorization Requests. + */ +public class SQLQueries { + + private SQLQueries() { + // Private constructor to prevent instantiation + } + + public static final String ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS = + "INSERT INTO IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS " + + "(CODE_ID, TYPE_ID, AUTHORIZATION_DETAILS, TENANT_ID) VALUES " + + "(?, (SELECT ID FROM IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), " + + "? FORMAT JSON, ?)"; + + public static final String GET_OAUTH2_CODE_AUTHORIZATION_DETAILS = + "SELECT IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS.AUTHORIZATION_DETAILS " + + "FROM IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS " + + "INNER JOIN IDN_OAUTH2_AUTHORIZATION_CODE " + + "ON IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS.CODE_ID = IDN_OAUTH2_AUTHORIZATION_CODE.CODE_ID " + + "WHERE IDN_OAUTH2_AUTHORIZATION_CODE.AUTHORIZATION_CODE=? " + + "AND IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS.TENANT_ID=?"; + + public static final String ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = + "INSERT INTO IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + + "(CONSENT_ID, TYPE_ID, AUTHORIZATION_DETAILS, CONSENT, TENANT_ID) VALUES " + + "(?,(SELECT ID FROM IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), " + + "? FORMAT JSON, ?, ?)"; + + public static final String UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = + "UPDATE IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + + "SET AUTHORIZATION_DETAILS=? CONSENT=? WHERE CONSENT_ID=? AND TENANT_ID=?"; + + public static final String GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = + "SELECT ID, TYPE_ID, AUTHORIZATION_DETAILS, CONSENT FROM IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + + "WHERE CONSENT_ID=? AND TENANT_ID=?"; + + public static final String DELETE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = + "DELETE FROM IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS WHERE CONSENT_ID=? AND TENANT_ID=?"; + + public static final String CREATE_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS = + "INSERT INTO IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS " + + "(AUTHORIZATION_DETAILS_TYPE, AUTHORIZATION_DETAILS, TOKEN_ID, TENANT_ID) VALUES (?, ?, ?, ?)"; + + public static final String GET_IDN_OAUTH2_USER_CONSENT_CONSENT_ID = + "SELECT CONSENT_ID FROM IDN_OAUTH2_USER_CONSENT WHERE USER_ID=? AND APP_ID=? AND TENANT_ID=?"; +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsCodeDTO.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsCodeDTO.java new file mode 100644 index 0000000000..bc143a9325 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsCodeDTO.java @@ -0,0 +1,22 @@ +package org.wso2.carbon.identity.oauth2.rar.common.dto; + +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; + +/** + * + */ +public class AuthorizationDetailsCodeDTO extends AuthorizationDetailsDTO { + + final String codeId; + + public AuthorizationDetailsCodeDTO(final String id, final String codeId, final int typeId, + final AuthorizationDetail authorizationDetail, final int tenantId) { + + super(id, typeId, authorizationDetail, tenantId); + this.codeId = codeId; + } + + public String getCodeId() { + return codeId; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsConsentDTO.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsConsentDTO.java new file mode 100644 index 0000000000..0cf61dc230 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsConsentDTO.java @@ -0,0 +1,38 @@ +package org.wso2.carbon.identity.oauth2.rar.common.dto; + +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; + +/** + * + */ +public class AuthorizationDetailsConsentDTO extends AuthorizationDetailsDTO { + + final String consentId; + final boolean isConsentActive; + + public AuthorizationDetailsConsentDTO(final String id, final String consentId, final int typeId, + final String authorizationDetail, + final boolean isConsentActive, final int tenantId) { + + super(id, typeId, authorizationDetail, tenantId); + this.consentId = consentId; + this.isConsentActive = isConsentActive; + } + + public AuthorizationDetailsConsentDTO(final String consentId, + final AuthorizationDetail authorizationDetail, + final boolean isConsentActive, final int tenantId) { + + super(authorizationDetail, tenantId); + this.consentId = consentId; + this.isConsentActive = isConsentActive; + } + + public boolean isConsentActive() { + return isConsentActive; + } + + public String getConsentId() { + return consentId; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsDTO.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsDTO.java new file mode 100644 index 0000000000..fa73865c8b --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsDTO.java @@ -0,0 +1,53 @@ +package org.wso2.carbon.identity.oauth2.rar.common.dto; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsCommonUtils; + +/** + * + */ +public class AuthorizationDetailsDTO { + + final String id; + final int typeId; + final AuthorizationDetail authorizationDetail; + final int tenantId; + + public AuthorizationDetailsDTO(final String id, final int typeId, final AuthorizationDetail authorizationDetail, + final int tenantId) { + + this.id = id; + this.typeId = typeId; + this.authorizationDetail = authorizationDetail; + this.tenantId = tenantId; + } + + public AuthorizationDetailsDTO(final String id, final int typeId, final String authorizationDetailJson, + final int tenantId) { + + this(id, typeId, AuthorizationDetailsCommonUtils + .fromJSON(authorizationDetailJson, AuthorizationDetail.class, new ObjectMapper()), tenantId); + } + + public AuthorizationDetailsDTO(final AuthorizationDetail authorizationDetail, final int tenantId) { + + this(null, 0, authorizationDetail, tenantId); + } + + public String getId() { + return this.id; + } + + public int getTypeId() { + return this.typeId; + } + + public AuthorizationDetail getAuthorizationDetail() { + return this.authorizationDetail; + } + + public int getTenantId() { + return this.tenantId; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetail.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetail.java new file mode 100644 index 0000000000..96194b3485 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetail.java @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.common.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsCommonUtils; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; + +/** + * Represents an individual authorization details object which specifies the authorization requirements for a + * specific resource type within the {@code authorization_details} request parameter used in OAuth 2.0 flows + * (as defined in RFC 9396: OAuth 2.0 Rich Authorization + * Requests). + * + *

This class encapsulates the various attributes and their corresponding values that can be included within an + * authorization details object. The mandatory {@code type} field identifies the resource type or access requirement + * being described.

+ *

+ * Here is an example of {@code authorization_details} with + * Common Data Fields. + *

 {@code
+ * [
+ *   {
+ *     "type": "customer_information",
+ *     "locations": [
+ *       "https://example.com/customers"
+ *     ],
+ *     "actions": [
+ *       "read",
+ *       "write"
+ *     ],
+ *     "datatypes": [
+ *       "contacts",
+ *       "photos"
+ *     ],
+ *     "identifier":"account-14-32-32-3",
+ *     "privileges": [
+ *       "admin"
+ *     ]
+ *   }
+ * ]
+ * } 
+ * + *

Refer to + * OAuth 2.0 Rich Authorization Requests for detailed information on the Authorization Details structure.

+ * + * @since 7.0.26.9 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AuthorizationDetail implements Serializable { + + private static final long serialVersionUID = -3928636285264078857L; + + @JsonIgnore + private String id; + private String type; + private List locations; + private List actions; + @JsonProperty("datatypes") + private List dataTypes; + private String identifier; + private List privileges; + private Map details; + private String consentDescription; + + public AuthorizationDetail() { + this.setId(UUID.randomUUID().toString()); + } + + public String getId() { + return this.id; + } + + @JsonProperty("_id") + public void setId(final String id) { + this.id = id; + } + + /** + * Gets the value of the type field associated with the authorization details object. + * + *

{@code type} is a unique identifier for the authorization details type as a string. The value of the type + * field determines the allowable contents of the object that contains it.

+ * + * @return The String value of the type field + * @see + * Authorization Details Types + */ + public String getType() { + return this.type; + } + + public void setType(final String type) { + this.type = type; + } + + /** + * Gets the optional list of locations associated with the authorization details object. + * + *

{@code locations} is an array of strings representing the location of the resource or RS. These strings are + * typically URIs identifying the location of the RS. This field can allow a client to specify a particular RS.

+ * + * @return A list of locations or {@code null} if the {@code locations} field is not present. + */ + public List getLocations() { + return this.locations; + } + + public void setLocations(final List locations) { + this.locations = locations; + } + + /** + * Gets the optional list of actions associated with the authorization details object. + * + *

{@code actions} is an array of strings representing the kinds of actions to be taken at the resource. + * + * @return A list of actions or {@code null} if the {@code actions} field is not present. + */ + public List getActions() { + return this.actions; + } + + public void setActions(final List actions) { + this.actions = actions; + } + + /** + * Gets the optional list of data types associated with the authorization details object. + * + *

{@code datatypes} is an array of strings representing what kinds of data being requested from the resource. + * + * @return A list of datatypes or {@code null} if the {@code datatypes} field is not present. + */ + public List getDataTypes() { + return this.dataTypes; + } + + public void setDataTypes(final List dataTypes) { + this.dataTypes = dataTypes; + } + + /** + * Gets the optional String identifier associated with the authorization details object. + * + *

{@code identifier} is a string identifier indicating a specific resource available at the API. + * + * @return The String value of the identifier or {@code null} if the {@code identifier} field is not present. + */ + public String getIdentifier() { + return this.identifier; + } + + public void setIdentifier(final String identifier) { + this.identifier = identifier; + } + + /** + * Gets the optional list of privileges associated with the authorization details object. + * + *

{@code privileges} is an array of strings representing the types or levels of privilege being requested + * at the resource. + * + * @return The String value of the privileges or {@code null} if the {@code privileges} field is not present. + */ + public List getPrivileges() { + return this.privileges; + } + + public void setPrivileges(final List privileges) { + this.privileges = privileges; + } + + /** + * Gets a map containing API-specific fields from the authorization details object. The presence and structure + * of these fields can vary depending on the specific API being accessed. + * + * @return A map containing API-specific fields or {@code null} if no fields are present. + */ + @JsonAnyGetter + public Map getDetails() { + return this.details; + } + + public void setDetails(final Map details) { + this.details = details; + } + + @JsonAnySetter + public void setDetail(final String key, final Object value) { + if (this.details == null) { + setDetails(new HashMap<>()); + } + this.details.put(key, value); + } + + /** + * Returns the consent description of an {@link AuthorizationDetail} instance. + * This value is only available after the enrichment process. The consent description provides a human-readable + * representation of the {@code authorization_details}, typically in the form of a sentence derived from the + * JSON object. + * + * @return A string representing the consent description of the {@code authorization_details}. + */ + public String getConsentDescription() { + return this.consentDescription; + } + + /** + * Sets a human-readable sentence that describes the {@code authorization_details}. This sentence is used to + * display to the user and obtain their consent for the current {@link AuthorizationDetail AuthorizationDetail}. + * + * @param consentDescription A string representing the description of the authorization detail. + * This description should be clear and understandable to the user, + * explaining what they are consenting to. + */ + public void setConsentDescription(final String consentDescription) { + this.consentDescription = consentDescription; + } + + /** + * Returns the consent description if present; otherwise, returns a value supplied by the provided {@link Function}. + * Example usage: + *

 {@code
+     * // Example 1: Using a simple default function that returns the "type", if description is missing
+     * AuthorizationDetail detail = new AuthorizationDetail();
+     * detail.setType("user_information");
+     * detail.setConsentDescription(""); // Empty description
+     * String result = detail.getConsentDescriptionOrDefault(authDetail -> authDetail.getType());
+     * // result will be "user_information"
+     *
+     * // Example 2: Consent description is already set and not empty
+     * AuthorizationDetail detail = new AuthorizationDetail();
+     * detail.setType("user_information");
+     * detail.setConsentDescription("User consented to data usage");
+     * String result = detail.getConsentDescriptionOrDefault(authDetail -> "Default Description");
+     * // result will be "User consented to data usage"
+     * } 
+ * + * @param defaultFunction the Function that provides a default value if the consent description is not present + * @return the consent description if present, otherwise the value from the Function + */ + public String getConsentDescriptionOrDefault(Function defaultFunction) { + return StringUtils.isNotEmpty(this.getConsentDescription()) ? + this.getConsentDescription() : defaultFunction.apply(this); + } + + /** + * Converts the current authorization detail instance to a JSON string. + * + * @return The JSON representation of the authorization detail. + */ + public String toJsonString() { + return AuthorizationDetailsCommonUtils.toJSON(this, new ObjectMapper()); + } + + @Override + public String toString() { + return "AuthorizationDetails {" + + "type='" + this.type + '\'' + + ", locations=" + this.locations + + ", actions=" + this.actions + + ", datatypes=" + this.dataTypes + + ", identifier=" + this.identifier + + ", privileges=" + this.privileges + + ", details=" + this.details + + ", consentDescription=" + this.consentDescription + + '}'; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetails.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetails.java new file mode 100644 index 0000000000..0befab02b1 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetails.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.common.model; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsCommonUtils; +import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Represents a set of {@link AuthorizationDetail} objects which specifies the authorization requirements for a + * specific resource type within the {@code authorization_details} request parameter used in OAuth 2.0 flows + * (as defined in RFC 9396: OAuth 2.0 Rich Authorization + * Requests). + * + *

Refer to + * OAuth 2.0 Rich Authorization Requests for detailed information on the Authorization Details structure.

+ * + * @see AuthorizationDetail + */ +public class AuthorizationDetails implements Serializable { + + private static final long serialVersionUID = -663187547075070618L; + + private final Set authorizationDetails; + + /** + * Constructs an empty set of {@link AuthorizationDetail}. + */ + public AuthorizationDetails() { + this(Collections.emptySet()); + } + + /** + * Constructs an immutable set of {@link AuthorizationDetail}. + * + * @param authorizationDetails The set of authorization details. If null, an empty set is assigned. + */ + public AuthorizationDetails(final Set authorizationDetails) { + this.authorizationDetails = Optional.ofNullable(authorizationDetails) + .map(Collections::unmodifiableSet) + .orElse(Collections.emptySet()); + } + + /** + * Constructs an immutable set of {@link AuthorizationDetail} from a JSON string. + * + * @param authorizationDetailsJson The JSON string representing the authorization details. + */ + public AuthorizationDetails(final String authorizationDetailsJson) { + this(AuthorizationDetailsCommonUtils.fromJSONArray( + authorizationDetailsJson, AuthorizationDetail.class, new ObjectMapper())); + } + + /** + * Returns a set of the {@code authorization_details}. + * + * @return A set of {@link AuthorizationDetail}. + */ + public Set getDetails() { + return this.authorizationDetails; + } + + /** + * Returns a set of the {@code authorization_details} filtered by provided type. + * + * @return A set of {@link AuthorizationDetail}. + */ + public Set getDetailsByType(final String type) { + return this.stream() + .filter(Objects::nonNull) + .filter(authorizationDetail -> StringUtils.equals(authorizationDetail.getType(), type)) + .collect(Collectors.toSet()); + } + + /** + * Converts the current set of authorization details to a JSON string. + * + * @return The JSON representation of the authorization details. + */ + public String toJsonString() { + return AuthorizationDetailsCommonUtils.toJSON(this.getDetails(), new ObjectMapper()); + } + + /** + * Converts the set of authorization details to a human-readable string. + * Each detail's consent description is obtained or the type if the description is unavailable. + * + * @return A string representing the authorization details in a human-readable format. + */ + public String toReadableText() { + + return this.stream() + .map(authorizationDetail -> + authorizationDetail.getConsentDescriptionOrDefault(AuthorizationDetail::getType)) + .collect(Collectors.joining(AuthorizationDetailsConstants.PARAM_SEPARATOR)); + } + + public Stream stream() { + return this.getDetails().stream(); + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsCommonUtils.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsCommonUtils.java new file mode 100644 index 0000000000..c908656d18 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsCommonUtils.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.common.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; + +import java.util.HashSet; +import java.util.Set; + +/** + * Utility class for handling OAuth2 Rich Authorization Requests. + */ +public class AuthorizationDetailsCommonUtils { + + private static final Log log = LogFactory.getLog(AuthorizationDetailsCommonUtils.class); + private static final String empty_json = "{}"; + private static final String empty_json_array = "[]"; + + private AuthorizationDetailsCommonUtils() { + // Private constructor to prevent instantiation + } + + /** + * Parses the given JSON array string into a set of {@link AuthorizationDetail} objects. + * + * @param authorizationDetailsJson A JSON string containing authorization details which comes in the + * OAuth 2.0 authorization request or token request + * @param objectMapper A Jackson {@link ObjectMapper} used for parsing + * @param clazz A Class that extends {@link AuthorizationDetail} to be parsed + * @param the type parameter extending {@code AuthorizationDetail} + * @return an immutable set of {@link AuthorizationDetail} objects parsed from the given JSON string, + * or an empty set if parsing fails + * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails + */ + public static Set fromJSONArray( + final String authorizationDetailsJson, final Class clazz, final ObjectMapper objectMapper) { + + try { + if (StringUtils.isNotEmpty(authorizationDetailsJson)) { + return objectMapper.readValue(authorizationDetailsJson, + objectMapper.getTypeFactory().constructCollectionType(Set.class, clazz)); + } + } catch (JsonProcessingException e) { + log.debug("Error occurred while parsing String to AuthorizationDetails. Caused by, ", e); + } + return new HashSet<>(); + } + + /** + * Parses the given JSON object string into an {@link AuthorizationDetail} object. + * + * @param authorizationDetailJson A JSON string containing authorization detail object + * @param objectMapper A Jackson {@link ObjectMapper} used for parsing + * @param clazz A Class that extends {@link AuthorizationDetail} to be parsed + * @param the type parameter extending {@code AuthorizationDetail} + * @return an {@link AuthorizationDetail} objects parsed from the given JSON string, + * or null if parsing fails + * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail + */ + public static T fromJSON( + final String authorizationDetailJson, final Class clazz, final ObjectMapper objectMapper) { + + try { + if (StringUtils.isNotEmpty(authorizationDetailJson)) { + return objectMapper.readValue(authorizationDetailJson, clazz); + } + } catch (JsonProcessingException e) { + log.debug("Error occurred while parsing String to AuthorizationDetails. Caused by, ", e); + } + return null; + } + + /** + * Converts a set of {@code AuthorizationDetail} objects into a JSON string. + *

+ * If the input set is {@code null} or an exception occurs during the conversion, + * an empty JSON array ({@code []}) is returned. + *

+ * + * @param authorizationDetails the set of {@code AuthorizationDetail} objects to convert + * @param objectMapper the {@code ObjectMapper} instance to use for serialization + * @param the type parameter extending {@code AuthorizationDetail} + * @return a JSON string representation of the authorization details set, + * or an empty JSON array if null or an error occurs + * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail + * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails + */ + public static String toJSON( + final Set authorizationDetails, final ObjectMapper objectMapper) { + + try { + if (authorizationDetails != null) { + return objectMapper.writeValueAsString(authorizationDetails); + } + } catch (JsonProcessingException e) { + log.debug("Error occurred while parsing AuthorizationDetails to String. Caused by, ", e); + } + return empty_json_array; + } + + /** + * Converts a single {@code AuthorizationDetail} object into a JSON string. + *

+ * If the input object is {@code null} or an exception occurs during the conversion, + * an empty JSON object ({@code {}}) is returned. + *

+ * + * @param authorizationDetail the {@code AuthorizationDetail} object to convert + * @param objectMapper the {@code ObjectMapper} instance to use for serialization + * @param the type parameter extending {@code AuthorizationDetail} + * @return a JSON string representation of the authorization detail, + * or an empty JSON object if null or an error occurs + * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail + * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails + */ + public static String toJSON( + final T authorizationDetail, final ObjectMapper objectMapper) { + + try { + if (authorizationDetail != null) { + return objectMapper.writeValueAsString(authorizationDetail); + } + } catch (JsonProcessingException e) { + log.debug("Error occurred while parsing AuthorizationDetail to String. Caused by, ", e); + } + return empty_json; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsConstants.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsConstants.java new file mode 100644 index 0000000000..5b1ab3d97f --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsConstants.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.common.util; + +/** + * Stores constants related to OAuth2 Rich Authorization Requests. + */ +public final class AuthorizationDetailsConstants { + + private AuthorizationDetailsConstants() { + // Private constructor to prevent instantiation + } + + public static final String AUTHORIZATION_DETAILS = "authorization_details"; + public static final String AUTHORIZATION_DETAILS_ID_PREFIX = "authorization_detail_id_"; + public static final String PARAM_SEPARATOR = "&&"; + + public static final String TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT = "%s is not a supported authorization details type"; + public static final String VALIDATION_FAILED_ERR_MSG = "Authorization details validation failed"; + public static final String VALIDATION_FAILED_ERR_CODE = "invalid_authorization_details"; +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml new file mode 100644 index 0000000000..bb6bc7c861 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -0,0 +1,108 @@ + + + + + + org.wso2.carbon.identity.inbound.auth.oauth2 + identity-inbound-auth-oauth + ../../pom.xml + 7.0.107-SNAPSHOT + + + 4.0.0 + org.wso2.carbon.identity.oauth.rar + bundle + WSO2 Carbon - Rich Authorization Requests + http://wso2.org + + + UTF-8 + + + + + org.wso2.carbon.identity.inbound.auth.oauth2 + org.wso2.carbon.identity.oauth + provided + + + + com.google.auto.service + auto-service + + + + org.wso2.carbon.identity.inbound.auth.oauth2 + org.wso2.carbon.identity.oauth.rar.common + + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + ${project.artifactId} + + + org.wso2.carbon.identity.oauth2.rar.internal + + + org.osgi.framework; version="${osgi.framework.imp.pkg.version.range}", + org.osgi.service.component; version="${osgi.service.component.imp.pkg.version.range}", + org.wso2.carbon.identity.oauth2.*; version="${identity.inbound.auth.oauth.exp.pkg.version}", + + + !org.wso2.carbon.identity.oauth2.rar.internal, + org.wso2.carbon.identity.oauth2.rar.*; + version="${identity.inbound.auth.oauth.exp.pkg.version}", + + * + <_dsannotations>* + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + + + + + com.github.spotbugs + spotbugs-maven-plugin + + High + 2048 + + + + + + diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java new file mode 100644 index 0000000000..00f4c97c96 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java @@ -0,0 +1,278 @@ +package org.wso2.carbon.identity.oauth2.rar; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.common.dao.AuthorizationDetailsDAO; +import org.wso2.carbon.identity.oauth2.rar.common.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProvider; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants.AUTHORIZATION_DETAILS_ID_PREFIX; + +/** + * + */ +public class AuthorizationDetailsService extends IdentityOAuth2AuthorizationDetailsService { + + private static final Log log = LogFactory.getLog(AuthorizationDetailsService.class); + private final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory; + + public AuthorizationDetailsService() { + + this(OAuthTokenPersistenceFactory.getInstance().getAuthorizationDetailsDAO(), + AuthorizationDetailsProviderFactory.getInstance()); + } + + public AuthorizationDetailsService(final AuthorizationDetailsDAO authorizationDetailsDAO, + final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory) { + + super(authorizationDetailsDAO); + this.authorizationDetailsProviderFactory = authorizationDetailsProviderFactory; + } + + public void storeUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, final String clientId, + final OAuth2Parameters oAuth2Parameters, + final AuthorizationDetails userConsentedAuthorizationDetails) + throws OAuthSystemException { + + if (!AuthorizationDetailsService.isRichAuthorizationRequest(oAuth2Parameters)) { + return; + } + + try { + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); + + if (consentId.isPresent()) { + + super.authorizationDetailsDAO.addUserConsentedAuthorizationDetails( + generateAuthorizationDetailsConsentDTOs(consentId.get(), + userConsentedAuthorizationDetails, tenantId)); + } + } catch (SQLException | IdentityOAuth2Exception e) { + log.error("Error occurred while storing user consented authorization details. Caused by, ", e); + throw new OAuthSystemException("Error occurred while storing authorization details", e); + } + } + + public void updateUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final String clientId, final OAuth2Parameters oAuth2Parameters, + final AuthorizationDetails userConsentedAuthorizationDetails) + throws OAuthSystemException { + + if (!AuthorizationDetailsService.isRichAuthorizationRequest(oAuth2Parameters)) { + return; + } + + try { + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); + + if (consentId.isPresent()) { + + super.authorizationDetailsDAO.updateUserConsentedAuthorizationDetails( + generateAuthorizationDetailsConsentDTOs(consentId.get(), + userConsentedAuthorizationDetails, tenantId)); + } + } catch (SQLException | IdentityOAuth2Exception e) { + log.error("Error occurred while updating user consented authorization details. Caused by, ", e); + throw new OAuthSystemException("Error occurred while updating authorization details", e); + } + } + + public void deleteUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final String clientId, final OAuth2Parameters oAuth2Parameters) + throws OAuthSystemException { + + if (!AuthorizationDetailsService.isRichAuthorizationRequest(oAuth2Parameters)) { + return; + } + + try { + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); + + if (consentId.isPresent()) { + + super.authorizationDetailsDAO.deleteUserConsentedAuthorizationDetails(consentId.get(), tenantId); + } + } catch (SQLException | IdentityOAuth2Exception e) { + log.error("Error occurred while deleting user consented authorization details. Caused by, ", e); + throw new OAuthSystemException("Error occurred while storing authorization details", e); + } + } + + public void storeOrReplaceUserConsentedAuthorizationDetails( + final AuthenticatedUser authenticatedUser, final String clientId, final OAuth2Parameters oAuth2Parameters, + final AuthorizationDetails userConsentedAuthorizationDetails) throws OAuthSystemException { + + this.deleteUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters); + this.storeUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters, + userConsentedAuthorizationDetails); + } + + /** + * Check if the user has already given consent to requested authorization details. + * + * @param authenticatedUser Authenticated user. + * @param oAuth2Parameters OAuth2 parameters. + * @return True if user has given consent to all the requested authorization details. + */ + public boolean isUserAlreadyConsentedForAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final OAuth2Parameters oAuth2Parameters) + throws OAuthSystemException { + + try { + final String userId = this.getUserId(authenticatedUser); + final String appId = this.getApplicationResourceIdFromClientId(oAuth2Parameters.getClientId()); + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + final Optional consentId = this.getConsentIdByUserIdAndAppId(userId, appId, tenantId); + + if (consentId.isPresent()) { + final Set consentedAuthorizationDetailsDTOs = + super.authorizationDetailsDAO.getUserConsentedAuthorizationDetails(consentId.get(), tenantId); + + final Map> consentedAuthorizationDetailsByType = + consentedAuthorizationDetailsDTOs + .stream() + .filter(AuthorizationDetailsConsentDTO::isConsentActive) + .map(AuthorizationDetailsConsentDTO::getAuthorizationDetail) + .collect(Collectors.groupingBy(AuthorizationDetail::getType, + Collectors.mapping(Function.identity(), Collectors.toSet()))); + + for (final AuthorizationDetail requestedAuthorizationDetail : + oAuth2Parameters.getAuthorizationDetails().getDetails()) { + + if (consentedAuthorizationDetailsByType.containsKey(requestedAuthorizationDetail.getType())) { + + final Optional provider = authorizationDetailsProviderFactory + .getProviderByType(requestedAuthorizationDetail.getType()); + if (provider.isPresent()) { + + final AuthorizationDetails existingAuthorizationDetails = new AuthorizationDetails( + consentedAuthorizationDetailsByType.get(requestedAuthorizationDetail.getType())); + if (!provider.get() + .isEqualOrSubset(requestedAuthorizationDetail, existingAuthorizationDetails)) { + + if (log.isDebugEnabled()) { + log.debug("User has not consented for the requested authorization details type: " + + requestedAuthorizationDetail.getType()); + + } + return false; + } + } + } + } + return true; + } + return false; + } catch (IdentityOAuth2Exception | SQLException e) { + log.error("Error occurred while extracting user consented authorization details. Caused by, ", e); + throw new OAuthSystemException("Error occurred while extracting user consented authorization details", e); + } + } + + /** + * Retrieves the user-consented authorization details based on the provided parameter map and OAuth2 parameters. + *

+ * This method is used to extract and return the authorization details that the user has consented to, + * filtering them based on a provided authorization details in the parameter map. + *

+ * + * @param parameterMap A map of query parameters. + * @param oAuth2Parameters The OAuth2 parameters that include the details of the authorization request. + * @return The {@link AuthorizationDetails} object containing the details the user has consented to. + */ + public AuthorizationDetails getUserConsentedAuthorizationDetails( + final Map parameterMap, final OAuth2Parameters oAuth2Parameters) { + + if (!isRichAuthorizationRequest(oAuth2Parameters)) { + return new AuthorizationDetails(); + } + + // Extract consented authorization detail IDs from the parameter map + final Set consentedAuthorizationDetailIDs = parameterMap.keySet().stream() + .filter(parameterName -> parameterName.startsWith(AUTHORIZATION_DETAILS_ID_PREFIX)) + .map(parameterName -> parameterName.substring(AUTHORIZATION_DETAILS_ID_PREFIX.length())) + .collect(Collectors.toSet()); + + // Filter and collect the consented authorization details + final Set consentedAuthorizationDetails = oAuth2Parameters.getAuthorizationDetails() + .stream() + .filter(authorizationDetail -> consentedAuthorizationDetailIDs.contains(authorizationDetail.getId())) + .collect(Collectors.toSet()); + + return new AuthorizationDetails(consentedAuthorizationDetails); + } + + public Optional getConsentIdByUserIdAndAppId(final String userId, final String appId, final int tenantId) + throws OAuthSystemException { + + try { + return Optional + .ofNullable(super.authorizationDetailsDAO.getConsentIdByUserIdAndAppId(userId, appId, tenantId)); + } catch (SQLException e) { + log.error(String.format("Error occurred while retrieving user consent by " + + "userId: %s and appId: %s. Caused by, ", userId, appId), e); + throw new OAuthSystemException("Error occurred while retrieving user consent", e); + } + } + + private String getApplicationResourceIdFromClientId(final String clientId) throws IdentityOAuth2Exception { + + final ServiceProvider serviceProvider = OAuth2Util.getServiceProvider(clientId); + if (serviceProvider != null) { + return serviceProvider.getApplicationResourceId(); + } + throw new IdentityOAuth2Exception("Unable to find a service provider for client Id: " + clientId); + } + + private String getUserId(final AuthenticatedUser authenticatedUser) throws OAuthSystemException { + try { + return authenticatedUser.getUserId(); + } catch (UserIdNotFoundException e) { + log.error("Error occurred while extracting userId from authenticated user. Caused by, ", e); + throw new OAuthSystemException( + "User id is not found for user: " + authenticatedUser.getLoggableMaskedUserId(), e); + } + } + + private List generateAuthorizationDetailsConsentDTOs( + final String consentId, final AuthorizationDetails userConsentedAuthorizationDetails, final int tenantId) { + + return userConsentedAuthorizationDetails.stream() + .map(authorizationDetail -> + new AuthorizationDetailsConsentDTO(consentId, authorizationDetail, true, tenantId)) + .collect(Collectors.toList()); + } + + private Optional getConsentId(final AuthenticatedUser authenticatedUser, final String clientId, + final int tenantId) + throws OAuthSystemException, IdentityOAuth2Exception { + + final String userId = this.getUserId(authenticatedUser); + final String appId = this.getApplicationResourceIdFromClientId(clientId); + + return this.getConsentIdByUserIdAndAppId(userId, appId, tenantId); + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsValidator.java new file mode 100644 index 0000000000..6b67f226d8 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsValidator.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProvider; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; +import org.wso2.carbon.identity.oauth2.rar.model.ValidationResult; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +/** + * {@code AuthorizationDetailsValidator} class responsible for managing and validating authorization details. + */ +public class AuthorizationDetailsValidator { + + private static final Log log = LogFactory.getLog(AuthorizationDetailsValidator.class); + private final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory; + + public AuthorizationDetailsValidator() { + + this(AuthorizationDetailsProviderFactory.getInstance()); + } + + public AuthorizationDetailsValidator(AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory) { + + this.authorizationDetailsProviderFactory = authorizationDetailsProviderFactory; + } + + /** + * Retrieves and validates the authorization details for a given OAuth2 parameters context. + * + * @param oAuth2Parameters The OAuth2 parameters associated with the request. + * @param oAuthAppDO The OAuth application details. + * @param authenticatedUser The authenticated user information. + * @return An {@link AuthorizationDetails} object containing the validated authorization details. + */ + public AuthorizationDetails getValidatedAuthorizationDetails( + final OAuth2Parameters oAuth2Parameters, final OAuthAppDO oAuthAppDO, + final AuthenticatedUser authenticatedUser) throws AuthorizationDetailsProcessingException { + + final Set validatedAuthorizationDetails = new HashSet<>(); + final Set authorizedAuthorizationDetailsTypes = this.getAuthorizedAuthorizationDetailsTypes( + oAuth2Parameters.getClientId(), oAuth2Parameters.getTenantDomain()); + for (AuthorizationDetail authorizationDetail : oAuth2Parameters.getAuthorizationDetails().getDetails()) { + + if (!isSupportedAuthorizationDetailType(authorizationDetail.getType())) { + throw new AuthorizationDetailsProcessingException(String.format(AuthorizationDetailsConstants + .TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT, authorizationDetail.getType())); + } + + if (isAuthorizedAuthorizationDetail(authorizationDetail, authorizedAuthorizationDetailsTypes)) { + + final AuthorizationDetailsContext authorizationDetailsContext = new AuthorizationDetailsContext( + oAuth2Parameters, oAuthAppDO, authenticatedUser, authorizationDetail); + + if (isValidAuthorizationDetail(authorizationDetailsContext)) { + validatedAuthorizationDetails.add(getEnrichedAuthorizationDetail(authorizationDetailsContext)); + } + } + } + + return new AuthorizationDetails(validatedAuthorizationDetails); + } + + private boolean isAuthorizedAuthorizationDetail(final AuthorizationDetail authorizationDetail, + final Set authorizedAuthorizationDetailsTypes) { + + return authorizedAuthorizationDetailsTypes.contains(authorizationDetail.getType()); + } + + private boolean isSupportedAuthorizationDetailType(final String authorizationDetailType) { + + return this.authorizationDetailsProviderFactory + .isSupportedAuthorizationDetailsType(authorizationDetailType); + } + + /** + * Checks if the provided authorization details context is valid. + * + * @param authorizationDetailsContext The context containing authorization details. + * @return {@code true} if the authorization details are valid; {@code false} otherwise. + */ + private boolean isValidAuthorizationDetail(final AuthorizationDetailsContext authorizationDetailsContext) + throws AuthorizationDetailsProcessingException { + + Optional optionalProvider = this.authorizationDetailsProviderFactory + .getProviderByType(authorizationDetailsContext.getAuthorizationDetail().getType()); + + if (optionalProvider.isPresent()) { + + final ValidationResult validationResult = optionalProvider.get().validate(authorizationDetailsContext); + if (log.isDebugEnabled() && validationResult.isInvalid()) { + + log.debug(String.format("Authorization details validation failed for type %s. Caused by, %s", + authorizationDetailsContext.getAuthorizationDetail().getType(), validationResult.getReason())); + + } + return validationResult.isValid(); + } + throw new AuthorizationDetailsProcessingException(String.format( + AuthorizationDetailsConstants.TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT, + authorizationDetailsContext.getAuthorizationDetail().getType())); + } + + /** + * Enriches the authorization details using the provided context. + * + * @param authorizationDetailsContext The context containing authorization details. + * @return An enriched {@link AuthorizationDetail} object. + */ + private AuthorizationDetail getEnrichedAuthorizationDetail( + final AuthorizationDetailsContext authorizationDetailsContext) { + + return this.authorizationDetailsProviderFactory + .getProviderByType(authorizationDetailsContext.getAuthorizationDetail().getType()) + .map(authorizationDetailsService -> authorizationDetailsService.enrich(authorizationDetailsContext)) + // If provider is missing, return the original authorization detail instance + .orElse(authorizationDetailsContext.getAuthorizationDetail()); + } + + /** + * Retrieves the set of authorized authorization types for the given client and tenant domain. + * + * @param clientID The client ID. + * @param tenantDomain The tenant domain. + * @return A set of strings representing the authorized authorization types. + */ + private Set getAuthorizedAuthorizationDetailsTypes(final String clientID, final String tenantDomain) { + +// try { +// final String appId = OAuth2Util +// .getApplicationResourceIDByClientId(clientID, tenantDomain, this.applicationMgtService); +// +//// OAuth2ServiceComponentHolder.getInstance().getAuthorizedAPIManagementService() +// .getAuthorizedAuthorizationDetailsTypes(appId, tenantDomain); +// } catch (IdentityOAuth2Exception e) { +// throw new RuntimeException(e); +// } + Set authorizedAuthorizationDetailsTypes = new HashSet<>(); + authorizedAuthorizationDetailsTypes.add("payment_initiation"); + return authorizedAuthorizationDetailsTypes; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProvider.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProvider.java new file mode 100644 index 0000000000..aa05dec625 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProvider.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.core; + +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; +import org.wso2.carbon.identity.oauth2.rar.model.ValidationResult; + +/** + * The {@code AuthorizationDetailsProvider} interface defines a contract for implementing + * different types of authorization detail providers in a Service Provider Interface (SPI) setup. + *

+ * Implementing classes are expected to provide mechanisms to validate, enrich, and identify + * authorization details specific to various types. + *

+ * + * @see Java SPI + */ +public interface AuthorizationDetailsProvider { + + /** + * Validates the provided authorization details context when a new Rich Authorization Request is received. + *

+ * This method is invoked once a new Rich Authorization Request is received to ensure that the + * authorization details are valid and meet the required criteria. The validation logic should + * be specific to the type of authorization details handled by the implementing class. + *

+ * + * @param authorizationDetailsContext the context containing the authorization details to be validated. + * @return a {@code ValidationResult} indicating the outcome of the validation process. Returns a valid result + * if the authorization details are correct and meet the criteria, otherwise returns an invalid result with an + * appropriate error message. + * @throws AuthorizationDetailsProcessingException if the validation fails and the authorization flow needs + * to be interrupted. + * @see AuthorizationDetailsContext + * @see ValidationResult + */ + ValidationResult validate(AuthorizationDetailsContext authorizationDetailsContext) + throws AuthorizationDetailsProcessingException; + + /** + * Retrieves the type of authorization details handled by this provider. + *

+ * Each implementation should return a unique type identifier that represents the kind of + * authorization details it processes. This identifier is used to differentiate between + * various providers in a service-oriented architecture. + *

+ * + * @return a {@code String} representing the type of authorization details managed by this provider + * @see AuthorizationDetail#getType() + */ + String getType(); + + // The existing authorization detail that was previously accepted by the resource owner. + boolean isEqualOrSubset(AuthorizationDetail requestedAuthorizationDetail, + AuthorizationDetails existingAuthorizationDetails); + + /** + *

+ * This method is invoked prior to presenting the consent UI to the user. Its purpose is to + * enhance or augment the authorization details, providing additional context or information + * that may be necessary for informed consent. This may include adding more descriptive + * information, default values, or other relevant details that are crucial for the user to + * understand the authorization request fully. + *

+ *

+ * It is also a responsibility of this method to generate a human-readable consent + * description from the provided authorization details, which will be displayed to the user for approval. + * The consent description should provide a clear, human-readable summary of the {@code authorization_details} + * object. + *

+ *

+ * This enrichment process aligns with the concepts outlined in + * RFC 9396, + * which describes the requirements for enriched authorization details to ensure clarity and transparency + * in consent management. + *

+ * + * @param authorizationDetailsContext the context containing the authorization details to be enriched. + * @return an enriched {@code AuthorizationDetail} object with additional information or context. + * This enriched object is intended to provide users with a clearer understanding of the + * authorization request when they are presented with the consent form. + * @see AuthorizationDetailsContext + * @see AuthorizationDetail + * @see AuthorizationDetail#setConsentDescription + * @see + * Enriched Authorization Details + */ + AuthorizationDetail enrich(AuthorizationDetailsContext authorizationDetailsContext); +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java new file mode 100644 index 0000000000..123e3cc3dd --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.core; + +import org.wso2.carbon.identity.oauth2.rar.internal.AuthorizationDetailsDataHolder; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * A factory class to manage and provide instances of {@link AuthorizationDetailsProvider} Service Provider Interface. + * This class follows the Singleton pattern to ensure only one instance is created. + * It uses {@link ServiceLoader} to dynamically load and manage {@link AuthorizationDetailsProvider} implementations. + *

Example usage: + *

 {@code
+ * // Get a specific provider by type
+ * AuthorizationDetailsProviderFactory.getInstance()
+ *     .getProviderByType("customer_information")
+ *     .ifPresentOrElse(
+ *         p -> log.debug("Provider for type " + type + ": " + p.getClass().getName()),
+ *         () -> log.debug("No provider found for type " + type)
+ *     );
+ * } 

+ * + * @see AuthorizationDetailsProvider AuthorizationDetailsService + * @see + * Request Parameter "authorization_details" + * @since 7.0.26.9 + */ +public class AuthorizationDetailsProviderFactory { + + private static volatile AuthorizationDetailsProviderFactory instance; + private final Map supportedAuthorizationDetailsTypes; + + /** + * Private constructor to initialize the factory. + *

This constructor is intentionally private to prevent direct instantiation of the + * {@code AuthorizationDetailsProviderFactory} class. + * Instead, use the {@link #getInstance()} method to obtain the singleton instance.

+ */ + private AuthorizationDetailsProviderFactory() { + + this.supportedAuthorizationDetailsTypes = this.loadSupportedAuthorizationDetailsTypes(); + } + + /** + * Loads supported authorization details types from the provided {@link ServiceLoader}. + * + * @return Map of authorization details types with their corresponding services. + */ + private Map loadSupportedAuthorizationDetailsTypes() { + + return AuthorizationDetailsDataHolder.getInstance() + .getAuthorizationDetailsProviders() + .stream() + .collect(Collectors.toMap(AuthorizationDetailsProvider::getType, Function.identity())); + } + + /** + * Provides the singleton instance of {@code AuthorizationDetailsProviderFactory}. + * + * @return Singleton instance of {@code AuthorizationDetailsProviderFactory}. + */ + public static AuthorizationDetailsProviderFactory getInstance() { + + if (instance == null) { + synchronized (AuthorizationDetailsProviderFactory.class) { + if (instance == null) { + instance = new AuthorizationDetailsProviderFactory(); + } + } + } + return instance; + } + + /** + * Returns the {@link AuthorizationDetailsProvider} provider for the given type. + * + * @param type A supported authorization details type. + * @return {@link Optional} containing the {@link AuthorizationDetailsProvider} if present, otherwise empty. + * @see AuthorizationDetailsProvider#getType() getAuthorizationDetailsType + */ + public Optional getProviderByType(final String type) { + + return Optional.ofNullable(this.supportedAuthorizationDetailsTypes.get(type)); + } + + /** + * Checks if a given type has a valid service provider implementation. + * + * @param type The type to check. + * @return {@code true} if the type is supported, {@code false} otherwise. + * @see AuthorizationDetailsProvider AuthorizationDetailsService + */ + public boolean isSupportedAuthorizationDetailsType(final String type) { + + return this.supportedAuthorizationDetailsTypes.containsKey(type); + } + + /** + * Returns a {@link Collections#unmodifiableSet} of all supported authorization details types. + *

To be included as a supported authorization details type, there must be a custom implementation + * of the {@link AuthorizationDetailsProvider} Service Provider Interface (SPI) available in the classpath + * for the specified type.

+ * + * @return A set of supported authorization details types. + */ + public Set getSupportedAuthorizationDetailTypes() { + + return Collections.unmodifiableSet(this.supportedAuthorizationDetailsTypes.keySet()); + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java new file mode 100644 index 0000000000..62a65d9859 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java @@ -0,0 +1,30 @@ +package org.wso2.carbon.identity.oauth2.rar.exception; + +/** + * + */ +public class AuthorizationDetailsProcessingException extends RuntimeException { + + private static final long serialVersionUID = -206212512259482200L; + + /** + * Constructs a new exception with an error message. + * + * @param message The detail message. + */ + public AuthorizationDetailsProcessingException(String message) { + + super(message); + } + + /** + * Constructs a new exception with the message and cause. + * + * @param message The detail message. + * @param cause The cause. + */ + public AuthorizationDetailsProcessingException(String message, Throwable cause) { + + super(message, cause); + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/handler/RARAccessTokenResponseHandler.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/handler/RARAccessTokenResponseHandler.java new file mode 100644 index 0000000000..a35e8bd0ae --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/handler/RARAccessTokenResponseHandler.java @@ -0,0 +1,61 @@ +package org.wso2.carbon.identity.oauth2.rar.handler; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.token.handlers.response.AccessTokenResponseHandler; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class RARAccessTokenResponseHandler implements AccessTokenResponseHandler { + private static final ObjectMapper OBJECT_MAPPER = new JsonMapper(); + private static final Log LOG = LogFactory.getLog(RARAccessTokenResponseHandler.class); + + @Override +// public Map getAdditionalTokenResponseAttributes(OAuthTokenReqMessageContext tokReqMsgCtx) +// throws IdentityOAuth2Exception { +// +// List authorizationDetails = AuthorizationDetailService.getInstance() +// .getConsentedAuthorizationDetailsByAuthzCode(tokReqMsgCtx.getOauth2AccessTokenReqDTO() +// .getAuthorizationCode()); +// +// Map additionalAttributes = new HashMap<>(); +// if (isNotEmptyList(authorizationDetails)) { +// additionalAttributes.put(AUTHORIZATION_DETAILS, convertToJsonArray(authorizationDetails)); +// } +// return additionalAttributes; +// } + + public Map getAdditionalTokenResponseAttributes(OAuthTokenReqMessageContext tokReqMsgCtx) + throws IdentityOAuth2Exception { + + Map additionalAttributes = new HashMap<>(); + + return additionalAttributes; + } + + + private boolean isNotEmptyList(List list) { + return list != null && !list.isEmpty(); + } + + private JSONArray convertToJsonArray(List authorizationDetails) { + try { + return OBJECT_MAPPER.convertValue(OBJECT_MAPPER.writeValueAsString(authorizationDetails), JSONArray.class); + } catch (JsonProcessingException e) { + LOG.error("Serialization error. Caused by, ", e); + } + return new JSONArray(authorizationDetails); + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsDataHolder.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsDataHolder.java new file mode 100644 index 0000000000..bd0c92f5f3 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsDataHolder.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.internal; + +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProvider; + +import java.util.HashSet; +import java.util.Set; + +/** + * Singleton class that holds rich authorization details data. + *

This class uses the singleton design pattern to ensure there is only one instance + * managing the authorization details providers. The instance is lazily initialized + * with double-checked locking to ensure thread safety.

+ *

The class provides methods to retrieve and set the authorization details data, + * which can be used in different parts of the application to manage rich authorization details.

+ */ +public class AuthorizationDetailsDataHolder { + + private static volatile AuthorizationDetailsDataHolder instance; + private Set authorizationDetailsProviders; + + /** + * Private constructor to prevent instantiation from outside the class. + */ + private AuthorizationDetailsDataHolder() { + + this.authorizationDetailsProviders = new HashSet<>(); + } + + /** + * Returns the singleton instance of {@link AuthorizationDetailsDataHolder}. + * + *

This method uses double-checked locking to ensure that the instance is initialized + * only once and in a thread-safe manner. If the instance is not already created, it + * will be created and returned; otherwise, the existing instance will be returned.

+ * + * @return The singleton instance of {@link AuthorizationDetailsDataHolder}. + */ + public static AuthorizationDetailsDataHolder getInstance() { + + if (instance == null) { + synchronized (AuthorizationDetailsDataHolder.class) { + if (instance == null) { + instance = new AuthorizationDetailsDataHolder(); + } + } + } + return instance; + } + + /** + * Returns the current set of {@link AuthorizationDetailsProvider} instances. + * + *

This method provides access to the authorization details providers. + * The returned set can be used to query or modify the authorization details providers.

+ * + * @return A {@link Set} of {@link AuthorizationDetailsProvider} instances. + */ + public Set getAuthorizationDetailsProviders() { + + return this.authorizationDetailsProviders; + } + + /** + * Sets the set of {@link AuthorizationDetailsProvider} instances to the provided value. + * + *

This method replaces the current set of authorization details providers with the + * provided set. It can be used to update the list of providers that the application + * uses to manage authorization details.

+ * + * @param authorizationDetailsProviders The new {@link Set} of {@link AuthorizationDetailsProvider} instances. + */ + public void setAuthorizationDetailsProviders(Set authorizationDetailsProviders) { + + this.authorizationDetailsProviders = authorizationDetailsProviders; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsServiceComponent.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsServiceComponent.java new file mode 100644 index 0000000000..2cd272dc71 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsServiceComponent.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProvider; + +import java.util.ServiceLoader; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * Authorization Details OSGI service component. + */ +@Component(name = "org.wso2.carbon.identity.oauth.rar.internal.AuthorizationDetailsServiceComponent") +public class AuthorizationDetailsServiceComponent { + private static final Log log = LogFactory.getLog(AuthorizationDetailsServiceComponent.class); + + @Activate + protected void activate(ComponentContext context) { + + AuthorizationDetailsDataHolder.getInstance().setAuthorizationDetailsProviders( + loadAuthorizationDetailsProviders(ServiceLoader.load(AuthorizationDetailsProvider.class, + this.getClass().getClassLoader()))); + + log.debug("AuthorizationDetailsServiceComponent is activated"); + } + + @Deactivate + protected void deactivate(ComponentContext context) { + + log.debug("AuthorizationDetailsServiceComponent is deactivated"); + } + + /** + * Loads supported authorization details providers from the provided {@link ServiceLoader}. + * + * @param serviceLoader {@link ServiceLoader} for {@link AuthorizationDetailsProvider}. + * @return Set of authorization details providers. + */ + private Set loadAuthorizationDetailsProviders( + final ServiceLoader serviceLoader) { + + return StreamSupport.stream(serviceLoader.spliterator(), false) + .collect(Collectors.toSet()); + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java new file mode 100644 index 0000000000..00cd4de10d --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.model; + +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; + +import java.util.Objects; + +/** + * Represents the context for rich authorization requests in an OAuth2 flow. + *

+ * This class holds relevant details such as OAuth2 parameters, application details, the authenticated user, + * and specific authorization details. It is immutable to ensure that the context remains consistent throughout its use. + *

+ */ +public class AuthorizationDetailsContext { + + private final OAuth2Parameters oAuth2Parameters; + private final OAuthAppDO oAuthAppDO; + private final AuthenticatedUser authenticatedUser; + private final AuthorizationDetail authorizationDetail; + + /** + * Constructs a new {@code AuthorizationDetailsContext}. + *

+ * This constructor ensures that all necessary details for an authorization context are provided. + *

+ * + * @param oAuth2Parameters the OAuth2 parameters. + * @param oAuthAppDO the OAuth application details. + * @param authenticatedUser the authenticated user. + * @param authorizationDetail the specific authorization detail. + * @throws NullPointerException if any of the arguments are {@code null}. + */ + public AuthorizationDetailsContext(final OAuth2Parameters oAuth2Parameters, final OAuthAppDO oAuthAppDO, + final AuthenticatedUser authenticatedUser, + final AuthorizationDetail authorizationDetail) { + this.oAuth2Parameters = Objects.requireNonNull(oAuth2Parameters, "oAuth2Parameters cannot be null"); + this.oAuthAppDO = Objects.requireNonNull(oAuthAppDO, "oAuthAppDO cannot be null"); + this.authenticatedUser = Objects.requireNonNull(authenticatedUser, "authenticatedUser cannot be null"); + this.authorizationDetail = Objects.requireNonNull(authorizationDetail, "authorizationDetail cannot be null"); + } + + /** + * Returns the {@code AuthorizationDetail} instance. + * + * @return the {@link AuthorizationDetail} instance. + */ + public AuthorizationDetail getAuthorizationDetail() { + return this.authorizationDetail; + } + + /** + * Returns the OAuth2 parameters. + * + * @return the {@link OAuth2Parameters} instance. + */ + public OAuth2Parameters getOAuth2Parameters() { + return this.oAuth2Parameters; + } + + /** + * Returns the OAuth application details. + * + * @return the {@link OAuthAppDO} instance. + */ + public OAuthAppDO getoAuthAppDO() { + return this.oAuthAppDO; + } + + /** + * Returns the authenticated user. + * + * @return the {@link AuthenticatedUser} instance. + */ + public AuthenticatedUser getAuthenticatedUser() { + return this.authenticatedUser; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/ValidationResult.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/ValidationResult.java new file mode 100644 index 0000000000..5bf5c9ed0c --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/ValidationResult.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.model; + +import java.util.Map; + +/** + * Represents the result of authorization details validation operation, encapsulating the status, reason for failure, + * and additional metadata. + *

+ * This class provides a way to create validation results that can be either valid or invalid, with + * optional metadata for further context. + *

+ */ +public class ValidationResult { + + private final boolean status; + private final String reason; + private final Map meta; + + /** + * Constructs a new {@code ValidationResult}. + * + * @param status whether the validation is successful. + * @param reason the reason for validation failure, if applicable. + * @param meta additional metadata related to the validation result. + */ + public ValidationResult(final boolean status, final String reason, final Map meta) { + this.status = status; + this.reason = reason; + this.meta = meta; + } + + /** + * Creates a new {@code ValidationResult} indicating a successful validation. + *

+ * This method should be used to indicate that the validation passed without any issues. + *

+ * + * @return a {@code ValidationResult} indicating a successful validation. + */ + public static ValidationResult valid() { + return new ValidationResult(true, null, null); + } + + /** + * Creates a new {@code ValidationResult} indicating a failed validation with a specified reason. + *

+ * This method should be used to indicate that the validation failed and provide a reason for the failure. + *

+ * + * @param reason the reason why the validation failed. + * @return a {@code ValidationResult} indicating a failed validation. + */ + public static ValidationResult invalid(final String reason) { + return new ValidationResult(false, reason, null); + } + + /** + * Creates a new {@code ValidationResult} indicating a failed validation with a specified reason and metadata. + *

+ * This method should be used to indicate that the validation failed, provide a reason, and include + * additional context or metadata. + *

+ * + * @param reason the reason why the validation failed. + * @param meta additional metadata related to the validation result. + * @return a {@code ValidationResult} indicating a failed validation with metadata. + */ + public static ValidationResult invalid(final String reason, final Map meta) { + return new ValidationResult(false, reason, meta); + } + + /** + * Returns whether the validation was successful. + * + * @return {@code true} if the validation was successful, {@code false} otherwise. + */ + public boolean isValid() { + return this.status; + } + + /** + * Returns whether the validation failed. + * + * @return {@code true} if the validation failed, {@code false} otherwise. + */ + public boolean isInvalid() { + return !this.isValid(); + } + + /** + * Returns the reason for validation failure, if applicable. + * + * @return the reason for validation failure, or {@code null} if the validation was successful. + */ + public String getReason() { + return this.reason; + } + + /** + * Returns additional metadata related to the validation result. + * + * @return an unmodifiable map of metadata, or an empty map if no metadata is present. + */ + public Map getMeta() { + return this.meta; + } + + @Override + public String toString() { + return "ValidationResult{" + + "status=" + status + + ", reason='" + reason + '\'' + + ", meta=" + meta + + '}'; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java new file mode 100644 index 0000000000..34af49529c --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.util; + +import org.apache.commons.lang.StringUtils; +import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; + +/** + * Utility class for handling and validating authorization details in OAuth2 requests. + */ +public class AuthorizationDetailsUtils { + + /** + * Determines if the given {@link OAuth2Parameters} object contains + * {@link org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails AuthorizationDetails}. + * + * @param oAuth2Parameters The requested OAuth2 parameters to check. + * @return {@code true} if the OAuth2 parameters contain non-empty authorization details array, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuth2Parameters oAuth2Parameters) { + + return oAuth2Parameters.getAuthorizationDetails() != null && + !oAuth2Parameters.getAuthorizationDetails().getDetails().isEmpty(); + } + + /** + * Determines if the given {@link OAuthAuthzRequest} object contains {@code authorization_details}. + * + * @param oauthRequest The OAuth Authorization Request to check. + * @return {@code true} if the OAuth authorization request contains a non-blank authorization details parameter, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuthAuthzRequest oauthRequest) { + + return StringUtils.isNotBlank(oauthRequest.getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); + } +} diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 68e661c2aa..92f3e93171 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -258,6 +258,11 @@ org.wso2.orbit.javax.xml.bind jaxb-api
+ + org.wso2.carbon.identity.inbound.auth.oauth2 + org.wso2.carbon.identity.oauth.rar.common + provided + org.testng diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/IdentityOAuth2AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/IdentityOAuth2AuthorizationDetailsService.java new file mode 100644 index 0000000000..21ac2f67fd --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/IdentityOAuth2AuthorizationDetailsService.java @@ -0,0 +1,134 @@ +package org.wso2.carbon.identity.oauth2; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; +import org.wso2.carbon.identity.oauth2.model.AuthzCodeDO; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.common.dao.AuthorizationDetailsDAO; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; + +import java.sql.SQLException; +import java.util.Objects; + +/** + * IdentityOAuth2AuthorizationDetailsService is responsible for managing and handling OAuth2 authorization details, + * specifically in the context of rich authorization requests. + *

+ * This class integrates with the {@link AuthorizationDetailsDAO} to persist these details in the underlying data store. + * It also provides utility methods to check if a request contains rich authorization details. + *

+ * + * @see AuthorizationDetailsDAO + * @see AuthorizationDetails + */ +public class IdentityOAuth2AuthorizationDetailsService { + + private static final Log log = LogFactory.getLog(IdentityOAuth2AuthorizationDetailsService.class); + protected final AuthorizationDetailsDAO authorizationDetailsDAO; + + /** + * Default constructor that initializes the service with the default {@link AuthorizationDetailsDAO}. + *

+ * This constructor uses the default DAO provided by the {@link OAuthTokenPersistenceFactory} + * to handle the persistence of authorization details. + *

+ */ + public IdentityOAuth2AuthorizationDetailsService() { + + this(OAuthTokenPersistenceFactory.getInstance().getAuthorizationDetailsDAO()); + } + + /** + * Constructor that initializes the service with a given {@link AuthorizationDetailsDAO}. + * + * @param authorizationDetailsDAO The {@link AuthorizationDetailsDAO} instance to be used for + * handling authorization details persistence. Must not be {@code null}. + */ + public IdentityOAuth2AuthorizationDetailsService(final AuthorizationDetailsDAO authorizationDetailsDAO) { + + this.authorizationDetailsDAO = Objects + .requireNonNull(authorizationDetailsDAO, "AuthorizationDetailsDAO must not be null"); + } + + /** + * Determines if the given {@link OAuthAuthzReqMessageContext} object contains {@link AuthorizationDetails}. + * + * @param oAuthAuthzReqMessageContext The requested OAuthAuthzReqMessageContext to check. + * @return {@code true} if the OAuthAuthzReqMessageContext contains non-empty authorization details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) { + + return isRichAuthorizationRequest(oAuthAuthzReqMessageContext.getAuthorizationDetails()); + } + + /** + * Determines if the request is a rich authorization request using provided {@link AuthorizationDetails} object. + *

+ * This method checks if the specified {@link AuthorizationDetails} instance is not {@code null} + * and has a non-empty details set. + * + * @param authorizationDetails The {@link AuthorizationDetails} to check. + * @return {@code true} if the {@link AuthorizationDetails} is not {@code null} and has a non-empty details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final AuthorizationDetails authorizationDetails) { + + return authorizationDetails != null && !authorizationDetails.getDetails().isEmpty(); + } + + /** + * Determines if the given {@link OAuth2Parameters} object contains {@link AuthorizationDetails}. + * + * @param oAuth2Parameters The requested OAuth2Parameters to check. + * @return {@code true} if the OAuth2Parameters contains non-empty authorization details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuth2Parameters oAuth2Parameters) { + + return isRichAuthorizationRequest(oAuth2Parameters.getAuthorizationDetails()); + } + + /** + * Stores the OAuth2 code authorization details if the request is a rich authorization request. + *

+ * This method checks whether the given {@link OAuthAuthzReqMessageContext} contains {@link AuthorizationDetails}. + * If it does, it retrieves the tenant ID from the request context and stores the authorization + * details using the {@link AuthorizationDetailsDAO}. + *

+ * + * @param authzCodeDO The {@link AuthzCodeDO} object containing the authorization code details. + * @param oAuthAuthzReqMessageContext The {@link OAuthAuthzReqMessageContext} containing the request context. + * @throws IdentityOAuth2Exception If an error occurs while storing the authorization details. + */ + public void storeOAuth2CodeAuthorizationDetails(final AuthzCodeDO authzCodeDO, + final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) + throws IdentityOAuth2Exception { + + if (!isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) { + log.debug("Request is not a rich authorization request. Skipping storage of code authorization details."); + return; + } + + try { + final int tenantID = OAuth2Util.getTenantId( + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getTenantDomain()); + // Storing the authorization details. + this.authorizationDetailsDAO.addOAuth2CodeAuthorizationDetails( + authzCodeDO.getAuthzCodeId(), + oAuthAuthzReqMessageContext.getAuthorizationDetails(), + tenantID); + + if (log.isDebugEnabled()) { + log.debug("Successfully stored OAuth2 Code authorization details for code Id: " + + authzCodeDO.getAuthzCodeId()); + } + } catch (SQLException e) { + log.error("Error occurred while storing OAuth2 Code authorization details. Caused by, ", e); + throw new IdentityOAuth2Exception("Error occurred while storing authorization details", e); + } + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java index c2c0d44ecf..a654475ddb 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java @@ -676,7 +676,7 @@ private boolean isInvalidResponseType(OAuth2AuthorizeReqDTO authzReqDTO, OAuth2A return false; } - private OAuthAppDO getAppInformation(OAuth2AuthorizeReqDTO authzReqDTO) throws IdentityOAuth2Exception, + public OAuthAppDO getAppInformation(OAuth2AuthorizeReqDTO authzReqDTO) throws IdentityOAuth2Exception, InvalidOAuthClientException { OAuthAppDO oAuthAppDO = AppInfoCache.getInstance().getValueFromCache(authzReqDTO.getConsumerKey()); if (oAuthAppDO != null) { diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java index 35d57287f7..2df67714c2 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.oauth2.authz; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; import java.io.Serializable; import java.util.Properties; @@ -56,6 +57,8 @@ public class OAuthAuthzReqMessageContext implements Serializable { private Properties properties = new Properties(); + private AuthorizationDetails authorizationDetails; + public OAuthAuthzReqMessageContext(OAuth2AuthorizeReqDTO authorizationReqDTO) { this.authorizationReqDTO = authorizationReqDTO; @@ -212,4 +215,26 @@ public void setSubjectTokenFlow(boolean subjectTokenFlow) { isSubjectTokenFlow = subjectTokenFlow; } + + /** + * Retrieves the current authorization details. + * + * @return the {@link AuthorizationDetails} instance representing the current authorization information. + * If no authorization details are available, it will return {@code null}. + */ + public AuthorizationDetails getAuthorizationDetails() { + + return this.authorizationDetails; + } + + /** + * Sets the authorization details. + * This method updates the authorization details with the provided {@link AuthorizationDetails} instance. + * + * @param authorizationDetails the {@link AuthorizationDetails} to set. + */ + public void setAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + this.authorizationDetails = authorizationDetails; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java index bc1b5a78bb..287d2d8b57 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java @@ -32,6 +32,7 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2AuthorizationDetailsService; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; @@ -59,6 +60,7 @@ public abstract class AbstractResponseTypeHandler implements ResponseTypeHandler protected boolean cacheEnabled; protected OAuthCache oauthCache; private OAuthCallbackManager callbackManager; + protected IdentityOAuth2AuthorizationDetailsService identityOAuth2AuthorizationDetailsService; @Override public void init() throws IdentityOAuth2Exception { @@ -68,6 +70,7 @@ public void init() throws IdentityOAuth2Exception { if (cacheEnabled) { oauthCache = OAuthCache.getInstance(); } + this.identityOAuth2AuthorizationDetailsService = new IdentityOAuth2AuthorizationDetailsService(); } @Override diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandler.java index adb9dfefd1..489226250f 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandler.java @@ -47,6 +47,8 @@ public OAuth2AuthorizeRespDTO issue(OAuthAuthzReqMessageContext oauthAuthzMsgCtx AuthzCodeDO authorizationCode = ResponseTypeHandlerUtil.generateAuthorizationCode(oauthAuthzMsgCtx, cacheEnabled); + super.identityOAuth2AuthorizationDetailsService + .storeOAuth2CodeAuthorizationDetails(authorizationCode, oauthAuthzMsgCtx); String sessionDataKey = oauthAuthzMsgCtx.getAuthorizationReqDTO().getSessionDataKey(); if (log.isDebugEnabled()) { 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 c90c4285e6..68aa46f7d8 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 @@ -21,6 +21,8 @@ package org.wso2.carbon.identity.oauth2.dao; import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; +import org.wso2.carbon.identity.oauth2.rar.common.dao.AuthorizationDetailsDAO; +import org.wso2.carbon.identity.oauth2.rar.common.dao.AuthorizationDetailsDAOImpl; import org.wso2.carbon.identity.openidconnect.dao.CacheBackedScopeClaimMappingDAOImpl; import org.wso2.carbon.identity.openidconnect.dao.RequestObjectDAO; import org.wso2.carbon.identity.openidconnect.dao.RequestObjectDAOImpl; @@ -40,6 +42,7 @@ public class OAuthTokenPersistenceFactory { private ScopeClaimMappingDAO scopeClaimMappingDAO; private TokenBindingMgtDAO tokenBindingMgtDAO; private OAuthUserConsentedScopesDAO oauthUserConsentedScopesDAO; + private final AuthorizationDetailsDAO authorizationDetailsDAO; public OAuthTokenPersistenceFactory() { @@ -51,6 +54,7 @@ public OAuthTokenPersistenceFactory() { this.scopeClaimMappingDAO = new CacheBackedScopeClaimMappingDAOImpl(); this.tokenBindingMgtDAO = new TokenBindingMgtDAOImpl(); this.oauthUserConsentedScopesDAO = new CacheBackedOAuthUserConsentedScopesDAOImpl(); + this.authorizationDetailsDAO = new AuthorizationDetailsDAOImpl(); } public static OAuthTokenPersistenceFactory getInstance() { @@ -107,4 +111,17 @@ public OAuthUserConsentedScopesDAO getOAuthUserConsentedScopesDAO() { return oauthUserConsentedScopesDAO; } + + /** + * Retrieves the DAO for authorization details. + *

+ * This method returns an {@link AuthorizationDetailsDAO} singleton instance that provides access to the + * {@link org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails} data. This DAO is used to interact + * with the underlying data store to fetch and manipulate authorization information. + *

+ * @return the {@link AuthorizationDetailsDAO} instance that provides access to authorization details data. + */ + public AuthorizationDetailsDAO getAuthorizationDetailsDAO() { + return this.authorizationDetailsDAO; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/model/OAuth2Parameters.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/model/OAuth2Parameters.java index 5bc77e5bea..868a5ff164 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/model/OAuth2Parameters.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/model/OAuth2Parameters.java @@ -18,6 +18,8 @@ package org.wso2.carbon.identity.oauth2.model; +import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; + import java.io.Serializable; import java.util.LinkedHashSet; import java.util.Set; @@ -55,6 +57,7 @@ public class OAuth2Parameters implements Serializable { private boolean isRequestObjectFlow; private boolean isMtlsRequest; private String requestedSubjectId; + private AuthorizationDetails authorizationDetails; public String getRequestedSubjectId() { @@ -328,4 +331,26 @@ public void setIsMtlsRequest(boolean isMtlsRequest) { this.isMtlsRequest = isMtlsRequest; } + + /** + * Retrieves the current authorization details. + * + * @return the {@link AuthorizationDetails} instance representing the current authorization information. + * If no authorization details are available, it will return {@code null}. + */ + public AuthorizationDetails getAuthorizationDetails() { + + return this.authorizationDetails; + } + + /** + * Sets the authorization details. + * This method updates the authorization details with the provided {@link AuthorizationDetails} instance. + * + * @param authorizationDetails the {@link AuthorizationDetails} to set. + */ + public void setAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + this.authorizationDetails = authorizationDetails; + } } diff --git a/pom.xml b/pom.xml index 93aaedf6c6..278ca1bfc9 100644 --- a/pom.xml +++ b/pom.xml @@ -67,6 +67,8 @@ features/org.wso2.carbon.identity.oauth.server.feature features/org.wso2.carbon.identity.oauth.ui.feature features/org.wso2.carbon.identity.oauth.dcr.server.feature + components/org.wso2.carbon.identity.oauth.rar.common + components/org.wso2.carbon.identity.oauth.rar @@ -402,6 +404,11 @@ gson ${com.google.code.gson.version}
+ + com.google.auto.service + auto-service + ${com.google.auto.service.version} + @@ -547,6 +554,16 @@ org.wso2.carbon.identity.oauth.extension ${project.version} + + org.wso2.carbon.identity.inbound.auth.oauth2 + org.wso2.carbon.identity.oauth.rar + ${project.version} + + + org.wso2.carbon.identity.inbound.auth.oauth2 + org.wso2.carbon.identity.oauth.rar.common + ${project.version} + @@ -994,6 +1011,7 @@ 2.4.7 5.2 9.2 + 1.1.1 5.1.2 From f7544ce0bcef1945b2015994e49b7e8cc8fb9c1a Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 26 Jul 2024 17:10:34 +0530 Subject: [PATCH 02/28] Accept and persist authorization_details of token request - Accept 'authorization_details' field in the token request - Persist access token authorization details in the database - Moving common logic from oauth.rar.common module to a new rar package within oauth module - Adds RAR support for hybrid authorization flows --- .../identity/oauth/common/OAuthConstants.java | 4 + .../endpoint/authz/OAuth2AuthzEndpoint.java | 90 ++- .../AuthorizationDetailsServiceFactory.java | 47 ++ .../endpoint/token/OAuth2TokenEndpoint.java | 16 + .../oauth/endpoint/util/EndpointUtil.java | 30 +- .../src/main/webapp/WEB-INF/cxf-servlet.xml | 2 + .../pom.xml | 60 -- .../common/dao/AuthorizationDetailsDAO.java | 69 --- .../dto/AuthorizationDetailsCodeDTO.java | 22 - .../dto/AuthorizationDetailsConsentDTO.java | 38 -- .../common/dto/AuthorizationDetailsDTO.java | 53 -- .../pom.xml | 44 +- .../rar/AuthorizationDetailsService.java | 278 --------- .../rar/AuthorizationDetailsValidator.java | 171 ------ .../rar/dao/AuthorizationDetailsDAO.java | 125 ++++ .../rar}/dao/AuthorizationDetailsDAOImpl.java | 156 +++-- .../identity/oauth2/rar}/dao/SQLQueries.java | 35 +- .../dto/AuthorizationDetailsConsentDTO.java | 67 +++ .../rar/dto/AuthorizationDetailsDTO.java | 98 +++ .../rar/dto/AuthorizationDetailsTokenDTO.java | 51 ++ ...thorizationDetailsProcessingException.java | 30 - .../RARAccessTokenResponseHandler.java | 61 -- .../AuthorizationDetailsDataHolder.java | 94 --- .../AuthorizationDetailsServiceComponent.java | 69 --- .../rar}/model/AuthorizationDetail.java | 61 +- .../rar}/model/AuthorizationDetails.java | 39 +- .../model/AuthorizationDetailsContext.java | 98 --- .../util/AuthorizationDetailsCommonUtils.java | 76 ++- .../util/AuthorizationDetailsConstants.java | 2 +- .../rar/util/AuthorizationDetailsUtils.java | 56 -- .../org.wso2.carbon.identity.oauth/pom.xml | 2 +- ...tityOAuth2AuthorizationDetailsService.java | 134 ----- .../authz/AuthorizationHandlerManager.java | 22 + .../authz/OAuthAuthzReqMessageContext.java | 2 +- .../handlers/AbstractResponseTypeHandler.java | 4 +- .../handlers/CodeResponseTypeHandler.java | 2 - .../util/ResponseTypeHandlerUtil.java | 3 + .../dao/OAuthTokenPersistenceFactory.java | 4 +- .../oauth2/dto/OAuth2AccessTokenReqDTO.java | 25 + .../oauth2/dto/OAuth2AuthorizeReqDTO.java | 24 + .../oauth2/dto/OAuth2AuthorizeRespDTO.java | 25 + .../internal/OAuth2ServiceComponent.java | 9 + .../OAuth2ServiceComponentHolder.java | 32 +- .../oauth2/model/OAuth2Parameters.java | 2 +- .../rar/AuthorizationDetailsService.java | 558 ++++++++++++++++++ .../core/AuthorizationDetailsProcessor.java} | 30 +- .../AuthorizationDetailsProviderFactory.java | 39 +- ...thorizationDetailsProcessingException.java | 37 ++ .../model/AuthorizationDetailsContext.java | 154 +++++ .../token/AccessTokenResponseRARHandler.java | 49 ++ .../token/IntrospectionRARDataProvider.java | 118 ++++ .../token/JWTAccessTokenRARClaimProvider.java | 70 +++ .../rar/util/AuthorizationDetailsUtils.java | 341 +++++++++++ .../AuthorizationDetailsValidator.java | 62 ++ .../DefaultAuthorizationDetailsValidator.java | 289 +++++++++ .../provider/SuccessResponseDTO.java | 23 + .../impl/FragmentResponseModeProvider.java | 10 + .../oauth2/token/AccessTokenIssuer.java | 37 ++ .../token/OAuthTokenReqMessageContext.java | 25 + .../AbstractAuthorizationGrantHandler.java | 27 + .../grant/AuthorizationCodeGrantHandler.java | 5 +- .../handlers/grant/RefreshGrantHandler.java | 3 + pom.xml | 6 - 63 files changed, 2761 insertions(+), 1454 deletions(-) create mode 100644 components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/AuthorizationDetailsServiceFactory.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/pom.xml delete mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAO.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsCodeDTO.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsConsentDTO.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsDTO.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsValidator.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java rename components/{org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common => org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar}/dao/AuthorizationDetailsDAOImpl.java (64%) rename components/{org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common => org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar}/dao/SQLQueries.java (58%) create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsConsentDTO.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsTokenDTO.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/handler/RARAccessTokenResponseHandler.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsDataHolder.java delete mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsServiceComponent.java rename components/{org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common => org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar}/model/AuthorizationDetail.java (91%) rename components/{org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common => org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar}/model/AuthorizationDetails.java (80%) delete mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java rename components/{org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common => org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar}/util/AuthorizationDetailsCommonUtils.java (68%) rename components/{org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common => org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar}/util/AuthorizationDetailsConstants.java (96%) delete mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java delete mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/IdentityOAuth2AuthorizationDetailsService.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java rename components/{org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProvider.java => org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessor.java} (75%) rename components/{org.wso2.carbon.identity.oauth.rar => org.wso2.carbon.identity.oauth}/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java (75%) create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/AuthorizationDetailsValidator.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java diff --git a/components/org.wso2.carbon.identity.oauth.common/src/main/java/org/wso2/carbon/identity/oauth/common/OAuthConstants.java b/components/org.wso2.carbon.identity.oauth.common/src/main/java/org/wso2/carbon/identity/oauth/common/OAuthConstants.java index 57e7feac1e..78437a236b 100644 --- a/components/org.wso2.carbon.identity.oauth.common/src/main/java/org/wso2/carbon/identity/oauth/common/OAuthConstants.java +++ b/components/org.wso2.carbon.identity.oauth.common/src/main/java/org/wso2/carbon/identity/oauth/common/OAuthConstants.java @@ -749,6 +749,9 @@ public static class ActionIDs { public static final String VALIDATE_EXISTING_CONSENT = "validate-existing-consent"; public static final String GENERATE_INTROSPECTION_RESPONSE = "generate-introspect-response"; public static final String RECEIVE_REVOKE_REQUEST = "receive-revoke-request"; + public static final String VALIDATE_AUTHORIZATION_DETAILS = "validate-authorization-details"; + public static final String VALIDATE_AUTHORIZATION_DETAILS_BEFORE_CONSENT + = "validate-authorization-details-before-consent"; } /** @@ -768,6 +771,7 @@ public static class InputKeys { public static final String CALLBACK_URI = "callback URI"; public static final String PROMPT = "prompt"; public static final String APP_STATE = "app state"; + public static final String REQUESTED_AUTHORIZATION_DETAILS = "requested authorization details"; } /** diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java index 47f2f21f5b..6c3a897d52 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java @@ -116,10 +116,10 @@ import org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.IdentityOAuth2ScopeException; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException; import org.wso2.carbon.identity.oauth2.IdentityOAuth2UnauthorizedScopeException; import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.RequestObjectException; -import org.wso2.carbon.identity.oauth2.authz.AuthorizationHandlerManager; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthService; @@ -136,10 +136,9 @@ import org.wso2.carbon.identity.oauth2.model.HttpRequestHeaderHandler; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; -import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsValidator; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; -import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.responsemode.provider.AuthorizationResponseDTO; import org.wso2.carbon.identity.oauth2.responsemode.provider.ResponseModeProvider; @@ -1717,13 +1716,12 @@ private void storeUserConsent(OAuthMessage oAuthMessage, String consent) throws if (approvedAlways) { OpenIDConnectUserRPStore.getInstance().putUserRPToStore(loggedInUser, applicationName, true, clientId); - final AuthorizationDetails userConsentedAuthorizationDetails = - authorizationDetailsService.getUserConsentedAuthorizationDetails( - oAuthMessage.getRequest().getParameterMap(), oauth2Params); + final AuthorizationDetails userConsentedAuthorizationDetails = AuthorizationDetailsUtils + .extractAuthorizationDetailsFromRequest(oAuthMessage.getRequest(), oauth2Params); if (hasPromptContainsConsent(oauth2Params)) { EndpointUtil.storeOAuthScopeConsent(loggedInUser, oauth2Params, true); - authorizationDetailsService.storeOrReplaceUserConsentedAuthorizationDetails(loggedInUser, + authorizationDetailsService.replaceUserConsentedAuthorizationDetails(loggedInUser, clientId, oauth2Params, userConsentedAuthorizationDetails); } else { EndpointUtil.storeOAuthScopeConsent(loggedInUser, oauth2Params, false); @@ -1868,6 +1866,7 @@ private OAuthResponse handleSuccessAuthorization(OAuthMessage oAuthMessage, OIDC if (isResponseTypeNotIdTokenOrNone(responseType, authzRespDTO)) { setAccessToken(authzRespDTO, builder, authorizationResponseDTO); setScopes(authzRespDTO, builder, authorizationResponseDTO); + setAuthorizationDetails(authzRespDTO, builder, authorizationResponseDTO); } if (isSubjectTokenFlow(responseType, authzRespDTO)) { setSubjectToken(authzRespDTO, builder, authorizationResponseDTO); @@ -2606,9 +2605,11 @@ private String populateOauthParameters(OAuth2Parameters params, OAuthMessage oAu } if (AuthorizationDetailsUtils.isRichAuthorizationRequest(oauthRequest)) { + final String authorizationDetailsJson = oauthRequest .getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS); - params.setAuthorizationDetails(new AuthorizationDetails(authorizationDetailsJson)); + params.setAuthorizationDetails(AuthorizationDetailsUtils + .generateAndAssignUniqueIDs(authorizationDetailsJson)); } handleMaxAgeParameter(oauthRequest, params); @@ -3015,7 +3016,7 @@ private String doUserAuthorization(OAuthMessage oAuthMessage, String sessionData } try { - validateAuthorizationDetailsBeforeConsent(oAuthMessage, oauth2Params, authzReqDTO); + validateAuthorizationDetailsBeforeConsent(oAuthMessage, oauth2Params); } catch (AuthorizationDetailsProcessingException e) { log.debug("Error occurred while validating authorization details. Caused by, ", e); @@ -3728,6 +3729,9 @@ private boolean isUserAlreadyApproved(OAuth2Parameters oauth2Params, Authenticat } catch (IdentityOAuth2ScopeException | IdentityOAuthAdminException e) { throw new OAuthSystemException("Error occurred while checking user has already approved the consent " + "required OAuth scopes.", e); + } catch (IdentityOAuth2Exception e) { + throw new OAuthSystemException("Error occurred while checking user has already approved the consent " + + "required authorization details.", e); } } @@ -3820,6 +3824,7 @@ private OAuth2AuthorizeReqDTO buildAuthRequest(OAuth2Parameters oauth2Params, Se authzReqDTO.setState(oauth2Params.getState()); authzReqDTO.setHttpServletRequestWrapper(new HttpServletRequestWrapper(request)); authzReqDTO.setRequestedSubjectId(oauth2Params.getRequestedSubjectId()); + authzReqDTO.setAuthorizationDetails(oauth2Params.getAuthorizationDetails()); if (sessionDataCacheEntry.getParamMap() != null && sessionDataCacheEntry.getParamMap().get(OAuthConstants .AMR) != null) { @@ -4808,14 +4813,12 @@ private Response handleUnsupportedGrantForApiBasedAuth() { * * @param oAuthMessage The {@link OAuthMessage} containing the authorization request details. * @param oAuth2Parameters The {@link OAuth2Parameters} object holding the parameters of the OAuth request. - * @param oAuth2AuthorizeReqDTO The {@link OAuth2AuthorizeReqDTO} object containing the authorization request. - * @throws OAuthSystemException If there is an error during the validation process. * @throws AuthorizationDetailsProcessingException If there is an error processing the authorization details. + * @throws OAuthSystemException If there is an error during the validation process. */ private void validateAuthorizationDetailsBeforeConsent(final OAuthMessage oAuthMessage, - final OAuth2Parameters oAuth2Parameters, - final OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO) - throws OAuthSystemException, AuthorizationDetailsProcessingException { + final OAuth2Parameters oAuth2Parameters) + throws AuthorizationDetailsProcessingException, OAuthSystemException { if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuth2Parameters)) { log.debug("Authorization request is not a rich authorization request. Skipping validation."); @@ -4823,26 +4826,61 @@ private void validateAuthorizationDetailsBeforeConsent(final OAuthMessage oAuthM } try { - final OAuthAppDO oAuthAppDO = AuthorizationHandlerManager.getInstance() - .getAppInformation(oAuth2AuthorizeReqDTO); + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + OAuthConstants.LogConstants.OAUTH_INBOUND_SERVICE, + OAuthConstants.LogConstants.ActionIDs.VALIDATE_AUTHORIZATION_DETAILS_BEFORE_CONSENT); + diagnosticLogBuilder.inputParam(LogConstants.InputKeys.CLIENT_ID, oAuth2Parameters.getClientId()) + .inputParam(LogConstants.InputKeys.APPLICATION_NAME, oAuth2Parameters.getApplicationName()) + .inputParam("authorization details to be validated", + oAuth2Parameters.getAuthorizationDetails().toSet()) + .resultStatus(DiagnosticLog.ResultStatus.SUCCESS) + .resultMessage("authorization details validation started") + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + + final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext = + oAuthMessage.getSessionDataCacheEntry().getAuthzReqMsgCtx(); + // Validate the authorization details - final AuthorizationDetails validatedAuthorizationDetails = new AuthorizationDetailsValidator() - .getValidatedAuthorizationDetails(oAuth2Parameters, oAuthAppDO, oAuth2AuthorizeReqDTO.getUser()); + final AuthorizationDetails validatedAuthorizationDetails = OAuth2ServiceComponentHolder.getInstance() + .getAuthorizationDetailsValidator() + .getValidatedAuthorizationDetails(oAuthAuthzReqMessageContext); - if (log.isDebugEnabled()) { - log.debug("Authorization details validated successfully for user: " - + oAuth2AuthorizeReqDTO.getUser().getLoggableMaskedUserId()); - } // update oAuth2Parameters with validated authorization details oAuth2Parameters.setAuthorizationDetails(validatedAuthorizationDetails); // Update the authorization message context with validated authorization details - OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext = - oAuthMessage.getSessionDataCacheEntry().getAuthzReqMsgCtx(); oAuthAuthzReqMessageContext.setAuthorizationDetails(validatedAuthorizationDetails); - } catch (IdentityOAuth2Exception | InvalidOAuthClientException e) { + oAuthMessage.getSessionDataCacheEntry().setAuthzReqMsgCtx(oAuthAuthzReqMessageContext); + + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + OAuthConstants.LogConstants.OAUTH_INBOUND_SERVICE, + OAuthConstants.LogConstants.ActionIDs.VALIDATE_AUTHORIZATION_DETAILS_BEFORE_CONSENT); + diagnosticLogBuilder.inputParam(LogConstants.InputKeys.CLIENT_ID, oAuth2Parameters.getClientId()) + .inputParam(LogConstants.InputKeys.APPLICATION_NAME, oAuth2Parameters.getApplicationName()) + .inputParam("authorization details after validation", + oAuth2Parameters.getAuthorizationDetails().toSet()) + .resultStatus(DiagnosticLog.ResultStatus.SUCCESS) + .resultMessage("authorization details validation completed") + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + } catch (IdentityOAuth2ServerException e) { log.error("Error occurred while validating authorization details. Caused by, ", e); throw new OAuthSystemException("Error occurred while validating requested authorization details", e); } } + + private void setAuthorizationDetails(final OAuth2AuthorizeRespDTO oAuth2AuthorizeRespDTO, + final OAuthASResponse.OAuthAuthorizationResponseBuilder builder, + final AuthorizationResponseDTO authorizationResponseDTO) { + + final AuthorizationDetails authorizationDetails = oAuth2AuthorizeRespDTO.getAuthorizationDetails(); + builder.setParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS, + AuthorizationDetailsUtils.getUrlEncodedAuthorizationDetails(authorizationDetails)); + authorizationResponseDTO.getSuccessResponseDTO().setAuthorizationDetails(authorizationDetails); + } } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/AuthorizationDetailsServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/AuthorizationDetailsServiceFactory.java new file mode 100644 index 0000000000..f33588a722 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/AuthorizationDetailsServiceFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth.endpoint.factory; + +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; + +/** + * This class is used to register AuthorizationDetailsService as a factory bean. + */ +public class AuthorizationDetailsServiceFactory extends AbstractFactoryBean { + + private AuthorizationDetailsService authorizationDetailsService; + + @Override + public Class getObjectType() { + + return AuthorizationDetailsService.class; + } + + @Override + protected AuthorizationDetailsService createInstance() throws Exception { + + if (this.authorizationDetailsService == null) { + this.authorizationDetailsService = + OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsService(); + } + return this.authorizationDetailsService; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/token/OAuth2TokenEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/token/OAuth2TokenEndpoint.java index 54403f9d35..b521a4c799 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/token/OAuth2TokenEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/token/OAuth2TokenEndpoint.java @@ -46,6 +46,9 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO; import org.wso2.carbon.identity.oauth2.model.CarbonOAuthTokenRequest; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.token.handlers.response.OAuth2TokenResponse; import org.wso2.carbon.user.core.util.UserCoreUtil; import org.wso2.carbon.utils.DiagnosticLog; @@ -407,6 +410,19 @@ private OAuth2AccessTokenReqDTO buildAccessTokenReqDTO(CarbonOAuthTokenRequest o tokenReqDTO.setWindowsToken(oauthRequest.getWindowsToken()); } tokenReqDTO.addAuthenticationMethodReference(grantType); + + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(oauthRequest)) { + final String encodedAuthorizationDetailsJson = oauthRequest + .getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS); + final String authorizationDetailsJson = AuthorizationDetailsUtils + .getUrlDecodedAuthorizationDetails(encodedAuthorizationDetailsJson); + + if (log.isDebugEnabled()) { + log.debug("Adding requested authorization details to tokenReqDTO: " + authorizationDetailsJson); + } + tokenReqDTO.setAuthorizationDetails(new AuthorizationDetails(authorizationDetailsJson)); + } + return tokenReqDTO; } } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java index 4129b752b7..4d0d9a3722 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java @@ -103,7 +103,8 @@ import org.wso2.carbon.identity.oauth2.model.CarbonOAuthAuthzRequest; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.model.OAuth2ScopeConsentResponse; -import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.scopeservice.OAuth2Resource; import org.wso2.carbon.identity.oauth2.scopeservice.ScopeMetadataService; @@ -872,8 +873,9 @@ public static String getUserConsentURL(OAuth2Parameters params, String loggedInU // Append authorization details to consent page url if (AuthorizationDetailsUtils.isRichAuthorizationRequest(params)) { - consentPageUrl = consentPageUrl + "&" + AuthorizationDetailsConstants.AUTHORIZATION_DETAILS + "=" - + URLEncoder.encode(params.getAuthorizationDetails().toJsonString(), UTF_8); + additionalQueryParams = additionalQueryParams + "&" + + AuthorizationDetailsConstants.AUTHORIZATION_DETAILS + "=" + AuthorizationDetailsUtils + .getUrlEncodedAuthorizationDetails(filterConsentRequiredAuthorizationDetails(user, params)); } // Append scope metadata to additionalQueryParams. @@ -2153,4 +2155,26 @@ public static void preHandleParRequest(HttpServletRequest request, Map + @@ -103,4 +104,5 @@ + diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/pom.xml b/components/org.wso2.carbon.identity.oauth.rar.common/pom.xml deleted file mode 100644 index 1ac995d59f..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar.common/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - org.wso2.carbon.identity.inbound.auth.oauth2 - identity-inbound-auth-oauth - 7.0.107-SNAPSHOT - ../../pom.xml - - - 4.0.0 - org.wso2.carbon.identity.oauth.rar.common - jar - WSO2 Carbon - Rich Authorization Requests Common - http://wso2.org - - - UTF-8 - - - - - org.wso2.carbon.identity.framework - org.wso2.carbon.identity.core - provided - - - - com.fasterxml.jackson.core - jackson-databind - provided - - - - junit - junit - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - - - - com.github.spotbugs - spotbugs-maven-plugin - - High - 2048 - - - - - - diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAO.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAO.java deleted file mode 100644 index a21b68b4d7..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAO.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.oauth2.rar.common.dao; - -import org.wso2.carbon.identity.oauth2.rar.common.dto.AuthorizationDetailsConsentDTO; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; - -import java.sql.SQLException; -import java.util.List; -import java.util.Set; - -/** - * Provides methods to interact with the database to manage authorization details. - */ -public interface AuthorizationDetailsDAO { - - /** - * Adds authorization details against a given OAuth2 code. - * - * @param authorizationCodeID The ID of the authorization code. - * @param authorizationDetails The authorization details to store. - * @param tenantId The tenant ID. - * @return An array of positive integers indicating the number of rows affected for each batch operation, - * or negative integers if any of the batch operations fail. - * @throws SQLException If a database access error occurs. - */ - int[] addOAuth2CodeAuthorizationDetails(String authorizationCodeID, AuthorizationDetails authorizationDetails, - int tenantId) throws SQLException; - - /** - * Adds user consented authorization details. - * - * @param authorizationDetailsConsentDTOs List of user consented authorization details DTOs. - * {@link AuthorizationDetailsConsentDTO } - * @return An array of positive integers indicating the number of rows affected for each batch operation, - * or negative integers if any of the batch operations fail. - * @throws SQLException If a database access error occurs. - */ - int[] addUserConsentedAuthorizationDetails(List authorizationDetailsConsentDTOs) - throws SQLException; - - int deleteUserConsentedAuthorizationDetails(String consentId, int tenantId) - throws SQLException; - - // add a todo and mention to move this to consent module - String getConsentIdByUserIdAndAppId(String userId, String appId, int tenantId) throws SQLException; - - Set getUserConsentedAuthorizationDetails(String consentId, int tenantId) - throws SQLException; - - int[] updateUserConsentedAuthorizationDetails(List authorizationDetailsConsentDTOs) - throws SQLException; -} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsCodeDTO.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsCodeDTO.java deleted file mode 100644 index bc143a9325..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsCodeDTO.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.wso2.carbon.identity.oauth2.rar.common.dto; - -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; - -/** - * - */ -public class AuthorizationDetailsCodeDTO extends AuthorizationDetailsDTO { - - final String codeId; - - public AuthorizationDetailsCodeDTO(final String id, final String codeId, final int typeId, - final AuthorizationDetail authorizationDetail, final int tenantId) { - - super(id, typeId, authorizationDetail, tenantId); - this.codeId = codeId; - } - - public String getCodeId() { - return codeId; - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsConsentDTO.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsConsentDTO.java deleted file mode 100644 index 0cf61dc230..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsConsentDTO.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.wso2.carbon.identity.oauth2.rar.common.dto; - -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; - -/** - * - */ -public class AuthorizationDetailsConsentDTO extends AuthorizationDetailsDTO { - - final String consentId; - final boolean isConsentActive; - - public AuthorizationDetailsConsentDTO(final String id, final String consentId, final int typeId, - final String authorizationDetail, - final boolean isConsentActive, final int tenantId) { - - super(id, typeId, authorizationDetail, tenantId); - this.consentId = consentId; - this.isConsentActive = isConsentActive; - } - - public AuthorizationDetailsConsentDTO(final String consentId, - final AuthorizationDetail authorizationDetail, - final boolean isConsentActive, final int tenantId) { - - super(authorizationDetail, tenantId); - this.consentId = consentId; - this.isConsentActive = isConsentActive; - } - - public boolean isConsentActive() { - return isConsentActive; - } - - public String getConsentId() { - return consentId; - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsDTO.java b/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsDTO.java deleted file mode 100644 index fa73865c8b..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dto/AuthorizationDetailsDTO.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.wso2.carbon.identity.oauth2.rar.common.dto; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; -import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsCommonUtils; - -/** - * - */ -public class AuthorizationDetailsDTO { - - final String id; - final int typeId; - final AuthorizationDetail authorizationDetail; - final int tenantId; - - public AuthorizationDetailsDTO(final String id, final int typeId, final AuthorizationDetail authorizationDetail, - final int tenantId) { - - this.id = id; - this.typeId = typeId; - this.authorizationDetail = authorizationDetail; - this.tenantId = tenantId; - } - - public AuthorizationDetailsDTO(final String id, final int typeId, final String authorizationDetailJson, - final int tenantId) { - - this(id, typeId, AuthorizationDetailsCommonUtils - .fromJSON(authorizationDetailJson, AuthorizationDetail.class, new ObjectMapper()), tenantId); - } - - public AuthorizationDetailsDTO(final AuthorizationDetail authorizationDetail, final int tenantId) { - - this(null, 0, authorizationDetail, tenantId); - } - - public String getId() { - return this.id; - } - - public int getTypeId() { - return this.typeId; - } - - public AuthorizationDetail getAuthorizationDetail() { - return this.authorizationDetail; - } - - public int getTenantId() { - return this.tenantId; - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index bb6bc7c861..ad80a06a34 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -29,7 +29,7 @@ 4.0.0 org.wso2.carbon.identity.oauth.rar - bundle + jar WSO2 Carbon - Rich Authorization Requests http://wso2.org @@ -39,8 +39,8 @@ - org.wso2.carbon.identity.inbound.auth.oauth2 - org.wso2.carbon.identity.oauth + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.core provided @@ -50,42 +50,20 @@ - org.wso2.carbon.identity.inbound.auth.oauth2 - org.wso2.carbon.identity.oauth.rar.common + com.fasterxml.jackson.core + jackson-databind + provided + + junit + junit + test + - - org.apache.felix - maven-bundle-plugin - true - - - - ${project.artifactId} - - - org.wso2.carbon.identity.oauth2.rar.internal - - - org.osgi.framework; version="${osgi.framework.imp.pkg.version.range}", - org.osgi.service.component; version="${osgi.service.component.imp.pkg.version.range}", - org.wso2.carbon.identity.oauth2.*; version="${identity.inbound.auth.oauth.exp.pkg.version}", - - - !org.wso2.carbon.identity.oauth2.rar.internal, - org.wso2.carbon.identity.oauth2.rar.*; - version="${identity.inbound.auth.oauth.exp.pkg.version}", - - * - <_dsannotations>* - - - - org.apache.maven.plugins maven-compiler-plugin diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java deleted file mode 100644 index 00f4c97c96..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java +++ /dev/null @@ -1,278 +0,0 @@ -package org.wso2.carbon.identity.oauth2.rar; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.oltu.oauth2.common.exception.OAuthSystemException; -import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; -import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; -import org.wso2.carbon.identity.application.common.model.ServiceProvider; -import org.wso2.carbon.identity.oauth2.IdentityOAuth2AuthorizationDetailsService; -import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; -import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; -import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; -import org.wso2.carbon.identity.oauth2.rar.common.dao.AuthorizationDetailsDAO; -import org.wso2.carbon.identity.oauth2.rar.common.dto.AuthorizationDetailsConsentDTO; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProvider; -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; -import org.wso2.carbon.identity.oauth2.util.OAuth2Util; - -import java.sql.SQLException; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants.AUTHORIZATION_DETAILS_ID_PREFIX; - -/** - * - */ -public class AuthorizationDetailsService extends IdentityOAuth2AuthorizationDetailsService { - - private static final Log log = LogFactory.getLog(AuthorizationDetailsService.class); - private final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory; - - public AuthorizationDetailsService() { - - this(OAuthTokenPersistenceFactory.getInstance().getAuthorizationDetailsDAO(), - AuthorizationDetailsProviderFactory.getInstance()); - } - - public AuthorizationDetailsService(final AuthorizationDetailsDAO authorizationDetailsDAO, - final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory) { - - super(authorizationDetailsDAO); - this.authorizationDetailsProviderFactory = authorizationDetailsProviderFactory; - } - - public void storeUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, final String clientId, - final OAuth2Parameters oAuth2Parameters, - final AuthorizationDetails userConsentedAuthorizationDetails) - throws OAuthSystemException { - - if (!AuthorizationDetailsService.isRichAuthorizationRequest(oAuth2Parameters)) { - return; - } - - try { - final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); - final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); - - if (consentId.isPresent()) { - - super.authorizationDetailsDAO.addUserConsentedAuthorizationDetails( - generateAuthorizationDetailsConsentDTOs(consentId.get(), - userConsentedAuthorizationDetails, tenantId)); - } - } catch (SQLException | IdentityOAuth2Exception e) { - log.error("Error occurred while storing user consented authorization details. Caused by, ", e); - throw new OAuthSystemException("Error occurred while storing authorization details", e); - } - } - - public void updateUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, - final String clientId, final OAuth2Parameters oAuth2Parameters, - final AuthorizationDetails userConsentedAuthorizationDetails) - throws OAuthSystemException { - - if (!AuthorizationDetailsService.isRichAuthorizationRequest(oAuth2Parameters)) { - return; - } - - try { - final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); - final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); - - if (consentId.isPresent()) { - - super.authorizationDetailsDAO.updateUserConsentedAuthorizationDetails( - generateAuthorizationDetailsConsentDTOs(consentId.get(), - userConsentedAuthorizationDetails, tenantId)); - } - } catch (SQLException | IdentityOAuth2Exception e) { - log.error("Error occurred while updating user consented authorization details. Caused by, ", e); - throw new OAuthSystemException("Error occurred while updating authorization details", e); - } - } - - public void deleteUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, - final String clientId, final OAuth2Parameters oAuth2Parameters) - throws OAuthSystemException { - - if (!AuthorizationDetailsService.isRichAuthorizationRequest(oAuth2Parameters)) { - return; - } - - try { - final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); - final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); - - if (consentId.isPresent()) { - - super.authorizationDetailsDAO.deleteUserConsentedAuthorizationDetails(consentId.get(), tenantId); - } - } catch (SQLException | IdentityOAuth2Exception e) { - log.error("Error occurred while deleting user consented authorization details. Caused by, ", e); - throw new OAuthSystemException("Error occurred while storing authorization details", e); - } - } - - public void storeOrReplaceUserConsentedAuthorizationDetails( - final AuthenticatedUser authenticatedUser, final String clientId, final OAuth2Parameters oAuth2Parameters, - final AuthorizationDetails userConsentedAuthorizationDetails) throws OAuthSystemException { - - this.deleteUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters); - this.storeUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters, - userConsentedAuthorizationDetails); - } - - /** - * Check if the user has already given consent to requested authorization details. - * - * @param authenticatedUser Authenticated user. - * @param oAuth2Parameters OAuth2 parameters. - * @return True if user has given consent to all the requested authorization details. - */ - public boolean isUserAlreadyConsentedForAuthorizationDetails(final AuthenticatedUser authenticatedUser, - final OAuth2Parameters oAuth2Parameters) - throws OAuthSystemException { - - try { - final String userId = this.getUserId(authenticatedUser); - final String appId = this.getApplicationResourceIdFromClientId(oAuth2Parameters.getClientId()); - final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); - final Optional consentId = this.getConsentIdByUserIdAndAppId(userId, appId, tenantId); - - if (consentId.isPresent()) { - final Set consentedAuthorizationDetailsDTOs = - super.authorizationDetailsDAO.getUserConsentedAuthorizationDetails(consentId.get(), tenantId); - - final Map> consentedAuthorizationDetailsByType = - consentedAuthorizationDetailsDTOs - .stream() - .filter(AuthorizationDetailsConsentDTO::isConsentActive) - .map(AuthorizationDetailsConsentDTO::getAuthorizationDetail) - .collect(Collectors.groupingBy(AuthorizationDetail::getType, - Collectors.mapping(Function.identity(), Collectors.toSet()))); - - for (final AuthorizationDetail requestedAuthorizationDetail : - oAuth2Parameters.getAuthorizationDetails().getDetails()) { - - if (consentedAuthorizationDetailsByType.containsKey(requestedAuthorizationDetail.getType())) { - - final Optional provider = authorizationDetailsProviderFactory - .getProviderByType(requestedAuthorizationDetail.getType()); - if (provider.isPresent()) { - - final AuthorizationDetails existingAuthorizationDetails = new AuthorizationDetails( - consentedAuthorizationDetailsByType.get(requestedAuthorizationDetail.getType())); - if (!provider.get() - .isEqualOrSubset(requestedAuthorizationDetail, existingAuthorizationDetails)) { - - if (log.isDebugEnabled()) { - log.debug("User has not consented for the requested authorization details type: " - + requestedAuthorizationDetail.getType()); - - } - return false; - } - } - } - } - return true; - } - return false; - } catch (IdentityOAuth2Exception | SQLException e) { - log.error("Error occurred while extracting user consented authorization details. Caused by, ", e); - throw new OAuthSystemException("Error occurred while extracting user consented authorization details", e); - } - } - - /** - * Retrieves the user-consented authorization details based on the provided parameter map and OAuth2 parameters. - *

- * This method is used to extract and return the authorization details that the user has consented to, - * filtering them based on a provided authorization details in the parameter map. - *

- * - * @param parameterMap A map of query parameters. - * @param oAuth2Parameters The OAuth2 parameters that include the details of the authorization request. - * @return The {@link AuthorizationDetails} object containing the details the user has consented to. - */ - public AuthorizationDetails getUserConsentedAuthorizationDetails( - final Map parameterMap, final OAuth2Parameters oAuth2Parameters) { - - if (!isRichAuthorizationRequest(oAuth2Parameters)) { - return new AuthorizationDetails(); - } - - // Extract consented authorization detail IDs from the parameter map - final Set consentedAuthorizationDetailIDs = parameterMap.keySet().stream() - .filter(parameterName -> parameterName.startsWith(AUTHORIZATION_DETAILS_ID_PREFIX)) - .map(parameterName -> parameterName.substring(AUTHORIZATION_DETAILS_ID_PREFIX.length())) - .collect(Collectors.toSet()); - - // Filter and collect the consented authorization details - final Set consentedAuthorizationDetails = oAuth2Parameters.getAuthorizationDetails() - .stream() - .filter(authorizationDetail -> consentedAuthorizationDetailIDs.contains(authorizationDetail.getId())) - .collect(Collectors.toSet()); - - return new AuthorizationDetails(consentedAuthorizationDetails); - } - - public Optional getConsentIdByUserIdAndAppId(final String userId, final String appId, final int tenantId) - throws OAuthSystemException { - - try { - return Optional - .ofNullable(super.authorizationDetailsDAO.getConsentIdByUserIdAndAppId(userId, appId, tenantId)); - } catch (SQLException e) { - log.error(String.format("Error occurred while retrieving user consent by " + - "userId: %s and appId: %s. Caused by, ", userId, appId), e); - throw new OAuthSystemException("Error occurred while retrieving user consent", e); - } - } - - private String getApplicationResourceIdFromClientId(final String clientId) throws IdentityOAuth2Exception { - - final ServiceProvider serviceProvider = OAuth2Util.getServiceProvider(clientId); - if (serviceProvider != null) { - return serviceProvider.getApplicationResourceId(); - } - throw new IdentityOAuth2Exception("Unable to find a service provider for client Id: " + clientId); - } - - private String getUserId(final AuthenticatedUser authenticatedUser) throws OAuthSystemException { - try { - return authenticatedUser.getUserId(); - } catch (UserIdNotFoundException e) { - log.error("Error occurred while extracting userId from authenticated user. Caused by, ", e); - throw new OAuthSystemException( - "User id is not found for user: " + authenticatedUser.getLoggableMaskedUserId(), e); - } - } - - private List generateAuthorizationDetailsConsentDTOs( - final String consentId, final AuthorizationDetails userConsentedAuthorizationDetails, final int tenantId) { - - return userConsentedAuthorizationDetails.stream() - .map(authorizationDetail -> - new AuthorizationDetailsConsentDTO(consentId, authorizationDetail, true, tenantId)) - .collect(Collectors.toList()); - } - - private Optional getConsentId(final AuthenticatedUser authenticatedUser, final String clientId, - final int tenantId) - throws OAuthSystemException, IdentityOAuth2Exception { - - final String userId = this.getUserId(authenticatedUser); - final String appId = this.getApplicationResourceIdFromClientId(clientId); - - return this.getConsentIdByUserIdAndAppId(userId, appId, tenantId); - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsValidator.java deleted file mode 100644 index 6b67f226d8..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsValidator.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.oauth2.rar; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; -import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; -import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; -import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProvider; -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; -import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; -import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; -import org.wso2.carbon.identity.oauth2.rar.model.ValidationResult; - -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -/** - * {@code AuthorizationDetailsValidator} class responsible for managing and validating authorization details. - */ -public class AuthorizationDetailsValidator { - - private static final Log log = LogFactory.getLog(AuthorizationDetailsValidator.class); - private final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory; - - public AuthorizationDetailsValidator() { - - this(AuthorizationDetailsProviderFactory.getInstance()); - } - - public AuthorizationDetailsValidator(AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory) { - - this.authorizationDetailsProviderFactory = authorizationDetailsProviderFactory; - } - - /** - * Retrieves and validates the authorization details for a given OAuth2 parameters context. - * - * @param oAuth2Parameters The OAuth2 parameters associated with the request. - * @param oAuthAppDO The OAuth application details. - * @param authenticatedUser The authenticated user information. - * @return An {@link AuthorizationDetails} object containing the validated authorization details. - */ - public AuthorizationDetails getValidatedAuthorizationDetails( - final OAuth2Parameters oAuth2Parameters, final OAuthAppDO oAuthAppDO, - final AuthenticatedUser authenticatedUser) throws AuthorizationDetailsProcessingException { - - final Set validatedAuthorizationDetails = new HashSet<>(); - final Set authorizedAuthorizationDetailsTypes = this.getAuthorizedAuthorizationDetailsTypes( - oAuth2Parameters.getClientId(), oAuth2Parameters.getTenantDomain()); - for (AuthorizationDetail authorizationDetail : oAuth2Parameters.getAuthorizationDetails().getDetails()) { - - if (!isSupportedAuthorizationDetailType(authorizationDetail.getType())) { - throw new AuthorizationDetailsProcessingException(String.format(AuthorizationDetailsConstants - .TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT, authorizationDetail.getType())); - } - - if (isAuthorizedAuthorizationDetail(authorizationDetail, authorizedAuthorizationDetailsTypes)) { - - final AuthorizationDetailsContext authorizationDetailsContext = new AuthorizationDetailsContext( - oAuth2Parameters, oAuthAppDO, authenticatedUser, authorizationDetail); - - if (isValidAuthorizationDetail(authorizationDetailsContext)) { - validatedAuthorizationDetails.add(getEnrichedAuthorizationDetail(authorizationDetailsContext)); - } - } - } - - return new AuthorizationDetails(validatedAuthorizationDetails); - } - - private boolean isAuthorizedAuthorizationDetail(final AuthorizationDetail authorizationDetail, - final Set authorizedAuthorizationDetailsTypes) { - - return authorizedAuthorizationDetailsTypes.contains(authorizationDetail.getType()); - } - - private boolean isSupportedAuthorizationDetailType(final String authorizationDetailType) { - - return this.authorizationDetailsProviderFactory - .isSupportedAuthorizationDetailsType(authorizationDetailType); - } - - /** - * Checks if the provided authorization details context is valid. - * - * @param authorizationDetailsContext The context containing authorization details. - * @return {@code true} if the authorization details are valid; {@code false} otherwise. - */ - private boolean isValidAuthorizationDetail(final AuthorizationDetailsContext authorizationDetailsContext) - throws AuthorizationDetailsProcessingException { - - Optional optionalProvider = this.authorizationDetailsProviderFactory - .getProviderByType(authorizationDetailsContext.getAuthorizationDetail().getType()); - - if (optionalProvider.isPresent()) { - - final ValidationResult validationResult = optionalProvider.get().validate(authorizationDetailsContext); - if (log.isDebugEnabled() && validationResult.isInvalid()) { - - log.debug(String.format("Authorization details validation failed for type %s. Caused by, %s", - authorizationDetailsContext.getAuthorizationDetail().getType(), validationResult.getReason())); - - } - return validationResult.isValid(); - } - throw new AuthorizationDetailsProcessingException(String.format( - AuthorizationDetailsConstants.TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT, - authorizationDetailsContext.getAuthorizationDetail().getType())); - } - - /** - * Enriches the authorization details using the provided context. - * - * @param authorizationDetailsContext The context containing authorization details. - * @return An enriched {@link AuthorizationDetail} object. - */ - private AuthorizationDetail getEnrichedAuthorizationDetail( - final AuthorizationDetailsContext authorizationDetailsContext) { - - return this.authorizationDetailsProviderFactory - .getProviderByType(authorizationDetailsContext.getAuthorizationDetail().getType()) - .map(authorizationDetailsService -> authorizationDetailsService.enrich(authorizationDetailsContext)) - // If provider is missing, return the original authorization detail instance - .orElse(authorizationDetailsContext.getAuthorizationDetail()); - } - - /** - * Retrieves the set of authorized authorization types for the given client and tenant domain. - * - * @param clientID The client ID. - * @param tenantDomain The tenant domain. - * @return A set of strings representing the authorized authorization types. - */ - private Set getAuthorizedAuthorizationDetailsTypes(final String clientID, final String tenantDomain) { - -// try { -// final String appId = OAuth2Util -// .getApplicationResourceIDByClientId(clientID, tenantDomain, this.applicationMgtService); -// -//// OAuth2ServiceComponentHolder.getInstance().getAuthorizedAPIManagementService() -// .getAuthorizedAuthorizationDetailsTypes(appId, tenantDomain); -// } catch (IdentityOAuth2Exception e) { -// throw new RuntimeException(e); -// } - Set authorizedAuthorizationDetailsTypes = new HashSet<>(); - authorizedAuthorizationDetailsTypes.add("payment_initiation"); - return authorizedAuthorizationDetailsTypes; - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java new file mode 100644 index 0000000000..5c467f47bf --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.dao; + +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; + +import java.sql.SQLException; +import java.util.List; +import java.util.Set; + +/** + * Provides methods to interact with the database to manage rich authorization requests. + * + *

{@link AuthorizationDetailsDAO} provides methods to add, update, retrieve, and delete authorization details + * associated with user consent and access tokens. + */ +public interface AuthorizationDetailsDAO { + + /** + * Adds user consented authorization details to the database. + * + * @param authorizationDetailsConsentDTOs List of user consented authorization details DTOs. + * {@link AuthorizationDetailsConsentDTO } + * @return An array of positive integers indicating the number of rows affected for each batch operation, + * or negative integers if any of the batch operations fail. + * @throws SQLException If a database access error occurs. + */ + int[] addUserConsentedAuthorizationDetails(List authorizationDetailsConsentDTOs) + throws SQLException; + + /** + * Retrieves user consented authorization details from the database. + * + * @param consentId The ID of the consent. + * @param tenantId The tenant ID. + * @return A set of user consented authorization details DTOs. + * @throws SQLException If a database access error occurs. + */ + Set getUserConsentedAuthorizationDetails(String consentId, int tenantId) + throws SQLException; + + /** + * Updates user consented authorization details in the database. + * + * @param authorizationDetailsConsentDTOs A list of user consented authorization details DTOs. + * {@link AuthorizationDetailsConsentDTO} + * @return An array of integers indicating the number of rows affected for each batch operation. + * Positive values indicate success, negative values indicate failure. + * @throws SQLException If a database access error occurs. + */ + int[] updateUserConsentedAuthorizationDetails(List authorizationDetailsConsentDTOs) + throws SQLException; + + /** + * Deletes user consented authorization details from the database. + * + * @param consentId The ID of the consent. + * @param tenantId The tenant ID. + * @return The number of rows affected by the delete operation. + * @throws SQLException If a database access error occurs. + */ + int deleteUserConsentedAuthorizationDetails(String consentId, int tenantId) throws SQLException; + + /** + * Adds access token authorization details to the database. + * + * @param authorizationDetailsTokenDTOs A list of access token authorization details DTOs. + * {@link AuthorizationDetailsTokenDTO} + * @return An array of integers indicating the number of rows affected for each batch operation. + * Positive values indicate success, negative values indicate failure. + * @throws SQLException If a database access error occurs. + */ + int[] addAccessTokenAuthorizationDetails(List authorizationDetailsTokenDTOs) + throws SQLException; + + /** + * Retrieves access token authorization details from the database. + * + * @param accessTokenId The ID of the access token. + * @param tenantId The tenant ID. + * @return A set of access token authorization details DTOs. + * @throws SQLException If a database access error occurs. + */ + Set getAccessTokenAuthorizationDetails(String accessTokenId, int tenantId) + throws SQLException; + + /** + * Deletes access token authorization details from the database. + * + * @param accessTokenId The ID of the access token. + * @param tenantId The tenant ID. + * @return The number of rows affected by the delete operation. + * @throws SQLException If a database access error occurs. + */ + int deleteAccessTokenAuthorizationDetails(String accessTokenId, int tenantId) throws SQLException; + + /** + * Retrieves the consent ID associated with a specific user ID and application ID. + * + * @param userId The user ID. + * @param appId The application ID. + * @param tenantId The tenant ID. + * @return The consent ID as a string. + * @throws SQLException If a database access error occurs. + */ + // TODO: Move this method to the consent module + String getConsentIdByUserIdAndAppId(String userId, String appId, int tenantId) throws SQLException; +} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAOImpl.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java similarity index 64% rename from components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAOImpl.java rename to components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java index 839f23c464..b7a561d0f5 100644 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/AuthorizationDetailsDAOImpl.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java @@ -16,12 +16,11 @@ * under the License. */ -package org.wso2.carbon.identity.oauth2.rar.common.dao; +package org.wso2.carbon.identity.oauth2.rar.dao; import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; -import org.wso2.carbon.identity.oauth2.rar.common.dto.AuthorizationDetailsConsentDTO; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; import java.sql.Connection; import java.sql.PreparedStatement; @@ -32,36 +31,31 @@ import java.util.Set; /** - * Implementation of {@link AuthorizationDetailsDAO}. - * This class provides methods to add authorization details to the database. + * Implements the {@link AuthorizationDetailsDAO} interface to manage rich authorization requests. + * + *

{@link AuthorizationDetailsDAO} provides methods to add, update, retrieve, and delete authorization details + * associated with user consent and access tokens. */ public class AuthorizationDetailsDAOImpl implements AuthorizationDetailsDAO { /** - * Stores authorization details against the provided OAuth2 authorization code. - * - * @param authorizationCodeID The ID of the authorization code. - * @param authorizationDetails The details to be added. - * @param tenantId The tenant ID. - * @return An array of positive integers indicating the number of rows affected for each batch operation, - * or negative integers if any of the batch operations fail. - * @throws SQLException If a database access error occurs. + * {@inheritDoc} */ @Override - public int[] addOAuth2CodeAuthorizationDetails(final String authorizationCodeID, - final AuthorizationDetails authorizationDetails, - final int tenantId) throws SQLException { + public int[] addUserConsentedAuthorizationDetails( + final List authorizationDetailsConsentDTOs) throws SQLException { try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = - connection.prepareStatement(SQLQueries.ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS)) { - - for (AuthorizationDetail authorizationDetail : authorizationDetails.getDetails()) { - ps.setString(1, authorizationCodeID); - ps.setString(2, authorizationDetail.getType()); - ps.setInt(3, tenantId); - ps.setString(4, authorizationDetail.toJsonString()); - ps.setInt(5, tenantId); + connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + + for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { + ps.setString(1, consentDTO.getConsentId()); + ps.setString(2, consentDTO.getAuthorizationDetail().toJsonString()); + ps.setBoolean(3, consentDTO.isConsentActive()); + ps.setString(4, consentDTO.getAuthorizationDetail().getType()); + ps.setInt(5, consentDTO.getTenantId()); + ps.setInt(6, consentDTO.getTenantId()); ps.addBatch(); } return ps.executeBatch(); @@ -69,34 +63,39 @@ public int[] addOAuth2CodeAuthorizationDetails(final String authorizationCodeID, } /** - * Stores user consented authorization details. - * - * @param authorizationDetailsConsentDTOs The user consented authorization details DTOs - * @return An array of positive integers indicating the number of rows affected for each batch operation, - * or negative integers if any of the batch operations fail. - * @throws SQLException If a database access error occurs. + * {@inheritDoc} */ @Override - public int[] addUserConsentedAuthorizationDetails( - final List authorizationDetailsConsentDTOs) throws SQLException { + public Set getUserConsentedAuthorizationDetails(final String consentId, + final int tenantId) + throws SQLException { try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = - connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + connection.prepareStatement(SQLQueries.GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { - for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { - ps.setString(1, consentDTO.getConsentId()); - ps.setString(2, consentDTO.getAuthorizationDetail().getType()); - ps.setInt(3, consentDTO.getTenantId()); - ps.setString(4, consentDTO.getAuthorizationDetail().toJsonString()); - ps.setBoolean(5, consentDTO.isConsentActive()); - ps.setInt(6, consentDTO.getTenantId()); - ps.addBatch(); + ps.setString(1, consentId); + ps.setInt(2, tenantId); + try (ResultSet rs = ps.executeQuery()) { + + final Set authorizationDetailsConsentDTOs = new HashSet<>(); + while (rs.next()) { + final String id = rs.getString(1); + final int typeId = rs.getInt(2); + final String authorizationDetail = rs.getString(3); + final boolean isConsentActive = rs.getBoolean(4); + + authorizationDetailsConsentDTOs.add(new AuthorizationDetailsConsentDTO(id, consentId, typeId, + authorizationDetail, isConsentActive, tenantId)); + } + return authorizationDetailsConsentDTOs; } - return ps.executeBatch(); } } + /** + * {@inheritDoc} + */ @Override public int[] updateUserConsentedAuthorizationDetails( final List authorizationDetailsConsentDTOs) throws SQLException { @@ -116,6 +115,9 @@ public int[] updateUserConsentedAuthorizationDetails( } } + /** + * {@inheritDoc} + */ @Override public int deleteUserConsentedAuthorizationDetails(final String consentId, final int tenantId) throws SQLException { @@ -130,42 +132,76 @@ public int deleteUserConsentedAuthorizationDetails(final String consentId, final } } + /** + * {@inheritDoc} + */ @Override - public Set getUserConsentedAuthorizationDetails(final String consentId, - final int tenantId) - throws SQLException { + public int[] addAccessTokenAuthorizationDetails(final List + authorizationDetailsTokenDTOs) throws SQLException { + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.ADD_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) { + + for (AuthorizationDetailsTokenDTO tokenDTO : authorizationDetailsTokenDTOs) { + ps.setString(1, tokenDTO.getAccessTokenId()); + ps.setString(2, tokenDTO.getAuthorizationDetail().toJsonString()); + ps.setString(3, tokenDTO.getAuthorizationDetail().getType()); + ps.setInt(4, tokenDTO.getTenantId()); + ps.setInt(5, tokenDTO.getTenantId()); + ps.addBatch(); + } + return ps.executeBatch(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Set getAccessTokenAuthorizationDetails( + final String accessTokenId, final int tenantId) throws SQLException { try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = - connection.prepareStatement(SQLQueries.GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + connection.prepareStatement(SQLQueries.GET_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) { - ps.setString(1, consentId); + ps.setString(1, accessTokenId); ps.setInt(2, tenantId); try (ResultSet rs = ps.executeQuery()) { - final Set authorizationDetailsConsentDTOs = new HashSet<>(); + final Set authorizationDetailsTokenDTO = new HashSet<>(); while (rs.next()) { final String id = rs.getString(1); final int typeId = rs.getInt(2); final String authorizationDetail = rs.getString(3); - final boolean isConsentActive = rs.getBoolean(4); - authorizationDetailsConsentDTOs.add(new AuthorizationDetailsConsentDTO(id, consentId, typeId, - authorizationDetail, isConsentActive, tenantId)); + authorizationDetailsTokenDTO.add( + new AuthorizationDetailsTokenDTO(id, accessTokenId, typeId, authorizationDetail, tenantId)); } - return authorizationDetailsConsentDTOs; + return authorizationDetailsTokenDTO; } } } /** - * Retrieves the first consent ID for a given user ID and application ID. - * - * @param userId The ID of the user. - * @param appId The ID of the application. - * @param tenantId The tenant ID. - * @return The first consent ID found, or null if no consent ID is found. - * @throws SQLException If a database access error occurs. + * {@inheritDoc} + */ + @Override + public int deleteAccessTokenAuthorizationDetails(final String accessTokenId, final int tenantId) + throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.DELETE_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) { + + ps.setString(1, accessTokenId); + ps.setInt(2, tenantId); + return ps.executeUpdate(); + } + } + + /** + * {@inheritDoc} */ @Override public String getConsentIdByUserIdAndAppId(final String userId, final String appId, final int tenantId) diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/SQLQueries.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java similarity index 58% rename from components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/SQLQueries.java rename to components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java index 79faa31c9e..9cbed27365 100644 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/dao/SQLQueries.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java @@ -16,7 +16,7 @@ * under the License. */ -package org.wso2.carbon.identity.oauth2.rar.common.dao; +package org.wso2.carbon.identity.oauth2.rar.dao; /** * The {@code SQLQueries} class contains SQL query constants used for performing @@ -28,25 +28,11 @@ private SQLQueries() { // Private constructor to prevent instantiation } - public static final String ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS = - "INSERT INTO IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS " + - "(CODE_ID, TYPE_ID, AUTHORIZATION_DETAILS, TENANT_ID) VALUES " + - "(?, (SELECT ID FROM IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), " + - "? FORMAT JSON, ?)"; - - public static final String GET_OAUTH2_CODE_AUTHORIZATION_DETAILS = - "SELECT IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS.AUTHORIZATION_DETAILS " + - "FROM IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS " + - "INNER JOIN IDN_OAUTH2_AUTHORIZATION_CODE " + - "ON IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS.CODE_ID = IDN_OAUTH2_AUTHORIZATION_CODE.CODE_ID " + - "WHERE IDN_OAUTH2_AUTHORIZATION_CODE.AUTHORIZATION_CODE=? " + - "AND IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS.TENANT_ID=?"; - public static final String ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = "INSERT INTO IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + - "(CONSENT_ID, TYPE_ID, AUTHORIZATION_DETAILS, CONSENT, TENANT_ID) VALUES " + - "(?,(SELECT ID FROM IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), " + - "? FORMAT JSON, ?, ?)"; + "(CONSENT_ID, AUTHORIZATION_DETAILS, CONSENT, TYPE_ID, TENANT_ID) " + + "VALUES (?, ? FORMAT JSON, ?," + + "(SELECT ID FROM IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; public static final String UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = "UPDATE IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + @@ -59,9 +45,18 @@ private SQLQueries() { public static final String DELETE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = "DELETE FROM IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS WHERE CONSENT_ID=? AND TENANT_ID=?"; - public static final String CREATE_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS = + public static final String ADD_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS = "INSERT INTO IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS " + - "(AUTHORIZATION_DETAILS_TYPE, AUTHORIZATION_DETAILS, TOKEN_ID, TENANT_ID) VALUES (?, ?, ?, ?)"; + "(TOKEN_ID, AUTHORIZATION_DETAILS, TYPE_ID, TENANT_ID) " + + "VALUES (?, ? FORMAT JSON, " + + "(SELECT ID FROM IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; + + public static final String DELETE_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS = + "DELETE FROM IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS WHERE TOKEN_ID=? AND TENANT_ID=?"; + + public static final String GET_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS = + "SELECT ID, TYPE_ID, AUTHORIZATION_DETAILS FROM IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS " + + "WHERE TOKEN_ID=? AND TENANT_ID=?"; public static final String GET_IDN_OAUTH2_USER_CONSENT_CONSENT_ID = "SELECT CONSENT_ID FROM IDN_OAUTH2_USER_CONSENT WHERE USER_ID=? AND APP_ID=? AND TENANT_ID=?"; diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsConsentDTO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsConsentDTO.java new file mode 100644 index 0000000000..c70619615f --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsConsentDTO.java @@ -0,0 +1,67 @@ +package org.wso2.carbon.identity.oauth2.rar.dto; + +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; + +/** + * Data Transfer Object (DTO) for representing authorization details along with consent information. + * This class extends {@link AuthorizationDetailsDTO} to include additional fields for consent ID and consent status. + */ +public class AuthorizationDetailsConsentDTO extends AuthorizationDetailsDTO { + + final String consentId; + final boolean isConsentActive; + + /** + * Constructs an {@link AuthorizationDetailsConsentDTO} with all required fields. + * + * @param id the ID of the authorization detail DTO. + * @param consentId the consent ID associated with the authorization detail. + * @param typeId the type ID of the authorization detail. + * @param authorizationDetailJson the JSON string of the authorization detail. + * @param isConsentActive the consent status. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsConsentDTO(final String id, final String consentId, final int typeId, + final String authorizationDetailJson, + final boolean isConsentActive, final int tenantId) { + + super(id, typeId, authorizationDetailJson, tenantId); + this.consentId = consentId; + this.isConsentActive = isConsentActive; + } + + /** + * Constructs an {@link AuthorizationDetailsConsentDTO} with essential fields. + * + * @param consentId the consent ID associated with the authorization detail. + * @param authorizationDetail the {@link AuthorizationDetail} object. + * @param isConsentActive the consent status. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsConsentDTO(final String consentId, + final AuthorizationDetail authorizationDetail, + final boolean isConsentActive, final int tenantId) { + + super(authorizationDetail, tenantId); + this.consentId = consentId; + this.isConsentActive = isConsentActive; + } + + /** + * Checks if the consent is active. + * + * @return {@code true} if consent is active, {@code false} otherwise. + */ + public boolean isConsentActive() { + return isConsentActive; + } + + /** + * Gets the consent ID associated with the authorization detail. + * + * @return the consent ID. + */ + public String getConsentId() { + return consentId; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java new file mode 100644 index 0000000000..fe6a85b8ef --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java @@ -0,0 +1,98 @@ +package org.wso2.carbon.identity.oauth2.rar.dto; + +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils; + +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils.getDefaultObjectMapper; + +/** + * Data Transfer Object (DTO) for representing authorization details. + *

This class encapsulates the details of authorization, including the ID, type ID, + * authorization detail object, and tenant ID. + */ +public class AuthorizationDetailsDTO { + + final String id; + final int typeId; + final AuthorizationDetail authorizationDetail; + final int tenantId; + + /** + * Constructs an AuthorizationDetailsDTO with all fields. + * + * @param id the ID of the authorization detail DTO. + * @param typeId the type ID of the authorization detail. + * @param authorizationDetail the authorization detail object. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsDTO(final String id, final int typeId, final AuthorizationDetail authorizationDetail, + final int tenantId) { + + this.id = id; + this.typeId = typeId; + this.authorizationDetail = authorizationDetail; + this.tenantId = tenantId; + } + + /** + * Constructs an AuthorizationDetailsDTO from authorization detail JSON string. + * + * @param id the ID of the authorization detail DTO. + * @param typeId the type ID of the authorization detail. + * @param authorizationDetailJson the JSON string of the authorization detail. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsDTO(final String id, final int typeId, final String authorizationDetailJson, + final int tenantId) { + + this(id, typeId, AuthorizationDetailsCommonUtils + .fromJSON(authorizationDetailJson, AuthorizationDetail.class, getDefaultObjectMapper()), tenantId); + } + + /** + * Constructs an AuthorizationDetailsDTO with an authorization detail object and tenant ID. + * + * @param authorizationDetail the authorization detail object. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsDTO(final AuthorizationDetail authorizationDetail, final int tenantId) { + + this(null, 0, authorizationDetail, tenantId); + } + + /** + * Gets the ID of the authorization detail. + * + * @return the ID of the authorization detail. + */ + public String getId() { + return this.id; + } + + /** + * Gets the type ID of the authorization detail. + * + * @return the type ID of the authorization detail. + */ + public int getTypeId() { + return this.typeId; + } + + /** + * Gets the authorization detail object. + * + * @return the authorization detail object. + */ + public AuthorizationDetail getAuthorizationDetail() { + return this.authorizationDetail; + } + + /** + * Gets the tenant ID. + * + * @return the tenant ID. + */ + public int getTenantId() { + return this.tenantId; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsTokenDTO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsTokenDTO.java new file mode 100644 index 0000000000..a75d7b8681 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsTokenDTO.java @@ -0,0 +1,51 @@ +package org.wso2.carbon.identity.oauth2.rar.dto; + +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; + +/** + * Data Transfer Object (DTO) for representing authorization details along with access token information. + * This class extends {@link AuthorizationDetailsDTO} to include additional fields for access token ID. + */ +public class AuthorizationDetailsTokenDTO extends AuthorizationDetailsDTO { + + final String accessTokenId; + + /** + * Constructs an {@link AuthorizationDetailsTokenDTO} with all required fields. + * + * @param id the ID of the authorization detail DTO. + * @param accessTokenId the access token ID associated with the authorization detail. + * @param typeId the type ID of the authorization detail. + * @param authorizationDetail the {@link AuthorizationDetail} object. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsTokenDTO(final String id, final String accessTokenId, final int typeId, + final String authorizationDetail, final int tenantId) { + + super(id, typeId, authorizationDetail, tenantId); + this.accessTokenId = accessTokenId; + } + + /** + * Constructs an {@link AuthorizationDetailsTokenDTO} with essential fields. + * + * @param accessTokenId the access token ID associated with the authorization detail. + * @param authorizationDetail the {@link AuthorizationDetail} object. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsTokenDTO(final String accessTokenId, final AuthorizationDetail authorizationDetail, + final int tenantId) { + + super(authorizationDetail, tenantId); + this.accessTokenId = accessTokenId; + } + + /** + * Gets the access token ID associated with the authorization detail. + * + * @return the access token ID. + */ + public String getAccessTokenId() { + return this.accessTokenId; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java deleted file mode 100644 index 62a65d9859..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.wso2.carbon.identity.oauth2.rar.exception; - -/** - * - */ -public class AuthorizationDetailsProcessingException extends RuntimeException { - - private static final long serialVersionUID = -206212512259482200L; - - /** - * Constructs a new exception with an error message. - * - * @param message The detail message. - */ - public AuthorizationDetailsProcessingException(String message) { - - super(message); - } - - /** - * Constructs a new exception with the message and cause. - * - * @param message The detail message. - * @param cause The cause. - */ - public AuthorizationDetailsProcessingException(String message, Throwable cause) { - - super(message, cause); - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/handler/RARAccessTokenResponseHandler.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/handler/RARAccessTokenResponseHandler.java deleted file mode 100644 index a35e8bd0ae..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/handler/RARAccessTokenResponseHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.wso2.carbon.identity.oauth2.rar.handler; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.json.JSONArray; -import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; -import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; -import org.wso2.carbon.identity.oauth2.token.handlers.response.AccessTokenResponseHandler; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * - */ -public class RARAccessTokenResponseHandler implements AccessTokenResponseHandler { - private static final ObjectMapper OBJECT_MAPPER = new JsonMapper(); - private static final Log LOG = LogFactory.getLog(RARAccessTokenResponseHandler.class); - - @Override -// public Map getAdditionalTokenResponseAttributes(OAuthTokenReqMessageContext tokReqMsgCtx) -// throws IdentityOAuth2Exception { -// -// List authorizationDetails = AuthorizationDetailService.getInstance() -// .getConsentedAuthorizationDetailsByAuthzCode(tokReqMsgCtx.getOauth2AccessTokenReqDTO() -// .getAuthorizationCode()); -// -// Map additionalAttributes = new HashMap<>(); -// if (isNotEmptyList(authorizationDetails)) { -// additionalAttributes.put(AUTHORIZATION_DETAILS, convertToJsonArray(authorizationDetails)); -// } -// return additionalAttributes; -// } - - public Map getAdditionalTokenResponseAttributes(OAuthTokenReqMessageContext tokReqMsgCtx) - throws IdentityOAuth2Exception { - - Map additionalAttributes = new HashMap<>(); - - return additionalAttributes; - } - - - private boolean isNotEmptyList(List list) { - return list != null && !list.isEmpty(); - } - - private JSONArray convertToJsonArray(List authorizationDetails) { - try { - return OBJECT_MAPPER.convertValue(OBJECT_MAPPER.writeValueAsString(authorizationDetails), JSONArray.class); - } catch (JsonProcessingException e) { - LOG.error("Serialization error. Caused by, ", e); - } - return new JSONArray(authorizationDetails); - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsDataHolder.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsDataHolder.java deleted file mode 100644 index bd0c92f5f3..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsDataHolder.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.oauth2.rar.internal; - -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProvider; - -import java.util.HashSet; -import java.util.Set; - -/** - * Singleton class that holds rich authorization details data. - *

This class uses the singleton design pattern to ensure there is only one instance - * managing the authorization details providers. The instance is lazily initialized - * with double-checked locking to ensure thread safety.

- *

The class provides methods to retrieve and set the authorization details data, - * which can be used in different parts of the application to manage rich authorization details.

- */ -public class AuthorizationDetailsDataHolder { - - private static volatile AuthorizationDetailsDataHolder instance; - private Set authorizationDetailsProviders; - - /** - * Private constructor to prevent instantiation from outside the class. - */ - private AuthorizationDetailsDataHolder() { - - this.authorizationDetailsProviders = new HashSet<>(); - } - - /** - * Returns the singleton instance of {@link AuthorizationDetailsDataHolder}. - * - *

This method uses double-checked locking to ensure that the instance is initialized - * only once and in a thread-safe manner. If the instance is not already created, it - * will be created and returned; otherwise, the existing instance will be returned.

- * - * @return The singleton instance of {@link AuthorizationDetailsDataHolder}. - */ - public static AuthorizationDetailsDataHolder getInstance() { - - if (instance == null) { - synchronized (AuthorizationDetailsDataHolder.class) { - if (instance == null) { - instance = new AuthorizationDetailsDataHolder(); - } - } - } - return instance; - } - - /** - * Returns the current set of {@link AuthorizationDetailsProvider} instances. - * - *

This method provides access to the authorization details providers. - * The returned set can be used to query or modify the authorization details providers.

- * - * @return A {@link Set} of {@link AuthorizationDetailsProvider} instances. - */ - public Set getAuthorizationDetailsProviders() { - - return this.authorizationDetailsProviders; - } - - /** - * Sets the set of {@link AuthorizationDetailsProvider} instances to the provided value. - * - *

This method replaces the current set of authorization details providers with the - * provided set. It can be used to update the list of providers that the application - * uses to manage authorization details.

- * - * @param authorizationDetailsProviders The new {@link Set} of {@link AuthorizationDetailsProvider} instances. - */ - public void setAuthorizationDetailsProviders(Set authorizationDetailsProviders) { - - this.authorizationDetailsProviders = authorizationDetailsProviders; - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsServiceComponent.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsServiceComponent.java deleted file mode 100644 index 2cd272dc71..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/internal/AuthorizationDetailsServiceComponent.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.oauth2.rar.internal; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.osgi.service.component.ComponentContext; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Deactivate; -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProvider; - -import java.util.ServiceLoader; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -/** - * Authorization Details OSGI service component. - */ -@Component(name = "org.wso2.carbon.identity.oauth.rar.internal.AuthorizationDetailsServiceComponent") -public class AuthorizationDetailsServiceComponent { - private static final Log log = LogFactory.getLog(AuthorizationDetailsServiceComponent.class); - - @Activate - protected void activate(ComponentContext context) { - - AuthorizationDetailsDataHolder.getInstance().setAuthorizationDetailsProviders( - loadAuthorizationDetailsProviders(ServiceLoader.load(AuthorizationDetailsProvider.class, - this.getClass().getClassLoader()))); - - log.debug("AuthorizationDetailsServiceComponent is activated"); - } - - @Deactivate - protected void deactivate(ComponentContext context) { - - log.debug("AuthorizationDetailsServiceComponent is deactivated"); - } - - /** - * Loads supported authorization details providers from the provided {@link ServiceLoader}. - * - * @param serviceLoader {@link ServiceLoader} for {@link AuthorizationDetailsProvider}. - * @return Set of authorization details providers. - */ - private Set loadAuthorizationDetailsProviders( - final ServiceLoader serviceLoader) { - - return StreamSupport.stream(serviceLoader.spliterator(), false) - .collect(Collectors.toSet()); - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetail.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetail.java similarity index 91% rename from components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetail.java rename to components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetail.java index 96194b3485..9d3c87af10 100644 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetail.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetail.java @@ -16,24 +16,23 @@ * under the License. */ -package org.wso2.carbon.identity.oauth2.rar.common.model; +package org.wso2.carbon.identity.oauth2.rar.model; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang.StringUtils; -import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsCommonUtils; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.function.Function; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils.getDefaultObjectMapper; + /** * Represents an individual authorization details object which specifies the authorization requirements for a * specific resource type within the {@code authorization_details} request parameter used in OAuth 2.0 flows @@ -71,15 +70,13 @@ * *

Refer to * OAuth 2.0 Rich Authorization Requests for detailed information on the Authorization Details structure.

- * - * @since 7.0.26.9 */ @JsonInclude(JsonInclude.Include.NON_NULL) public class AuthorizationDetail implements Serializable { private static final long serialVersionUID = -3928636285264078857L; - @JsonIgnore + @JsonProperty("_id") private String id; private String type; private List locations; @@ -91,16 +88,21 @@ public class AuthorizationDetail implements Serializable { private Map details; private String consentDescription; - public AuthorizationDetail() { - this.setId(UUID.randomUUID().toString()); - } - + /** + * Gets the unique ID of the authorization detail. + * + * @return the ID of the authorization detail. + */ public String getId() { + return this.id; } - @JsonProperty("_id") + /** + * Sets a unique temporary ID for a given authorization detail instance. + */ public void setId(final String id) { + this.id = id; } @@ -112,13 +114,15 @@ public void setId(final String id) { * * @return The String value of the type field * @see - * Authorization Details Types + * Authorization Details Types */ public String getType() { + return this.type; } public void setType(final String type) { + this.type = type; } @@ -131,10 +135,12 @@ public void setType(final String type) { * @return A list of locations or {@code null} if the {@code locations} field is not present. */ public List getLocations() { + return this.locations; } public void setLocations(final List locations) { + this.locations = locations; } @@ -146,10 +152,12 @@ public void setLocations(final List locations) { * @return A list of actions or {@code null} if the {@code actions} field is not present. */ public List getActions() { + return this.actions; } public void setActions(final List actions) { + this.actions = actions; } @@ -161,10 +169,12 @@ public void setActions(final List actions) { * @return A list of datatypes or {@code null} if the {@code datatypes} field is not present. */ public List getDataTypes() { + return this.dataTypes; } public void setDataTypes(final List dataTypes) { + this.dataTypes = dataTypes; } @@ -176,10 +186,12 @@ public void setDataTypes(final List dataTypes) { * @return The String value of the identifier or {@code null} if the {@code identifier} field is not present. */ public String getIdentifier() { + return this.identifier; } public void setIdentifier(final String identifier) { + this.identifier = identifier; } @@ -192,10 +204,12 @@ public void setIdentifier(final String identifier) { * @return The String value of the privileges or {@code null} if the {@code privileges} field is not present. */ public List getPrivileges() { + return this.privileges; } public void setPrivileges(final List privileges) { + this.privileges = privileges; } @@ -207,15 +221,18 @@ public void setPrivileges(final List privileges) { */ @JsonAnyGetter public Map getDetails() { + return this.details; } public void setDetails(final Map details) { + this.details = details; } @JsonAnySetter public void setDetail(final String key, final Object value) { + if (this.details == null) { setDetails(new HashMap<>()); } @@ -243,6 +260,7 @@ public String getConsentDescription() { * explaining what they are consenting to. */ public void setConsentDescription(final String consentDescription) { + this.consentDescription = consentDescription; } @@ -269,6 +287,7 @@ public void setConsentDescription(final String consentDescription) { * @return the consent description if present, otherwise the value from the Function */ public String getConsentDescriptionOrDefault(Function defaultFunction) { + return StringUtils.isNotEmpty(this.getConsentDescription()) ? this.getConsentDescription() : defaultFunction.apply(this); } @@ -279,11 +298,23 @@ public String getConsentDescriptionOrDefault(Function} representation of the authorization detail. + */ + public Map toMap() { + + return AuthorizationDetailsCommonUtils.toMap(this, getDefaultObjectMapper()); } @Override public String toString() { + return "AuthorizationDetails {" + "type='" + this.type + '\'' + ", locations=" + this.locations + diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetails.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetails.java similarity index 80% rename from components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetails.java rename to components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetails.java index 0befab02b1..11c16e87fb 100644 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/model/AuthorizationDetails.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetails.java @@ -16,21 +16,23 @@ * under the License. */ -package org.wso2.carbon.identity.oauth2.rar.common.model; +package org.wso2.carbon.identity.oauth2.rar.model; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang.StringUtils; -import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsCommonUtils; -import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; import java.io.Serializable; import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils.getDefaultObjectMapper; + /** * Represents a set of {@link AuthorizationDetail} objects which specifies the authorization requirements for a * specific resource type within the {@code authorization_details} request parameter used in OAuth 2.0 flows @@ -52,6 +54,7 @@ public class AuthorizationDetails implements Serializable { * Constructs an empty set of {@link AuthorizationDetail}. */ public AuthorizationDetails() { + this(Collections.emptySet()); } @@ -61,6 +64,7 @@ public AuthorizationDetails() { * @param authorizationDetails The set of authorization details. If null, an empty set is assigned. */ public AuthorizationDetails(final Set authorizationDetails) { + this.authorizationDetails = Optional.ofNullable(authorizationDetails) .map(Collections::unmodifiableSet) .orElse(Collections.emptySet()); @@ -72,8 +76,9 @@ public AuthorizationDetails(final Set authorizationDetails) * @param authorizationDetailsJson The JSON string representing the authorization details. */ public AuthorizationDetails(final String authorizationDetailsJson) { + this(AuthorizationDetailsCommonUtils.fromJSONArray( - authorizationDetailsJson, AuthorizationDetail.class, new ObjectMapper())); + authorizationDetailsJson, AuthorizationDetail.class, getDefaultObjectMapper())); } /** @@ -82,15 +87,30 @@ public AuthorizationDetails(final String authorizationDetailsJson) { * @return A set of {@link AuthorizationDetail}. */ public Set getDetails() { + return this.authorizationDetails; } + /** + * Converts a stream of AuthorizationDetail objects into a {@link Set} of {@link Map}. + * + *

Each AuthorizationDetail object is transformed into a Map representation using + * the {@link AuthorizationDetail#toMap} method. + * + * @return a Set of Maps representing the AuthorizationDetail objects. + */ + public Set> toSet() { + + return this.stream().map(AuthorizationDetail::toMap).collect(Collectors.toSet()); + } + /** * Returns a set of the {@code authorization_details} filtered by provided type. * * @return A set of {@link AuthorizationDetail}. */ public Set getDetailsByType(final String type) { + return this.stream() .filter(Objects::nonNull) .filter(authorizationDetail -> StringUtils.equals(authorizationDetail.getType(), type)) @@ -103,7 +123,8 @@ public Set getDetailsByType(final String type) { * @return The JSON representation of the authorization details. */ public String toJsonString() { - return AuthorizationDetailsCommonUtils.toJSON(this.getDetails(), new ObjectMapper()); + + return AuthorizationDetailsCommonUtils.toJSON(this.getDetails(), getDefaultObjectMapper()); } /** @@ -120,7 +141,13 @@ public String toReadableText() { .collect(Collectors.joining(AuthorizationDetailsConstants.PARAM_SEPARATOR)); } + /** + * Converts the current set of authorization details to a {@link Stream}. + * + * @return The Stream representation of the {@code authorization_details}. + */ public Stream stream() { + return this.getDetails().stream(); } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java deleted file mode 100644 index 00cd4de10d..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.oauth2.rar.model; - -import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; -import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; -import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; - -import java.util.Objects; - -/** - * Represents the context for rich authorization requests in an OAuth2 flow. - *

- * This class holds relevant details such as OAuth2 parameters, application details, the authenticated user, - * and specific authorization details. It is immutable to ensure that the context remains consistent throughout its use. - *

- */ -public class AuthorizationDetailsContext { - - private final OAuth2Parameters oAuth2Parameters; - private final OAuthAppDO oAuthAppDO; - private final AuthenticatedUser authenticatedUser; - private final AuthorizationDetail authorizationDetail; - - /** - * Constructs a new {@code AuthorizationDetailsContext}. - *

- * This constructor ensures that all necessary details for an authorization context are provided. - *

- * - * @param oAuth2Parameters the OAuth2 parameters. - * @param oAuthAppDO the OAuth application details. - * @param authenticatedUser the authenticated user. - * @param authorizationDetail the specific authorization detail. - * @throws NullPointerException if any of the arguments are {@code null}. - */ - public AuthorizationDetailsContext(final OAuth2Parameters oAuth2Parameters, final OAuthAppDO oAuthAppDO, - final AuthenticatedUser authenticatedUser, - final AuthorizationDetail authorizationDetail) { - this.oAuth2Parameters = Objects.requireNonNull(oAuth2Parameters, "oAuth2Parameters cannot be null"); - this.oAuthAppDO = Objects.requireNonNull(oAuthAppDO, "oAuthAppDO cannot be null"); - this.authenticatedUser = Objects.requireNonNull(authenticatedUser, "authenticatedUser cannot be null"); - this.authorizationDetail = Objects.requireNonNull(authorizationDetail, "authorizationDetail cannot be null"); - } - - /** - * Returns the {@code AuthorizationDetail} instance. - * - * @return the {@link AuthorizationDetail} instance. - */ - public AuthorizationDetail getAuthorizationDetail() { - return this.authorizationDetail; - } - - /** - * Returns the OAuth2 parameters. - * - * @return the {@link OAuth2Parameters} instance. - */ - public OAuth2Parameters getOAuth2Parameters() { - return this.oAuth2Parameters; - } - - /** - * Returns the OAuth application details. - * - * @return the {@link OAuthAppDO} instance. - */ - public OAuthAppDO getoAuthAppDO() { - return this.oAuthAppDO; - } - - /** - * Returns the authenticated user. - * - * @return the {@link AuthenticatedUser} instance. - */ - public AuthenticatedUser getAuthenticatedUser() { - return this.authenticatedUser; - } -} diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsCommonUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java similarity index 68% rename from components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsCommonUtils.java rename to components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java index c908656d18..d34bfedb27 100644 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsCommonUtils.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java @@ -16,16 +16,21 @@ * under the License. */ -package org.wso2.carbon.identity.oauth2.rar.common.util; +package org.wso2.carbon.identity.oauth2.rar.util; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -36,6 +41,7 @@ public class AuthorizationDetailsCommonUtils { private static final Log log = LogFactory.getLog(AuthorizationDetailsCommonUtils.class); private static final String empty_json = "{}"; private static final String empty_json_array = "[]"; + private static final ObjectMapper objectMapper = createDefaultObjectMapper(); private AuthorizationDetailsCommonUtils() { // Private constructor to prevent instantiation @@ -51,7 +57,7 @@ private AuthorizationDetailsCommonUtils() { * @param the type parameter extending {@code AuthorizationDetail} * @return an immutable set of {@link AuthorizationDetail} objects parsed from the given JSON string, * or an empty set if parsing fails - * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails + * @see AuthorizationDetails */ public static Set fromJSONArray( final String authorizationDetailsJson, final Class clazz, final ObjectMapper objectMapper) { @@ -71,12 +77,12 @@ public static Set fromJSONArray( * Parses the given JSON object string into an {@link AuthorizationDetail} object. * * @param authorizationDetailJson A JSON string containing authorization detail object - * @param objectMapper A Jackson {@link ObjectMapper} used for parsing - * @param clazz A Class that extends {@link AuthorizationDetail} to be parsed - * @param the type parameter extending {@code AuthorizationDetail} + * @param objectMapper A Jackson {@link ObjectMapper} used for parsing + * @param clazz A Class that extends {@link AuthorizationDetail} to be parsed + * @param the type parameter extending {@code AuthorizationDetail} * @return an {@link AuthorizationDetail} objects parsed from the given JSON string, * or null if parsing fails - * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail + * @see AuthorizationDetail */ public static T fromJSON( final String authorizationDetailJson, final Class clazz, final ObjectMapper objectMapper) { @@ -103,8 +109,8 @@ public static T fromJSON( * @param the type parameter extending {@code AuthorizationDetail} * @return a JSON string representation of the authorization details set, * or an empty JSON array if null or an error occurs - * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail - * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails + * @see AuthorizationDetail + * @see AuthorizationDetails */ public static String toJSON( final Set authorizationDetails, final ObjectMapper objectMapper) { @@ -131,8 +137,8 @@ public static String toJSON( * @param the type parameter extending {@code AuthorizationDetail} * @return a JSON string representation of the authorization detail, * or an empty JSON object if null or an error occurs - * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail - * @see org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails + * @see AuthorizationDetail + * @see AuthorizationDetails */ public static String toJSON( final T authorizationDetail, final ObjectMapper objectMapper) { @@ -146,4 +152,52 @@ public static String toJSON( } return empty_json; } + + /** + * Converts a single {@code AuthorizationDetail} object into a {@link Map}. + *

+ * If the input object is {@code null} or an exception occurs during the conversion, + * an empty {@link HashMap} is returned. + *

+ * + * @param authorizationDetail the {@code AuthorizationDetail} object to convert + * @param objectMapper the {@code ObjectMapper} instance to use for serialization + * @param the type parameter extending {@code AuthorizationDetail} + * @return a {@code Map} representation of the authorization detail, + * or an empty {@code HashMap} if null or an error occurs + * @see AuthorizationDetail + * @see AuthorizationDetails + */ + public static Map toMap( + final T authorizationDetail, final ObjectMapper objectMapper) { + + if (authorizationDetail != null) { + return objectMapper.convertValue(authorizationDetail, new TypeReference>() { + }); + } + return new HashMap<>(); + } + + /** + * Creates a singleton instance of {@link ObjectMapper}. + * + * @return the singleton {@link ObjectMapper} instance. + */ + private static ObjectMapper createDefaultObjectMapper() { + + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return objectMapper; + } + + /** + * Returns a configured default {@link ObjectMapper} instance. + * + *

This singleton ObjectMapper is configured to exclude properties with null values from the JSON output. + * + * @return a configured {@link ObjectMapper} instance. + */ + public static ObjectMapper getDefaultObjectMapper() { + return objectMapper; + } } diff --git a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsConstants.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsConstants.java similarity index 96% rename from components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsConstants.java rename to components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsConstants.java index 5b1ab3d97f..62128f272d 100644 --- a/components/org.wso2.carbon.identity.oauth.rar.common/src/main/java/org/wso2/carbon/identity/oauth2/rar/common/util/AuthorizationDetailsConstants.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsConstants.java @@ -16,7 +16,7 @@ * under the License. */ -package org.wso2.carbon.identity.oauth2.rar.common.util; +package org.wso2.carbon.identity.oauth2.rar.util; /** * Stores constants related to OAuth2 Rich Authorization Requests. diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java deleted file mode 100644 index 34af49529c..0000000000 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.oauth2.rar.util; - -import org.apache.commons.lang.StringUtils; -import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest; -import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; -import org.wso2.carbon.identity.oauth2.rar.common.util.AuthorizationDetailsConstants; - -/** - * Utility class for handling and validating authorization details in OAuth2 requests. - */ -public class AuthorizationDetailsUtils { - - /** - * Determines if the given {@link OAuth2Parameters} object contains - * {@link org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails AuthorizationDetails}. - * - * @param oAuth2Parameters The requested OAuth2 parameters to check. - * @return {@code true} if the OAuth2 parameters contain non-empty authorization details array, - * {@code false} otherwise. - */ - public static boolean isRichAuthorizationRequest(final OAuth2Parameters oAuth2Parameters) { - - return oAuth2Parameters.getAuthorizationDetails() != null && - !oAuth2Parameters.getAuthorizationDetails().getDetails().isEmpty(); - } - - /** - * Determines if the given {@link OAuthAuthzRequest} object contains {@code authorization_details}. - * - * @param oauthRequest The OAuth Authorization Request to check. - * @return {@code true} if the OAuth authorization request contains a non-blank authorization details parameter, - * {@code false} otherwise. - */ - public static boolean isRichAuthorizationRequest(final OAuthAuthzRequest oauthRequest) { - - return StringUtils.isNotBlank(oauthRequest.getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); - } -} diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 92f3e93171..99450b2ae1 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -260,7 +260,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 - org.wso2.carbon.identity.oauth.rar.common + org.wso2.carbon.identity.oauth.rar provided diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/IdentityOAuth2AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/IdentityOAuth2AuthorizationDetailsService.java deleted file mode 100644 index 21ac2f67fd..0000000000 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/IdentityOAuth2AuthorizationDetailsService.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.wso2.carbon.identity.oauth2; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; -import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; -import org.wso2.carbon.identity.oauth2.model.AuthzCodeDO; -import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; -import org.wso2.carbon.identity.oauth2.rar.common.dao.AuthorizationDetailsDAO; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; -import org.wso2.carbon.identity.oauth2.util.OAuth2Util; - -import java.sql.SQLException; -import java.util.Objects; - -/** - * IdentityOAuth2AuthorizationDetailsService is responsible for managing and handling OAuth2 authorization details, - * specifically in the context of rich authorization requests. - *

- * This class integrates with the {@link AuthorizationDetailsDAO} to persist these details in the underlying data store. - * It also provides utility methods to check if a request contains rich authorization details. - *

- * - * @see AuthorizationDetailsDAO - * @see AuthorizationDetails - */ -public class IdentityOAuth2AuthorizationDetailsService { - - private static final Log log = LogFactory.getLog(IdentityOAuth2AuthorizationDetailsService.class); - protected final AuthorizationDetailsDAO authorizationDetailsDAO; - - /** - * Default constructor that initializes the service with the default {@link AuthorizationDetailsDAO}. - *

- * This constructor uses the default DAO provided by the {@link OAuthTokenPersistenceFactory} - * to handle the persistence of authorization details. - *

- */ - public IdentityOAuth2AuthorizationDetailsService() { - - this(OAuthTokenPersistenceFactory.getInstance().getAuthorizationDetailsDAO()); - } - - /** - * Constructor that initializes the service with a given {@link AuthorizationDetailsDAO}. - * - * @param authorizationDetailsDAO The {@link AuthorizationDetailsDAO} instance to be used for - * handling authorization details persistence. Must not be {@code null}. - */ - public IdentityOAuth2AuthorizationDetailsService(final AuthorizationDetailsDAO authorizationDetailsDAO) { - - this.authorizationDetailsDAO = Objects - .requireNonNull(authorizationDetailsDAO, "AuthorizationDetailsDAO must not be null"); - } - - /** - * Determines if the given {@link OAuthAuthzReqMessageContext} object contains {@link AuthorizationDetails}. - * - * @param oAuthAuthzReqMessageContext The requested OAuthAuthzReqMessageContext to check. - * @return {@code true} if the OAuthAuthzReqMessageContext contains non-empty authorization details set, - * {@code false} otherwise. - */ - public static boolean isRichAuthorizationRequest(final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) { - - return isRichAuthorizationRequest(oAuthAuthzReqMessageContext.getAuthorizationDetails()); - } - - /** - * Determines if the request is a rich authorization request using provided {@link AuthorizationDetails} object. - *

- * This method checks if the specified {@link AuthorizationDetails} instance is not {@code null} - * and has a non-empty details set. - * - * @param authorizationDetails The {@link AuthorizationDetails} to check. - * @return {@code true} if the {@link AuthorizationDetails} is not {@code null} and has a non-empty details set, - * {@code false} otherwise. - */ - public static boolean isRichAuthorizationRequest(final AuthorizationDetails authorizationDetails) { - - return authorizationDetails != null && !authorizationDetails.getDetails().isEmpty(); - } - - /** - * Determines if the given {@link OAuth2Parameters} object contains {@link AuthorizationDetails}. - * - * @param oAuth2Parameters The requested OAuth2Parameters to check. - * @return {@code true} if the OAuth2Parameters contains non-empty authorization details set, - * {@code false} otherwise. - */ - public static boolean isRichAuthorizationRequest(final OAuth2Parameters oAuth2Parameters) { - - return isRichAuthorizationRequest(oAuth2Parameters.getAuthorizationDetails()); - } - - /** - * Stores the OAuth2 code authorization details if the request is a rich authorization request. - *

- * This method checks whether the given {@link OAuthAuthzReqMessageContext} contains {@link AuthorizationDetails}. - * If it does, it retrieves the tenant ID from the request context and stores the authorization - * details using the {@link AuthorizationDetailsDAO}. - *

- * - * @param authzCodeDO The {@link AuthzCodeDO} object containing the authorization code details. - * @param oAuthAuthzReqMessageContext The {@link OAuthAuthzReqMessageContext} containing the request context. - * @throws IdentityOAuth2Exception If an error occurs while storing the authorization details. - */ - public void storeOAuth2CodeAuthorizationDetails(final AuthzCodeDO authzCodeDO, - final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) - throws IdentityOAuth2Exception { - - if (!isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) { - log.debug("Request is not a rich authorization request. Skipping storage of code authorization details."); - return; - } - - try { - final int tenantID = OAuth2Util.getTenantId( - oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getTenantDomain()); - // Storing the authorization details. - this.authorizationDetailsDAO.addOAuth2CodeAuthorizationDetails( - authzCodeDO.getAuthzCodeId(), - oAuthAuthzReqMessageContext.getAuthorizationDetails(), - tenantID); - - if (log.isDebugEnabled()) { - log.debug("Successfully stored OAuth2 Code authorization details for code Id: " + - authzCodeDO.getAuthzCodeId()); - } - } catch (SQLException e) { - log.error("Error occurred while storing OAuth2 Code authorization details. Caused by, ", e); - throw new IdentityOAuth2Exception("Error occurred while storing authorization details", e); - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java index a654475ddb..705f4a58a4 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java @@ -40,7 +40,10 @@ import org.wso2.carbon.identity.oauth2.authz.handlers.ResponseTypeHandler; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO; +import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.oauth2.validators.DefaultOAuth2ScopeValidator; @@ -255,6 +258,7 @@ public OAuth2AuthorizeRespDTO handleAuthorization(OAuthAuthzReqMessageContext au // set the authorization request context to be used by downstream handlers. This is introduced as a fix for // IDENTITY-4111 OAuth2Util.setAuthzRequestContext(authzReqMsgCtx); + this.setUserConsentedAuthorizationDetails(authzReqMsgCtx); authorizeRespDTO = authzHandler.issue(authzReqMsgCtx); } finally { // clears authorization request context @@ -723,4 +727,22 @@ public OAuthErrorDTO handleAuthenticationFailure(OAuth2Parameters oAuth2Paramete ResponseTypeHandler responseTypeHandler = responseHandlers.get(oAuth2Parameters.getResponseType()); return responseTypeHandler.handleAuthenticationFailure(oAuth2Parameters); } + + private void setUserConsentedAuthorizationDetails(final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) + throws IdentityOAuth2Exception { + + OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO = oAuthAuthzReqMessageContext.getAuthorizationReqDTO(); + if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuth2AuthorizeReqDTO)) { + return; + } + + final AuthorizationDetails authorizationDetails = OAuth2ServiceComponentHolder.getInstance() + .getAuthorizationDetailsService() + .getUserConsentedAuthorizationDetails( + oAuth2AuthorizeReqDTO.getUser(), + oAuth2AuthorizeReqDTO.getConsumerKey(), + IdentityTenantUtil.getTenantId(oAuth2AuthorizeReqDTO.getTenantDomain()) + ); + oAuthAuthzReqMessageContext.setAuthorizationDetails(authorizationDetails); + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java index 2df67714c2..8b7cc822f4 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java @@ -19,7 +19,7 @@ package org.wso2.carbon.identity.oauth2.authz; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import java.io.Serializable; import java.util.Properties; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java index 287d2d8b57..4be8704f12 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java @@ -32,7 +32,6 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; -import org.wso2.carbon.identity.oauth2.IdentityOAuth2AuthorizationDetailsService; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; @@ -60,7 +59,6 @@ public abstract class AbstractResponseTypeHandler implements ResponseTypeHandler protected boolean cacheEnabled; protected OAuthCache oauthCache; private OAuthCallbackManager callbackManager; - protected IdentityOAuth2AuthorizationDetailsService identityOAuth2AuthorizationDetailsService; @Override public void init() throws IdentityOAuth2Exception { @@ -70,7 +68,6 @@ public void init() throws IdentityOAuth2Exception { if (cacheEnabled) { oauthCache = OAuthCache.getInstance(); } - this.identityOAuth2AuthorizationDetailsService = new IdentityOAuth2AuthorizationDetailsService(); } @Override @@ -228,6 +225,7 @@ public OAuth2AuthorizeRespDTO initResponse(OAuthAuthzReqMessageContext oauthAuth OAuth2AuthorizeReqDTO authorizationReqDTO = oauthAuthzMsgCtx.getAuthorizationReqDTO(); respDTO.setCallbackURI(authorizationReqDTO.getCallbackUrl()); respDTO.setScope(oauthAuthzMsgCtx.getApprovedScope()); + respDTO.setAuthorizationDetails(oauthAuthzMsgCtx.getAuthorizationDetails()); return respDTO; } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandler.java index 489226250f..adb9dfefd1 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandler.java @@ -47,8 +47,6 @@ public OAuth2AuthorizeRespDTO issue(OAuthAuthzReqMessageContext oauthAuthzMsgCtx AuthzCodeDO authorizationCode = ResponseTypeHandlerUtil.generateAuthorizationCode(oauthAuthzMsgCtx, cacheEnabled); - super.identityOAuth2AuthorizationDetailsService - .storeOAuth2CodeAuthorizationDetails(authorizationCode, oauthAuthzMsgCtx); String sessionDataKey = oauthAuthzMsgCtx.getAuthorizationReqDTO().getSessionDataKey(); if (log.isDebugEnabled()) { diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/util/ResponseTypeHandlerUtil.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/util/ResponseTypeHandlerUtil.java index 188b70cc8a..dc85dbcbd1 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/util/ResponseTypeHandlerUtil.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/util/ResponseTypeHandlerUtil.java @@ -610,6 +610,9 @@ private static AccessTokenDO generateNewAccessToken(OAuthAuthzReqMessageContext // Persist the access token in database persistAccessTokenInDB(oauthAuthzMsgCtx, existingTokenBean, newTokenBean); deactivateCurrentAuthorizationCode(newTokenBean.getAuthorizationCode(), newTokenBean.getTokenId()); + // Persist access token authorization details in database + OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsService() + .storeAccessTokenAuthorizationDetails(newTokenBean, oauthAuthzMsgCtx); //update cache with newly added token if (isHashDisabled && cacheEnabled) { addTokenToCache(getOAuthCacheKey(consumerKey, scope, authorizedUserId, authenticatedIDP), 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 68aa46f7d8..3737e52311 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 @@ -21,8 +21,8 @@ package org.wso2.carbon.identity.oauth2.dao; import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; -import org.wso2.carbon.identity.oauth2.rar.common.dao.AuthorizationDetailsDAO; -import org.wso2.carbon.identity.oauth2.rar.common.dao.AuthorizationDetailsDAOImpl; +import org.wso2.carbon.identity.oauth2.rar.dao.AuthorizationDetailsDAO; +import org.wso2.carbon.identity.oauth2.rar.dao.AuthorizationDetailsDAOImpl; import org.wso2.carbon.identity.openidconnect.dao.CacheBackedScopeClaimMappingDAOImpl; import org.wso2.carbon.identity.openidconnect.dao.RequestObjectDAO; import org.wso2.carbon.identity.openidconnect.dao.RequestObjectDAOImpl; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AccessTokenReqDTO.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AccessTokenReqDTO.java index 193a61fd30..d6f98c73b3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AccessTokenReqDTO.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AccessTokenReqDTO.java @@ -22,6 +22,7 @@ import org.wso2.carbon.identity.oauth2.model.AccessTokenExtendedAttributes; import org.wso2.carbon.identity.oauth2.model.HttpRequestHeader; import org.wso2.carbon.identity.oauth2.model.RequestParameter; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import java.util.ArrayList; import java.util.Collections; @@ -62,6 +63,8 @@ public class OAuth2AccessTokenReqDTO { private AccessTokenExtendedAttributes accessTokenExtendedAttributes; + private AuthorizationDetails authorizationDetails; + public String getClientId() { return clientId; } @@ -252,4 +255,26 @@ public HttpServletResponseWrapper getHttpServletResponseWrapper() { public void setHttpServletResponseWrapper(HttpServletResponseWrapper httpServletResponseWrapper) { this.httpServletResponseWrapper = httpServletResponseWrapper; } + + /** + * Retrieves the authorization details requested in the token request. + * + * @return the {@link AuthorizationDetails} instance representing the rich authorization requests. + * If no authorization details are requested by the client, the method will return {@code null}. + */ + public AuthorizationDetails getAuthorizationDetails() { + + return this.authorizationDetails; + } + + /** + * Sets the authorization details. + * This method updates the authorization details with the provided {@link AuthorizationDetails} instance. + * + * @param authorizationDetails the {@link AuthorizationDetails} to set. + */ + public void setAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + this.authorizationDetails = authorizationDetails; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AuthorizeReqDTO.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AuthorizeReqDTO.java index e3db5c1381..438810665a 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AuthorizeReqDTO.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AuthorizeReqDTO.java @@ -20,6 +20,7 @@ import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.oauth2.model.HttpRequestHeader; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.openidconnect.model.RequestObject; import java.util.LinkedHashSet; @@ -61,6 +62,7 @@ public class OAuth2AuthorizeReqDTO { private boolean isRequestObjectFlow; private String state; private String requestedSubjectId; + private AuthorizationDetails authorizationDetails; public String getRequestedSubjectId() { @@ -303,4 +305,26 @@ public void setHttpServletRequestWrapper(HttpServletRequestWrapper httpServletRe this.httpServletRequestWrapper = httpServletRequestWrapper; } + + /** + * Retrieves the authorization details requested by the client. + * + * @return the {@link AuthorizationDetails} instance representing the {@code authorization_details} requested + * by the client. If no authorization details are available, it will return {@code null}. + */ + public AuthorizationDetails getAuthorizationDetails() { + + return this.authorizationDetails; + } + + /** + * Sets the authorization details requested by the client. + * This method updates the authorization details with the provided {@link AuthorizationDetails} instance. + * + * @param authorizationDetails the {@link AuthorizationDetails} to set. + */ + public void setAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + this.authorizationDetails = authorizationDetails; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AuthorizeRespDTO.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AuthorizeRespDTO.java index 6cb706807c..8c248bfc4b 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AuthorizeRespDTO.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dto/OAuth2AuthorizeRespDTO.java @@ -18,6 +18,8 @@ package org.wso2.carbon.identity.oauth2.dto; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; + import java.util.Properties; /** @@ -39,6 +41,7 @@ public class OAuth2AuthorizeRespDTO { private String pkceCodeChallenge; private String pkceCodeChallengeMethod; private String oidcSessionId; + private AuthorizationDetails authorizationDetails; private String subjectToken; public String getAuthorizationCode() { @@ -200,4 +203,26 @@ public void setSubjectToken(String subjectToken) { this.subjectToken = subjectToken; } + + /** + * Retrieves the validated authorization details to be included in the authorize response. + * + * @return the {@link AuthorizationDetails} instance representing the validated authorization information. + * If no authorization details are available, it will return {@code null}. + */ + public AuthorizationDetails getAuthorizationDetails() { + + return this.authorizationDetails; + } + + /** + * Sets the authorization details. + * This method sets {@link AuthorizationDetails} that can potentially be included in the authorization response. + * + * @param authorizationDetails the {@link AuthorizationDetails} to set. + */ + public void setAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + this.authorizationDetails = authorizationDetails; + } } 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 2c4e41025b..c1f54cc544 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 @@ -56,6 +56,7 @@ import org.wso2.carbon.identity.oauth.tokenprocessor.OAuth2RevocationProcessor; import org.wso2.carbon.identity.oauth.tokenprocessor.RefreshTokenGrantProcessor; import org.wso2.carbon.identity.oauth.tokenprocessor.TokenProvider; +import org.wso2.carbon.identity.oauth2.IntrospectionDataProvider; import org.wso2.carbon.identity.oauth2.OAuth2ScopeService; import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; @@ -82,6 +83,9 @@ import org.wso2.carbon.identity.oauth2.keyidprovider.KeyIDProvider; import org.wso2.carbon.identity.oauth2.listener.TenantCreationEventListener; import org.wso2.carbon.identity.oauth2.model.ResourceAccessControlKey; +import org.wso2.carbon.identity.oauth2.rar.token.AccessTokenResponseRARHandler; +import org.wso2.carbon.identity.oauth2.rar.token.IntrospectionRARDataProvider; +import org.wso2.carbon.identity.oauth2.rar.token.JWTAccessTokenRARClaimProvider; import org.wso2.carbon.identity.oauth2.scopeservice.APIResourceBasedScopeMetadataService; import org.wso2.carbon.identity.oauth2.scopeservice.ScopeMetadataService; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; @@ -401,6 +405,11 @@ protected void activate(ComponentContext context) { bundleContext.registerService(ImpersonationConfigMgtService.class, new ImpersonationConfigMgtServiceImpl(), null); + bundleContext.registerService(AccessTokenResponseHandler.class, new AccessTokenResponseRARHandler(), null); + bundleContext.registerService(JWTAccessTokenClaimProvider.class, + new JWTAccessTokenRARClaimProvider(), null); + bundleContext.registerService(IntrospectionDataProvider.class, new IntrospectionRARDataProvider(), null); + // Note : DO NOT add any activation related code below this point, // to make sure the server doesn't start up if any activation failures occur } catch (Throwable e) { 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 c22e3f9ffd..28845ea0ce 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 @@ -44,6 +44,9 @@ import org.wso2.carbon.identity.oauth2.impersonation.services.ImpersonationMgtService; import org.wso2.carbon.identity.oauth2.impersonation.validators.ImpersonationValidator; import org.wso2.carbon.identity.oauth2.keyidprovider.KeyIDProvider; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.rar.validator.AuthorizationDetailsValidator; +import org.wso2.carbon.identity.oauth2.rar.validator.DefaultAuthorizationDetailsValidator; import org.wso2.carbon.identity.oauth2.responsemode.provider.ResponseModeProvider; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; import org.wso2.carbon.identity.oauth2.token.handlers.claims.JWTAccessTokenClaimProvider; @@ -122,7 +125,8 @@ public class OAuth2ServiceComponentHolder { private List impersonationValidators = new ArrayList<>(); private ConfigurationManager configurationManager; - + private AuthorizationDetailsService authorizationDetailsService; + private AuthorizationDetailsValidator authorizationDetailsValidator; private OAuth2ServiceComponentHolder() { @@ -889,4 +893,30 @@ public void setConfigurationManager(ConfigurationManager configurationManager) { this.configurationManager = configurationManager; } + + /** + * Get an {@link AuthorizationDetailsService} instance. + * + * @return A {@link AuthorizationDetailsService} singleton instance. + */ + public AuthorizationDetailsService getAuthorizationDetailsService() { + + if (this.authorizationDetailsService == null) { + this.authorizationDetailsService = new AuthorizationDetailsService(); + } + return this.authorizationDetailsService; + } + + /** + * Get an {@link AuthorizationDetailsValidator} instance. + * + * @return A {@link AuthorizationDetailsValidator} singleton instance. + */ + public AuthorizationDetailsValidator getAuthorizationDetailsValidator() { + + if (this.authorizationDetailsValidator == null) { + this.authorizationDetailsValidator = new DefaultAuthorizationDetailsValidator(); + } + return this.authorizationDetailsValidator; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/model/OAuth2Parameters.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/model/OAuth2Parameters.java index 868a5ff164..520e9a4f31 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/model/OAuth2Parameters.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/model/OAuth2Parameters.java @@ -18,7 +18,7 @@ package org.wso2.carbon.identity.oauth2.model; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import java.io.Serializable; import java.util.LinkedHashSet; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java new file mode 100644 index 0000000000..1170f33070 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java @@ -0,0 +1,558 @@ +package org.wso2.carbon.identity.oauth2.rar; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; +import org.wso2.carbon.identity.oauth2.rar.dao.AuthorizationDetailsDAO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; + +import java.sql.SQLException; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.getAuthorizationDetailsConsentDTOs; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.isRichAuthorizationRequest; + +/** + * AuthorizationDetailsService is responsible for managing and handling OAuth2 authorization details, + * specifically in the context of rich authorization requests. + *

+ * This class integrates with the {@link AuthorizationDetailsDAO} to persist these details in the underlying data store. + * It also provides utility methods to check if a request contains rich authorization details. + *

+ * + * @see AuthorizationDetailsDAO + * @see AuthorizationDetails + */ +public class AuthorizationDetailsService { + + private static final Log log = LogFactory.getLog(AuthorizationDetailsService.class); + private final AuthorizationDetailsDAO authorizationDetailsDAO; + private final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory; + + /** + * Default constructor that initializes the service with the default {@link AuthorizationDetailsDAO} and + * {@link AuthorizationDetailsProviderFactory}. + *

+ * This constructor uses the default DAO provided by the {@link OAuthTokenPersistenceFactory} + * to handle the persistence of authorization details. + *

+ */ + public AuthorizationDetailsService() { + + this( + AuthorizationDetailsProviderFactory.getInstance(), + OAuthTokenPersistenceFactory.getInstance().getAuthorizationDetailsDAO() + ); + } + + /** + * Constructor that initializes the service with a given {@link AuthorizationDetailsDAO}. + * + * @param authorizationDetailsProviderFactory Factory instance for providing authorization details. + * @param authorizationDetailsDAO The {@link AuthorizationDetailsDAO} instance to be used for + * handling authorization details persistence. Must not be {@code null}. + */ + public AuthorizationDetailsService(final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory, + final AuthorizationDetailsDAO authorizationDetailsDAO) { + + this.authorizationDetailsDAO = Objects + .requireNonNull(authorizationDetailsDAO, "AuthorizationDetailsDAO must not be null"); + this.authorizationDetailsProviderFactory = Objects.requireNonNull(authorizationDetailsProviderFactory, + "AuthorizationDetailsProviderFactory must not be null"); + } + + /** + * Stores user-consented authorization details. + * + * @param authenticatedUser The authenticated user. + * @param clientId The client ID. + * @param oAuth2Parameters Requested OAuth2 parameters. + * @param userConsentedAuthorizationDetails User consented authorization details. + * @throws OAuthSystemException if an error occurs while storing user consented authorization details. + */ + public void storeUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, final String clientId, + final OAuth2Parameters oAuth2Parameters, + final AuthorizationDetails userConsentedAuthorizationDetails) + throws OAuthSystemException { + + if (!isRichAuthorizationRequest(oAuth2Parameters)) { + log.debug("Request is not a rich authorization request. Skipping storage of authorization details."); + return; + } + + try { + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); + + if (consentId.isPresent()) { + final AuthorizationDetails trimmedAuthorizationDetails = AuthorizationDetailsUtils + .getTrimmedAuthorizationDetails(userConsentedAuthorizationDetails); + + final List authorizationDetailsConsentDTOs = + getAuthorizationDetailsConsentDTOs(consentId.get(), trimmedAuthorizationDetails, tenantId); + + this.authorizationDetailsDAO.addUserConsentedAuthorizationDetails(authorizationDetailsConsentDTOs); + if (log.isDebugEnabled()) { + log.debug("User consented authorization details stored successfully. consentId: " + + consentId.get()); + } + } + } catch (SQLException | IdentityOAuth2Exception e) { + log.error("Error occurred while storing user consented authorization details. Caused by, ", e); + throw new OAuthSystemException("Error occurred while storing authorization details", e); + } + } + + public void updateUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final String clientId, final OAuth2Parameters oAuth2Parameters, + final AuthorizationDetails userConsentedAuthorizationDetails) + throws OAuthSystemException { + + if (!isRichAuthorizationRequest(oAuth2Parameters)) { + return; + } + + try { + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); + + if (consentId.isPresent()) { + + final List authorizationDetailsConsentDTOs = + getAuthorizationDetailsConsentDTOs(consentId.get(), + userConsentedAuthorizationDetails, tenantId); + + this.authorizationDetailsDAO.updateUserConsentedAuthorizationDetails(authorizationDetailsConsentDTOs); + } + } catch (SQLException | IdentityOAuth2Exception e) { + log.error("Error occurred while updating user consented authorization details. Caused by, ", e); + throw new OAuthSystemException("Error occurred while updating authorization details", e); + } + } + + /** + * Deletes user-consented authorization details. + * + * @param authenticatedUser The authenticated user. + * @param clientId The client ID. + * @param oAuth2Parameters Requested OAuth2 parameters. + * @throws OAuthSystemException if an error occurs while deleting authorization details. + */ + public void deleteUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final String clientId, final OAuth2Parameters oAuth2Parameters) + throws OAuthSystemException { + + if (!isRichAuthorizationRequest(oAuth2Parameters)) { + log.debug("Request is not a rich authorization request. Skipping deletion of authorization details."); + return; + } + + try { + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); + + if (consentId.isPresent()) { + + this.authorizationDetailsDAO.deleteUserConsentedAuthorizationDetails(consentId.get(), tenantId); + + if (log.isDebugEnabled()) { + log.debug("User consented authorization details deleted successfully. consentId: " + + consentId.get()); + } + } + } catch (SQLException | IdentityOAuth2Exception e) { + log.error("Error occurred while deleting user consented authorization details. Caused by, ", e); + throw new OAuthSystemException("Error occurred while storing authorization details", e); + } + } + + /** + * Replaces the user consented authorization details. + * + * @param authenticatedUser The authenticated user. + * @param clientId The client ID. + * @param oAuth2Parameters Requested OAuth2 parameters. + * @param userConsentedAuthorizationDetails User consented authorization details. + * @throws OAuthSystemException if an error occurs while storing or replacing authorization details. + */ + public void replaceUserConsentedAuthorizationDetails( + final AuthenticatedUser authenticatedUser, final String clientId, final OAuth2Parameters oAuth2Parameters, + final AuthorizationDetails userConsentedAuthorizationDetails) throws OAuthSystemException { + + this.deleteUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters); + this.storeUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters, + userConsentedAuthorizationDetails); + } + + /** + * Check if the user has already given consent to requested authorization details. + * + * @param authenticatedUser Authenticated user. + * @param oAuth2Parameters OAuth2 parameters. + * @return {@code true} if user has given consent to all the requested authorization details, + * {@code false} otherwise. + */ + public boolean isUserAlreadyConsentedForAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final OAuth2Parameters oAuth2Parameters) + throws IdentityOAuth2Exception { + + if (!isRichAuthorizationRequest(oAuth2Parameters)) { + return true; + } + + return this.getConsentRequiredAuthorizationDetails(authenticatedUser, oAuth2Parameters).getDetails().isEmpty(); + } + + /** + * Retrieves the user consented authorization details for a given user, client, and tenant. + * + * @param authenticatedUser The authenticated user. + * @param clientId The client ID. + * @param tenantId The tenant ID. + * @return The user consented authorization details. + * @throws IdentityOAuth2Exception If an error occurs while retrieving the details. + */ + public AuthorizationDetails getUserConsentedAuthorizationDetails( + final AuthenticatedUser authenticatedUser, final String clientId, final int tenantId) + throws IdentityOAuth2Exception { + + try { + final Set consentedAuthorizationDetails = new HashSet<>(); + final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); + if (consentId.isPresent()) { + final Set consentedAuthorizationDetailsDTOs = + this.authorizationDetailsDAO.getUserConsentedAuthorizationDetails(consentId.get(), tenantId); + + consentedAuthorizationDetailsDTOs + .stream() + .filter(AuthorizationDetailsConsentDTO::isConsentActive) + .map(AuthorizationDetailsConsentDTO::getAuthorizationDetail) + .forEach(consentedAuthorizationDetails::add); + } + return new AuthorizationDetails(consentedAuthorizationDetails); + } catch (SQLException e) { + log.error("Error occurred while retrieving user consented authorization details. Caused by, ", e); + throw new IdentityOAuth2Exception("Unable to retrieve user consented authorization details", e); + } + } + + /** + * Retrieves the user consented authorization details for a given user and OAuth2 parameters. + * + * @param authenticatedUser The authenticated user. + * @param oAuth2Parameters The OAuth2 parameters. + * @return The user consented authorization details. + * @throws IdentityOAuth2Exception If an error occurs while retrieving the details. + */ + public AuthorizationDetails getUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final OAuth2Parameters oAuth2Parameters) + throws IdentityOAuth2Exception { + + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + return this.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters.getClientId(), tenantId); + } + + /** + * Retrieves the authorization details associated with a given access token. + * + * @param accessTokenId The access token ID. + * @param tenantId The tenant ID. + * @return The access token authorization details. + * @throws IdentityOAuth2Exception If an error occurs while retrieving the details. + */ + public AuthorizationDetails getAccessTokenAuthorizationDetails(final String accessTokenId, final int tenantId) + throws IdentityOAuth2Exception { + + try { + final Set authorizationDetailsTokenDTOs = + this.authorizationDetailsDAO.getAccessTokenAuthorizationDetails(accessTokenId, tenantId); + + final Set accessTokenAuthorizationDetails = new HashSet<>(); + authorizationDetailsTokenDTOs + .stream() + .map(AuthorizationDetailsTokenDTO::getAuthorizationDetail) + .forEach(accessTokenAuthorizationDetails::add); + + return new AuthorizationDetails(accessTokenAuthorizationDetails); + } catch (SQLException e) { + log.error("Error occurred while retrieving access token authorization details. Caused by, ", e); + throw new IdentityOAuth2Exception("Unable to retrieve access token authorization details", e); + } + } + + /** + * Stores the authorization details for a given access token and OAuth authorization request context. + * + * @param accessTokenDO The access token data object. + * @param oAuthAuthzReqMessageContext The OAuth authorization request message context. + * @throws IdentityOAuth2Exception If an error occurs while storing the details. + */ + public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessTokenDO, + final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) + throws IdentityOAuth2Exception { + + if (!isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) { + log.debug("Request is not a rich authorization request. Skipping storage of token authorization details."); + return; + } + + this.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthAuthzReqMessageContext.getAuthorizationDetails()); + } + + /** + * Stores the authorization details for a given access token and OAuth token request context. + * + * @param accessTokenDO The access token data object. + * @param oAuthTokenReqMessageContext The OAuth token request message context. + * @throws IdentityOAuth2Exception If an error occurs while storing the details. + */ + public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessTokenDO, + final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) + throws IdentityOAuth2Exception { + + if (!isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { + log.debug("Request is not a rich authorization request. Skipping storage of token authorization details."); + return; + } + + this.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthTokenReqMessageContext.getAuthorizationDetails()); + } + + /** + * Stores the authorization details for a given access token and authorization details. + * + * @param accessTokenDO The access token data object. + * @param authorizationDetails The authorization details. + * @throws IdentityOAuth2Exception If an error occurs while storing the details. + */ + public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessTokenDO, + final AuthorizationDetails authorizationDetails) + throws IdentityOAuth2Exception { + + try { + final AuthorizationDetails trimmedAuthorizationDetails = AuthorizationDetailsUtils + .getTrimmedAuthorizationDetails(authorizationDetails); + + final List authorizationDetailsTokenDTOs = AuthorizationDetailsUtils + .getAccessTokenAuthorizationDetailsDTOs(accessTokenDO, trimmedAuthorizationDetails); + + // Storing the authorization details. + this.authorizationDetailsDAO.addAccessTokenAuthorizationDetails(authorizationDetailsTokenDTOs); + + if (log.isDebugEnabled()) { + log.debug("Successfully stored access token authorization details for tokenId: " + + accessTokenDO.getTokenId()); + } + } catch (SQLException e) { + log.error("Error occurred while storing access token authorization details. Caused by, ", e); + throw new IdentityOAuth2Exception("Error occurred while storing access token authorization details", e); + } + } + + /** + * Stores or replaces the authorization details for a new access token and + * optionally deletes the old token's details. + * + * @param newAccessTokenDO The new access token data object. + * @param oldAccessTokenDO The old access token data object. + * @param oAuthTokenReqMessageContext The OAuth token request message context. + * @throws IdentityOAuth2Exception If an error occurs while storing or replacing the details. + */ + public void storeOrReplaceAccessTokenAuthorizationDetails( + final AccessTokenDO newAccessTokenDO, final AccessTokenDO oldAccessTokenDO, + final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) throws IdentityOAuth2Exception { + + if (!isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { + log.debug("Request is not a rich authorization request. Skipping storage of token authorization details."); + return; + } + + if (Objects.nonNull(oldAccessTokenDO)) { + this.deleteAccessTokenAuthorizationDetails(oldAccessTokenDO.getTokenId(), oldAccessTokenDO.getTenantID()); + } + + this.storeAccessTokenAuthorizationDetails(newAccessTokenDO, + oAuthTokenReqMessageContext.getAuthorizationDetails()); + } + + /** + * Replaces the authorization details for an old access token with the details of a new access token. + * + * @param oldAccessTokenId The old access token ID. + * @param newAccessTokenDO The new access token data object. + * @param oAuthTokenReqMessageContext The OAuth token request message context. + * @throws IdentityOAuth2Exception If an error occurs while replacing the details. + */ + public void replaceAccessTokenAuthorizationDetails(final String oldAccessTokenId, + final AccessTokenDO newAccessTokenDO, + final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) + throws IdentityOAuth2Exception { + + if (!isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { + log.debug("Request is not a rich authorization request. Skipping replacement of authorization details."); + return; + } + this.deleteAccessTokenAuthorizationDetails(oldAccessTokenId, newAccessTokenDO.getTenantID()); + this.storeAccessTokenAuthorizationDetails(newAccessTokenDO, oAuthTokenReqMessageContext); + } + + /** + * Deletes the authorization details associated with a given access token. + * + * @param accessTokenId The access token ID. + * @param tenantId The tenant ID. + * @throws IdentityOAuth2Exception If an error occurs while deleting the details. + */ + public void deleteAccessTokenAuthorizationDetails(final String accessTokenId, final int tenantId) + throws IdentityOAuth2Exception { + + try { + this.authorizationDetailsDAO.deleteAccessTokenAuthorizationDetails(accessTokenId, tenantId); + if (log.isDebugEnabled()) { + log.debug("Access token authorization details deleted successfully. accessTokenId: " + accessTokenId); + } + } catch (SQLException e) { + log.error("Error occurred while deleting access token authorization details. Caused by, ", e); + throw new IdentityOAuth2Exception("Error occurred while deleting access token authorization details", e); + } + } + + /** + * Retrieves the consent ID for the given user, client, and tenant. + * + * @param authenticatedUser The authenticated user. + * @param clientId The client ID. + * @param tenantId The tenant ID. + * @return An {@link Optional} containing the consent ID if present. + * @throws IdentityOAuth2Exception if an error occurs related to OAuth2 identity. + */ + private Optional getConsentId(final AuthenticatedUser authenticatedUser, final String clientId, + final int tenantId) + throws IdentityOAuth2Exception { + + final String userId = AuthorizationDetailsUtils.getIdFromAuthenticatedUser(authenticatedUser); + final String appId = AuthorizationDetailsUtils.getApplicationResourceIdFromClientId(clientId); + + return this.getConsentIdByUserIdAndAppId(userId, appId, tenantId); + } + + /** + * Retrieves the consent ID by user ID and application ID. + * + * @param userId The user ID. + * @param appId The application ID. + * @param tenantId The tenant ID. + * @return An {@link Optional} containing the consent ID if present. + * @throws IdentityOAuth2Exception if an error occurs while retrieving the consent ID. + */ + public Optional getConsentIdByUserIdAndAppId(final String userId, final String appId, final int tenantId) + throws IdentityOAuth2Exception { + + try { + return Optional + .ofNullable(this.authorizationDetailsDAO.getConsentIdByUserIdAndAppId(userId, appId, tenantId)); + } catch (SQLException e) { + log.error(String.format("Error occurred while retrieving user consent by " + + "userId: %s and appId: %s. Caused by, ", userId, appId), e); + throw new IdentityOAuth2Exception("Error occurred while retrieving user consent", e); + } + } + + public AuthorizationDetails getConsentRequiredAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final OAuth2Parameters oAuth2Parameters) + throws IdentityOAuth2Exception { + + if (!isRichAuthorizationRequest(oAuth2Parameters)) { + log.debug("Request is not a rich authorization request. Skipping the authorization details retrieval."); + return new AuthorizationDetails(); + } + + final Map> consentedAuthorizationDetailsByType = + getUserConsentedAuthorizationDetailsByType(authenticatedUser, oAuth2Parameters); + + final Set consentRequiredAuthorizationDetails = new HashSet<>(); + oAuth2Parameters.getAuthorizationDetails().stream() + .filter(requestedDetail -> + !this.isUserConsentedAuthorizationDetail(consentedAuthorizationDetailsByType, requestedDetail)) + .forEach(consentRequiredAuthorizationDetails::add); + + return new AuthorizationDetails(consentRequiredAuthorizationDetails); + } + + private Map> getUserConsentedAuthorizationDetailsByType( + final AuthenticatedUser authenticatedUser, final OAuth2Parameters oAuth2Parameters) + throws IdentityOAuth2Exception { + + return this.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters) + .stream() + .collect(Collectors.groupingBy(AuthorizationDetail::getType, + Collectors.mapping(Function.identity(), Collectors.toSet()))); + } + + /** + * Checks if the user has already consented to the requested authorization detail. + * + *

This method validates if the requested authorization detail is part of the consented authorization details. + * It uses the appropriate provider to compare the requested detail with the existing consented details.

+ * + * @param consentedAuthorizationDetailsByType a map of consented authorization details grouped by type + * @param requestedAuthorizationDetail the authorization detail to be checked + * @return {@code true} if the user has consented to the requested authorization detail, {@code false} otherwise + */ + public boolean isUserConsentedAuthorizationDetail( + final Map> consentedAuthorizationDetailsByType, + final AuthorizationDetail requestedAuthorizationDetail) { + + if (!consentedAuthorizationDetailsByType.containsKey(requestedAuthorizationDetail.getType())) { + log.debug("Request is not a rich authorization request. Skipping the validation."); + return false; + } + + final Optional provider = this.authorizationDetailsProviderFactory + .getProviderByType(requestedAuthorizationDetail.getType()); + if (provider.isPresent()) { + + if (log.isDebugEnabled()) { + log.debug("Validating equality of requested and existing authorization details " + + "using provider class: " + provider.get().getClass().getSimpleName()); + } + + final AuthorizationDetails existingAuthorizationDetails = new AuthorizationDetails( + consentedAuthorizationDetailsByType.get(requestedAuthorizationDetail.getType())); + boolean isEqualOrSubset = provider.get() + .isEqualOrSubset(requestedAuthorizationDetail, existingAuthorizationDetails); + + if (log.isDebugEnabled() && isEqualOrSubset) { + log.debug("User has already consented for the requested authorization details type: " + + requestedAuthorizationDetail.getType()); + } + return isEqualOrSubset; + } + if (log.isDebugEnabled()) { + log.debug(String.format("Ignores unsupported authorization details type: %s", + requestedAuthorizationDetail.getType())); + } + return true; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessor.java similarity index 75% rename from components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProvider.java rename to components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessor.java index aa05dec625..44b68875a4 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProvider.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessor.java @@ -18,14 +18,15 @@ package org.wso2.carbon.identity.oauth2.rar.core; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetail; -import org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException; import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; import org.wso2.carbon.identity.oauth2.rar.model.ValidationResult; /** - * The {@code AuthorizationDetailsProvider} interface defines a contract for implementing + * The {@code AuthorizationDetailsProcessor} interface defines a contract for implementing * different types of authorization detail providers in a Service Provider Interface (SPI) setup. *

* Implementing classes are expected to provide mechanisms to validate, enrich, and identify @@ -34,7 +35,7 @@ * * @see Java SPI */ -public interface AuthorizationDetailsProvider { +public interface AuthorizationDetailsProcessor { /** * Validates the provided authorization details context when a new Rich Authorization Request is received. @@ -48,13 +49,15 @@ public interface AuthorizationDetailsProvider { * @return a {@code ValidationResult} indicating the outcome of the validation process. Returns a valid result * if the authorization details are correct and meet the criteria, otherwise returns an invalid result with an * appropriate error message. - * @throws AuthorizationDetailsProcessingException if the validation fails and the authorization flow needs - * to be interrupted. + * @throws AuthorizationDetailsProcessingException if the validation fails due to a request error and the + * authorization flow needs to be interrupted. + * @throws IdentityOAuth2ServerException if the validation fails due to a server error and the + * authorization flow needs to be interrupted. * @see AuthorizationDetailsContext * @see ValidationResult */ ValidationResult validate(AuthorizationDetailsContext authorizationDetailsContext) - throws AuthorizationDetailsProcessingException; + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException; /** * Retrieves the type of authorization details handled by this provider. @@ -69,7 +72,18 @@ ValidationResult validate(AuthorizationDetailsContext authorizationDetailsContex */ String getType(); - // The existing authorization detail that was previously accepted by the resource owner. + /** + * Checks if the requested authorization detail is equal to or a subset of the existing authorization details. + * + *

This method verifies if the provided {@code requestedAuthorizationDetail} is either exactly the same as or + * a subset of the {@code existingAuthorizationDetails} that have been previously accepted by the resource owner. + * + * @param requestedAuthorizationDetail The {@link AuthorizationDetail} being requested by the client. + * @param existingAuthorizationDetails The set of {@link AuthorizationDetail} that have been previously accepted + * by the resource owner. + * @return {@code true} if the requested authorization detail is equal to or a subset of the existing + * authorization details, {@code false} otherwise. + */ boolean isEqualOrSubset(AuthorizationDetail requestedAuthorizationDetail, AuthorizationDetails existingAuthorizationDetails); diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java similarity index 75% rename from components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java rename to components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java index 123e3cc3dd..64ca86d097 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java @@ -18,8 +18,6 @@ package org.wso2.carbon.identity.oauth2.rar.core; -import org.wso2.carbon.identity.oauth2.rar.internal.AuthorizationDetailsDataHolder; - import java.util.Collections; import java.util.Map; import java.util.Optional; @@ -27,11 +25,12 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; /** - * A factory class to manage and provide instances of {@link AuthorizationDetailsProvider} Service Provider Interface. + * A factory class to manage and provide instances of {@link AuthorizationDetailsProcessor} Service Provider Interface. * This class follows the Singleton pattern to ensure only one instance is created. - * It uses {@link ServiceLoader} to dynamically load and manage {@link AuthorizationDetailsProvider} implementations. + * It uses {@link ServiceLoader} to dynamically load and manage {@link AuthorizationDetailsProcessor} implementations. *

Example usage: *

 {@code
  * // Get a specific provider by type
@@ -43,15 +42,14 @@
  *     );
  * } 

* - * @see AuthorizationDetailsProvider AuthorizationDetailsService + * @see AuthorizationDetailsProcessor AuthorizationDetailsService * @see * Request Parameter "authorization_details" - * @since 7.0.26.9 */ public class AuthorizationDetailsProviderFactory { private static volatile AuthorizationDetailsProviderFactory instance; - private final Map supportedAuthorizationDetailsTypes; + private final Map supportedAuthorizationDetailsTypes; /** * Private constructor to initialize the factory. @@ -65,16 +63,17 @@ private AuthorizationDetailsProviderFactory() { } /** - * Loads supported authorization details types from the provided {@link ServiceLoader}. + * Loads supported authorization details Processors from the provided {@link ServiceLoader}. * - * @return Map of authorization details types with their corresponding services. + * @return Map of authorization details types with their corresponding SPI services. */ - private Map loadSupportedAuthorizationDetailsTypes() { + private Map loadSupportedAuthorizationDetailsTypes() { + + final ServiceLoader serviceLoader = ServiceLoader + .load(AuthorizationDetailsProcessor.class, this.getClass().getClassLoader()); - return AuthorizationDetailsDataHolder.getInstance() - .getAuthorizationDetailsProviders() - .stream() - .collect(Collectors.toMap(AuthorizationDetailsProvider::getType, Function.identity())); + return StreamSupport.stream(serviceLoader.spliterator(), false) + .collect(Collectors.toMap(AuthorizationDetailsProcessor::getType, Function.identity())); } /** @@ -95,13 +94,13 @@ public static AuthorizationDetailsProviderFactory getInstance() { } /** - * Returns the {@link AuthorizationDetailsProvider} provider for the given type. + * Returns the {@link AuthorizationDetailsProcessor} provider for the given type. * * @param type A supported authorization details type. - * @return {@link Optional} containing the {@link AuthorizationDetailsProvider} if present, otherwise empty. - * @see AuthorizationDetailsProvider#getType() getAuthorizationDetailsType + * @return {@link Optional} containing the {@link AuthorizationDetailsProcessor} if present, otherwise empty. + * @see AuthorizationDetailsProcessor#getType() getAuthorizationDetailsType */ - public Optional getProviderByType(final String type) { + public Optional getProviderByType(final String type) { return Optional.ofNullable(this.supportedAuthorizationDetailsTypes.get(type)); } @@ -111,7 +110,7 @@ public Optional getProviderByType(final String typ * * @param type The type to check. * @return {@code true} if the type is supported, {@code false} otherwise. - * @see AuthorizationDetailsProvider AuthorizationDetailsService + * @see AuthorizationDetailsProcessor AuthorizationDetailsService */ public boolean isSupportedAuthorizationDetailsType(final String type) { @@ -121,7 +120,7 @@ public boolean isSupportedAuthorizationDetailsType(final String type) { /** * Returns a {@link Collections#unmodifiableSet} of all supported authorization details types. *

To be included as a supported authorization details type, there must be a custom implementation - * of the {@link AuthorizationDetailsProvider} Service Provider Interface (SPI) available in the classpath + * of the {@link AuthorizationDetailsProcessor} Service Provider Interface (SPI) available in the classpath * for the specified type.

* * @return A set of supported authorization details types. diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java new file mode 100644 index 0000000000..3ccc2784cc --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java @@ -0,0 +1,37 @@ +package org.wso2.carbon.identity.oauth2.rar.exception; + +import org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException; + +/** + * Exception class to represent failures related to Rich Authorization Requests in OAuth 2.0 clients. + * + *

This exception is thrown when there are errors in processing authorization details during the OAuth 2.0 + * authorization flow. It extends the {@link IdentityOAuth2ClientException} class, providing more specific + * context for authorization-related issues.

+ */ +public class AuthorizationDetailsProcessingException extends IdentityOAuth2ClientException { + + private static final long serialVersionUID = -206212512259482200L; + + /** + * Constructs a new exception with the specified detail message. + * + * @param message The detail message. It provides information about the cause of the exception. + */ + public AuthorizationDetailsProcessingException(final String message) { + + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + * @param message The detail message. It provides information about the cause of the exception. + * @param cause The cause of the exception. It can be used to retrieve the stack trace or other information + * about the root cause of the exception. + */ + public AuthorizationDetailsProcessingException(final String message, final Throwable cause) { + + super(message, cause); + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java new file mode 100644 index 0000000000..998ea794ac --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.model; + +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; + +import java.util.Objects; + +import javax.servlet.http.HttpServletRequestWrapper; + +import static org.wso2.carbon.identity.oauth2.authz.AuthorizationHandlerManager.OAUTH_APP_PROPERTY; + +/** + * Represents the context for rich authorization requests in an OAuth2 flow. + *

+ * This class holds relevant details such as OAuth2 parameters, application details, the authenticated user, + * and specific authorization details. It is immutable to ensure that the context remains consistent throughout its use. + *

+ */ +public class AuthorizationDetailsContext { + + private final AuthenticatedUser authenticatedUser; + private final AuthorizationDetail authorizationDetail; + private final HttpServletRequestWrapper httpServletRequestWrapper; + private final OAuthAppDO oAuthAppDO; + private final String[] scopes; + + /** + * Constructs a new {@code AuthorizationDetailsContext}. + *

+ * This constructor ensures that all necessary details for an authorization context are provided. + *

+ * + * @param authenticatedUser the {@link AuthenticatedUser}. + * @param authorizationDetail the specific {@link AuthorizationDetail} to be validated. + * @param httpServletRequestWrapper the {@link HttpServletRequestWrapper} instance containing request details. + * @param oAuthAppDO the {@link OAuthAppDO} containing application details. + * @param scopes the array of scopes requested. + * @throws NullPointerException if any of the arguments are {@code null}. + */ + public AuthorizationDetailsContext(final AuthenticatedUser authenticatedUser, + final AuthorizationDetail authorizationDetail, + final HttpServletRequestWrapper httpServletRequestWrapper, + final OAuthAppDO oAuthAppDO, + final String[] scopes) { + + this.authenticatedUser = Objects.requireNonNull(authenticatedUser, "authenticatedUser cannot be null"); + this.authorizationDetail = Objects.requireNonNull(authorizationDetail, "authorizationDetail cannot be null"); + this.httpServletRequestWrapper = Objects + .requireNonNull(httpServletRequestWrapper, "httpServletRequestWrapper cannot be null"); + this.oAuthAppDO = Objects.requireNonNull(oAuthAppDO, "oAuthAppDO cannot be null"); + this.scopes = Objects.requireNonNull(scopes, "scopes cannot be null"); + } + + /** + * Constructs a new {@code AuthorizationDetailsContext}. + * + * @param authorizationDetail the specific {@link AuthorizationDetail} to be validated. + * @param oAuthAuthzReqMessageContext the {@link OAuthAuthzReqMessageContext} instance which represent + * the authorization request context. + * @throws NullPointerException if any of the arguments are {@code null}. + */ + public AuthorizationDetailsContext(final AuthorizationDetail authorizationDetail, + final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) { + + this(oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getUser(), + authorizationDetail, + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getHttpServletRequestWrapper(), + (OAuthAppDO) oAuthAuthzReqMessageContext.getProperty(OAUTH_APP_PROPERTY), + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getScopes()); + } + + /** + * Constructs a new {@code AuthorizationDetailsContext}. + * + * @param authorizationDetail the specific {@link AuthorizationDetail} to be validated. + * @param oAuthTokenReqMessageContext the {@link OAuthTokenReqMessageContext} instance which represent + * the token request context. + * @throws NullPointerException if any of the arguments are {@code null}. + */ + public AuthorizationDetailsContext(final AuthorizationDetail authorizationDetail, + final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) { + + this(oAuthTokenReqMessageContext.getAuthorizedUser(), + authorizationDetail, + oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getHttpServletRequestWrapper(), + (OAuthAppDO) oAuthTokenReqMessageContext.getProperty(OAUTH_APP_PROPERTY), + oAuthTokenReqMessageContext.getScope()); + } + + /** + * Returns the {@code AuthorizationDetail} instance. + * + * @return the {@link AuthorizationDetail} instance. + */ + public AuthorizationDetail getAuthorizationDetail() { + return this.authorizationDetail; + } + + /** + * Returns the OAuth application details. + * + * @return the {@link OAuthAppDO} instance. + */ + public OAuthAppDO getoAuthAppDO() { + return this.oAuthAppDO; + } + + /** + * Returns the authenticated user. + * + * @return the {@link AuthenticatedUser} instance. + */ + public AuthenticatedUser getAuthenticatedUser() { + return this.authenticatedUser; + } + + /** + * Returns the HTTP servlet request user. + * + * @return the {@link HttpServletRequestWrapper} instance containing HTTP request details. + */ + public HttpServletRequestWrapper getHttpServletRequestWrapper() { + return this.httpServletRequestWrapper; + } + + /** + * Returns the valid scopes requested by the client. + * + * @return the {@link String} array of scopes. + */ + public String[] getScopes() { + return this.scopes; + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java new file mode 100644 index 0000000000..a6d4baa1cd --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java @@ -0,0 +1,49 @@ +package org.wso2.carbon.identity.oauth2.rar.token; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.token.handlers.response.AccessTokenResponseHandler; + +import java.util.HashMap; +import java.util.Map; + +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.isRichAuthorizationRequest; + +/** + * Class responsible for modifying the access token response to include user-consented authorization details. + * + *

This class enhances the access token response by appending user-consented authorization details. + * It is invoked by the {@link org.wso2.carbon.identity.oauth2.token.AccessTokenIssuer#issue} method during + * the OAuth 2.0 token issuance process.

+ */ +public class AccessTokenResponseRARHandler implements AccessTokenResponseHandler { + + private static final Log log = LogFactory.getLog(AccessTokenResponseRARHandler.class); + + /** + * Returns Rich Authorization Request attributes to be added to the access token response. + * + * @param oAuthTokenReqMessageContext {@link OAuthTokenReqMessageContext} token request message context. + * @return Map of additional attributes to be added to the token response. + * @throws IdentityOAuth2Exception Error while constructing additional token response attributes. + */ + @Override + public Map getAdditionalTokenResponseAttributes( + final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) throws IdentityOAuth2Exception { + + Map additionalAttributes = new HashMap<>(); + if (isRichAuthorizationRequest(oAuthTokenReqMessageContext.getAuthorizationDetails())) { + + if (log.isDebugEnabled()) { + log.debug("Processing Rich Authorization Request in token flow. authorization_details: " + + oAuthTokenReqMessageContext.getAuthorizationDetails().toJsonString()); + } + additionalAttributes.put(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS, + oAuthTokenReqMessageContext.getAuthorizationDetails().toSet()); + } + return additionalAttributes; + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java new file mode 100644 index 0000000000..e2399aff36 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java @@ -0,0 +1,118 @@ +package org.wso2.carbon.identity.oauth2.rar.token; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.oauth.common.OAuthConstants; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.IntrospectionDataProvider; +import org.wso2.carbon.identity.oauth2.dto.OAuth2IntrospectionResponseDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO; +import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.validator.AuthorizationDetailsValidator; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.oauth2.validators.OAuth2TokenValidationMessageContext; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.AUTHORIZATION_DETAILS; + +/** + * Class responsible for modifying the introspection response to include user-consented authorization details. + * + *

This class enhances the introspection response by appending user-consented authorization details. + * It is invoked by the /introspect endpoint of the oauth.endpoint webapp during the token introspection process.

+ */ +public class IntrospectionRARDataProvider implements IntrospectionDataProvider { + + private static final Log log = LogFactory.getLog(IntrospectionRARDataProvider.class); + private final AuthorizationDetailsValidator authorizationDetailsValidator; + + public IntrospectionRARDataProvider() { + + this.authorizationDetailsValidator = + OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsValidator(); + } + + /** + * Provides additional Rich Authorization Requests data for OAuth token introspection. + * + * @param tokenValidationRequestDTO Token validation request DTO. + * @param introspectionResponseDTO Token introspection response DTO. + * @return Map of additional data to be added to the introspection response. + * @throws IdentityOAuth2Exception If an error occurs while setting additional introspection data. + */ + @Override + public Map getIntrospectionData( + final OAuth2TokenValidationRequestDTO tokenValidationRequestDTO, + final OAuth2IntrospectionResponseDTO introspectionResponseDTO) throws IdentityOAuth2Exception { + + final Map introspectionData = new HashMap<>(); + final OAuth2TokenValidationMessageContext tokenValidationMessageContext = + generateOAuth2TokenValidationMessageContext(tokenValidationRequestDTO, introspectionResponseDTO); + + if (Objects.nonNull(tokenValidationMessageContext)) { + final AuthorizationDetails validatedAuthorizationDetails = this.authorizationDetailsValidator + .getValidatedAuthorizationDetails(tokenValidationMessageContext); + introspectionData.put(AUTHORIZATION_DETAILS, validatedAuthorizationDetails.toSet()); + } + return introspectionData; + } + + /** + * Generates an OAuth2TokenValidationMessageContext based on the token validation request and + * introspection response. + * + * @param tokenValidationRequestDTO The OAuth2 token validation request DTO. + * @param introspectionResponseDTO The OAuth2 introspection response DTO. + * @return The generated OAuth2TokenValidationMessageContext. + * @throws IdentityOAuth2Exception If an error occurs during the generation of the context. + */ + private OAuth2TokenValidationMessageContext generateOAuth2TokenValidationMessageContext( + final OAuth2TokenValidationRequestDTO tokenValidationRequestDTO, + final OAuth2IntrospectionResponseDTO introspectionResponseDTO) throws IdentityOAuth2Exception { + + // Check if the introspection response contains a validation message context + if (introspectionResponseDTO.getProperties().containsKey(OAuth2Util.OAUTH2_VALIDATION_MESSAGE_CONTEXT)) { + log.debug("Introspection response contains a validation message context."); + + final Object oAuth2TokenValidationMessageContext = introspectionResponseDTO.getProperties() + .get(OAuth2Util.OAUTH2_VALIDATION_MESSAGE_CONTEXT); + + if (oAuth2TokenValidationMessageContext instanceof OAuth2TokenValidationMessageContext) { + return (OAuth2TokenValidationMessageContext) oAuth2TokenValidationMessageContext; + } + } else { + // Create a new validation message context + final OAuth2TokenValidationMessageContext oAuth2TokenValidationMessageContext = + new OAuth2TokenValidationMessageContext(tokenValidationRequestDTO, + generateOAuth2TokenValidationResponseDTO(introspectionResponseDTO)); + + final AccessTokenDO accessTokenDO = OAuth2ServiceComponentHolder.getInstance().getTokenProvider() + .getVerifiedAccessToken(tokenValidationRequestDTO.getAccessToken().getIdentifier(), false); + + oAuth2TokenValidationMessageContext.addProperty(OAuthConstants.ACCESS_TOKEN_DO, accessTokenDO); + + return oAuth2TokenValidationMessageContext; + } + + log.debug("OAuth2TokenValidationMessageContext could not be generated. returning null"); + return null; + } + + private OAuth2TokenValidationResponseDTO generateOAuth2TokenValidationResponseDTO( + final OAuth2IntrospectionResponseDTO oAuth2IntrospectionResponseDTO) { + + final OAuth2TokenValidationResponseDTO tokenValidationResponseDTO = new OAuth2TokenValidationResponseDTO(); + tokenValidationResponseDTO.setValid(oAuth2IntrospectionResponseDTO.isActive()); + tokenValidationResponseDTO.setErrorMsg(oAuth2IntrospectionResponseDTO.getError()); + tokenValidationResponseDTO.setScope(OAuth2Util.buildScopeArray(oAuth2IntrospectionResponseDTO.getScope())); + tokenValidationResponseDTO.setExpiryTime(oAuth2IntrospectionResponseDTO.getExp()); + + return tokenValidationResponseDTO; + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java new file mode 100644 index 0000000000..d429390131 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java @@ -0,0 +1,70 @@ +package org.wso2.carbon.identity.oauth2.rar.token; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.token.handlers.claims.JWTAccessTokenClaimProvider; + +import java.util.HashMap; +import java.util.Map; + +/** + * Provides additional claims related to Rich Authorization Requests to be included in JWT Access Tokens. + * This implementation supports both the OAuth2 authorization and token flows. + */ +public class JWTAccessTokenRARClaimProvider implements JWTAccessTokenClaimProvider { + + private static final Log log = LogFactory.getLog(JWTAccessTokenRARClaimProvider.class); + + /** + * Returns a map of additional claims related to Rich Authorization Requests to be included in + * JWT Access Tokens issued in the OAuth2 authorize flow. + * + * @param oAuthAuthzReqMessageContext The OAuth authorization request message context. + * @return A map of additional claims. + * @throws IdentityOAuth2Exception If an error occurs during claim retrieval. + */ + @Override + public Map getAdditionalClaims(final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) + throws IdentityOAuth2Exception { + + final Map additionalClaims = new HashMap<>(); + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) { + if (log.isDebugEnabled()) { + log.debug("Processing Rich Authorization Request in authorization flow. authorization_details: " + + oAuthAuthzReqMessageContext.getAuthorizationDetails().toJsonString()); + } + additionalClaims.put(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS, + oAuthAuthzReqMessageContext.getAuthorizationDetails().toSet()); + } + return additionalClaims; + } + + /** + * Returns a map of additional claims related to Rich Authorization Requests to be included in + * JWT Access Tokens issued in the OAuth2 token flow. + * + * @param oAuthTokenReqMessageContext The OAuth token request message context. + * @return A map of additional claims. + * @throws IdentityOAuth2Exception If an error occurs during claim retrieval. + */ + @Override + public Map getAdditionalClaims(final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) + throws IdentityOAuth2Exception { + + final Map additionalClaims = new HashMap<>(); + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { + if (log.isDebugEnabled()) { + log.debug("Processing Rich Authorization Request in token flow.authorization_details: " + + oAuthTokenReqMessageContext.getAuthorizationDetails().toJsonString()); + } + additionalClaims.put(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS, + oAuthTokenReqMessageContext.getAuthorizationDetails().toSet()); + } + return additionalClaims; + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java new file mode 100644 index 0000000000..eaf24b4c39 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java @@ -0,0 +1,341 @@ +package org.wso2.carbon.identity.oauth2.rar.util; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest; +import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.CarbonOAuthTokenRequest; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; + +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.AUTHORIZATION_DETAILS_ID_PREFIX; + +/** + * Utility class for handling and validating authorization details in OAuth2 requests. + */ +public class AuthorizationDetailsUtils { + + private static final Log log = LogFactory.getLog(AuthorizationDetailsUtils.class); + + /** + * Determines if the given {@link OAuthAuthzReqMessageContext} object contains {@link AuthorizationDetails}. + * + * @param oAuthAuthzReqMessageContext The requested OAuthAuthzReqMessageContext to check. + * @return {@code true} if the OAuthAuthzReqMessageContext contains non-empty authorization details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) { + + return isRichAuthorizationRequest(oAuthAuthzReqMessageContext.getAuthorizationDetails()); + } + + /** + * Determines if the given {@link OAuthAuthzRequest} object contains {@code authorization_details}. + * + * @param oauthRequest The OAuth Authorization Request to check. + * @return {@code true} if the OAuth authorization request contains a non-blank authorization details parameter, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuthAuthzRequest oauthRequest) { + + return StringUtils.isNotBlank(oauthRequest.getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); + } + + /** + * Determines if the given {@link CarbonOAuthTokenRequest} object contains {@code authorization_details}. + * + * @param carbonOAuthTokenRequest The OAuth Token Request to check. + * @return {@code true} if the OAuth token request contains a non-blank authorization details parameter, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final CarbonOAuthTokenRequest carbonOAuthTokenRequest) { + + return StringUtils + .isNotBlank(carbonOAuthTokenRequest.getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); + } + + /** + * Determines if the request is a rich authorization request using provided {@link AuthorizationDetails} object. + *

+ * This method checks if the specified {@link AuthorizationDetails} instance is not {@code null} + * and has a non-empty details set. + * + * @param authorizationDetails The {@link AuthorizationDetails} to check. + * @return {@code true} if the {@link AuthorizationDetails} is not {@code null} and has a non-empty details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final AuthorizationDetails authorizationDetails) { + + return authorizationDetails != null && !authorizationDetails.getDetails().isEmpty(); + } + + /** + * Determines if the given {@link OAuth2Parameters} object contains {@link AuthorizationDetails}. + * + * @param oAuth2Parameters The requested OAuth2Parameters to check. + * @return {@code true} if the OAuth2Parameters contains non-empty authorization details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuth2Parameters oAuth2Parameters) { + + return isRichAuthorizationRequest(oAuth2Parameters.getAuthorizationDetails()); + } + + /** + * Determines if the given {@link OAuthTokenReqMessageContext} object or the + * {@link OAuthTokenReqMessageContext#getOauth2AccessTokenReqDTO} contains {@link AuthorizationDetails}. + * + * @param oAuthTokenReqMessageContext The requested oAuthTokenReqMessageContext to check. + * @return {@code true} if the oAuthTokenReqMessageContext contains non-empty authorization details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) { + + return isRichAuthorizationRequest(oAuthTokenReqMessageContext.getAuthorizationDetails()) || + isRichAuthorizationRequest(oAuthTokenReqMessageContext + .getOauth2AccessTokenReqDTO().getAuthorizationDetails()); + } + + /** + * Determines if the given {@link OAuth2AuthorizeReqDTO} object contains {@link AuthorizationDetails}. + * + * @param oAuth2AuthorizeReqDTO The requested oAuth2AuthorizeReqDTO to check. + * @return {@code true} if the oAuth2AuthorizeReqDTO contains non-empty authorization details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO) { + + return isRichAuthorizationRequest(oAuth2AuthorizeReqDTO.getAuthorizationDetails()); + } + + /** + * Retrieves the application resource ID from the client ID. + * + * @param clientId The client ID. + * @return The application resource ID. + * @throws IdentityOAuth2Exception if an error occurs while retrieving the application resource ID. + */ + public static String getApplicationResourceIdFromClientId(final String clientId) throws IdentityOAuth2Exception { + + final ServiceProvider serviceProvider = OAuth2Util.getServiceProvider(clientId); + if (serviceProvider != null) { + return serviceProvider.getApplicationResourceId(); + } + throw new IdentityOAuth2Exception("Unable to find a service provider for client Id: " + clientId); + } + + /** + * Retrieves the user ID from the authenticated user. + * + * @param authenticatedUser The authenticated user. + * @return The user ID. + * @throws IdentityOAuth2Exception if an error occurs while retrieving the user ID. + */ + public static String getIdFromAuthenticatedUser(final AuthenticatedUser authenticatedUser) + throws IdentityOAuth2Exception { + + try { + return authenticatedUser.getUserId(); + } catch (UserIdNotFoundException e) { + log.error("Error occurred while extracting userId from authenticated user. Caused by, ", e); + throw new IdentityOAuth2Exception( + "User id is not found for user: " + authenticatedUser.getLoggableMaskedUserId(), e); + } + } + + /** + * Generates a list of {@link AuthorizationDetailsConsentDTO} from the provided consent ID, + * authorization details, and tenant ID. + * + * @param consentId The consent ID. + * @param userConsentedAuthorizationDetails The user-consented authorization details. + * @param tenantId The tenant ID. + * @return A list of {@link AuthorizationDetailsConsentDTO}. + */ + public static List getAuthorizationDetailsConsentDTOs( + final String consentId, final AuthorizationDetails userConsentedAuthorizationDetails, final int tenantId) { + + return userConsentedAuthorizationDetails.stream() + .map(detail -> new AuthorizationDetailsConsentDTO(consentId, detail, true, tenantId)) + .collect(Collectors.toList()); + } + + /** + * Generates a list of {@link AuthorizationDetailsTokenDTO} from the provided access token and + * authorization details. + * + * @param accessTokenDO The access token data object. + * @param authorizationDetails The user-consented authorization details. + * @return A list of {@link AuthorizationDetailsTokenDTO}. + */ + public static List getAccessTokenAuthorizationDetailsDTOs( + final AccessTokenDO accessTokenDO, final AuthorizationDetails authorizationDetails) { + + return authorizationDetails + .stream() + .map(authorizationDetail -> new AuthorizationDetailsTokenDTO( + accessTokenDO.getTokenId(), authorizationDetail, accessTokenDO.getTenantID())) + .collect(Collectors.toList()); + } + + /** + * Extracts the user-consented authorization details from the request parameters and OAuth2 parameters. + * + * @param httpServletRequest The HTTP servlet request containing the authorization details. + * @param oAuth2Parameters The OAuth2 parameters that include the authorization details. + * @return The {@link AuthorizationDetails} containing the user-consented authorization details. + */ + public static AuthorizationDetails extractAuthorizationDetailsFromRequest( + final HttpServletRequest httpServletRequest, final OAuth2Parameters oAuth2Parameters) { + + if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuth2Parameters)) { + log.debug("Request is not a rich authorization request. Returning empty authorization details."); + return new AuthorizationDetails(); + } + + // Extract consented authorization detail IDs from the parameter map + final Set consentedAuthorizationDetailIDs = httpServletRequest.getParameterMap().keySet().stream() + .filter(parameterName -> parameterName.startsWith(AUTHORIZATION_DETAILS_ID_PREFIX)) + .map(parameterName -> parameterName.substring(AUTHORIZATION_DETAILS_ID_PREFIX.length())) + .collect(Collectors.toSet()); + + // Filter and collect the consented authorization details + final Set consentedAuthorizationDetails = oAuth2Parameters.getAuthorizationDetails() + .stream() + .filter(authorizationDetail -> consentedAuthorizationDetailIDs.contains(authorizationDetail.getId())) + .collect(Collectors.toSet()); + + log.debug("User consented authorization details extracted successfully."); + return new AuthorizationDetails(consentedAuthorizationDetails); + } + + /** + * Transforms the given {@link AuthorizationDetails} by creating a new set of {@link AuthorizationDetail} objects + * with only the displayable fields ({@code type}, {@code id}, {@code consentDescription}) copied over. + * + * @param authorizationDetails The original AuthorizationDetails to be transformed. + * @return A new {@link AuthorizationDetails} object containing the displayable authorization details. + */ + public static AuthorizationDetails getDisplayableAuthorizationDetails( + final AuthorizationDetails authorizationDetails) { + + final Set displayableAuthorizationDetails = authorizationDetails.stream() + .map(protectedAuthorizationDetail -> { + final AuthorizationDetail authorizationDetail = new AuthorizationDetail(); + authorizationDetail.setType(protectedAuthorizationDetail.getType()); + authorizationDetail.setId(protectedAuthorizationDetail.getId()); + authorizationDetail.setConsentDescription(protectedAuthorizationDetail.getConsentDescription()); + return authorizationDetail; + }).collect(Collectors.toSet()); + + return new AuthorizationDetails(displayableAuthorizationDetails); + } + + /** + * Trims the given {@link AuthorizationDetails} by setting the temporary {@code id} and {@code consentDescription} + * fields to null for each {@link AuthorizationDetail}. + * + * @param authorizationDetails The original AuthorizationDetails to be trimmed. + * @return The same AuthorizationDetails object with trimmed fields. + */ + public static AuthorizationDetails getTrimmedAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + authorizationDetails.stream().forEach(authorizationDetail -> { + authorizationDetail.setId(null); + authorizationDetail.setConsentDescription(null); + }); + return authorizationDetails; + } + + /** + * Generates an {@link AuthorizationDetails} instance from given JSON string + * and assigns unique IDs for each {@link AuthorizationDetail}. + * + * @param authorizationDetailsJson The JSON string representing the authorization details. + * @return The AuthorizationDetails object with unique IDs assigned to each AuthorizationDetail. + */ + public static AuthorizationDetails generateAndAssignUniqueIDs(final String authorizationDetailsJson) { + + return assignUniqueIDsToAuthorizationDetails(new AuthorizationDetails(authorizationDetailsJson)); + } + + /** + * Generates unique IDs for each {@link AuthorizationDetail} within the given {@link AuthorizationDetails} object. + * + * @param authorizationDetails The AuthorizationDetails object containing a set of AuthorizationDetail objects. + * @return The AuthorizationDetails object with unique IDs assigned to each AuthorizationDetail. + */ + public static AuthorizationDetails assignUniqueIDsToAuthorizationDetails(final AuthorizationDetails + authorizationDetails) { + + authorizationDetails.stream().filter(Objects::nonNull) + .forEach(authorizationDetail -> authorizationDetail.setId(UUID.randomUUID().toString())); + return authorizationDetails; + } + + /** + * Encodes the given AuthorizationDetails object to a URL-encoded JSON string. + * + * @param authorizationDetails The AuthorizationDetails object to be encoded. + * @return A URL-encoded JSON string representing the authorization details. + */ + public static String getUrlEncodedAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + try { + if (log.isDebugEnabled()) { + log.debug("Starts URL encoding authorization details: " + authorizationDetails.toJsonString()); + } + if (isRichAuthorizationRequest(authorizationDetails)) { + return URLEncoder.encode(authorizationDetails.toJsonString(), StandardCharsets.UTF_8.toString()); + } + } catch (UnsupportedEncodingException e) { + log.error("Error occurred while URL encoding authorization details. Caused by, ", e); + } + return StringUtils.EMPTY; + } + + /** + * Decodes the given URL-encoded AuthorizationDetails JSON String. + * + * @param encodedAuthorizationDetails The encoded AuthorizationDetails String to be decoded. + * @return A URL-decoded JSON string representing the authorization details. + */ + public static String getUrlDecodedAuthorizationDetails(final String encodedAuthorizationDetails) { + + try { + if (log.isDebugEnabled()) { + log.debug("Starts decoding URL encoded authorization details JSON: " + encodedAuthorizationDetails); + } + if (StringUtils.isNotEmpty(encodedAuthorizationDetails)) { + return URLDecoder.decode(encodedAuthorizationDetails, StandardCharsets.UTF_8.toString()); + } + } catch (UnsupportedEncodingException e) { + log.error("Error occurred while URL decoding authorization details Json. Caused by, ", e); + } + return StringUtils.EMPTY; + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/AuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/AuthorizationDetailsValidator.java new file mode 100644 index 0000000000..2cdf2afd7f --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/AuthorizationDetailsValidator.java @@ -0,0 +1,62 @@ +package org.wso2.carbon.identity.oauth2.rar.validator; + +import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.validators.OAuth2TokenValidationMessageContext; + +/** + * Interface for validating {@link AuthorizationDetails} in different OAuth2 message contexts. + * + *

This interface provides methods to validate {@link AuthorizationDetails} across various OAuth2 message contexts, + * including authorization requests, token requests, and token validation requests. Implementations of this + * interface should handle the validation logic specific to the type of request and ensure that the returned + * AuthorizationDetails are accurate and compliant with the application's security policies.

+ */ +public interface AuthorizationDetailsValidator { + + /** + * Validates and returns the {@link AuthorizationDetails} for the given {@link OAuthAuthzReqMessageContext}. + *

+ * Validates the {@link AuthorizationDetails} during the authorization request phase. + * This is typically invoked when an authorization request is received and needs to be processed. + * + * @param oAuthAuthzReqMessageContext The OAuth authorization request message context. + * @return The validated {@link AuthorizationDetails}. + * @throws AuthorizationDetailsProcessingException If an error occurs during the processing of authorization details + * @throws IdentityOAuth2ServerException if the validation fails due to a server error. + */ + AuthorizationDetails getValidatedAuthorizationDetails(OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException; + + /** + * Validates and returns the {@link AuthorizationDetails} for the given {@link OAuthTokenReqMessageContext}. + *

+ * Validates the AuthorizationDetails during the token request phase. This is usually called when an authorization + * code is exchanged for an access token, or when a refresh token request is made. + * + * @param oAuthTokenReqMessageContext The OAuth token request message context. + * @return The validated {@link AuthorizationDetails}. + * @throws AuthorizationDetailsProcessingException If an error occurs during the processing of authorization details + * @throws IdentityOAuth2ServerException if the validation fails due to a server error. + */ + AuthorizationDetails getValidatedAuthorizationDetails(OAuthTokenReqMessageContext oAuthTokenReqMessageContext) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException; + + /** + * Validates and returns the {@link AuthorizationDetails} for the given {@link OAuth2TokenValidationMessageContext}. + *

+ * Validates the {@link AuthorizationDetails} during the token validation phase. This method is often used when an + * access token is being introspected to ensure its legitimacy and the associated AuthorizationDetails. + * + * @param oAuth2TokenValidationMessageContext The OAuth2 token validation message context. + * @return The validated {@link AuthorizationDetails}. + * @throws AuthorizationDetailsProcessingException If an error occurs during the processing of authorization details + * @throws IdentityOAuth2ServerException If an error occurs related to the OAuth2 server. + */ + AuthorizationDetails getValidatedAuthorizationDetails(OAuth2TokenValidationMessageContext + oAuth2TokenValidationMessageContext) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException; +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java new file mode 100644 index 0000000000..52fce6d3e8 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.validator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.oltu.oauth2.common.message.types.GrantType; +import org.wso2.carbon.identity.oauth.common.OAuthConstants; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +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.rar.AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; +import org.wso2.carbon.identity.oauth2.rar.model.ValidationResult; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.oauth2.validators.OAuth2TokenValidationMessageContext; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Default implementation class responsible for validating {@link AuthorizationDetails} in different + * OAuth2 message contexts. + */ +public class DefaultAuthorizationDetailsValidator implements AuthorizationDetailsValidator { + + private static final Log log = LogFactory.getLog(DefaultAuthorizationDetailsValidator.class); + private final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory; + private final AuthorizationDetailsService authorizationDetailsService; + + public DefaultAuthorizationDetailsValidator() { + + this( + AuthorizationDetailsProviderFactory.getInstance(), + OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsService() + ); + } + + public DefaultAuthorizationDetailsValidator( + final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory, + final AuthorizationDetailsService authorizationDetailsService) { + + this.authorizationDetailsProviderFactory = authorizationDetailsProviderFactory; + this.authorizationDetailsService = authorizationDetailsService; + } + + /** + * {@inheritDoc} + */ + @Override + public AuthorizationDetails getValidatedAuthorizationDetails(final OAuthAuthzReqMessageContext + oAuthAuthzReqMessageContext) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { + + try { + return this.getValidatedAuthorizationDetails( + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getConsumerKey(), + OAuth2Util.getTenantId(oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getTenantDomain()), + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getAuthorizationDetails(), + authorizationDetail -> + new AuthorizationDetailsContext(authorizationDetail, oAuthAuthzReqMessageContext) + ); + } catch (IdentityOAuth2Exception e) { + log.error("Unable find the tenant ID of the domain: " + + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getTenantDomain() + " Caused by, ", e); + throw new AuthorizationDetailsProcessingException("Invalid tenant domain", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public AuthorizationDetails getValidatedAuthorizationDetails(final OAuthTokenReqMessageContext + oAuthTokenReqMessageContext) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { + + final OAuth2AccessTokenReqDTO accessTokenReqDTO = oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO(); + + if (GrantType.AUTHORIZATION_CODE.toString().equals(accessTokenReqDTO.getGrantType())) { + if (log.isDebugEnabled()) { + log.debug("Skipping the authorization_details validation for authorization code flow " + + "as this validation has already happened in the authorize flow."); + } + return oAuthTokenReqMessageContext.getAuthorizationDetails(); + } + + if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(accessTokenReqDTO.getAuthorizationDetails())) { + if (log.isDebugEnabled()) { + log.debug("Client application does not request new authorization details. " + + "Returning previously validated authorization details."); + + } + return oAuthTokenReqMessageContext.getAuthorizationDetails(); + } + + return this.getValidatedAuthorizationDetails( + accessTokenReqDTO.getClientId(), + oAuthTokenReqMessageContext.getTenantID(), + accessTokenReqDTO.getAuthorizationDetails(), + authorizationDetail -> new AuthorizationDetailsContext(authorizationDetail, oAuthTokenReqMessageContext) + ); + } + + /** + * {@inheritDoc} + */ + @Override + public AuthorizationDetails getValidatedAuthorizationDetails( + final OAuth2TokenValidationMessageContext oAuth2TokenValidationMessageContext) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { + + try { + final AccessTokenDO accessTokenDO = (AccessTokenDO) oAuth2TokenValidationMessageContext + .getProperty(OAuthConstants.ACCESS_TOKEN_DO); + + final AuthorizationDetails accessTokenAuthorizationDetails = this.authorizationDetailsService + .getAccessTokenAuthorizationDetails(accessTokenDO.getTokenId(), accessTokenDO.getTenantID()); + + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(accessTokenAuthorizationDetails)) { + final Set authorizedAuthorizationDetails = + this.getAuthorizedAuthorizationDetails( + accessTokenDO.getConsumerKey(), + accessTokenDO.getTenantID(), + accessTokenAuthorizationDetails); + return new AuthorizationDetails(authorizedAuthorizationDetails); + } + } catch (IdentityOAuth2Exception e) { + log.error("Error occurred while retrieving access token authorization details. Caused by, ", e); + throw new AuthorizationDetailsProcessingException("Unable to retrieve token authorization details", e); + } + return new AuthorizationDetails(); + } + + /** + * Validates the authorization details for OAuthTokenReqMessageContext. + * + * @param clientId The client ID. + * @param tenantId The tenant ID. + * @param authorizationDetails The set of authorization details to validate. + * @param contextProvider A lambda function to create the AuthorizationDetailsContext. + * @return An {@link AuthorizationDetails} object containing the validated authorization details. + * @throws AuthorizationDetailsProcessingException if validation fails. + */ + private AuthorizationDetails getValidatedAuthorizationDetails( + final String clientId, final int tenantId, final AuthorizationDetails authorizationDetails, + final Function contextProvider) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { + + final Set validatedAuthorizationDetails = new HashSet<>(); + for (final AuthorizationDetail authorizationDetail : + this.getAuthorizedAuthorizationDetails(clientId, tenantId, authorizationDetails)) { + + if (!isSupportedAuthorizationDetailType(authorizationDetail.getType())) { + throw new AuthorizationDetailsProcessingException(String.format(AuthorizationDetailsConstants + .TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT, authorizationDetail.getType())); + } + + if (log.isDebugEnabled()) { + log.debug("Validation started for authorization detail of type: " + authorizationDetail.getType()); + } + + final AuthorizationDetailsContext authorizationDetailsContext = contextProvider.apply(authorizationDetail); + + if (this.isValidAuthorizationDetail(authorizationDetailsContext)) { + validatedAuthorizationDetails.add(getEnrichedAuthorizationDetail(authorizationDetailsContext)); + } + } + + return new AuthorizationDetails(validatedAuthorizationDetails); + } + + private Set getAuthorizedAuthorizationDetails( + final String clientId, final int tenantId, final AuthorizationDetails authorizationDetails) { + + final Set authorizedAuthorizationDetailsTypes = + this.getAuthorizedAuthorizationDetailsTypes(clientId, tenantId); + + return authorizationDetails.stream() + .filter(authorizationDetail -> + authorizedAuthorizationDetailsTypes.contains(authorizationDetail.getType())) + .collect(Collectors.toSet()); + } + + private boolean isSupportedAuthorizationDetailType(final String authorizationDetailType) { + + return this.authorizationDetailsProviderFactory + .isSupportedAuthorizationDetailsType(authorizationDetailType); + } + + /** + * Checks if the provided authorization details context is valid. + * + * @param authorizationDetailsContext The context containing authorization details. + * @return {@code true} if the authorization details are valid; {@code false} otherwise. + */ + private boolean isValidAuthorizationDetail(final AuthorizationDetailsContext authorizationDetailsContext) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { + + Optional optionalProvider = this.authorizationDetailsProviderFactory + .getProviderByType(authorizationDetailsContext.getAuthorizationDetail().getType()); + + if (optionalProvider.isPresent()) { + + final ValidationResult validationResult = optionalProvider.get().validate(authorizationDetailsContext); + if (log.isDebugEnabled() && validationResult.isInvalid()) { + + log.debug(String.format("Authorization details validation failed for type %s. Caused by, %s", + authorizationDetailsContext.getAuthorizationDetail().getType(), validationResult.getReason())); + + } + return validationResult.isValid(); + } + throw new AuthorizationDetailsProcessingException(String.format( + AuthorizationDetailsConstants.TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT, + authorizationDetailsContext.getAuthorizationDetail().getType())); + } + + /** + * Enriches the authorization details using the provided context. + * + * @param authorizationDetailsContext The context containing authorization details. + * @return An enriched {@link AuthorizationDetail} object. + */ + private AuthorizationDetail getEnrichedAuthorizationDetail( + final AuthorizationDetailsContext authorizationDetailsContext) { + + return this.authorizationDetailsProviderFactory + .getProviderByType(authorizationDetailsContext.getAuthorizationDetail().getType()) + .map(authorizationDetailsProcessor -> authorizationDetailsProcessor.enrich(authorizationDetailsContext)) + // If provider is missing, return the original authorization detail instance + .orElse(authorizationDetailsContext.getAuthorizationDetail()); + } + + /** + * Retrieves the set of authorized authorization types for the given client and tenant domain. + * + * @param clientId The client ID. + * @param tenantId The tenant ID. + * @return A set of strings representing the authorized authorization types. + */ + private Set getAuthorizedAuthorizationDetailsTypes(final String clientId, final int tenantId) { + +// try { +// final String appId = OAuth2Util +// .getApplicationResourceIDByClientId(clientID, tenantDomain, this.applicationMgtService); +// +//// OAuth2ServiceComponentHolder.getInstance().getAuthorizedAPIManagementService() +// .getAuthorizedAuthorizationDetailsTypes(appId, tenantDomain); +// } catch (IdentityOAuth2Exception e) { +// throw new RuntimeException(e); +// } + Set authorizedAuthorizationDetailsTypes = new HashSet<>(); + authorizedAuthorizationDetailsTypes.add("payment_initiation"); + return authorizedAuthorizationDetailsTypes; + } + + +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/responsemode/provider/SuccessResponseDTO.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/responsemode/provider/SuccessResponseDTO.java index 4c96445fe5..524e5ce2ab 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/responsemode/provider/SuccessResponseDTO.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/responsemode/provider/SuccessResponseDTO.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.oauth2.responsemode.provider; import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import java.util.Set; @@ -34,6 +35,7 @@ public class SuccessResponseDTO { private String formPostBody; private String subjectToken; private Set scope = null; + private AuthorizationDetails authorizationDetails; public String getAuthorizationCode() { @@ -117,4 +119,25 @@ public void setSubjectToken(String subjectToken) { this.subjectToken = subjectToken; } + + /** + * Retrieves the authorization details to be included in the successful authorization response. + * + * @return the {@link AuthorizationDetails} instance representing the current authorization information. + * If no authorization details are available, it will return {@code null}. + */ + public AuthorizationDetails getAuthorizationDetails() { + + return this.authorizationDetails; + } + + /** + * Sets the authorization details to be included in the successful authorization response. + * + * @param authorizationDetails the {@link AuthorizationDetails} to set. + */ + public void setAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + this.authorizationDetails = authorizationDetails; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/responsemode/provider/impl/FragmentResponseModeProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/responsemode/provider/impl/FragmentResponseModeProvider.java index 51c5237234..313353d82e 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/responsemode/provider/impl/FragmentResponseModeProvider.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/responsemode/provider/impl/FragmentResponseModeProvider.java @@ -20,6 +20,9 @@ import org.apache.commons.lang.StringUtils; import org.wso2.carbon.identity.oauth.common.OAuthConstants; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.responsemode.provider.AbstractResponseModeProvider; import org.wso2.carbon.identity.oauth2.responsemode.provider.AuthorizationResponseDTO; @@ -55,6 +58,8 @@ public String getAuthResponseRedirectUrl(AuthorizationResponseDTO authorizationR String scope = authorizationResponseDTO.getSuccessResponseDTO().getScope(); String authenticatedIdPs = authorizationResponseDTO.getAuthenticatedIDPs(); String subjectToken = authorizationResponseDTO.getSuccessResponseDTO().getSubjectToken(); + final AuthorizationDetails authorizationDetails = authorizationResponseDTO.getSuccessResponseDTO() + .getAuthorizationDetails(); List params = new ArrayList<>(); if (accessToken != null) { params.add(OAuthConstants.ACCESS_TOKEN_RESPONSE_PARAM + "=" + accessToken); @@ -93,6 +98,11 @@ public String getAuthResponseRedirectUrl(AuthorizationResponseDTO authorizationR params.add(OAuthConstants.SUBJECT_TOKEN + "=" + subjectToken); } + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(authorizationDetails)) { + params.add(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS + "=" + + AuthorizationDetailsUtils.getUrlEncodedAuthorizationDetails(authorizationDetails)); + } + redirectUrl += "#" + String.join("&", params); } else { diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/AccessTokenIssuer.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/AccessTokenIssuer.java index 6d6f986290..ee5054ee99 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/AccessTokenIssuer.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/AccessTokenIssuer.java @@ -64,6 +64,12 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; +import org.wso2.carbon.identity.oauth2.rar.validator.AuthorizationDetailsValidator; +import org.wso2.carbon.identity.oauth2.rar.validator.DefaultAuthorizationDetailsValidator; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinding; import org.wso2.carbon.identity.oauth2.token.handlers.grant.AuthorizationGrantHandler; @@ -116,6 +122,7 @@ public class AccessTokenIssuer { private Map authzGrantHandlers; public static final String OAUTH_APP_DO = "OAuthAppDO"; private static final String SERVICE_PROVIDERS_SUB_CLAIM = "ServiceProviders.UseUsernameAsSubClaim"; + private final AuthorizationDetailsValidator authorizationDetailsValidator; /** * Private constructor which will not allow to create objects of this class from outside @@ -123,6 +130,7 @@ public class AccessTokenIssuer { private AccessTokenIssuer() throws IdentityOAuth2Exception { authzGrantHandlers = OAuthServerConfiguration.getInstance().getSupportedGrantTypes(); + this.authorizationDetailsValidator = new DefaultAuthorizationDetailsValidator(); AppInfoCache appInfoCache = AppInfoCache.getInstance(); if (appInfoCache != null) { if (log.isDebugEnabled()) { @@ -449,6 +457,35 @@ private OAuth2AccessTokenRespDTO validateGrantAndIssueToken(OAuth2AccessTokenReq return tokenRespDTO; } + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(tokReqMsgCtx)) { + try { + final AuthorizationDetails validatedAuthorizationDetails = this.authorizationDetailsValidator + .getValidatedAuthorizationDetails(tokReqMsgCtx); + tokReqMsgCtx.setAuthorizationDetails(validatedAuthorizationDetails); + } catch (AuthorizationDetailsProcessingException e) { + if (log.isDebugEnabled()) { + log.debug("Invalid authorization details requested by client Id: " + tokenReqDTO.getClientId()); + } + + if (LoggerUtils.isDiagnosticLogsEnabled()) { + LoggerUtils.triggerDiagnosticLogEvent(new DiagnosticLog.DiagnosticLogBuilder( + OAuthConstants.LogConstants.OAUTH_INBOUND_SERVICE, + OAuthConstants.LogConstants.ActionIDs.VALIDATE_AUTHORIZATION_DETAILS) + .inputParam(LogConstants.InputKeys.CLIENT_ID, tokenReqDTO.getClientId()) + .inputParam(OAuthConstants.LogConstants.InputKeys.REQUESTED_AUTHORIZATION_DETAILS, + tokenReqDTO.getAuthorizationDetails().toSet()) + .resultMessage(AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_MSG) + .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.FAILED)); + } + tokenRespDTO = handleError(AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_CODE, + AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_MSG, tokenReqDTO); + setResponseHeaders(tokReqMsgCtx, tokenRespDTO); + triggerPostListeners(tokenReqDTO, tokenRespDTO, tokReqMsgCtx, isRefreshRequest); + return tokenRespDTO; + } + } + handleTokenBinding(tokenReqDTO, grantType, tokReqMsgCtx, oAuthAppDO); try { diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/OAuthTokenReqMessageContext.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/OAuthTokenReqMessageContext.java index 4f1a55358a..693b7fe8ab 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/OAuthTokenReqMessageContext.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/OAuthTokenReqMessageContext.java @@ -21,6 +21,7 @@ import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinding; import java.util.Properties; @@ -56,6 +57,8 @@ public class OAuthTokenReqMessageContext { private boolean isImpersonationRequest; + private AuthorizationDetails authorizationDetails; + public OAuthTokenReqMessageContext(OAuth2AccessTokenReqDTO oauth2AccessTokenReqDTO) { this.oauth2AccessTokenReqDTO = oauth2AccessTokenReqDTO; @@ -183,4 +186,26 @@ public void setImpersonationRequest(boolean impersonationRequest) { isImpersonationRequest = impersonationRequest; } + + /** + * Retrieves the user consented or authorized authorization details. + * + * @return the {@link AuthorizationDetails} instance representing the rich authorization requests. + * If no authorization details are available, it will return {@code null}. + */ + public AuthorizationDetails getAuthorizationDetails() { + + return this.authorizationDetails; + } + + /** + * Sets the validated authorization details. + * This method updates the authorization details with the provided {@link AuthorizationDetails} instance. + * + * @param authorizationDetails the {@link AuthorizationDetails} to set. + */ + public void setAuthorizationDetails(final AuthorizationDetails authorizationDetails) { + + this.authorizationDetails = authorizationDetails; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java index 4fefb780b8..1ab7b78a5c 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java @@ -54,6 +54,9 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuer; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; @@ -89,6 +92,7 @@ public abstract class AbstractAuthorizationGrantHandler implements Authorization protected static final String EXISTING_TOKEN_ISSUED = "existingTokenUsed"; protected static final int SECONDS_TO_MILISECONDS_FACTOR = 1000; private boolean isHashDisabled = OAuth2Util.isHashDisabled(); + protected AuthorizationDetailsService authorizationDetailsService; @Override public void init() throws IdentityOAuth2Exception { @@ -98,6 +102,7 @@ public void init() throws IdentityOAuth2Exception { cacheEnabled = true; oauthCache = OAuthCache.getInstance(); } + this.authorizationDetailsService = OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsService(); } @Override @@ -419,6 +424,11 @@ private OAuth2AccessTokenRespDTO issueExistingAccessToken(OAuthTokenReqMessageCo existingTokenBean.getTokenId(), true); } + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(tokReqMsgCtx)) { + this.authorizationDetailsService.replaceAccessTokenAuthorizationDetails(existingTokenBean.getTokenId(), + existingTokenBean, tokReqMsgCtx); + } + setDetailsToMessageContext(tokReqMsgCtx, existingTokenBean); return createResponseWithTokenBean(existingTokenBean, expireTime, scope); } @@ -555,6 +565,8 @@ private void persistAccessTokenInDB(OAuthTokenReqMessageContext tokReqMsgCtx, Ac } storeAccessToken(tokenReq, getUserStoreDomain(tokReqMsgCtx.getAuthorizedUser()), newTokenBean, newAccessToken, existingTokenBean); + this.authorizationDetailsService + .storeOrReplaceAccessTokenAuthorizationDetails(newTokenBean, existingTokenBean, tokReqMsgCtx); } private void updateCacheIfEnabled(AccessTokenDO newTokenBean, String scope, OauthTokenIssuer oauthTokenIssuer) @@ -1176,4 +1188,19 @@ private boolean isFederatedUser(OAuthTokenReqMessageContext tokReqMsgCtx) { } return tokReqMsgCtx.getAuthorizedUser().isFederatedUser(); } + + protected void setRARPropertiesForTokenGeneration(final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) + throws IdentityOAuth2Exception { + + final int tenantId = OAuth2Util + .getTenantId(oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getTenantDomain()); + + final AuthorizationDetails userConsentedAuthorizationDetails = + this.authorizationDetailsService.getUserConsentedAuthorizationDetails( + oAuthTokenReqMessageContext.getAuthorizedUser(), + oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getClientId(), + tenantId); + + oAuthTokenReqMessageContext.setAuthorizationDetails(userConsentedAuthorizationDetails); + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AuthorizationCodeGrantHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AuthorizationCodeGrantHandler.java index 21b3ae46d0..e111552248 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AuthorizationCodeGrantHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AuthorizationCodeGrantHandler.java @@ -126,12 +126,15 @@ public String buildSyncLockString(OAuthTokenReqMessageContext tokReqMsgCtx) { } private void setPropertiesForTokenGeneration(OAuthTokenReqMessageContext tokReqMsgCtx, - OAuth2AccessTokenReqDTO tokenReq, AuthzCodeDO authzCodeBean) { + OAuth2AccessTokenReqDTO tokenReq, AuthzCodeDO authzCodeBean) + throws IdentityOAuth2Exception { + tokReqMsgCtx.setAuthorizedUser(authzCodeBean.getAuthorizedUser()); tokReqMsgCtx.setScope(authzCodeBean.getScope()); // keep the pre processed authz code as a OAuthTokenReqMessageContext property to avoid // calculating it again when issuing the access token. tokReqMsgCtx.addProperty(AUTHZ_CODE, tokenReq.getAuthorizationCode()); + super.setRARPropertiesForTokenGeneration(tokReqMsgCtx); } private boolean validateCallbackUrlFromRequest(String callbackUrlFromRequest, 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 8a2752997c..ccebaa2650 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 @@ -131,6 +131,8 @@ public OAuth2AccessTokenRespDTO issue(OAuthTokenReqMessageContext tokReqMsgCtx) // sets accessToken, refreshToken and validity data setTokenData(accessTokenBean, tokReqMsgCtx, validationBean, tokenReq, accessTokenBean.getIssuedTime()); persistNewToken(tokReqMsgCtx, accessTokenBean, tokenReq.getClientId()); + super.authorizationDetailsService + .replaceAccessTokenAuthorizationDetails(validationBean.getTokenId(), accessTokenBean, tokReqMsgCtx); if (log.isDebugEnabled()) { log.debug("Persisted an access token for the refresh token, " + @@ -222,6 +224,7 @@ private void setPropertiesForTokenGeneration(OAuthTokenReqMessageContext tokReqM // Store the old access token as a OAuthTokenReqMessageContext property, this is already // a preprocessed token. tokReqMsgCtx.addProperty(PREV_ACCESS_TOKEN, validationBean); + super.setRARPropertiesForTokenGeneration(tokReqMsgCtx); } private boolean validateRefreshTokenInRequest(OAuth2AccessTokenReqDTO tokenReq, diff --git a/pom.xml b/pom.xml index 278ca1bfc9..e9dec24b8d 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,6 @@ features/org.wso2.carbon.identity.oauth.server.feature features/org.wso2.carbon.identity.oauth.ui.feature features/org.wso2.carbon.identity.oauth.dcr.server.feature - components/org.wso2.carbon.identity.oauth.rar.common components/org.wso2.carbon.identity.oauth.rar @@ -559,11 +558,6 @@ org.wso2.carbon.identity.oauth.rar ${project.version} - - org.wso2.carbon.identity.inbound.auth.oauth2 - org.wso2.carbon.identity.oauth.rar.common - ${project.version} - From 824163c0d3fffeccb7bfe1e6d09c471782de863e Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Wed, 7 Aug 2024 15:43:34 +0530 Subject: [PATCH 03/28] Add unit tests for the rar module --- .../pom.xml | 106 ++++++++++++- .../rar/dao/AuthorizationDetailsDAOImpl.java | 27 ++-- .../dao/AuthorizationDetailsDAOImplTest.java | 143 ++++++++++++++++++ .../AuthorizationDetailsCommonUtilsTest.java | 136 +++++++++++++++++ .../identity/oauth2/rar/util/DAOUtils.java | 46 ++++++ .../src/test/resources/dbScripts/h2.sql | 29 ++++ .../src/test/resources/testng.xml | 28 ++++ 7 files changed, 501 insertions(+), 14 deletions(-) create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/DAOUtils.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/test/resources/testng.xml diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index b0999a268f..bccfc86fe7 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -55,11 +55,32 @@ provided + - junit - junit + org.testng + testng test + + + org.mockito + mockito-testng + test + + + + org.jacoco + org.jacoco.agent + runtime + test + + + + com.h2database + h2 + test + + @@ -80,6 +101,87 @@ 2048 + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + target/jacoco.exec + + true + + + + + org.jacoco + jacoco-maven-plugin + + + + **/*Constants.class + **/model/** + **/dto/** + + + + + default-prepare-agent + + prepare-agent + + + + default-instrument + + instrument + + + + default-restore-instrumented-classes + + restore-instrumented-classes + + + + default-report + prepare-package + + report + + + + default-report-integration + + report-integration + + + + default-check + + check + + + + + BUNDLE + + + COMPLEXITY + COVEREDRATIO + 0.80 + + + + + + + + + diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java index b7a561d0f5..224a4c7e11 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java @@ -100,19 +100,22 @@ public Set getUserConsentedAuthorizationDetails( public int[] updateUserConsentedAuthorizationDetails( final List authorizationDetailsConsentDTOs) throws SQLException { - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); - final PreparedStatement ps = - connection.prepareStatement(SQLQueries.UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { +// todo: This won't update the expected element. Hence, need to revisit the update logic + return null; - for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { - ps.setString(1, consentDTO.getAuthorizationDetail().toJsonString()); - ps.setBoolean(2, consentDTO.isConsentActive()); - ps.setString(3, consentDTO.getConsentId()); - ps.setInt(4, consentDTO.getTenantId()); - ps.addBatch(); - } - return ps.executeBatch(); - } +// try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); +// final PreparedStatement ps = +// connection.prepareStatement(SQLQueries.UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { +// +// for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { +// ps.setString(1, consentDTO.getAuthorizationDetail().toJsonString()); +// ps.setBoolean(2, consentDTO.isConsentActive()); +// ps.setString(3, consentDTO.getConsentId()); +// ps.setInt(4, consentDTO.getTenantId()); +// ps.addBatch(); +// } +// return ps.executeBatch(); +// } } /** diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java new file mode 100644 index 0000000000..c5784f9a80 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java @@ -0,0 +1,143 @@ +package org.wso2.carbon.identity.oauth2.rar.dao; + +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.util.DAOUtils; + +import java.sql.SQLException; +import java.util.Collections; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; + +public class AuthorizationDetailsDAOImplTest { + + private static final String TEST_CONSENT_ID = "52481ccd-0927-4d17-8cfc-5110fc4aa009"; + private static final String TEST_DB_NAME = "TEST_IAM_RAR_DATABASE"; + private static final int TEST_TENANT_ID = 1234; + private static final String TEST_TOKEN_ID = "e1fea951-a3b5-4347-bd73-b18b3feecd54"; + private static final String TEST_TYPE = "test_type_v1"; + + private MockedStatic identityDatabaseUtilMock; + private AuthorizationDetailsDAO uut; + + @BeforeClass + public void setUp() throws SQLException { + this.uut = new AuthorizationDetailsDAOImpl(); + DAOUtils.initializeDataSource(TEST_DB_NAME, DAOUtils.getFilePath("h2.sql")); + this.identityDatabaseUtilMock = Mockito.mockStatic(IdentityDatabaseUtil.class); + } + + @AfterClass + public void tearDown() throws SQLException { + + if (this.identityDatabaseUtilMock != null && !this.identityDatabaseUtilMock.isClosed()) { + this.identityDatabaseUtilMock.close(); + } + } + + @BeforeMethod + public void setUpBeforeMethod() throws SQLException { + this.identityDatabaseUtilMock + .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) + .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + } + + @Test(priority = 0) + public void testAddUserConsentedAuthorizationDetails() throws SQLException { + + assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size()); + + this.identityDatabaseUtilMock + .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) + .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + + AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail(); + testAuthorizationDetail.setType(TEST_TYPE); + + AuthorizationDetailsConsentDTO consentDTO = + new AuthorizationDetailsConsentDTO(TEST_CONSENT_ID, testAuthorizationDetail, true, TEST_TENANT_ID); + int[] result = uut.addUserConsentedAuthorizationDetails(Collections.singletonList(consentDTO)); + + assertEquals(1, result.length); + } + + @Test(priority = 1) + public void testGetUserConsentedAuthorizationDetails() throws SQLException { + + Set consentDTOs = + this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID); + + assertEquals(1, consentDTOs.size()); + consentDTOs.forEach(dto -> { + assertEquals(TEST_CONSENT_ID, dto.getConsentId()); + assertNotNull(dto.getAuthorizationDetail()); + assertEquals(TEST_TYPE, dto.getAuthorizationDetail().getType()); + }); + } + + @Test(priority = 2) + public void testDeleteUserConsentedAuthorizationDetails() throws SQLException { + + assertEquals(1, uut.deleteUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID)); + + this.identityDatabaseUtilMock + .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) + .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + + assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size()); + } + + @Test(priority = 0) + public void testAddAccessTokenAuthorizationDetails() throws SQLException { + assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size()); + + this.identityDatabaseUtilMock + .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) + .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + + AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail(); + testAuthorizationDetail.setType(TEST_TYPE); + + AuthorizationDetailsTokenDTO tokenDTO = + new AuthorizationDetailsTokenDTO(TEST_TOKEN_ID, testAuthorizationDetail, TEST_TENANT_ID); + + int[] result = uut.addAccessTokenAuthorizationDetails(Collections.singletonList(tokenDTO)); + + assertEquals(1, result.length); + } + + @Test(priority = 1) + public void testGetAccessTokenAuthorizationDetails() throws SQLException { + Set tokenDTOs = + this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID); + + assertEquals(1, tokenDTOs.size()); + tokenDTOs.forEach(dto -> { + assertEquals(TEST_TOKEN_ID, dto.getAccessTokenId()); + assertNotNull(dto.getAuthorizationDetail()); + assertEquals(TEST_TYPE, dto.getAuthorizationDetail().getType()); + }); + } + + @Test(priority = 2) + public void testDeleteAccessTokenAuthorizationDetails() throws SQLException { + assertEquals(1, uut.deleteAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID)); + + this.identityDatabaseUtilMock + .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) + .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + + assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size()); + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java new file mode 100644 index 0000000000..e5c35d5d05 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java @@ -0,0 +1,136 @@ +package org.wso2.carbon.identity.oauth2.rar.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.mockito.Mockito; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.testng.collections.Sets; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; + +/** + * Test class for {@link AuthorizationDetailsCommonUtils}. + */ +public class AuthorizationDetailsCommonUtilsTest { + + private ObjectMapper objectMapper; + private ObjectMapper mockObjectMapper; + private static final String TEST_TYPE = "test_type_v1"; + + @BeforeClass + public void setUp() throws JsonProcessingException { + + this.objectMapper = AuthorizationDetailsCommonUtils.getDefaultObjectMapper(); + this.mockObjectMapper = Mockito.spy(this.objectMapper); + + // mock + doThrow(JsonProcessingException.class) + .when(this.mockObjectMapper).writeValueAsString(any(TestAuthorizationDetail.class)); + doThrow(JsonProcessingException.class).when(this.mockObjectMapper).writeValueAsString(any(Set.class)); + } + + @DataProvider(name = "AuthorizationDetailsCommonUtilsTestDataProvider") + public Object[][] provideAuthorizationDetailsCommonUtilsTestData(Method testMethod) { + + switch (testMethod.getName()) { + case "shouldReturnNull_whenJSONIsInvalid": + case "shouldReturnCorrectSize_whenJSONArrayIsValid": + return new Object[][]{ + {null, 0}, + {"", 0}, + {" ", 0}, + {"invalid JSON", 0}, + {"[]", 0}, + {"[{}]", 1}, + {"[{},{}]", 2} + }; + case "shouldReturnCorrectType_whenJSONIsValid": + return new Object[][]{ + {AuthorizationDetail.class}, + {TestAuthorizationDetail.class} + }; + } + return null; + } + + @Test(dataProvider = "AuthorizationDetailsCommonUtilsTestDataProvider") + public void shouldReturnCorrectSize_whenJSONArrayIsValid(String inputJson, int expectedSize) { + + Set actualAuthorizationDetails = AuthorizationDetailsCommonUtils + .fromJSONArray(inputJson, AuthorizationDetail.class, objectMapper); + + assertEquals(expectedSize, actualAuthorizationDetails.size()); + } + + @Test(dataProvider = "AuthorizationDetailsCommonUtilsTestDataProvider") + public void shouldReturnNull_whenJSONIsInvalid(String inputJson, int expectedSize) { + + assertNull(AuthorizationDetailsCommonUtils.fromJSON(inputJson, AuthorizationDetail.class, objectMapper)); + } + + @Test(dataProvider = "AuthorizationDetailsCommonUtilsTestDataProvider") + public void shouldReturnCorrectType_whenJSONIsValid(Class expectedClazz) { + + final String inputJson = "{\"type\": \"" + TEST_TYPE + "\"}"; + AuthorizationDetail actualAuthorizationDetail = + AuthorizationDetailsCommonUtils.fromJSON(inputJson, expectedClazz, objectMapper); + + assertNotNull(actualAuthorizationDetail); + assertEquals(TEST_TYPE, actualAuthorizationDetail.getType()); + } + + @Test + public void shouldReturnCorrectJson_whenAuthorizationDetailsAreValid() { + + AuthorizationDetail inputAuthorizationDetail = new TestAuthorizationDetail(); + inputAuthorizationDetail.setType(TEST_TYPE); + + assertTrue(AuthorizationDetailsCommonUtils.toJSON(Sets.newHashSet(inputAuthorizationDetail), objectMapper) + .contains(TEST_TYPE)); + assertEquals("[]", AuthorizationDetailsCommonUtils.toJSON((Set) null, objectMapper)); + assertEquals("[]", + AuthorizationDetailsCommonUtils.toJSON(Sets.newHashSet(inputAuthorizationDetail), mockObjectMapper)); + } + + @Test + public void shouldReturnCorrectJson_whenAuthorizationDetailIsValid() { + + AuthorizationDetail inputAuthorizationDetail = new TestAuthorizationDetail(); + inputAuthorizationDetail.setType(TEST_TYPE); + + assertTrue(AuthorizationDetailsCommonUtils.toJSON(inputAuthorizationDetail, objectMapper).contains(TEST_TYPE)); + assertEquals("{}", AuthorizationDetailsCommonUtils.toJSON((TestAuthorizationDetail) null, objectMapper)); + assertEquals("{}", AuthorizationDetailsCommonUtils.toJSON(new TestAuthorizationDetail(), mockObjectMapper)); + } + + @Test + public void shouldReturnMap_whenAuthorizationDetailIsValid() { + + AuthorizationDetail inputAuthorizationDetail = new TestAuthorizationDetail(); + inputAuthorizationDetail.setType(TEST_TYPE); + Map actualMap = AuthorizationDetailsCommonUtils.toMap(inputAuthorizationDetail, objectMapper); + + assertTrue(actualMap.containsKey("type")); + assertEquals(TEST_TYPE, String.valueOf(actualMap.get("type"))); + assertEquals(1, actualMap.keySet().size()); + + assertFalse(AuthorizationDetailsCommonUtils.toMap(null, objectMapper).containsKey(TEST_TYPE)); + } + + private static class TestAuthorizationDetail extends AuthorizationDetail { + // Test authorization detail class which extends AuthorizationDetail + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/DAOUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/DAOUtils.java new file mode 100644 index 0000000000..9440b079be --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/DAOUtils.java @@ -0,0 +1,46 @@ +package org.wso2.carbon.identity.oauth2.rar.util; + +import org.apache.commons.dbcp.BasicDataSource; +import org.apache.commons.lang.StringUtils; + +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +/** + * DB Utils. + */ +public class DAOUtils { + + private static final Map dataSourceMap = new HashMap<>(); + + public static void initializeDataSource(String databaseName, String scriptPath) throws SQLException { + BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName("org.h2.Driver"); + dataSource.setUsername("username"); + dataSource.setPassword("password"); + dataSource.setUrl("jdbc:h2:mem:" + databaseName); + + try (Connection connection = dataSource.getConnection()) { + connection.createStatement().executeUpdate("RUNSCRIPT FROM '" + scriptPath + "'"); + } + dataSourceMap.put(databaseName, dataSource); + } + + public static Connection getConnection(String database) throws SQLException { + if (dataSourceMap.get(database) != null) { + return dataSourceMap.get(database).getConnection(); + } + throw new RuntimeException("Invalid datasource."); + } + + public static String getFilePath(String fileName) { + if (StringUtils.isNotBlank(fileName)) { + return Paths.get(System.getProperty("user.dir"), "src", "test", "resources", "dbScripts", fileName) + .toString(); + } + return null; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql new file mode 100644 index 0000000000..65c28adf66 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql @@ -0,0 +1,29 @@ +CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES( + ID INTEGER NOT NULL AUTO_INCREMENT, + TYPE VARCHAR(255) NOT NULL, + CURSOR_KEY INTEGER DEFAULT 1, + NAME VARCHAR(255), + DESCRIPTION VARCHAR (255), + JSON_SCHEMA JSON NOT NULL, + TENANT_ID INTEGER DEFAULT -1 +); + +CREATE TABLE IF NOT EXISTS IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS ( + ID INTEGER NOT NULL AUTO_INCREMENT, + CONSENT_ID VARCHAR(255) NOT NULL, + TYPE_ID INTEGER NOT NULL, + AUTHORIZATION_DETAILS JSON NOT NULL, + CONSENT BOOLEAN NOT NULL DEFAULT 1, + TENANT_ID INTEGER NOT NULL DEFAULT -1 +); + +CREATE TABLE IF NOT EXISTS IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS ( + ID INTEGER NOT NULL AUTO_INCREMENT, + TYPE_ID INTEGER NOT NULL, + AUTHORIZATION_DETAILS JSON NOT NULL, + TOKEN_ID VARCHAR (255), + TENANT_ID INTEGER DEFAULT -1 +); + +INSERT INTO IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES (TYPE, NAME, DESCRIPTION, JSON_SCHEMA, TENANT_ID) +VALUES ('test_type_v1', 'Test Type', 'Test Type V1', '{}', 1234); diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/testng.xml new file mode 100644 index 0000000000..f2065912fc --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/testng.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + From 3031c3268d63ab5457a7ba637653e571db010dc2 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Tue, 3 Sep 2024 15:54:49 +0530 Subject: [PATCH 04/28] Add unit tests --- .../dao/AuthorizationDetailsDAOImplTest.java | 25 +- .../AuthorizationDetailsCommonUtilsTest.java | 2 +- .../oauth2/rar/util/TestConstants.java | 17 + .../util/{DAOUtils.java => TestDAOUtils.java} | 4 +- .../authz/AuthorizationHandlerManager.java | 24 +- .../token/IntrospectionRARDataProvider.java | 15 +- .../rar/util/AuthorizationDetailsUtils.java | 56 ++- .../DefaultAuthorizationDetailsValidator.java | 3 +- .../carbon/identity/oauth2/TestConstants.java | 6 + .../rar/AuthorizationDetailsServiceTest.java | 403 ++++++++++++++++++ .../AccessTokenResponseRARHandlerTest.java | 34 ++ .../IntrospectionRARDataProviderTest.java | 111 +++++ .../JWTAccessTokenRARClaimProviderTest.java | 49 +++ .../utils/AuthorizationDetailsBaseTest.java | 140 ++++++ ...aultAuthorizationDetailsValidatorTest.java | 52 +++ .../src/test/resources/testng.xml | 10 + 16 files changed, 888 insertions(+), 63 deletions(-) create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestConstants.java rename components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/{DAOUtils.java => TestDAOUtils.java} (97%) create mode 100644 components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandlerTest.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProviderTest.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java index c5784f9a80..e507d24f25 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java @@ -10,7 +10,7 @@ import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; -import org.wso2.carbon.identity.oauth2.rar.util.DAOUtils; +import org.wso2.carbon.identity.oauth2.rar.util.TestDAOUtils; import java.sql.SQLException; import java.util.Collections; @@ -19,22 +19,21 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_CONSENT_ID; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_DB_NAME; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TENANT_ID; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TOKEN_ID; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TYPE; public class AuthorizationDetailsDAOImplTest { - private static final String TEST_CONSENT_ID = "52481ccd-0927-4d17-8cfc-5110fc4aa009"; - private static final String TEST_DB_NAME = "TEST_IAM_RAR_DATABASE"; - private static final int TEST_TENANT_ID = 1234; - private static final String TEST_TOKEN_ID = "e1fea951-a3b5-4347-bd73-b18b3feecd54"; - private static final String TEST_TYPE = "test_type_v1"; - private MockedStatic identityDatabaseUtilMock; private AuthorizationDetailsDAO uut; @BeforeClass public void setUp() throws SQLException { this.uut = new AuthorizationDetailsDAOImpl(); - DAOUtils.initializeDataSource(TEST_DB_NAME, DAOUtils.getFilePath("h2.sql")); + TestDAOUtils.initializeDataSource(TEST_DB_NAME, TestDAOUtils.getFilePath("h2.sql")); this.identityDatabaseUtilMock = Mockito.mockStatic(IdentityDatabaseUtil.class); } @@ -50,7 +49,7 @@ public void tearDown() throws SQLException { public void setUpBeforeMethod() throws SQLException { this.identityDatabaseUtilMock .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) - .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME)); } @Test(priority = 0) @@ -60,7 +59,7 @@ public void testAddUserConsentedAuthorizationDetails() throws SQLException { this.identityDatabaseUtilMock .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) - .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME)); AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail(); testAuthorizationDetail.setType(TEST_TYPE); @@ -93,7 +92,7 @@ public void testDeleteUserConsentedAuthorizationDetails() throws SQLException { this.identityDatabaseUtilMock .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) - .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME)); assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size()); } @@ -104,7 +103,7 @@ public void testAddAccessTokenAuthorizationDetails() throws SQLException { this.identityDatabaseUtilMock .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) - .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME)); AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail(); testAuthorizationDetail.setType(TEST_TYPE); @@ -136,7 +135,7 @@ public void testDeleteAccessTokenAuthorizationDetails() throws SQLException { this.identityDatabaseUtilMock .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) - .thenReturn(DAOUtils.getConnection(TEST_DB_NAME)); + .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME)); assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size()); } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java index e5c35d5d05..ccf61b834c 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TYPE; /** * Test class for {@link AuthorizationDetailsCommonUtils}. @@ -28,7 +29,6 @@ public class AuthorizationDetailsCommonUtilsTest { private ObjectMapper objectMapper; private ObjectMapper mockObjectMapper; - private static final String TEST_TYPE = "test_type_v1"; @BeforeClass public void setUp() throws JsonProcessingException { diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestConstants.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestConstants.java new file mode 100644 index 0000000000..b8e276837a --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestConstants.java @@ -0,0 +1,17 @@ +package org.wso2.carbon.identity.oauth2.rar.util; + +/** + * Rich Authorization Requests Test Constants. + */ +public class TestConstants { + + private TestConstants() { + // Private constructor to prevent instantiation + } + + public static final String TEST_CONSENT_ID = "52481ccd-0927-4d17-8cfc-5110fc4aa009"; + public static final String TEST_DB_NAME = "TEST_IAM_RAR_DATABASE"; + public static final int TEST_TENANT_ID = 1234; + public static final String TEST_TOKEN_ID = "e1fea951-a3b5-4347-bd73-b18b3feecd54"; + public static final String TEST_TYPE = "test_type_v1"; +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/DAOUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java similarity index 97% rename from components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/DAOUtils.java rename to components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java index 9440b079be..8c354b8217 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/DAOUtils.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java @@ -10,9 +10,9 @@ import java.util.Map; /** - * DB Utils. + * Test DB Utils. */ -public class DAOUtils { +public class TestDAOUtils { private static final Map dataSourceMap = new HashMap<>(); diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java index 705f4a58a4..a9f1307804 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java @@ -40,9 +40,7 @@ import org.wso2.carbon.identity.oauth2.authz.handlers.ResponseTypeHandler; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO; -import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; -import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; @@ -258,7 +256,7 @@ public OAuth2AuthorizeRespDTO handleAuthorization(OAuthAuthzReqMessageContext au // set the authorization request context to be used by downstream handlers. This is introduced as a fix for // IDENTITY-4111 OAuth2Util.setAuthzRequestContext(authzReqMsgCtx); - this.setUserConsentedAuthorizationDetails(authzReqMsgCtx); + AuthorizationDetailsUtils.setRARPropertiesToAuthzRequestContext(authzReqMsgCtx); authorizeRespDTO = authzHandler.issue(authzReqMsgCtx); } finally { // clears authorization request context @@ -680,7 +678,7 @@ private boolean isInvalidResponseType(OAuth2AuthorizeReqDTO authzReqDTO, OAuth2A return false; } - public OAuthAppDO getAppInformation(OAuth2AuthorizeReqDTO authzReqDTO) throws IdentityOAuth2Exception, + private OAuthAppDO getAppInformation(OAuth2AuthorizeReqDTO authzReqDTO) throws IdentityOAuth2Exception, InvalidOAuthClientException { OAuthAppDO oAuthAppDO = AppInfoCache.getInstance().getValueFromCache(authzReqDTO.getConsumerKey()); if (oAuthAppDO != null) { @@ -727,22 +725,4 @@ public OAuthErrorDTO handleAuthenticationFailure(OAuth2Parameters oAuth2Paramete ResponseTypeHandler responseTypeHandler = responseHandlers.get(oAuth2Parameters.getResponseType()); return responseTypeHandler.handleAuthenticationFailure(oAuth2Parameters); } - - private void setUserConsentedAuthorizationDetails(final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) - throws IdentityOAuth2Exception { - - OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO = oAuthAuthzReqMessageContext.getAuthorizationReqDTO(); - if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuth2AuthorizeReqDTO)) { - return; - } - - final AuthorizationDetails authorizationDetails = OAuth2ServiceComponentHolder.getInstance() - .getAuthorizationDetailsService() - .getUserConsentedAuthorizationDetails( - oAuth2AuthorizeReqDTO.getUser(), - oAuth2AuthorizeReqDTO.getConsumerKey(), - IdentityTenantUtil.getTenantId(oAuth2AuthorizeReqDTO.getTenantDomain()) - ); - oAuthAuthzReqMessageContext.setAuthorizationDetails(authorizationDetails); - } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java index e2399aff36..e6d3f97244 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java @@ -11,6 +11,7 @@ import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.rar.validator.AuthorizationDetailsValidator; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.oauth2.validators.OAuth2TokenValidationMessageContext; @@ -34,8 +35,12 @@ public class IntrospectionRARDataProvider implements IntrospectionDataProvider { public IntrospectionRARDataProvider() { - this.authorizationDetailsValidator = - OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsValidator(); + this(OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsValidator()); + } + + public IntrospectionRARDataProvider(final AuthorizationDetailsValidator authorizationDetailsValidator) { + + this.authorizationDetailsValidator = authorizationDetailsValidator; } /** @@ -56,9 +61,13 @@ public Map getIntrospectionData( generateOAuth2TokenValidationMessageContext(tokenValidationRequestDTO, introspectionResponseDTO); if (Objects.nonNull(tokenValidationMessageContext)) { + final AuthorizationDetails validatedAuthorizationDetails = this.authorizationDetailsValidator .getValidatedAuthorizationDetails(tokenValidationMessageContext); - introspectionData.put(AUTHORIZATION_DETAILS, validatedAuthorizationDetails.toSet()); + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(validatedAuthorizationDetails)) { + + introspectionData.put(AUTHORIZATION_DETAILS, validatedAuthorizationDetails.toSet()); + } } return introspectionData; } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java index eaf24b4c39..ade73ab635 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java @@ -7,9 +7,11 @@ import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; +import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.model.CarbonOAuthTokenRequest; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; @@ -20,7 +22,6 @@ import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; -import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -289,8 +290,8 @@ public static AuthorizationDetails generateAndAssignUniqueIDs(final String autho * @param authorizationDetails The AuthorizationDetails object containing a set of AuthorizationDetail objects. * @return The AuthorizationDetails object with unique IDs assigned to each AuthorizationDetail. */ - public static AuthorizationDetails assignUniqueIDsToAuthorizationDetails(final AuthorizationDetails - authorizationDetails) { + public static AuthorizationDetails assignUniqueIDsToAuthorizationDetails( + final AuthorizationDetails authorizationDetails) { authorizationDetails.stream().filter(Objects::nonNull) .forEach(authorizationDetail -> authorizationDetail.setId(UUID.randomUUID().toString())); @@ -305,15 +306,11 @@ public static AuthorizationDetails assignUniqueIDsToAuthorizationDetails(final A */ public static String getUrlEncodedAuthorizationDetails(final AuthorizationDetails authorizationDetails) { - try { - if (log.isDebugEnabled()) { - log.debug("Starts URL encoding authorization details: " + authorizationDetails.toJsonString()); - } - if (isRichAuthorizationRequest(authorizationDetails)) { - return URLEncoder.encode(authorizationDetails.toJsonString(), StandardCharsets.UTF_8.toString()); - } - } catch (UnsupportedEncodingException e) { - log.error("Error occurred while URL encoding authorization details. Caused by, ", e); + if (log.isDebugEnabled()) { + log.debug("Starts URL encoding authorization details: " + authorizationDetails.toJsonString()); + } + if (isRichAuthorizationRequest(authorizationDetails)) { + return URLEncoder.encode(authorizationDetails.toJsonString(), StandardCharsets.UTF_8); } return StringUtils.EMPTY; } @@ -326,16 +323,35 @@ public static String getUrlEncodedAuthorizationDetails(final AuthorizationDetail */ public static String getUrlDecodedAuthorizationDetails(final String encodedAuthorizationDetails) { - try { + if (log.isDebugEnabled()) { + log.debug("Starts decoding URL encoded authorization details JSON: " + encodedAuthorizationDetails); + } + if (StringUtils.isNotEmpty(encodedAuthorizationDetails)) { + return URLDecoder.decode(encodedAuthorizationDetails, StandardCharsets.UTF_8); + } + return StringUtils.EMPTY; + } + + public static void setRARPropertiesToAuthzRequestContext( + final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) throws IdentityOAuth2Exception { + + OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO = oAuthAuthzReqMessageContext.getAuthorizationReqDTO(); + if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuth2AuthorizeReqDTO)) { if (log.isDebugEnabled()) { - log.debug("Starts decoding URL encoded authorization details JSON: " + encodedAuthorizationDetails); + log.debug("Request is not a rich authorization request. " + + "Skips adding authorization details to OAuthAuthzReqMessageContext"); } - if (StringUtils.isNotEmpty(encodedAuthorizationDetails)) { - return URLDecoder.decode(encodedAuthorizationDetails, StandardCharsets.UTF_8.toString()); - } - } catch (UnsupportedEncodingException e) { - log.error("Error occurred while URL decoding authorization details Json. Caused by, ", e); + return; } - return StringUtils.EMPTY; + + final AuthorizationDetails authorizationDetails = OAuth2ServiceComponentHolder.getInstance() + .getAuthorizationDetailsService() + .getUserConsentedAuthorizationDetails( + oAuth2AuthorizeReqDTO.getUser(), + oAuth2AuthorizeReqDTO.getConsumerKey(), + IdentityTenantUtil.getTenantId(oAuth2AuthorizeReqDTO.getTenantDomain()) + ); + + oAuthAuthzReqMessageContext.setAuthorizationDetails(authorizationDetails); } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java index 52fce6d3e8..3ea9e29085 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java @@ -214,8 +214,7 @@ private Set getAuthorizedAuthorizationDetails( private boolean isSupportedAuthorizationDetailType(final String authorizationDetailType) { - return this.authorizationDetailsProviderFactory - .isSupportedAuthorizationDetailsType(authorizationDetailType); + return this.authorizationDetailsProviderFactory.isSupportedAuthorizationDetailsType(authorizationDetailType); } /** diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/TestConstants.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/TestConstants.java index b07c1e8dd2..add9c80106 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/TestConstants.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/TestConstants.java @@ -88,4 +88,10 @@ public class TestConstants { public static final String FAPI_SIGNATURE_ALG_CONFIGURATION = "OAuth.OpenIDConnect.FAPI." + "AllowedSignatureAlgorithms.AllowedSignatureAlgorithm"; + + // Rich Authorization Requests + public static final String TEST_CONSENT_ID = "52481ccd-0927-4d17-8cfc-5110fc4aa009"; + public static final String TEST_USER_ID = "c2179b58-b048-49d1-acb4-45b672d6fe5f"; + public static final String TEST_APP_ID = "a49257ea-3d5d-4558-b0c5-f9b3b0ca2fb0"; + public static final String TEST_TYPE = "test_type_v1"; } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java new file mode 100644 index 0000000000..4c72935ff5 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java @@ -0,0 +1,403 @@ +package org.wso2.carbon.identity.oauth2.rar; + +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.dao.AuthorizationDetailsDAO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.utils.AuthorizationDetailsBaseTest; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; + +import java.sql.SQLException; +import java.util.Collections; +import java.util.Set; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toSet; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.wso2.carbon.identity.oauth2.TestConstants.ACESS_TOKEN_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.CLIENT_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.TENANT_DOMAIN; +import static org.wso2.carbon.identity.oauth2.TestConstants.TENANT_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.TEST_APP_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.TEST_CONSENT_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.TEST_TYPE; +import static org.wso2.carbon.identity.oauth2.TestConstants.TEST_USER_ID; + +/** + * Test class for {@link AuthorizationDetailsService}. + */ +@WithCarbonHome +public class AuthorizationDetailsServiceTest extends AuthorizationDetailsBaseTest { + + private AuthorizationDetailsDAO authorizationDetailsDAOMock; + private MockedStatic oAuth2UtilMock; + + private AuthorizationDetailsService uut; + + @BeforeClass + public void setUp() throws SQLException { + + this.oAuth2UtilMock = Mockito.mockStatic(OAuth2Util.class); + this.oAuth2UtilMock.when(() -> OAuth2Util.getTenantId(TENANT_DOMAIN)).thenReturn(TENANT_ID); + + ServiceProvider serviceProvider = new ServiceProvider(); + serviceProvider.setApplicationResourceId(TEST_APP_ID); + this.oAuth2UtilMock.when(() -> OAuth2Util.getServiceProvider(CLIENT_ID)).thenReturn(serviceProvider); + } + + @AfterClass + public void tearDown() { + + if (this.oAuth2UtilMock != null && !this.oAuth2UtilMock.isClosed()) { + this.oAuth2UtilMock.close(); + } + } + + @BeforeMethod() + public void setUpMethod() throws SQLException { + + this.authorizationDetailsDAOMock = Mockito.mock(AuthorizationDetailsDAO.class); + when(this.authorizationDetailsDAOMock.getConsentIdByUserIdAndAppId(TEST_USER_ID, TEST_APP_ID, TENANT_ID)) + .thenReturn(TEST_CONSENT_ID); + + when(this.authorizationDetailsDAOMock.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TENANT_ID)) + .thenReturn(Collections.singleton(new AuthorizationDetailsConsentDTO(TEST_CONSENT_ID, + this.authorizationDetail, true, TENANT_ID))); + + when(this.authorizationDetailsDAOMock.getAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID)) + .thenReturn(Collections.singleton(new AuthorizationDetailsTokenDTO(ACESS_TOKEN_ID, + this.authorizationDetail, TENANT_ID))); + + uut = new AuthorizationDetailsService(this.providerFactoryMock, this.authorizationDetailsDAOMock); + } + + @BeforeMethod(onlyForGroups = {"error-flow-tests"}, dependsOnMethods = {"setUpMethod"}) + public void setUpErrorMethod() throws SQLException { + + when(this.authorizationDetailsDAOMock.addUserConsentedAuthorizationDetails(anyList())) + .thenThrow(SQLException.class); + when(this.authorizationDetailsDAOMock.deleteUserConsentedAuthorizationDetails(anyString(), anyInt())) + .thenThrow(SQLException.class); + when(this.authorizationDetailsDAOMock.getUserConsentedAuthorizationDetails(anyString(), anyInt())) + .thenThrow(SQLException.class); + when(this.authorizationDetailsDAOMock.getAccessTokenAuthorizationDetails(anyString(), anyInt())) + .thenThrow(SQLException.class); + when(this.authorizationDetailsDAOMock.addAccessTokenAuthorizationDetails(anyList())) + .thenThrow(SQLException.class); + when(this.authorizationDetailsDAOMock.deleteAccessTokenAuthorizationDetails(anyString(), anyInt())) + .thenThrow(SQLException.class); + + uut = new AuthorizationDetailsService(this.providerFactoryMock, this.authorizationDetailsDAOMock); + } + + @Test + public void shouldNotAddUserConsentedAuthorizationDetails_ifNotRichAuthorizationRequest() + throws OAuthSystemException, SQLException { + + uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + new OAuth2Parameters(), authorizationDetails); + + verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anyList()); + } + + @Test + public void shouldNotAddUserConsentedAuthorizationDetails_whenConsentIsNotFound() + throws OAuthSystemException, SQLException { + + final OAuth2Parameters oAuth2Parameters = new OAuth2Parameters(); + oAuth2Parameters.setAuthorizationDetails(authorizationDetails); + + uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + oAuth2Parameters, authorizationDetails); + + verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anyList()); + } + + @Test + public void shouldAddUserConsentedAuthorizationDetails_ifRichAuthorizationRequest() + throws OAuthSystemException, SQLException { + + uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + oAuth2Parameters, authorizationDetails); + + verify(authorizationDetailsDAOMock, times(1)).addUserConsentedAuthorizationDetails(anyList()); + } + + @Test + public void shouldNotDeleteUserConsentedAuthorizationDetails_ifNotRichAuthorizationRequest() + throws OAuthSystemException, SQLException { + + uut.deleteUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, new OAuth2Parameters()); + + verify(authorizationDetailsDAOMock, times(0)).deleteUserConsentedAuthorizationDetails(anyString(), anyInt()); + } + + @Test + public void shouldNotDeleteUserConsentedAuthorizationDetails_whenConsentIsNotFound() + throws OAuthSystemException, SQLException { + + final OAuth2Parameters oAuth2Parameters = new OAuth2Parameters(); + oAuth2Parameters.setAuthorizationDetails(authorizationDetails); + + uut.deleteUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters); + + verify(authorizationDetailsDAOMock, times(0)).deleteUserConsentedAuthorizationDetails(anyString(), anyInt()); + } + + @Test + public void shouldDeleteUserConsentedAuthorizationDetails_ifRichAuthorizationRequest() + throws OAuthSystemException, SQLException { + + uut.deleteUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters); + + verify(authorizationDetailsDAOMock, times(1)).deleteUserConsentedAuthorizationDetails(anyString(), anyInt()); + } + + @Test + public void shouldReplaceUserConsentedAuthorizationDetails_ifRichAuthorizationRequest() + throws OAuthSystemException, SQLException { + + uut.replaceUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + oAuth2Parameters, authorizationDetails); + + verify(authorizationDetailsDAOMock, times(1)) + .deleteUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TENANT_ID); + verify(authorizationDetailsDAOMock, times(1)).addUserConsentedAuthorizationDetails(anyList()); + } + + @Test + public void shouldReturnTrue_ifNotRichAuthorizationRequest() throws IdentityOAuth2Exception { + + assertTrue(uut.isUserAlreadyConsentedForAuthorizationDetails(authenticatedUser, new OAuth2Parameters())); + } + + @Test + public void shouldReturnFalse_ifAuthorizationDetailsAlreadyConsented() throws IdentityOAuth2Exception { + + assertFalse(uut.isUserAlreadyConsentedForAuthorizationDetails(authenticatedUser, oAuth2Parameters)); + } + + @Test + public void shouldReturnEmptyAuthorizationDetails_whenConsentIsInvalid() throws IdentityOAuth2Exception { + + AuthenticatedUser invalidUser = new AuthenticatedUser(); + invalidUser.setUserId("invalid-user-id"); + + assertTrue(uut.getUserConsentedAuthorizationDetails(invalidUser, CLIENT_ID, TENANT_ID) + .getDetails().isEmpty()); + } + + @Test + public void shouldReturnUserConsentedAuthorizationDetails_whenConsentIsValid() throws IdentityOAuth2Exception { + + final AuthorizationDetails authorizationDetails = + uut.getUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, TENANT_ID); + + assertEquals(1, authorizationDetails.getDetails().size()); + authorizationDetails.stream().forEach(detail -> assertEquals(TEST_TYPE, detail.getType())); + + final AuthorizationDetails authorizationDetails1 = + uut.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters); + + assertEquals(1, authorizationDetails1.getDetails().size()); + authorizationDetails1.stream().forEach(detail -> assertEquals(TEST_TYPE, detail.getType())); + } + + @Test + public void shouldReturnEmptyAuthorizationDetails_whenAccessTokenIsNotFound() throws IdentityOAuth2Exception { + + assertTrue(uut.getAccessTokenAuthorizationDetails("invalid-access-token", TENANT_ID) + .getDetails().isEmpty()); + } + + @Test + public void shouldReturnAccessTokenAuthorizationDetails_whenTokenIsValid() throws IdentityOAuth2Exception { + + AuthorizationDetails authorizationDetails = uut.getAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID); + + assertEquals(1, authorizationDetails.getDetails().size()); + authorizationDetails.stream().forEach(ad -> assertEquals(TEST_TYPE, ad.getType())); + } + + @Test + public void shouldNotAddAccessTokenAuthorizationDetails_ifNotRichAuthorizationRequest() + throws SQLException, IdentityOAuth2Exception { + + uut.storeAccessTokenAuthorizationDetails(accessTokenDO, new OAuthAuthzReqMessageContext(null)); + + verify(authorizationDetailsDAOMock, times(0)).addAccessTokenAuthorizationDetails(anyList()); + } + + @Test + public void shouldAddAccessTokenAuthorizationDetails_ifRichAuthorizationRequest() + throws SQLException, IdentityOAuth2Exception { + + OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext = new OAuthAuthzReqMessageContext(null); + oAuthAuthzReqMessageContext.setAuthorizationDetails(authorizationDetails); + + uut.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthAuthzReqMessageContext); + + verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anyList()); + } + + @Test + public void shouldNotReplaceAccessTokenAuthorizationDetails_ifNotRichAuthorizationRequest() + throws SQLException, IdentityOAuth2Exception { + + uut.storeOrReplaceAccessTokenAuthorizationDetails(accessTokenDO, accessTokenDO, + new OAuthTokenReqMessageContext(new OAuth2AccessTokenReqDTO())); + + verify(authorizationDetailsDAOMock, times(0)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(0)).deleteAccessTokenAuthorizationDetails(anyString(), anyInt()); + } + + @Test + public void shouldNotDeleteAccessTokenAuthorizationDetails_whenOldAccessTokenIsMissing() + throws SQLException, IdentityOAuth2Exception { + + OAuthTokenReqMessageContext messageContext = new OAuthTokenReqMessageContext(new OAuth2AccessTokenReqDTO()); + messageContext.setAuthorizationDetails(authorizationDetails); + + uut.storeOrReplaceAccessTokenAuthorizationDetails(accessTokenDO, null, messageContext); + + verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(0)).deleteAccessTokenAuthorizationDetails(anyString(), anyInt()); + } + + @Test + public void shouldReplaceAccessTokenAuthorizationDetails_whenOldAccessTokenIsPresent() + throws SQLException, IdentityOAuth2Exception { + + OAuthTokenReqMessageContext messageContext = new OAuthTokenReqMessageContext(new OAuth2AccessTokenReqDTO()); + messageContext.setAuthorizationDetails(authorizationDetails); + + uut.storeOrReplaceAccessTokenAuthorizationDetails(accessTokenDO, accessTokenDO, messageContext); + + verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(1)).deleteAccessTokenAuthorizationDetails(anyString(), anyInt()); + } + + @Test + public void shouldReplaceAccessTokenAuthorizationDetails_ifRichAuthorizationRequest() + throws SQLException, IdentityOAuth2Exception { + + OAuthTokenReqMessageContext messageContext = new OAuthTokenReqMessageContext(new OAuth2AccessTokenReqDTO()); + messageContext.setAuthorizationDetails(authorizationDetails); + + final String oldAccessTokenId = "b8488717-267c-4f45-b039-f31a8efe7cac"; + uut.replaceAccessTokenAuthorizationDetails(oldAccessTokenId, accessTokenDO, messageContext); + + verify(authorizationDetailsDAOMock, times(1)) + .deleteAccessTokenAuthorizationDetails(oldAccessTokenId, TENANT_ID); + verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anyList()); + } + + @Test + public void shouldDeleteAccessTokenAuthorizationDetails_ifAccessTokenIsValid() + throws SQLException, IdentityOAuth2Exception { + + uut.deleteAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID); + + verify(authorizationDetailsDAOMock, times(1)).deleteAccessTokenAuthorizationDetails(anyString(), anyInt()); + } + + @Test + public void shouldReturnEmptyAuthorizationDetails_ifNotRichAuthorizationRequest() throws IdentityOAuth2Exception { + + assertTrue(uut.getConsentRequiredAuthorizationDetails(authenticatedUser, new OAuth2Parameters()) + .getDetails().isEmpty()); + } + + @Test + public void shouldReturnEmptyAuthorizationDetails_ifProcessorIsMissing() throws IdentityOAuth2Exception { + + assertTrue(uut.getConsentRequiredAuthorizationDetails(authenticatedUser, new OAuth2Parameters()) + .getDetails().isEmpty()); + } + + @Test + public void shouldReturnConsentRequiredAuthorizationDetails() throws IdentityOAuth2Exception { + + final String testTypeV2 = "test_type_v2"; + AuthorizationDetail authorizationDetail = new AuthorizationDetail(); + authorizationDetail.setType(testTypeV2); + + Set detailSet = + Stream.of(authorizationDetails.getDetails(), Collections.singleton(authorizationDetail)) + .flatMap(Set::stream) + .collect(toSet()); + + oAuth2Parameters.setAuthorizationDetails(new AuthorizationDetails(detailSet)); + + uut.getConsentRequiredAuthorizationDetails(authenticatedUser, oAuth2Parameters) + .stream() + .forEach(ad -> assertEquals(testTypeV2, ad.getType())); + } + + @Test(groups = {"error-flow-tests"}, expectedExceptions = {OAuthSystemException.class}) + public void shouldThrowOAuthSystemException_onUserConsentAuthorizationDetailsInsertionFailure() + throws OAuthSystemException { + + uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + oAuth2Parameters, authorizationDetails); + } + + @Test(groups = {"error-flow-tests"}, expectedExceptions = {OAuthSystemException.class}) + public void shouldThrowOAuthSystemException_onUserConsentAuthorizationDetailsDeletionFailure() + throws OAuthSystemException { + + uut.deleteUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters); + } + + @Test(groups = {"error-flow-tests"}, expectedExceptions = {IdentityOAuth2Exception.class}) + public void shouldThrowIdentityOAuth2Exception_onUserConsentAuthorizationDetailsRetrievalFailure() + throws IdentityOAuth2Exception { + + uut.getUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, TENANT_ID); + } + + @Test(groups = {"error-flow-tests"}, expectedExceptions = {IdentityOAuth2Exception.class}) + public void shouldThrowIdentityOAuth2Exception_onAccessTokenAuthorizationDetailsRetrievalFailure() + throws IdentityOAuth2Exception { + + uut.getAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID); + } + + @Test(groups = {"error-flow-tests"}, expectedExceptions = {IdentityOAuth2Exception.class}) + public void shouldThrowIdentityOAuth2Exception_onAccessTokenAuthorizationDetailsInsertionFailure() + throws IdentityOAuth2Exception { + + uut.storeAccessTokenAuthorizationDetails(accessTokenDO, authorizationDetails); + } + + @Test(groups = {"error-flow-tests"}, expectedExceptions = {IdentityOAuth2Exception.class}) + public void shouldThrowIdentityOAuth2Exception_onAccessTokenAuthorizationDetailsDeletionFailure() + throws IdentityOAuth2Exception { + + uut.deleteAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID); + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandlerTest.java new file mode 100644 index 0000000000..26dae1ca6c --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandlerTest.java @@ -0,0 +1,34 @@ +package org.wso2.carbon.identity.oauth2.rar.token; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.rar.utils.AuthorizationDetailsBaseTest; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; + +/** + * Test class for {@link AccessTokenResponseRARHandler}. + */ +public class AccessTokenResponseRARHandlerTest extends AuthorizationDetailsBaseTest { + + private AccessTokenResponseRARHandler uut; + + @BeforeClass + public void setUp() { + this.uut = new AccessTokenResponseRARHandler(); + } + + @Test + public void shouldReturnAuthorizationDetails_ifRichAuthorizationRequest() throws IdentityOAuth2Exception { + + assertAuthorizationDetailsPresent(uut.getAdditionalTokenResponseAttributes(tokenReqMessageContext)); + } + + @Test + public void shouldReturnEmpty_ifNotRichAuthorizationRequest() throws IdentityOAuth2Exception { + + OAuthTokenReqMessageContext messageContext = new OAuthTokenReqMessageContext(new OAuth2AccessTokenReqDTO()); + assertAuthorizationDetailsMissing(uut.getAdditionalTokenResponseAttributes(messageContext)); + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java new file mode 100644 index 0000000000..c5bcda4332 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java @@ -0,0 +1,111 @@ +package org.wso2.carbon.identity.oauth2.rar.token; + +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.identity.oauth.tokenprocessor.TokenProvider; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO; +import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.utils.AuthorizationDetailsBaseTest; +import org.wso2.carbon.identity.oauth2.rar.validator.AuthorizationDetailsValidator; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.oauth2.validators.OAuth2TokenValidationMessageContext; + +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +/** + * Test class for {@link IntrospectionRARDataProvider}. + */ +@WithCarbonHome +public class IntrospectionRARDataProviderTest extends AuthorizationDetailsBaseTest { + + private AuthorizationDetailsValidator validatorMock; + private OAuth2ServiceComponentHolder componentHolderMock; + + private IntrospectionRARDataProvider uut; + + @BeforeClass + public void setUpClass() throws IdentityOAuth2Exception { + + this.validatorMock = Mockito.mock(AuthorizationDetailsValidator.class); + when(validatorMock.getValidatedAuthorizationDetails(any(OAuth2TokenValidationMessageContext.class))) + .thenReturn(authorizationDetails); + + this.uut = new IntrospectionRARDataProvider(validatorMock); + + AccessTokenDO accessTokenDO = new AccessTokenDO(); + + TokenProvider tokenProviderMock = Mockito.mock(TokenProvider.class); + when(tokenProviderMock.getVerifiedAccessToken(anyString(), anyBoolean())).thenReturn(accessTokenDO); + + this.componentHolderMock = Mockito.mock(OAuth2ServiceComponentHolder.class); + when(componentHolderMock.getTokenProvider()).thenReturn(tokenProviderMock); + } + + @Test(priority = 1) + public void shouldNotReturnAuthorizationDetails_ifNotRichAuthorizationRequest() + throws IdentityOAuth2Exception { + + when(validatorMock.getValidatedAuthorizationDetails(any(OAuth2TokenValidationMessageContext.class))) + .thenReturn(new AuthorizationDetails()); + + try (MockedStatic oAuth2UtilMock = Mockito.mockStatic(OAuth2Util.class); + MockedStatic componentHolderMock = + Mockito.mockStatic(OAuth2ServiceComponentHolder.class)) { + + oAuth2UtilMock.when(() -> OAuth2Util.buildScopeArray(any())).thenReturn(new String[0]); + componentHolderMock.when(OAuth2ServiceComponentHolder::getInstance) + .thenReturn(this.componentHolderMock); + + assertAuthorizationDetailsMissing(uut.getIntrospectionData(tokenValidationRequestDTO, + introspectionResponseDTO)); + } + } + + @Test + public void shouldReturnAuthorizationDetails_ifRichAuthorizationRequestAndContextIsMissing() + throws IdentityOAuth2Exception { + + try (MockedStatic oAuth2UtilMock = Mockito.mockStatic(OAuth2Util.class); + MockedStatic componentHolderMock = + Mockito.mockStatic(OAuth2ServiceComponentHolder.class)) { + + oAuth2UtilMock.when(() -> OAuth2Util.buildScopeArray(any())).thenReturn(new String[0]); + componentHolderMock.when(OAuth2ServiceComponentHolder::getInstance) + .thenReturn(this.componentHolderMock); + + assertAuthorizationDetailsPresent(uut.getIntrospectionData(tokenValidationRequestDTO, + introspectionResponseDTO)); + } + } + + @Test + public void shouldReturnAuthorizationDetails_ifRichAuthorizationRequestAndContextIsPresent() + throws IdentityOAuth2Exception { + + OAuth2TokenValidationMessageContext context = new OAuth2TokenValidationMessageContext(tokenValidationRequestDTO, + new OAuth2TokenValidationResponseDTO()); + + Map properties = new HashMap<>(); + properties.put(OAuth2Util.OAUTH2_VALIDATION_MESSAGE_CONTEXT, context); + this.introspectionResponseDTO.setProperties(properties); + + try (MockedStatic oAuth2UtilMock = Mockito.mockStatic(OAuth2Util.class)) { + + oAuth2UtilMock.when(() -> OAuth2Util.buildScopeArray(any())).thenReturn(new String[0]); + assertAuthorizationDetailsPresent(uut.getIntrospectionData(tokenValidationRequestDTO, + introspectionResponseDTO)); + } + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProviderTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProviderTest.java new file mode 100644 index 0000000000..7e8c99e6fc --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProviderTest.java @@ -0,0 +1,49 @@ +package org.wso2.carbon.identity.oauth2.rar.token; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; +import org.wso2.carbon.identity.oauth2.rar.utils.AuthorizationDetailsBaseTest; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; + +public class JWTAccessTokenRARClaimProviderTest extends AuthorizationDetailsBaseTest { + + private JWTAccessTokenRARClaimProvider uut; + + @BeforeClass + public void setUp() { + this.uut = new JWTAccessTokenRARClaimProvider(); + } + + @Test + public void shouldReturnEmptyForAuthzReq_ifNotRichAuthorizationRequest() throws IdentityOAuth2Exception { + + OAuthAuthzReqMessageContext messageContext = new OAuthAuthzReqMessageContext(new OAuth2AuthorizeReqDTO()); + assertAuthorizationDetailsMissing(uut.getAdditionalClaims(messageContext)); + } + + @Test + public void shouldReturnEmptyForTokenReq_ifNotRichAuthorizationRequest() throws IdentityOAuth2Exception { + + OAuthTokenReqMessageContext messageContext = new OAuthTokenReqMessageContext(new OAuth2AccessTokenReqDTO()); + + assertAuthorizationDetailsMissing(uut.getAdditionalClaims(messageContext)); + } + + @Test + public void shouldReturnAuthorizationDetailsForAuthzReq_ifNotRichAuthorizationRequest() + throws IdentityOAuth2Exception { + + assertAuthorizationDetailsPresent(uut.getAdditionalClaims(authzReqMessageContext)); + } + + @Test + public void shouldReturnAuthorizationDetailsForTokenReq_ifNotRichAuthorizationRequest() + throws IdentityOAuth2Exception { + + assertAuthorizationDetailsPresent(uut.getAdditionalClaims(tokenReqMessageContext)); + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java new file mode 100644 index 0000000000..5108f23f0a --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java @@ -0,0 +1,140 @@ +package org.wso2.carbon.identity.oauth2.rar.utils; + +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2IntrospectionResponseDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.wso2.carbon.identity.oauth2.TestConstants.ACESS_TOKEN_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.CLIENT_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.TENANT_DOMAIN; +import static org.wso2.carbon.identity.oauth2.TestConstants.TENANT_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.TEST_TYPE; +import static org.wso2.carbon.identity.oauth2.TestConstants.TEST_USER_ID; + +public class AuthorizationDetailsBaseTest { + + protected AuthorizationDetail authorizationDetail; + protected AuthorizationDetails authorizationDetails; + protected OAuthAuthzReqMessageContext authzReqMessageContext; + protected OAuthTokenReqMessageContext tokenReqMessageContext; + protected OAuth2TokenValidationRequestDTO tokenValidationRequestDTO; + protected OAuth2IntrospectionResponseDTO introspectionResponseDTO; + protected AuthenticatedUser authenticatedUser; + protected OAuth2Parameters oAuth2Parameters; + protected AccessTokenDO accessTokenDO; + protected OAuth2AccessTokenReqDTO accessTokenReqDTO; + + protected AuthorizationDetailsProviderFactory providerFactoryMock; + protected AuthorizationDetailsService serviceMock; + + public AuthorizationDetailsBaseTest() { + + this.authorizationDetail = new AuthorizationDetail(); + this.authorizationDetail.setType(TEST_TYPE); + + this.authorizationDetails = new AuthorizationDetails(Collections.singleton(this.authorizationDetail)); + + final OAuth2AuthorizeReqDTO authorizeReqDTO = new OAuth2AuthorizeReqDTO(); + authorizeReqDTO.setConsumerKey(CLIENT_ID); + authorizeReqDTO.setTenantDomain(TENANT_DOMAIN); + authorizeReqDTO.setAuthorizationDetails(this.authorizationDetails); + + this.authzReqMessageContext = new OAuthAuthzReqMessageContext(authorizeReqDTO); + this.authzReqMessageContext.setAuthorizationDetails(this.authorizationDetails); + + this.accessTokenReqDTO = new OAuth2AccessTokenReqDTO(); + this.accessTokenReqDTO.setAuthorizationDetails(authorizationDetails); + + this.tokenReqMessageContext = new OAuthTokenReqMessageContext(this.accessTokenReqDTO); + this.tokenReqMessageContext.setAuthorizationDetails(this.authorizationDetails); + + this.tokenValidationRequestDTO = new OAuth2TokenValidationRequestDTO(); + OAuth2TokenValidationRequestDTO.OAuth2AccessToken accessToken = + this.tokenValidationRequestDTO.new OAuth2AccessToken(); + accessToken.setIdentifier(ACESS_TOKEN_ID); + this.tokenValidationRequestDTO.setAccessToken(accessToken); + + this.introspectionResponseDTO = new OAuth2IntrospectionResponseDTO(); + + this.authenticatedUser = new AuthenticatedUser(); + this.authenticatedUser.setUserId(TEST_USER_ID); + + this.oAuth2Parameters = new OAuth2Parameters(); + this.oAuth2Parameters.setTenantDomain(TENANT_DOMAIN); + this.oAuth2Parameters.setAuthorizationDetails(this.authorizationDetails); + this.oAuth2Parameters.setClientId(CLIENT_ID); + + this.accessTokenDO = new AccessTokenDO(); + this.accessTokenDO.setTokenId(ACESS_TOKEN_ID); + this.accessTokenDO.setTenantID(TENANT_ID); + + mockAuthorizationDetailsProviderFactory(); + this.serviceMock = mock(AuthorizationDetailsService.class); + } + + public static void assertAuthorizationDetailsPresent(final Map attributes) { + + assertTrue(attributes.containsKey(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); + assertEquals(((Set) + attributes.get(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)).size(), 1); + } + + public static void assertAuthorizationDetailsMissing(final Map attributes) { + + assertFalse(attributes.containsKey(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); + } + + private void mockAuthorizationDetailsProviderFactory() { + + this.providerFactoryMock = spy(AuthorizationDetailsProviderFactory.class); + try { + Field privateField = AuthorizationDetailsProviderFactory.class + .getDeclaredField("supportedAuthorizationDetailsTypes"); + privateField.setAccessible(true); + + privateField.set(this.providerFactoryMock, new HashMap() {{ + put(TEST_TYPE, getAuthorizationDetailsProcessorMock()); + }}); + } catch (Exception e) { + // ignores the exceptions + } + } + + private AuthorizationDetailsProcessor getAuthorizationDetailsProcessorMock() { + final AuthorizationDetailsProcessor processorMock = mock(AuthorizationDetailsProcessor.class); + when(processorMock.getType()).thenReturn(TEST_TYPE); + when(processorMock.isEqualOrSubset(any(AuthorizationDetail.class), any(AuthorizationDetails.class))) + .thenAnswer(invocation -> { + AuthorizationDetail ad = invocation.getArgument(0, AuthorizationDetail.class); + AuthorizationDetails ads = invocation.getArgument(1, AuthorizationDetails.class); + + return ads.stream().map(AuthorizationDetail::getType).allMatch(type -> type.equals(ad.getType())); + }); + return processorMock; + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java new file mode 100644 index 0000000000..6b14dc1bf7 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java @@ -0,0 +1,52 @@ +package org.wso2.carbon.identity.oauth2.rar.validator; + +import org.apache.oltu.oauth2.common.message.types.GrantType; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.utils.AuthorizationDetailsBaseTest; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; + +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.wso2.carbon.identity.oauth2.TestConstants.ACESS_TOKEN_ID; +import static org.wso2.carbon.identity.oauth2.TestConstants.TENANT_ID; + +public class DefaultAuthorizationDetailsValidatorTest extends AuthorizationDetailsBaseTest { + + AuthorizationDetailsValidator uut; + + @BeforeClass + public void setUp() throws IdentityOAuth2Exception { + when(serviceMock.getAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID)) + .thenReturn(authorizationDetails); + + this.uut = new DefaultAuthorizationDetailsValidator(providerFactoryMock, serviceMock); + } + + @Test + public void shouldReturnContextAuthorizationDetails_ifGrantTypeIsAuthzCode() + throws IdentityOAuth2ServerException, AuthorizationDetailsProcessingException { + + OAuth2AccessTokenReqDTO reqDTO = new OAuth2AccessTokenReqDTO(); + reqDTO.setGrantType(GrantType.AUTHORIZATION_CODE.toString()); + + OAuthTokenReqMessageContext messageContext = new OAuthTokenReqMessageContext(reqDTO); + messageContext.setAuthorizationDetails(authorizationDetails); + + assertEquals(authorizationDetails, uut.getValidatedAuthorizationDetails(messageContext)); + } + + @Test + public void shouldReturnContextAuthorizationDetails_ifNoNewAuthorizationDetailsRequested() + throws IdentityOAuth2ServerException, AuthorizationDetailsProcessingException { + + OAuthTokenReqMessageContext messageContext = new OAuthTokenReqMessageContext(new OAuth2AccessTokenReqDTO()); + messageContext.setAuthorizationDetails(authorizationDetails); + + assertEquals(authorizationDetails, uut.getValidatedAuthorizationDetails(messageContext)); + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml index 94ae480fb7..e0e1ece301 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml @@ -122,6 +122,11 @@ + + + + + @@ -195,6 +200,11 @@ + + + + + From b12db7c9b5e3fe29bddf1cfb0d67e259fe52eebd Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Tue, 8 Oct 2024 15:47:40 +0530 Subject: [PATCH 05/28] Add schema validation - Add unit tests - Add 'authorization_details_types_supported' to /.well-known response --- .../pom.xml | 4 + .../discovery/DiscoveryConstants.java | 7 + .../discovery/OIDProviderConfigResponse.java | 13 + .../builders/ProviderConfigBuilder.java | 8 + .../builders/ProviderConfigBuilderTest.java | 16 +- .../pom.xml | 1 - .../endpoint/authz/OAuth2AuthzEndpoint.java | 9 +- .../oauth/endpoint/util/EndpointUtil.java | 3 +- .../pom.xml | 15 +- .../AuthorizationDetailsSchemaValidator.java | 207 +++++++++ .../rar/dao/AuthorizationDetailsDAO.java | 44 +- .../rar/dao/AuthorizationDetailsDAOImpl.java | 97 +++-- .../identity/oauth2/rar/dao/SQLQueries.java | 26 +- .../rar/dto/AuthorizationDetailsCodeDTO.java | 50 +++ .../dto/AuthorizationDetailsConsentDTO.java | 2 +- .../rar/dto/AuthorizationDetailsDTO.java | 10 +- .../rar/dto/AuthorizationDetailsTokenDTO.java | 2 +- ...thorizationDetailsProcessingException.java | 6 +- .../util/AuthorizationDetailsCommonUtils.java | 35 +- .../util/AuthorizationDetailsConstants.java | 17 +- ...thorizationDetailsSchemaValidatorTest.java | 105 +++++ .../dao/AuthorizationDetailsDAOImplTest.java | 103 ++++- .../AuthorizationDetailsCommonUtilsTest.java | 72 +++- .../oauth2/rar/util/TestConstants.java | 32 +- .../oauth2/rar/util/TestDAOUtils.java | 38 ++ .../src/test/resources/dbScripts/h2.sql | 46 +- .../src/test/resources/testng.xml | 3 +- .../org.wso2.carbon.identity.oauth/pom.xml | 1 - .../util/ResponseTypeHandlerUtil.java | 3 + .../internal/OAuth2ServiceComponent.java | 70 +++ .../OAuth2ServiceComponentHolder.java | 22 +- .../rar/AuthorizationDetailsService.java | 401 ++++++++++-------- .../core/AuthorizationDetailsProcessor.java | 4 +- .../AuthorizationDetailsProcessorFactory.java | 158 +++++++ .../AuthorizationDetailsProviderFactory.java | 132 ------ .../model/AuthorizationDetailsContext.java | 60 ++- .../token/IntrospectionRARDataProvider.java | 24 +- .../rar/util/AuthorizationDetailsUtils.java | 161 ++++--- .../DefaultAuthorizationDetailsValidator.java | 303 +++++++++---- .../AbstractAuthorizationGrantHandler.java | 33 +- .../rar/AuthorizationDetailsServiceTest.java | 56 ++- .../IntrospectionRARDataProviderTest.java | 5 +- .../utils/AuthorizationDetailsBaseTest.java | 17 +- ...aultAuthorizationDetailsValidatorTest.java | 2 +- pom.xml | 8 + 45 files changed, 1776 insertions(+), 655 deletions(-) create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidator.java create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsCodeDTO.java rename components/{org.wso2.carbon.identity.oauth => org.wso2.carbon.identity.oauth.rar}/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java (86%) create mode 100644 components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidatorTest.java create mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java delete mode 100644 components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java diff --git a/components/org.wso2.carbon.identity.discovery/pom.xml b/components/org.wso2.carbon.identity.discovery/pom.xml index cdfa432d5c..4f832e3978 100644 --- a/components/org.wso2.carbon.identity.discovery/pom.xml +++ b/components/org.wso2.carbon.identity.discovery/pom.xml @@ -52,6 +52,10 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.claim.metadata.mgt + + org.wso2.carbon.identity.inbound.auth.oauth2 + org.wso2.carbon.identity.oauth.rar + org.testng diff --git a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/DiscoveryConstants.java b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/DiscoveryConstants.java index a77e6a151f..76a6c551c2 100644 --- a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/DiscoveryConstants.java +++ b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/DiscoveryConstants.java @@ -377,4 +377,11 @@ public class DiscoveryConstants { * Authorization Server. */ public static final String MTLS_ENDPOINT_ALIASES = "mtls_endpoint_aliases"; + + /** + * authorization_details_types_supported. + *

OPTIONAL. JSON array containing the authorization details types the AS supports.

+ * @see rfc9396 + */ + public static final String AUTHORIZATION_DETAILS_TYPES_SUPPORTED = "authorization_details_types_supported"; } diff --git a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/OIDProviderConfigResponse.java b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/OIDProviderConfigResponse.java index d249651a23..78020c06d4 100644 --- a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/OIDProviderConfigResponse.java +++ b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/OIDProviderConfigResponse.java @@ -85,6 +85,7 @@ public class OIDProviderConfigResponse { private Boolean tlsClientCertificateBoundAccessTokens; private String mtlsTokenEndpoint; private String mtlsPushedAuthorizationRequestEndpoint; + private String[] authorizationDetailsTypesSupported; private static final String MUTUAL_TLS_ALIASES_ENABLED = "OAuth.MutualTLSAliases.Enabled"; @@ -530,6 +531,16 @@ public void setMtlsPushedAuthorizationRequestEndpoint(String mtlsPushedAuthoriza this.mtlsPushedAuthorizationRequestEndpoint = mtlsPushedAuthorizationRequestEndpoint; } + public String[] getAuthorizationDetailsTypesSupported() { + + return this.authorizationDetailsTypesSupported; + } + + public void setAuthorizationDetailsTypesSupported(String[] authorizationDetailsTypesSupported) { + + this.authorizationDetailsTypesSupported = authorizationDetailsTypesSupported; + } + public Map getConfigMap() { Map configMap = new HashMap(); configMap.put(DiscoveryConstants.ISSUER.toLowerCase(), this.issuer); @@ -604,6 +615,8 @@ public Map getConfigMap() { this.mtlsPushedAuthorizationRequestEndpoint); configMap.put(DiscoveryConstants.MTLS_ENDPOINT_ALIASES, mtlsAliases); } + configMap.put(DiscoveryConstants.AUTHORIZATION_DETAILS_TYPES_SUPPORTED, + this.authorizationDetailsTypesSupported); return configMap; } } diff --git a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java index 5da33e3c60..76c4e3ef40 100644 --- a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java +++ b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java @@ -32,6 +32,7 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.OAuth2Constants; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessorFactory; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import java.net.URISyntaxException; @@ -150,6 +151,13 @@ public OIDProviderConfigResponse buildOIDProviderConfig(OIDProviderRequest reque .contains(OAuth2Constants.TokenBinderType.CERTIFICATE_BASED_TOKEN_BINDER)); providerConfig.setMtlsTokenEndpoint(OAuth2Util.OAuthURL.getOAuth2MTLSTokenEPUrl()); providerConfig.setMtlsPushedAuthorizationRequestEndpoint(OAuth2Util.OAuthURL.getOAuth2MTLSParEPUrl()); + + final Set supportedTypes = AuthorizationDetailsProcessorFactory.getInstance() + .getSupportedAuthorizationDetailTypes(); + if (supportedTypes != null && !supportedTypes.isEmpty()) { + final int size = supportedTypes.size(); + providerConfig.setAuthorizationDetailsTypesSupported(supportedTypes.toArray(new String[size])); + } return providerConfig; } } diff --git a/components/org.wso2.carbon.identity.discovery/src/test/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilderTest.java b/components/org.wso2.carbon.identity.discovery/src/test/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilderTest.java index 0f25922434..c4aa460249 100644 --- a/components/org.wso2.carbon.identity.discovery/src/test/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilderTest.java +++ b/components/org.wso2.carbon.identity.discovery/src/test/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilderTest.java @@ -37,10 +37,12 @@ import org.wso2.carbon.identity.discovery.internal.OIDCDiscoveryDataHolder; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessorFactory; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import static org.mockito.ArgumentMatchers.anyString; @@ -67,6 +69,9 @@ public class ProviderConfigBuilderTest { @Mock private OIDProviderRequest mockOidProviderRequest; +// +// @Mock +// private AuthorizationDetailsProcessorFactory mockAuthorizationDetailsProcessorFactory; @BeforeMethod public void setUp() throws Exception { @@ -84,7 +89,9 @@ public void testBuildOIDProviderConfig() throws Exception { OAuthServerConfiguration mockOAuthServerConfiguration = mock(OAuthServerConfiguration.class); oAuthServerConfiguration.when( OAuthServerConfiguration::getInstance).thenReturn(mockOAuthServerConfiguration); - try (MockedStatic oAuth2Util = mockStatic(OAuth2Util.class);) { + try (MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); + MockedStatic factoryMock = + mockStatic(AuthorizationDetailsProcessorFactory.class)) { OIDCDiscoveryDataHolder mockOidcDiscoveryDataHolder = spy(new OIDCDiscoveryDataHolder()); mockOidcDiscoveryDataHolder.setClaimManagementService(mockClaimMetadataManagementService); @@ -107,6 +114,13 @@ public void testBuildOIDProviderConfig() throws Exception { .thenReturn(JWSAlgorithm.RS256); when(mockOidProviderRequest.getTenantDomain()).thenReturn( MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + + AuthorizationDetailsProcessorFactory processorFactoryMock = + spy(AuthorizationDetailsProcessorFactory.class); + when(processorFactoryMock.getSupportedAuthorizationDetailTypes()).thenReturn(new HashSet() {{ + add("test_type"); + }}); + factoryMock.when(AuthorizationDetailsProcessorFactory::getInstance).thenReturn(processorFactoryMock); assertNotNull(providerConfigBuilder.buildOIDProviderConfig(mockOidProviderRequest)); } } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index 37709e48b2..801e33d460 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -179,7 +179,6 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.oauth.rar - provided diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java index 6c3a897d52..6ac40579b5 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java @@ -2608,8 +2608,7 @@ private String populateOauthParameters(OAuth2Parameters params, OAuthMessage oAu final String authorizationDetailsJson = oauthRequest .getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS); - params.setAuthorizationDetails(AuthorizationDetailsUtils - .generateAndAssignUniqueIDs(authorizationDetailsJson)); + params.setAuthorizationDetails(new AuthorizationDetails(authorizationDetailsJson)); } handleMaxAgeParameter(oauthRequest, params); @@ -4849,10 +4848,12 @@ private void validateAuthorizationDetailsBeforeConsent(final OAuthMessage oAuthM .getValidatedAuthorizationDetails(oAuthAuthzReqMessageContext); // update oAuth2Parameters with validated authorization details - oAuth2Parameters.setAuthorizationDetails(validatedAuthorizationDetails); + oAuth2Parameters.setAuthorizationDetails(AuthorizationDetailsUtils + .assignUniqueIDsToAuthorizationDetails(validatedAuthorizationDetails)); // Update the authorization message context with validated authorization details - oAuthAuthzReqMessageContext.setAuthorizationDetails(validatedAuthorizationDetails); + oAuthAuthzReqMessageContext.setAuthorizationDetails(AuthorizationDetailsUtils + .assignUniqueIDsToAuthorizationDetails(validatedAuthorizationDetails)); oAuthMessage.getSessionDataCacheEntry().setAuthzReqMsgCtx(oAuthAuthzReqMessageContext); if (LoggerUtils.isDiagnosticLogsEnabled()) { diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java index d5ab7bb26e..6d74b5ce8c 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtil.java @@ -1102,7 +1102,8 @@ public static void storeOAuthScopeConsent(AuthenticatedUser user, OAuth2Paramete } try { Set userApprovedScopesSet = params.getConsentRequiredScopes(); - if (CollectionUtils.isNotEmpty(userApprovedScopesSet)) { + if (CollectionUtils.isNotEmpty(userApprovedScopesSet) || + AuthorizationDetailsUtils.isRichAuthorizationRequest(params)) { if (log.isDebugEnabled()) { log.debug("Storing user consent for approved scopes : " + userApprovedScopesSet.stream() .collect(Collectors.joining(" ")) + " of client : " + params.getClientId()); diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index b651d1161b..f9e8deb6bf 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -24,7 +24,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.133-SNAPSHOT + 7.0.150-SNAPSHOT 4.0.0 @@ -44,17 +44,17 @@ provided - - com.google.auto.service - auto-service - - com.fasterxml.jackson.core jackson-databind provided + + io.vertx + vertx-json-schema + + org.testng @@ -123,8 +123,9 @@ **/*Constants.class - **/model/** **/dto/** + **/exception/** + **/model/** diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidator.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidator.java new file mode 100644 index 0000000000..b476f62030 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidator.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar; + +import io.vertx.core.Vertx; +import io.vertx.core.json.DecodeException; +import io.vertx.core.json.JsonObject; +import io.vertx.json.schema.Draft; +import io.vertx.json.schema.JsonSchema; +import io.vertx.json.schema.JsonSchemaOptions; +import io.vertx.json.schema.JsonSchemaValidationException; +import io.vertx.json.schema.OutputFormat; +import io.vertx.json.schema.OutputUnit; +import io.vertx.json.schema.SchemaRepository; +import io.vertx.json.schema.Validator; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; + +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.SCHEMA_VALIDATION_FAILED_ERR_MSG_FORMAT; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.TYPE_VALIDATION_FAILED_ERR_MSG_FORMAT; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_MSG; + +/** + * The {@code AuthorizationDetailsSchemaValidator} is responsible for validating authorization details + * against a provided JSON schema. + *

+ * This class supports both validation of custom schemas provided as input and validation of default schemas + * based on the DRAFT202012 standard. + *

+ * Typical usage: + *

+ *     AuthorizationDetailsSchemaValidator validator = AuthorizationDetailsSchemaValidator.getInstance();
+ *     boolean isValid = validator.isSchemaCompliant(schemaString, authorizationDetail);
+ * 
+ * + *

Refer to + * json-schema for detailed information on the JSON documents structure.

+ * + * @see AuthorizationDetail + * @see JsonSchema + */ +public class AuthorizationDetailsSchemaValidator { + + private static final Log log = LogFactory.getLog(AuthorizationDetailsSchemaValidator.class); + + private static final String ADDITIONAL_PROPERTIES = "additionalProperties"; + private static final String BASE_URI = "https://wso2.com/identity-server/schemas"; + + private static volatile AuthorizationDetailsSchemaValidator instance; + private final JsonSchemaOptions jsonSchemaOptions; + private final SchemaRepository schemaRepository; + + private AuthorizationDetailsSchemaValidator() { + + this.jsonSchemaOptions = new JsonSchemaOptions() + .setBaseUri(BASE_URI) + .setDraft(Draft.DRAFT202012) + .setOutputFormat(OutputFormat.Basic); + + this.schemaRepository = SchemaRepository.create(this.jsonSchemaOptions) + .preloadMetaSchema(Vertx.vertx().fileSystem()); + } + + public static AuthorizationDetailsSchemaValidator getInstance() { + + if (instance == null) { + synchronized (AuthorizationDetailsSchemaValidator.class) { + if (instance == null) { + instance = new AuthorizationDetailsSchemaValidator(); + } + } + } + return instance; + } + + /** + * Validates whether the given schema is compliant with the JSON schema DRAFT202012 standard. + * + * @param schema the JSON schema as a string. + * @return true if the schema is valid, false if the schema is invalid or empty. + * @throws AuthorizationDetailsProcessingException if the validation fails or an error occurs during validation. + */ + public boolean isValidSchema(final String schema) throws AuthorizationDetailsProcessingException { + + if (StringUtils.isEmpty(schema)) { + log.debug("Schema validation failed. Schema cannot be null"); + return false; + } + + final OutputUnit outputUnit = this.buildOutputUnit(null, this.parseJsonString(schema)); + try { + // Validates the schema itself against the DRAFT202012 schema standard + outputUnit.checkValidity(); + } catch (JsonSchemaValidationException e) { + logDebugIfEnabled(String.format("Validation failed against DRAFT202012 schema for input: %s. Caused by, ", + schema), e); + throw new AuthorizationDetailsProcessingException(String.format(SCHEMA_VALIDATION_FAILED_ERR_MSG_FORMAT, + buildSchemaValidationErrorMessage(outputUnit, e)), e); + } + return true; + } + + private OutputUnit buildOutputUnit(final JsonObject jsonSchema, final JsonObject jsonInput) { + + // Validate the jsonSchema if present, otherwise validate the schema itself against json-schema DRAFT202012 + final Validator validator = (jsonSchema != null) + ? this.schemaRepository.validator(JsonSchema.of(jsonSchema), this.jsonSchemaOptions) + : this.schemaRepository.validator(this.jsonSchemaOptions.getDraft().getIdentifier()); + + return validator.validate(jsonInput); + } + + /** + * Converts a JSON string into a {@link JsonObject}. If the input is invalid, throws an exception. + * + * @param jsonString The input JSON string to be converted. + * @return A {@link JsonObject} created from the input string. + * @throws AuthorizationDetailsProcessingException if the input string is not valid JSON. + */ + private JsonObject parseJsonString(final String jsonString) throws AuthorizationDetailsProcessingException { + + try { + return new JsonObject(jsonString); + } catch (DecodeException e) { + this.logDebugIfEnabled(String.format("Failed to parse the JSON input: '%s'. Caused by, ", jsonString), e); + throw new AuthorizationDetailsProcessingException( + String.format("%s. Invalid Json input received.", VALIDATION_FAILED_ERR_MSG), e); + } + } + + private String buildSchemaValidationErrorMessage(final OutputUnit outputUnit, + final JsonSchemaValidationException ex) { + + // Extract the last validation error if available, otherwise use exception message. + if (outputUnit == null || CollectionUtils.isEmpty(outputUnit.getErrors())) { + return ex.getMessage(); + } + final OutputUnit lastError = outputUnit.getErrors().get(outputUnit.getErrors().size() - 1); + return lastError.getInstanceLocation() + StringUtils.SPACE + lastError.getError(); + } + + /** + * Validates whether the given authorization detail complies with the provided JSON schema. + * + * @param schema the JSON schema as a string. + * @param authorizationDetail the authorization detail to be validated. + * @return true if the authorization detail is schema compliant, false if schema or authorizationDetail is invalid. + * @throws AuthorizationDetailsProcessingException if the validation fails or an error occurs during validation. + */ + public boolean isSchemaCompliant(final String schema, final AuthorizationDetail authorizationDetail) + throws AuthorizationDetailsProcessingException { + + if (StringUtils.isEmpty(schema) || authorizationDetail == null) { + log.debug("Schema validation failed. Inputs cannot be null"); + return false; + } + + final JsonObject jsonSchema = this.parseJsonString(schema); + jsonSchema.put(ADDITIONAL_PROPERTIES, false); // Ensure no unknown fields are allowed + + final OutputUnit outputUnit = + this.buildOutputUnit(jsonSchema, this.parseJsonString(authorizationDetail.toJsonString())); + try { + // Validates the authorization detail against the schema + outputUnit.checkValidity(); + } catch (JsonSchemaValidationException e) { + logDebugIfEnabled(String.format("Schema validation failed for authorization details type: %s. Caused by, ", + authorizationDetail.getType()), e); + throw new AuthorizationDetailsProcessingException(String.format(TYPE_VALIDATION_FAILED_ERR_MSG_FORMAT, + authorizationDetail.getType(), buildSchemaValidationErrorMessage(outputUnit, e)), e); + } + return true; + } + + /** + * Logs a debug message along with the exception if debug logging is enabled. + * + * @param message The debug message to log. + * @param ex The exception to log along with the message. + */ + private void logDebugIfEnabled(final String message, final Exception ex) { + + if (log.isDebugEnabled()) { + log.debug(message, ex); + } + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java index 5c467f47bf..be49e2c822 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java @@ -18,11 +18,11 @@ package org.wso2.carbon.identity.oauth2.rar.dao; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsCodeDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; import java.sql.SQLException; -import java.util.List; import java.util.Set; /** @@ -36,13 +36,13 @@ public interface AuthorizationDetailsDAO { /** * Adds user consented authorization details to the database. * - * @param authorizationDetailsConsentDTOs List of user consented authorization details DTOs. + * @param authorizationDetailsConsentDTOs A set of user consented authorization details DTOs. * {@link AuthorizationDetailsConsentDTO } * @return An array of positive integers indicating the number of rows affected for each batch operation, * or negative integers if any of the batch operations fail. * @throws SQLException If a database access error occurs. */ - int[] addUserConsentedAuthorizationDetails(List authorizationDetailsConsentDTOs) + int[] addUserConsentedAuthorizationDetails(Set authorizationDetailsConsentDTOs) throws SQLException; /** @@ -56,18 +56,6 @@ int[] addUserConsentedAuthorizationDetails(List Set getUserConsentedAuthorizationDetails(String consentId, int tenantId) throws SQLException; - /** - * Updates user consented authorization details in the database. - * - * @param authorizationDetailsConsentDTOs A list of user consented authorization details DTOs. - * {@link AuthorizationDetailsConsentDTO} - * @return An array of integers indicating the number of rows affected for each batch operation. - * Positive values indicate success, negative values indicate failure. - * @throws SQLException If a database access error occurs. - */ - int[] updateUserConsentedAuthorizationDetails(List authorizationDetailsConsentDTOs) - throws SQLException; - /** * Deletes user consented authorization details from the database. * @@ -81,13 +69,13 @@ int[] updateUserConsentedAuthorizationDetails(List authorizationDetailsTokenDTOs) + int[] addAccessTokenAuthorizationDetails(Set authorizationDetailsTokenDTOs) throws SQLException; /** @@ -111,6 +99,28 @@ Set getAccessTokenAuthorizationDetails(String acce */ int deleteAccessTokenAuthorizationDetails(String accessTokenId, int tenantId) throws SQLException; + /** + * Adds authorization details against a given OAuth2 code. + * + * @param authorizationDetailsCodeDTOs A list of code authorization details DTOs to store. + * @return An array of positive integers indicating the number of rows affected for each batch operation, + * or negative integers if any of the batch operations fail. + * @throws SQLException If a database access error occurs. + */ + int[] addOAuth2CodeAuthorizationDetails(Set authorizationDetailsCodeDTOs) + throws SQLException; + + /** + * Retrieves authorization code authorization details from the database. + * + * @param authorizationCode The value of the authorization code. + * @param tenantId The tenant ID. + * @return A set of authorization code authorization details DTOs. + * @throws SQLException If a database access error occurs. + */ + Set getOAuth2CodeAuthorizationDetails(String authorizationCode, int tenantId) + throws SQLException; + /** * Retrieves the consent ID associated with a specific user ID and application ID. * diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java index 224a4c7e11..a50f8d5f2c 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.oauth2.rar.dao; import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsCodeDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; @@ -27,7 +28,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashSet; -import java.util.List; import java.util.Set; /** @@ -43,11 +43,12 @@ public class AuthorizationDetailsDAOImpl implements AuthorizationDetailsDAO { */ @Override public int[] addUserConsentedAuthorizationDetails( - final List authorizationDetailsConsentDTOs) throws SQLException { + final Set authorizationDetailsConsentDTOs) throws SQLException { try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); - final PreparedStatement ps = - connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + PreparedStatement ps = connection.getMetaData().getDatabaseProductName().contains("H2") + ? connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS_H2) + : connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { ps.setString(1, consentDTO.getConsentId()); @@ -81,7 +82,7 @@ public Set getUserConsentedAuthorizationDetails( final Set authorizationDetailsConsentDTOs = new HashSet<>(); while (rs.next()) { final String id = rs.getString(1); - final int typeId = rs.getInt(2); + final String typeId = rs.getString(2); final String authorizationDetail = rs.getString(3); final boolean isConsentActive = rs.getBoolean(4); @@ -93,31 +94,6 @@ public Set getUserConsentedAuthorizationDetails( } } - /** - * {@inheritDoc} - */ - @Override - public int[] updateUserConsentedAuthorizationDetails( - final List authorizationDetailsConsentDTOs) throws SQLException { - -// todo: This won't update the expected element. Hence, need to revisit the update logic - return null; - -// try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); -// final PreparedStatement ps = -// connection.prepareStatement(SQLQueries.UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { -// -// for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { -// ps.setString(1, consentDTO.getAuthorizationDetail().toJsonString()); -// ps.setBoolean(2, consentDTO.isConsentActive()); -// ps.setString(3, consentDTO.getConsentId()); -// ps.setInt(4, consentDTO.getTenantId()); -// ps.addBatch(); -// } -// return ps.executeBatch(); -// } - } - /** * {@inheritDoc} */ @@ -139,7 +115,7 @@ public int deleteUserConsentedAuthorizationDetails(final String consentId, final * {@inheritDoc} */ @Override - public int[] addAccessTokenAuthorizationDetails(final List + public int[] addAccessTokenAuthorizationDetails(final Set authorizationDetailsTokenDTOs) throws SQLException { try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = @@ -161,8 +137,9 @@ public int[] addAccessTokenAuthorizationDetails(final List getAccessTokenAuthorizationDetails( - final String accessTokenId, final int tenantId) throws SQLException { + public Set getAccessTokenAuthorizationDetails(final String accessTokenId, + final int tenantId) + throws SQLException { try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = @@ -175,7 +152,7 @@ public Set getAccessTokenAuthorizationDetails( final Set authorizationDetailsTokenDTO = new HashSet<>(); while (rs.next()) { final String id = rs.getString(1); - final int typeId = rs.getInt(2); + final String typeId = rs.getString(2); final String authorizationDetail = rs.getString(3); authorizationDetailsTokenDTO.add( @@ -203,6 +180,58 @@ public int deleteAccessTokenAuthorizationDetails(final String accessTokenId, fin } } + /** + * {@inheritDoc} + */ + @Override + public int[] addOAuth2CodeAuthorizationDetails(final Set authorizationDetailsCodeDTOs) + throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS)) { + + for (AuthorizationDetailsCodeDTO authorizationDetailsCodeDTO : authorizationDetailsCodeDTOs) { + ps.setString(1, authorizationDetailsCodeDTO.getAuthorizationCodeId()); + ps.setString(2, authorizationDetailsCodeDTO.getAuthorizationDetail().toJsonString()); + ps.setString(3, authorizationDetailsCodeDTO.getAuthorizationDetail().getType()); + ps.setInt(4, authorizationDetailsCodeDTO.getTenantId()); + ps.setInt(5, authorizationDetailsCodeDTO.getTenantId()); + ps.addBatch(); + } + return ps.executeBatch(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Set getOAuth2CodeAuthorizationDetails(final String authorizationCode, + final int tenantId) throws SQLException { + + try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); + final PreparedStatement ps = + connection.prepareStatement(SQLQueries.GET_OAUTH2_CODE_AUTHORIZATION_DETAILS_BY_CODE)) { + + ps.setString(1, authorizationCode); + ps.setInt(2, tenantId); + try (ResultSet rs = ps.executeQuery()) { + + final Set authorizationDetailsCodeDTOs = new HashSet<>(); + while (rs.next()) { + final String codeId = rs.getString(1); + final String typeId = rs.getString(2); + final String authorizationDetail = rs.getString(3); + + authorizationDetailsCodeDTOs.add(new AuthorizationDetailsCodeDTO( + codeId, typeId, authorizationDetail, tenantId)); + } + return authorizationDetailsCodeDTOs; + } + } + } + /** * {@inheritDoc} */ diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java index 9cbed27365..cc03a89d62 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java @@ -31,12 +31,14 @@ private SQLQueries() { public static final String ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = "INSERT INTO IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + "(CONSENT_ID, AUTHORIZATION_DETAILS, CONSENT, TYPE_ID, TENANT_ID) " + - "VALUES (?, ? FORMAT JSON, ?," + - "(SELECT ID FROM IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; + "VALUES (?, ?, ?," + + "(SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; - public static final String UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = - "UPDATE IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + - "SET AUTHORIZATION_DETAILS=? CONSENT=? WHERE CONSENT_ID=? AND TENANT_ID=?"; + public static final String ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS_H2 = + "INSERT INTO IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + + "(CONSENT_ID, AUTHORIZATION_DETAILS, CONSENT, TYPE_ID, TENANT_ID) " + + "VALUES (?, ? FORMAT JSON, ?," + + "(SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; public static final String GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = "SELECT ID, TYPE_ID, AUTHORIZATION_DETAILS, CONSENT FROM IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + @@ -49,7 +51,7 @@ private SQLQueries() { "INSERT INTO IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS " + "(TOKEN_ID, AUTHORIZATION_DETAILS, TYPE_ID, TENANT_ID) " + "VALUES (?, ? FORMAT JSON, " + - "(SELECT ID FROM IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; + "(SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; public static final String DELETE_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS = "DELETE FROM IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS WHERE TOKEN_ID=? AND TENANT_ID=?"; @@ -58,6 +60,18 @@ private SQLQueries() { "SELECT ID, TYPE_ID, AUTHORIZATION_DETAILS FROM IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS " + "WHERE TOKEN_ID=? AND TENANT_ID=?"; + public static final String ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS = + "INSERT INTO IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS" + + "(CODE_ID, AUTHORIZATION_DETAILS, TYPE_ID, TENANT_ID) " + + "VALUES (?, ? FORMAT JSON, " + + "(SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; + + public static final String GET_OAUTH2_CODE_AUTHORIZATION_DETAILS_BY_CODE = + "SELECT IOAC.CODE_ID, IOACAD.TYPE_ID, IOACAD.AUTHORIZATION_DETAILS " + + "FROM IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS IOACAD " + + "INNER JOIN IDN_OAUTH2_AUTHORIZATION_CODE IOAC ON IOACAD.CODE_ID = IOAC.CODE_ID " + + "WHERE IOAC.AUTHORIZATION_CODE=? AND IOACAD.TENANT_ID=?"; + public static final String GET_IDN_OAUTH2_USER_CONSENT_CONSENT_ID = "SELECT CONSENT_ID FROM IDN_OAUTH2_USER_CONSENT WHERE USER_ID=? AND APP_ID=? AND TENANT_ID=?"; } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsCodeDTO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsCodeDTO.java new file mode 100644 index 0000000000..4cbf2d1b57 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsCodeDTO.java @@ -0,0 +1,50 @@ +package org.wso2.carbon.identity.oauth2.rar.dto; + +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; + +/** + * Data Transfer Object (DTO) for representing authorization details along with authorization code. + * This class extends {@link AuthorizationDetailsDTO} to include additional fields for authorization code ID. + */ +public class AuthorizationDetailsCodeDTO extends AuthorizationDetailsDTO { + + final String codeId; + + /** + * Constructs an {@link AuthorizationDetailsCodeDTO} with all required fields. + * + * @param codeId the authorization code ID associated with the authorization detail. + * @param typeId the type ID of the authorization detail. + * @param authorizationDetail the {@link AuthorizationDetail} object. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsCodeDTO(final String codeId, final String typeId, + final String authorizationDetail, final int tenantId) { + + super(null, typeId, authorizationDetail, tenantId); + this.codeId = codeId; + } + + /** + * Constructs an {@link AuthorizationDetailsCodeDTO} with essential fields. + * + * @param codeId the authorization code ID associated with the authorization detail. + * @param authorizationDetail the {@link AuthorizationDetail} object. + * @param tenantId the tenant ID. + */ + public AuthorizationDetailsCodeDTO(final String codeId, final AuthorizationDetail authorizationDetail, + final int tenantId) { + + super(authorizationDetail, tenantId); + this.codeId = codeId; + } + + /** + * Gets the authorization code ID associated with the authorization detail. + * + * @return the authorization code ID. + */ + public String getAuthorizationCodeId() { + return this.codeId; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsConsentDTO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsConsentDTO.java index c70619615f..0af6fb9db5 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsConsentDTO.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsConsentDTO.java @@ -21,7 +21,7 @@ public class AuthorizationDetailsConsentDTO extends AuthorizationDetailsDTO { * @param isConsentActive the consent status. * @param tenantId the tenant ID. */ - public AuthorizationDetailsConsentDTO(final String id, final String consentId, final int typeId, + public AuthorizationDetailsConsentDTO(final String id, final String consentId, final String typeId, final String authorizationDetailJson, final boolean isConsentActive, final int tenantId) { diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java index fe6a85b8ef..00b705d29e 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java @@ -13,7 +13,7 @@ public class AuthorizationDetailsDTO { final String id; - final int typeId; + final String typeId; final AuthorizationDetail authorizationDetail; final int tenantId; @@ -25,7 +25,7 @@ public class AuthorizationDetailsDTO { * @param authorizationDetail the authorization detail object. * @param tenantId the tenant ID. */ - public AuthorizationDetailsDTO(final String id, final int typeId, final AuthorizationDetail authorizationDetail, + public AuthorizationDetailsDTO(final String id, final String typeId, final AuthorizationDetail authorizationDetail, final int tenantId) { this.id = id; @@ -42,7 +42,7 @@ public AuthorizationDetailsDTO(final String id, final int typeId, final Authoriz * @param authorizationDetailJson the JSON string of the authorization detail. * @param tenantId the tenant ID. */ - public AuthorizationDetailsDTO(final String id, final int typeId, final String authorizationDetailJson, + public AuthorizationDetailsDTO(final String id, final String typeId, final String authorizationDetailJson, final int tenantId) { this(id, typeId, AuthorizationDetailsCommonUtils @@ -57,7 +57,7 @@ public AuthorizationDetailsDTO(final String id, final int typeId, final String a */ public AuthorizationDetailsDTO(final AuthorizationDetail authorizationDetail, final int tenantId) { - this(null, 0, authorizationDetail, tenantId); + this(null, null, authorizationDetail, tenantId); } /** @@ -74,7 +74,7 @@ public String getId() { * * @return the type ID of the authorization detail. */ - public int getTypeId() { + public String getTypeId() { return this.typeId; } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsTokenDTO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsTokenDTO.java index a75d7b8681..4167d1159c 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsTokenDTO.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsTokenDTO.java @@ -19,7 +19,7 @@ public class AuthorizationDetailsTokenDTO extends AuthorizationDetailsDTO { * @param authorizationDetail the {@link AuthorizationDetail} object. * @param tenantId the tenant ID. */ - public AuthorizationDetailsTokenDTO(final String id, final String accessTokenId, final int typeId, + public AuthorizationDetailsTokenDTO(final String id, final String accessTokenId, final String typeId, final String authorizationDetail, final int tenantId) { super(id, typeId, authorizationDetail, tenantId); diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java similarity index 86% rename from components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java rename to components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java index 3ccc2784cc..5ed8d48ff6 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/exception/AuthorizationDetailsProcessingException.java @@ -1,15 +1,15 @@ package org.wso2.carbon.identity.oauth2.rar.exception; -import org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException; +import org.wso2.carbon.identity.base.IdentityException; /** * Exception class to represent failures related to Rich Authorization Requests in OAuth 2.0 clients. * *

This exception is thrown when there are errors in processing authorization details during the OAuth 2.0 - * authorization flow. It extends the {@link IdentityOAuth2ClientException} class, providing more specific + * authorization flow. It extends the {@link IdentityException} class, providing more specific * context for authorization-related issues.

*/ -public class AuthorizationDetailsProcessingException extends IdentityOAuth2ClientException { +public class AuthorizationDetailsProcessingException extends IdentityException { private static final long serialVersionUID = -206212512259482200L; diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java index d34bfedb27..e1e9c3040a 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java @@ -28,20 +28,23 @@ import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.EMPTY_JSON_ARRAY; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.EMPTY_JSON_OBJECT; + /** * Utility class for handling OAuth2 Rich Authorization Requests. */ public class AuthorizationDetailsCommonUtils { private static final Log log = LogFactory.getLog(AuthorizationDetailsCommonUtils.class); - private static final String empty_json = "{}"; - private static final String empty_json_array = "[]"; - private static final ObjectMapper objectMapper = createDefaultObjectMapper(); + + private static volatile ObjectMapper objectMapper; private AuthorizationDetailsCommonUtils() { // Private constructor to prevent instantiation @@ -122,7 +125,7 @@ public static String toJSON( } catch (JsonProcessingException e) { log.debug("Error occurred while parsing AuthorizationDetails to String. Caused by, ", e); } - return empty_json_array; + return EMPTY_JSON_ARRAY; } /** @@ -150,7 +153,7 @@ public static String toJSON( } catch (JsonProcessingException e) { log.debug("Error occurred while parsing AuthorizationDetail to String. Caused by, ", e); } - return empty_json; + return EMPTY_JSON_OBJECT; } /** @@ -175,19 +178,7 @@ public static Map toMap( return objectMapper.convertValue(authorizationDetail, new TypeReference>() { }); } - return new HashMap<>(); - } - - /** - * Creates a singleton instance of {@link ObjectMapper}. - * - * @return the singleton {@link ObjectMapper} instance. - */ - private static ObjectMapper createDefaultObjectMapper() { - - final ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - return objectMapper; + return Collections.emptyMap(); } /** @@ -198,6 +189,14 @@ private static ObjectMapper createDefaultObjectMapper() { * @return a configured {@link ObjectMapper} instance. */ public static ObjectMapper getDefaultObjectMapper() { + if (objectMapper == null) { + synchronized (AuthorizationDetailsCommonUtils.class) { + if (objectMapper == null) { + objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + } + } return objectMapper; } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsConstants.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsConstants.java index 62128f272d..45375fb806 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsConstants.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsConstants.java @@ -23,15 +23,20 @@ */ public final class AuthorizationDetailsConstants { - private AuthorizationDetailsConstants() { - // Private constructor to prevent instantiation - } - public static final String AUTHORIZATION_DETAILS = "authorization_details"; public static final String AUTHORIZATION_DETAILS_ID_PREFIX = "authorization_detail_id_"; public static final String PARAM_SEPARATOR = "&&"; - - public static final String TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT = "%s is not a supported authorization details type"; + public static final String TYPE_NOT_SUPPORTED_ERR_FORMAT = "%s is an unknown authorization details type value"; + public static final String TYPE_VALIDATION_FAILED_ERR_MSG_FORMAT = + "The payload of the authorization details type '%s' contains errors: %s"; + public static final String SCHEMA_VALIDATION_FAILED_ERR_MSG_FORMAT = + "The schema of the authorization details type contains errors: %s"; public static final String VALIDATION_FAILED_ERR_MSG = "Authorization details validation failed"; public static final String VALIDATION_FAILED_ERR_CODE = "invalid_authorization_details"; + public static final String EMPTY_JSON_OBJECT = "{}"; + public static final String EMPTY_JSON_ARRAY = "[]"; + + private AuthorizationDetailsConstants() { + // Private constructor to prevent instantiation + } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidatorTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidatorTest.java new file mode 100644 index 0000000000..b078f7ea08 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidatorTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.util.TestDAOUtils; + +import java.util.Arrays; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_SCHEMA; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TYPE; + +/** + * Test class for {@link AuthorizationDetailsSchemaValidator}. + */ +public class AuthorizationDetailsSchemaValidatorTest { + + private AuthorizationDetailsSchemaValidator uut; + + @BeforeClass + public void setUp() throws JsonProcessingException { + + this.uut = AuthorizationDetailsSchemaValidator.getInstance(); + } + + @Test + public void shouldReturnTrue_whenAuthorizationDetailIsSchemaCompliant() + throws AuthorizationDetailsProcessingException { + + AuthorizationDetail testAuthorizationDetail = new TestDAOUtils.TestAuthorizationDetail(); + testAuthorizationDetail.setType(TEST_TYPE); + + assertTrue(this.uut.isSchemaCompliant(TEST_SCHEMA, testAuthorizationDetail)); + } + + @Test + public void shouldReturnFalse_whenSchemaIsEmpty() throws AuthorizationDetailsProcessingException { + + assertFalse(this.uut.isSchemaCompliant(StringUtils.EMPTY, new TestDAOUtils.TestAuthorizationDetail())); + assertFalse(this.uut.isSchemaCompliant(TEST_SCHEMA, null)); + } + + @Test(expectedExceptions = {AuthorizationDetailsProcessingException.class}) + public void shouldThrowAuthorizationDetailsProcessingException_whenJsonSchemaIsInvalid() + throws AuthorizationDetailsProcessingException { + + this.uut.isSchemaCompliant("{", new TestDAOUtils.TestAuthorizationDetail()); + } + + @Test(expectedExceptions = {AuthorizationDetailsProcessingException.class}) + public void shouldThrowAuthorizationDetailsProcessingException_whenAuthorizationDetailIsNotSchemaCompliant() + throws AuthorizationDetailsProcessingException { + + AuthorizationDetail testAuthorizationDetail = new TestDAOUtils.TestAuthorizationDetail(); + testAuthorizationDetail.setType(TEST_TYPE); + testAuthorizationDetail.setActions(Arrays.asList("initiate", "cancel")); + + assertTrue(this.uut.isSchemaCompliant(TEST_SCHEMA, testAuthorizationDetail)); + } + + @Test(expectedExceptions = {AuthorizationDetailsProcessingException.class}) + public void shouldThrowAuthorizationDetailsProcessingException_whenSchemaIsInvalid1() + throws AuthorizationDetailsProcessingException { + + final String invalidSchema = "{\"type\":\"object\",\"required\":[\"type\"]," + + "\"properties\":{\"type\":{\"type\":\"string\"},\"creditorName\":\"string\"}}"; + + assertTrue(this.uut.isValidSchema(TEST_SCHEMA)); + assertFalse(this.uut.isValidSchema(StringUtils.EMPTY)); + assertFalse(this.uut.isValidSchema(invalidSchema)); + } + + @Test(expectedExceptions = {AuthorizationDetailsProcessingException.class}) + public void shouldThrowAuthorizationDetailsProcessingException_whenSchemaIsInvalid2() + throws AuthorizationDetailsProcessingException { + + final String invalidSchema = "{\"type\":\"object\",\"required\":[\"type\"]," + + "\"properties\":[{\"type\":{\"type\":\"string\"}}]}"; + + assertFalse(this.uut.isValidSchema(invalidSchema)); + } +} diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java index e507d24f25..cc35612769 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar.dao; import org.mockito.MockedStatic; @@ -7,18 +25,24 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsCodeDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; import org.wso2.carbon.identity.oauth2.rar.util.TestDAOUtils; +import java.sql.Connection; import java.sql.SQLException; import java.util.Collections; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_AUTHORIZATION_CODE; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_CODE_ID; import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_CONSENT_ID; import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_DB_NAME; import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TENANT_ID; @@ -47,12 +71,13 @@ public void tearDown() throws SQLException { @BeforeMethod public void setUpBeforeMethod() throws SQLException { + this.identityDatabaseUtilMock .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME)); } - @Test(priority = 0) + @Test public void testAddUserConsentedAuthorizationDetails() throws SQLException { assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size()); @@ -66,7 +91,7 @@ public void testAddUserConsentedAuthorizationDetails() throws SQLException { AuthorizationDetailsConsentDTO consentDTO = new AuthorizationDetailsConsentDTO(TEST_CONSENT_ID, testAuthorizationDetail, true, TEST_TENANT_ID); - int[] result = uut.addUserConsentedAuthorizationDetails(Collections.singletonList(consentDTO)); + int[] result = uut.addUserConsentedAuthorizationDetails(Collections.singleton(consentDTO)); assertEquals(1, result.length); } @@ -97,7 +122,7 @@ public void testDeleteUserConsentedAuthorizationDetails() throws SQLException { assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size()); } - @Test(priority = 0) + @Test public void testAddAccessTokenAuthorizationDetails() throws SQLException { assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size()); @@ -111,7 +136,7 @@ public void testAddAccessTokenAuthorizationDetails() throws SQLException { AuthorizationDetailsTokenDTO tokenDTO = new AuthorizationDetailsTokenDTO(TEST_TOKEN_ID, testAuthorizationDetail, TEST_TENANT_ID); - int[] result = uut.addAccessTokenAuthorizationDetails(Collections.singletonList(tokenDTO)); + int[] result = uut.addAccessTokenAuthorizationDetails(Collections.singleton(tokenDTO)); assertEquals(1, result.length); } @@ -139,4 +164,74 @@ public void testDeleteAccessTokenAuthorizationDetails() throws SQLException { assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size()); } + + @Test + public void testAddOAuth2CodeAuthorizationDetails() throws SQLException { + assertEquals(0, this.uut.getOAuth2CodeAuthorizationDetails(TEST_CODE_ID, TEST_TENANT_ID).size()); + + this.identityDatabaseUtilMock + .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) + .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME)); + + AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail(); + testAuthorizationDetail.setType(TEST_TYPE); + + AuthorizationDetailsCodeDTO codeDTO = + new AuthorizationDetailsCodeDTO(TEST_CODE_ID, testAuthorizationDetail, TEST_TENANT_ID); + + int[] result = uut.addOAuth2CodeAuthorizationDetails(Collections.singleton(codeDTO)); + + assertEquals(1, result.length); + } + + @Test(priority = 1) + public void testGetOAuth2CodeAuthorizationDetails() throws SQLException { + Set codeDTOs = + this.uut.getOAuth2CodeAuthorizationDetails(TEST_AUTHORIZATION_CODE, TEST_TENANT_ID); + + assertEquals(1, codeDTOs.size()); + codeDTOs.forEach(dto -> { + assertEquals(TEST_CODE_ID, dto.getAuthorizationCodeId()); + assertNotNull(dto.getAuthorizationDetail()); + assertEquals(TEST_TYPE, dto.getAuthorizationDetail().getType()); + }); + } + + @Test(priority = 3, expectedExceptions = {SQLException.class}) + public void shouldThrowSQLException_whenAddingConsentedAuthorizationDetailsFails() throws SQLException { + + try (Connection connectionMock = Mockito.spy(Connection.class)) { + + Mockito.when(connectionMock.getMetaData()).thenThrow(SQLException.class); + identityDatabaseUtilMock + .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) + .thenReturn(connectionMock); + uut.addUserConsentedAuthorizationDetails(Collections.emptySet()); + } + } + + @Test(priority = 3, expectedExceptions = {SQLException.class}) + public void shouldThrowSQLException_whenGettingConsentedAuthorizationDetailsFails() throws SQLException { + + try (Connection connectionMock = Mockito.spy(Connection.class)) { + + Mockito.when(connectionMock.prepareStatement(anyString())).thenThrow(SQLException.class); + identityDatabaseUtilMock + .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) + .thenReturn(connectionMock); + uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID); + } + } + + @Test + public void testGetConsentIdByUserIdAndAppId() throws SQLException { + + assertNotNull(this.uut.getConsentIdByUserIdAndAppId("valid_user_id", "valid_app_id", TEST_TENANT_ID)); + } + + @Test + public void shouldReturnNull_whenUserIdOrAppIdInvalid() throws SQLException { + + assertNull(this.uut.getConsentIdByUserIdAndAppId("invlid_user_id", "invalid_app_id", TEST_TENANT_ID)); + } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java index ccf61b834c..d556e4e9e2 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar.util; import com.fasterxml.jackson.core.JsonProcessingException; @@ -20,6 +38,9 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.EMPTY_JSON_ARRAY; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.EMPTY_JSON_OBJECT; +import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_NAME; import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TYPE; /** @@ -38,7 +59,7 @@ public void setUp() throws JsonProcessingException { // mock doThrow(JsonProcessingException.class) - .when(this.mockObjectMapper).writeValueAsString(any(TestAuthorizationDetail.class)); + .when(this.mockObjectMapper).writeValueAsString(any(TestDAOUtils.TestAuthorizationDetail.class)); doThrow(JsonProcessingException.class).when(this.mockObjectMapper).writeValueAsString(any(Set.class)); } @@ -60,7 +81,7 @@ public Object[][] provideAuthorizationDetailsCommonUtilsTestData(Method testMeth case "shouldReturnCorrectType_whenJSONIsValid": return new Object[][]{ {AuthorizationDetail.class}, - {TestAuthorizationDetail.class} + {TestDAOUtils.TestAuthorizationDetail.class} }; } return null; @@ -95,42 +116,53 @@ public void shouldReturnCorrectType_whenJSONIsVa @Test public void shouldReturnCorrectJson_whenAuthorizationDetailsAreValid() { - AuthorizationDetail inputAuthorizationDetail = new TestAuthorizationDetail(); + TestDAOUtils.TestAuthorizationDetail inputAuthorizationDetail = new TestDAOUtils.TestAuthorizationDetail(); inputAuthorizationDetail.setType(TEST_TYPE); + inputAuthorizationDetail.setName(TEST_NAME); + + final String authorizationDetails = AuthorizationDetailsCommonUtils + .toJSON(Sets.newHashSet(inputAuthorizationDetail), objectMapper); - assertTrue(AuthorizationDetailsCommonUtils.toJSON(Sets.newHashSet(inputAuthorizationDetail), objectMapper) - .contains(TEST_TYPE)); - assertEquals("[]", AuthorizationDetailsCommonUtils.toJSON((Set) null, objectMapper)); - assertEquals("[]", + assertTrue(authorizationDetails.contains(TEST_TYPE)); + assertTrue(authorizationDetails.contains(TEST_NAME)); + assertEquals(EMPTY_JSON_ARRAY, + AuthorizationDetailsCommonUtils.toJSON((Set) null, objectMapper)); + assertEquals(EMPTY_JSON_ARRAY, AuthorizationDetailsCommonUtils.toJSON(Sets.newHashSet(inputAuthorizationDetail), mockObjectMapper)); } @Test public void shouldReturnCorrectJson_whenAuthorizationDetailIsValid() { - AuthorizationDetail inputAuthorizationDetail = new TestAuthorizationDetail(); + TestDAOUtils.TestAuthorizationDetail inputAuthorizationDetail = new TestDAOUtils.TestAuthorizationDetail(); inputAuthorizationDetail.setType(TEST_TYPE); + inputAuthorizationDetail.setName(TEST_NAME); - assertTrue(AuthorizationDetailsCommonUtils.toJSON(inputAuthorizationDetail, objectMapper).contains(TEST_TYPE)); - assertEquals("{}", AuthorizationDetailsCommonUtils.toJSON((TestAuthorizationDetail) null, objectMapper)); - assertEquals("{}", AuthorizationDetailsCommonUtils.toJSON(new TestAuthorizationDetail(), mockObjectMapper)); + final String authorizationDetail = + AuthorizationDetailsCommonUtils.toJSON(inputAuthorizationDetail, objectMapper); + + assertTrue(authorizationDetail.contains(TEST_TYPE)); + assertTrue(authorizationDetail.contains(TEST_NAME)); + assertEquals(EMPTY_JSON_OBJECT, + AuthorizationDetailsCommonUtils.toJSON((TestDAOUtils.TestAuthorizationDetail) null, objectMapper)); + assertEquals(EMPTY_JSON_OBJECT, + AuthorizationDetailsCommonUtils.toJSON(new TestDAOUtils.TestAuthorizationDetail(), mockObjectMapper)); } @Test public void shouldReturnMap_whenAuthorizationDetailIsValid() { - AuthorizationDetail inputAuthorizationDetail = new TestAuthorizationDetail(); + TestDAOUtils.TestAuthorizationDetail inputAuthorizationDetail = new TestDAOUtils.TestAuthorizationDetail(); inputAuthorizationDetail.setType(TEST_TYPE); - Map actualMap = AuthorizationDetailsCommonUtils.toMap(inputAuthorizationDetail, objectMapper); + inputAuthorizationDetail.setName(TEST_NAME); + Map map = AuthorizationDetailsCommonUtils.toMap(inputAuthorizationDetail, objectMapper); - assertTrue(actualMap.containsKey("type")); - assertEquals(TEST_TYPE, String.valueOf(actualMap.get("type"))); - assertEquals(1, actualMap.keySet().size()); + assertTrue(map.containsKey("type")); + assertTrue(map.containsKey("name")); + assertEquals(TEST_TYPE, String.valueOf(map.get("type"))); + assertEquals(TEST_NAME, String.valueOf(map.get("name"))); + assertEquals(2, map.keySet().size()); assertFalse(AuthorizationDetailsCommonUtils.toMap(null, objectMapper).containsKey(TEST_TYPE)); } - - private static class TestAuthorizationDetail extends AuthorizationDetail { - // Test authorization detail class which extends AuthorizationDetail - } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestConstants.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestConstants.java index b8e276837a..9cd3712a5a 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestConstants.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestConstants.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar.util; /** @@ -5,13 +23,19 @@ */ public class TestConstants { - private TestConstants() { - // Private constructor to prevent instantiation - } - + public static final String TEST_AUTHORIZATION_CODE = "b1b833f0-f605-4f5c-add6-38ea8ce1b969"; + public static final String TEST_CODE_ID = "81197bc6-63f3-4c0f-90dd-1588076ab50f"; public static final String TEST_CONSENT_ID = "52481ccd-0927-4d17-8cfc-5110fc4aa009"; public static final String TEST_DB_NAME = "TEST_IAM_RAR_DATABASE"; public static final int TEST_TENANT_ID = 1234; public static final String TEST_TOKEN_ID = "e1fea951-a3b5-4347-bd73-b18b3feecd54"; public static final String TEST_TYPE = "test_type_v1"; + public static final String TEST_NAME = "test_name_v1"; + public static final String TEST_SCHEMA = "{\"type\":\"object\",\"required\":[\"type\"],\"properties\":" + + "{\"type\":{\"type\":\"string\",\"enum\":[\"test_type_v1\"]},\"actions\":{\"type\":\"array\"," + + "\"items\":{\"type\":\"string\",\"enum\":[\"initiate\"]}}}}"; + + private TestConstants() { + // Private constructor to prevent instantiation + } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java index 8c354b8217..fe2e3b0dd8 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java @@ -1,7 +1,26 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar.util; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; import java.nio.file.Paths; import java.sql.Connection; @@ -17,6 +36,7 @@ public class TestDAOUtils { private static final Map dataSourceMap = new HashMap<>(); public static void initializeDataSource(String databaseName, String scriptPath) throws SQLException { + BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUsername("username"); @@ -30,6 +50,7 @@ public static void initializeDataSource(String databaseName, String scriptPath) } public static Connection getConnection(String database) throws SQLException { + if (dataSourceMap.get(database) != null) { return dataSourceMap.get(database).getConnection(); } @@ -37,10 +58,27 @@ public static Connection getConnection(String database) throws SQLException { } public static String getFilePath(String fileName) { + if (StringUtils.isNotBlank(fileName)) { return Paths.get(System.getProperty("user.dir"), "src", "test", "resources", "dbScripts", fileName) .toString(); } return null; } + + /** + * Test authorization detail class which extends AuthorizationDetail + */ + public static class TestAuthorizationDetail extends AuthorizationDetail { + + private String name; + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql index 65c28adf66..7ab96e2b44 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql @@ -1,4 +1,4 @@ -CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES( +CREATE TABLE IF NOT EXISTS AUTHORIZATION_DETAILS_TYPES( ID INTEGER NOT NULL AUTO_INCREMENT, TYPE VARCHAR(255) NOT NULL, CURSOR_KEY INTEGER DEFAULT 1, @@ -25,5 +25,47 @@ CREATE TABLE IF NOT EXISTS IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS ( TENANT_ID INTEGER DEFAULT -1 ); -INSERT INTO IDN_OAUTH2_AUTHORIZATION_DETAILS_TYPES (TYPE, NAME, DESCRIPTION, JSON_SCHEMA, TENANT_ID) +CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS ( + ID INTEGER NOT NULL AUTO_INCREMENT, + TYPE_ID CHAR(36) NOT NULL, + AUTHORIZATION_DETAILS JSON NOT NULL, + CODE_ID VARCHAR (255), + TENANT_ID INTEGER +); + +CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHORIZATION_CODE ( + CODE_ID VARCHAR (255), + AUTHORIZATION_CODE VARCHAR (2048), + CONSUMER_KEY_ID INTEGER, + CALLBACK_URL VARCHAR (2048), + SCOPE VARCHAR(2048), + AUTHZ_USER VARCHAR (100), + TENANT_ID INTEGER, + USER_DOMAIN VARCHAR(50), + TIME_CREATED TIMESTAMP, + VALIDITY_PERIOD BIGINT, + STATE VARCHAR (25) DEFAULT 'ACTIVE', + TOKEN_ID VARCHAR(255), + SUBJECT_IDENTIFIER VARCHAR(255), + PKCE_CODE_CHALLENGE VARCHAR (255), + PKCE_CODE_CHALLENGE_METHOD VARCHAR(128), + AUTHORIZATION_CODE_HASH VARCHAR (512), + IDP_ID INTEGER DEFAULT -1 NOT NULL +); + +CREATE TABLE IF NOT EXISTS IDN_OAUTH2_USER_CONSENT ( + ID INTEGER NOT NULL AUTO_INCREMENT, + USER_ID VARCHAR(255) NOT NULL, + APP_ID CHAR(36) NOT NULL, + TENANT_ID INTEGER NOT NULL DEFAULT -1, + CONSENT_ID VARCHAR(255) NOT NULL +); + +INSERT INTO AUTHORIZATION_DETAILS_TYPES (TYPE, NAME, DESCRIPTION, JSON_SCHEMA, TENANT_ID) VALUES ('test_type_v1', 'Test Type', 'Test Type V1', '{}', 1234); + +INSERT INTO IDN_OAUTH2_AUTHORIZATION_CODE (CODE_ID, AUTHORIZATION_CODE, IDP_ID) +VALUES ('81197bc6-63f3-4c0f-90dd-1588076ab50f', 'b1b833f0-f605-4f5c-add6-38ea8ce1b969', 1); + +INSERT INTO IDN_OAUTH2_USER_CONSENT (USER_ID, APP_ID, TENANT_ID, CONSENT_ID) +VALUES ('valid_user_id', 'valid_app_id', 1234, '52481ccd-0927-4d17-8cfc-5110fc4aa009'); \ No newline at end of file diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/testng.xml index f2065912fc..74edf1ba2c 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/testng.xml @@ -20,8 +20,9 @@ - + + diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 8ea9ad8a35..005cd7ab0e 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -265,7 +265,6 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.oauth.rar - provided diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/util/ResponseTypeHandlerUtil.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/util/ResponseTypeHandlerUtil.java index 535b629e05..fcedf5cc7b 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/util/ResponseTypeHandlerUtil.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/util/ResponseTypeHandlerUtil.java @@ -299,6 +299,9 @@ public static AuthzCodeDO generateAuthorizationCode(OAuthAuthzReqMessageContext OAuthTokenPersistenceFactory.getInstance().getAuthorizationCodeDAO() .insertAuthorizationCode(authorizationCode, authorizationReqDTO.getConsumerKey(), appTenant, authorizationReqDTO.getCallbackUrl(), authzCodeDO); + + OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsService() + .storeAuthorizationCodeAuthorizationDetails(authzCodeDO, oauthAuthzMsgCtx); } else { OAuthTokenPersistenceFactory.getInstance().getAuthorizationCodeDAO() .insertAuthorizationCode(authorizationCode, authorizationReqDTO.getConsumerKey(), 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 c562585c65..c365269099 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 @@ -33,6 +33,7 @@ import org.osgi.service.component.annotations.ReferencePolicy; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.api.resource.mgt.APIResourceManager; +import org.wso2.carbon.identity.api.resource.mgt.AuthorizationDetailsTypeManager; import org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticationService; import org.wso2.carbon.identity.application.authentication.framework.AuthenticationDataPublisher; import org.wso2.carbon.identity.application.authentication.framework.AuthenticationMethodNameTranslator; @@ -84,6 +85,8 @@ import org.wso2.carbon.identity.oauth2.keyidprovider.KeyIDProvider; import org.wso2.carbon.identity.oauth2.listener.TenantCreationEventListener; import org.wso2.carbon.identity.oauth2.model.ResourceAccessControlKey; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessorFactory; import org.wso2.carbon.identity.oauth2.rar.token.AccessTokenResponseRARHandler; import org.wso2.carbon.identity.oauth2.rar.token.IntrospectionRARDataProvider; import org.wso2.carbon.identity.oauth2.rar.token.JWTAccessTokenRARClaimProvider; @@ -1621,4 +1624,71 @@ protected void unregisterConfigurationManager(ConfigurationManager configuration } OAuth2ServiceComponentHolder.getInstance().setConfigurationManager(null); } + + /** + * Registers the {@link AuthorizationDetailsTypeManager} service. + * + * @param typeManager The {@code AuthorizationDetailsTypeManager} instance. + */ + @Reference( + name = "org.wso2.carbon.identity.api.resource.mgt.AuthorizationDetailsTypeManager", + service = AuthorizationDetailsTypeManager.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unregisterAuthorizationDetailsTypeManager" + ) + protected void registerAuthorizationDetailsTypeManager(AuthorizationDetailsTypeManager typeManager) { + + if (log.isDebugEnabled()) { + log.debug("Registering the AuthorizationDetailsTypeManager service."); + } + OAuth2ServiceComponentHolder.getInstance().setAuthorizationDetailsTypeManager(typeManager); + } + + + /** + * Unset the {@link AuthorizationDetailsTypeManager} service. + * + * @param typeManager The {@code AuthorizationDetailsTypeManager} instance. + */ + protected void unregisterAuthorizationDetailsTypeManager(AuthorizationDetailsTypeManager typeManager) { + + if (log.isDebugEnabled()) { + log.debug("Unregistering the AuthorizationDetailsTypeManager service."); + } + OAuth2ServiceComponentHolder.getInstance().setAuthorizationDetailsTypeManager(null); + } + + /** + * Registers the {@link AuthorizationDetailsProcessor} service. + * + * @param processor The {@code AuthorizationDetailsProcessor} instance. + */ + @Reference( + name = "org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor", + service = AuthorizationDetailsProcessor.class, + cardinality = ReferenceCardinality.MULTIPLE, + policy = ReferencePolicy.DYNAMIC, + unbind = "unregisterAuthorizationDetailsProcessor" + ) + protected void registerAuthorizationDetailsProcessor(AuthorizationDetailsProcessor processor) { + + if (log.isDebugEnabled()) { + log.debug("Registering the AuthorizationDetailsProcessor service."); + } + AuthorizationDetailsProcessorFactory.getInstance().setAuthorizationDetailsProcessors(processor); + } + + /** + * Unset the {@link AuthorizationDetailsProcessor} service. + * + * @param processor The {@code AuthorizationDetailsProcessor} instance. + */ + protected void unregisterAuthorizationDetailsProcessor(AuthorizationDetailsProcessor processor) { + + if (log.isDebugEnabled()) { + log.debug("Unregistering the AuthorizationDetailsProcessor service."); + } + AuthorizationDetailsProcessorFactory.getInstance().setAuthorizationDetailsProcessors(null); + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java index 28845ea0ce..e1abdeae23 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 @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.oauth2.internal; import org.wso2.carbon.identity.api.resource.mgt.APIResourceManager; +import org.wso2.carbon.identity.api.resource.mgt.AuthorizationDetailsTypeManager; import org.wso2.carbon.identity.application.authentication.framework.AuthenticationDataPublisher; import org.wso2.carbon.identity.application.authentication.framework.AuthenticationMethodNameTranslator; import org.wso2.carbon.identity.application.authentication.framework.UserSessionManagementService; @@ -127,6 +128,7 @@ public class OAuth2ServiceComponentHolder { private ConfigurationManager configurationManager; private AuthorizationDetailsService authorizationDetailsService; private AuthorizationDetailsValidator authorizationDetailsValidator; + private AuthorizationDetailsTypeManager authorizationDetailsTypeManager; private OAuth2ServiceComponentHolder() { @@ -384,7 +386,7 @@ public IdpManager getIdpManager() { return idpManager; } - + /** * Set UserSessionManagementService Instance. * @@ -919,4 +921,22 @@ public AuthorizationDetailsValidator getAuthorizationDetailsValidator() { } return this.authorizationDetailsValidator; } + + /** + * Get an {@link AuthorizationDetailsTypeManager} instance. + * + * @return A {@link AuthorizationDetailsTypeManager} singleton instance. + */ + public AuthorizationDetailsTypeManager getAuthorizationDetailsTypeManager() { + + return this.authorizationDetailsTypeManager; + } + + /** + * set an {@link AuthorizationDetailsTypeManager} instance. + */ + public void setAuthorizationDetailsTypeManager(AuthorizationDetailsTypeManager authorizationDetailsTypeManager) { + + this.authorizationDetailsTypeManager = authorizationDetailsTypeManager; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java index 1170f33070..f870ae85d1 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java @@ -8,10 +8,12 @@ import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.AuthzCodeDO; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessorFactory; import org.wso2.carbon.identity.oauth2.rar.dao.AuthorizationDetailsDAO; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsCodeDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; @@ -22,15 +24,13 @@ import java.sql.SQLException; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.getAuthorizationDetailsConsentDTOs; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.getAuthorizationDetailsTypesMap; import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.isRichAuthorizationRequest; /** @@ -48,11 +48,11 @@ public class AuthorizationDetailsService { private static final Log log = LogFactory.getLog(AuthorizationDetailsService.class); private final AuthorizationDetailsDAO authorizationDetailsDAO; - private final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory; + private final AuthorizationDetailsProcessorFactory authorizationDetailsProcessorFactory; /** * Default constructor that initializes the service with the default {@link AuthorizationDetailsDAO} and - * {@link AuthorizationDetailsProviderFactory}. + * {@link AuthorizationDetailsProcessorFactory}. *

* This constructor uses the default DAO provided by the {@link OAuthTokenPersistenceFactory} * to handle the persistence of authorization details. @@ -61,7 +61,7 @@ public class AuthorizationDetailsService { public AuthorizationDetailsService() { this( - AuthorizationDetailsProviderFactory.getInstance(), + AuthorizationDetailsProcessorFactory.getInstance(), OAuthTokenPersistenceFactory.getInstance().getAuthorizationDetailsDAO() ); } @@ -69,16 +69,16 @@ public AuthorizationDetailsService() { /** * Constructor that initializes the service with a given {@link AuthorizationDetailsDAO}. * - * @param authorizationDetailsProviderFactory Factory instance for providing authorization details. - * @param authorizationDetailsDAO The {@link AuthorizationDetailsDAO} instance to be used for - * handling authorization details persistence. Must not be {@code null}. + * @param authorizationDetailsProcessorFactory Factory instance for providing authorization details. + * @param authorizationDetailsDAO The {@link AuthorizationDetailsDAO} instance to be used for + * handling authorization details persistence. Must not be {@code null}. */ - public AuthorizationDetailsService(final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory, + public AuthorizationDetailsService(final AuthorizationDetailsProcessorFactory authorizationDetailsProcessorFactory, final AuthorizationDetailsDAO authorizationDetailsDAO) { this.authorizationDetailsDAO = Objects .requireNonNull(authorizationDetailsDAO, "AuthorizationDetailsDAO must not be null"); - this.authorizationDetailsProviderFactory = Objects.requireNonNull(authorizationDetailsProviderFactory, + this.authorizationDetailsProcessorFactory = Objects.requireNonNull(authorizationDetailsProcessorFactory, "AuthorizationDetailsProviderFactory must not be null"); } @@ -109,7 +109,7 @@ public void storeUserConsentedAuthorizationDetails(final AuthenticatedUser authe final AuthorizationDetails trimmedAuthorizationDetails = AuthorizationDetailsUtils .getTrimmedAuthorizationDetails(userConsentedAuthorizationDetails); - final List authorizationDetailsConsentDTOs = + final Set authorizationDetailsConsentDTOs = getAuthorizationDetailsConsentDTOs(consentId.get(), trimmedAuthorizationDetails, tenantId); this.authorizationDetailsDAO.addUserConsentedAuthorizationDetails(authorizationDetailsConsentDTOs); @@ -124,33 +124,6 @@ public void storeUserConsentedAuthorizationDetails(final AuthenticatedUser authe } } - public void updateUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, - final String clientId, final OAuth2Parameters oAuth2Parameters, - final AuthorizationDetails userConsentedAuthorizationDetails) - throws OAuthSystemException { - - if (!isRichAuthorizationRequest(oAuth2Parameters)) { - return; - } - - try { - final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); - final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); - - if (consentId.isPresent()) { - - final List authorizationDetailsConsentDTOs = - getAuthorizationDetailsConsentDTOs(consentId.get(), - userConsentedAuthorizationDetails, tenantId); - - this.authorizationDetailsDAO.updateUserConsentedAuthorizationDetails(authorizationDetailsConsentDTOs); - } - } catch (SQLException | IdentityOAuth2Exception e) { - log.error("Error occurred while updating user consented authorization details. Caused by, ", e); - throw new OAuthSystemException("Error occurred while updating authorization details", e); - } - } - /** * Deletes user-consented authorization details. * @@ -224,13 +197,109 @@ public boolean isUserAlreadyConsentedForAuthorizationDetails(final Authenticated return this.getConsentRequiredAuthorizationDetails(authenticatedUser, oAuth2Parameters).getDetails().isEmpty(); } + public AuthorizationDetails getConsentRequiredAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final OAuth2Parameters oAuth2Parameters) + throws IdentityOAuth2Exception { + + if (!isRichAuthorizationRequest(oAuth2Parameters)) { + log.debug("Request is not a rich authorization request. Skipping the authorization details retrieval."); + return new AuthorizationDetails(); + } + + final Map> consentedAuthorizationDetailsByType = + this.getUserConsentedAuthorizationDetailsByType(authenticatedUser, oAuth2Parameters); + + final Set consentRequiredAuthorizationDetails = new HashSet<>(); + oAuth2Parameters.getAuthorizationDetails().stream() + .filter(requestedDetail -> + !this.isUserConsentedAuthorizationDetail(requestedDetail, consentedAuthorizationDetailsByType)) + .forEach(consentRequiredAuthorizationDetails::add); + + return new AuthorizationDetails(consentRequiredAuthorizationDetails); + } + + private Map> getUserConsentedAuthorizationDetailsByType( + final AuthenticatedUser authenticatedUser, final OAuth2Parameters oAuth2Parameters) + throws IdentityOAuth2Exception { + + return getAuthorizationDetailsTypesMap( + this.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters)); + } + + /** + * Checks if the user has already consented to the requested authorization detail. + * + *

This method validates if the requested authorization detail is part of the consented authorization details. + * It uses the appropriate provider to compare the requested detail with the existing consented details.

+ * + * @param requestedAuthorizationDetail the authorization detail to be checked + * @param consentedAuthorizationDetailsByType a map of consented authorization details grouped by type + * @return {@code true} if the user has consented to the requested authorization detail, {@code false} otherwise + */ + private boolean isUserConsentedAuthorizationDetail( + final AuthorizationDetail requestedAuthorizationDetail, + final Map> consentedAuthorizationDetailsByType) { + + final String requestedType = requestedAuthorizationDetail.getType(); + if (!consentedAuthorizationDetailsByType.containsKey(requestedType)) { + if (log.isDebugEnabled()) { + log.debug(String.format("User hasn't consented for the requested authorization details type '%s'.", + requestedType)); + } + return false; + } + + final Optional optProcessor = + this.authorizationDetailsProcessorFactory.getAuthorizationDetailsProcessorByType(requestedType); + + if (optProcessor.isPresent()) { + + if (log.isDebugEnabled()) { + log.debug("Validating equality of requested and existing authorization details " + + "using processor class: " + optProcessor.get().getClass().getSimpleName()); + } + + final AuthorizationDetails existingAuthorizationDetails = + new AuthorizationDetails(consentedAuthorizationDetailsByType.get(requestedType)); + boolean isEqualOrSubset = optProcessor.get() + .isEqualOrSubset(requestedAuthorizationDetail, existingAuthorizationDetails); + + if (log.isDebugEnabled()) { + log.debug(String.format("Verifying if the user has already consented to the requested " + + "authorization details type: '%s'. Result: %b", requestedType, isEqualOrSubset)); + } + return isEqualOrSubset; + } + if (log.isDebugEnabled()) { + log.debug(String.format("No AuthorizationDetailsProcessor implementation found for type: %s. " + + "Proceeding with user consent.", requestedType)); + } + return false; + } + + /** + * Retrieves the user consented authorization details for a given user and OAuth2 parameters. + * + * @param authenticatedUser The authenticated user. + * @param oAuth2Parameters The OAuth2 parameters. + * @return The user consented authorization details. + * @throws IdentityOAuth2Exception If an error occurs while retrieving the details. + */ + public AuthorizationDetails getUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, + final OAuth2Parameters oAuth2Parameters) + throws IdentityOAuth2Exception { + + final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); + return this.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters.getClientId(), tenantId); + } + /** * Retrieves the user consented authorization details for a given user, client, and tenant. * * @param authenticatedUser The authenticated user. * @param clientId The client ID. * @param tenantId The tenant ID. - * @return The user consented authorization details. + * @return The user consented authorization details, or {@code null} if no consent is found. * @throws IdentityOAuth2Exception If an error occurs while retrieving the details. */ public AuthorizationDetails getUserConsentedAuthorizationDetails( @@ -238,39 +307,62 @@ public AuthorizationDetails getUserConsentedAuthorizationDetails( throws IdentityOAuth2Exception { try { - final Set consentedAuthorizationDetails = new HashSet<>(); final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId); if (consentId.isPresent()) { - final Set consentedAuthorizationDetailsDTOs = - this.authorizationDetailsDAO.getUserConsentedAuthorizationDetails(consentId.get(), tenantId); - - consentedAuthorizationDetailsDTOs + final Set consentedAuthorizationDetails = new HashSet<>(); + this.authorizationDetailsDAO.getUserConsentedAuthorizationDetails(consentId.get(), tenantId) .stream() .filter(AuthorizationDetailsConsentDTO::isConsentActive) .map(AuthorizationDetailsConsentDTO::getAuthorizationDetail) .forEach(consentedAuthorizationDetails::add); + return new AuthorizationDetails(consentedAuthorizationDetails); } - return new AuthorizationDetails(consentedAuthorizationDetails); } catch (SQLException e) { log.error("Error occurred while retrieving user consented authorization details. Caused by, ", e); throw new IdentityOAuth2Exception("Unable to retrieve user consented authorization details", e); } + return null; } /** - * Retrieves the user consented authorization details for a given user and OAuth2 parameters. + * Retrieves the consent ID for the given user, client, and tenant. * * @param authenticatedUser The authenticated user. - * @param oAuth2Parameters The OAuth2 parameters. - * @return The user consented authorization details. - * @throws IdentityOAuth2Exception If an error occurs while retrieving the details. + * @param clientId The client ID. + * @param tenantId The tenant ID. + * @return An {@link Optional} containing the consent ID if present. + * @throws IdentityOAuth2Exception if an error occurs related to OAuth2 identity. */ - public AuthorizationDetails getUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, - final OAuth2Parameters oAuth2Parameters) + private Optional getConsentId(final AuthenticatedUser authenticatedUser, final String clientId, + final int tenantId) throws IdentityOAuth2Exception { - final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain()); - return this.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters.getClientId(), tenantId); + final String userId = AuthorizationDetailsUtils.getIdFromAuthenticatedUser(authenticatedUser); + final String appId = AuthorizationDetailsUtils.getApplicationResourceIdFromClientId(clientId); + + return this.getConsentIdByUserIdAndAppId(userId, appId, tenantId); + } + + /** + * Retrieves the consent ID by user ID and application ID. + * + * @param userId The user ID. + * @param appId The application ID. + * @param tenantId The tenant ID. + * @return An {@link Optional} containing the consent ID if present. + * @throws IdentityOAuth2Exception if an error occurs while retrieving the consent ID. + */ + public Optional getConsentIdByUserIdAndAppId(final String userId, final String appId, final int tenantId) + throws IdentityOAuth2Exception { + + try { + return Optional + .ofNullable(this.authorizationDetailsDAO.getConsentIdByUserIdAndAppId(userId, appId, tenantId)); + } catch (SQLException e) { + log.error(String.format("Error occurred while retrieving user consent by " + + "userId: %s and appId: %s. Caused by, ", userId, appId), e); + throw new IdentityOAuth2Exception("Error occurred while retrieving user consent", e); + } } /** @@ -320,25 +412,6 @@ public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessToken this.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthAuthzReqMessageContext.getAuthorizationDetails()); } - /** - * Stores the authorization details for a given access token and OAuth token request context. - * - * @param accessTokenDO The access token data object. - * @param oAuthTokenReqMessageContext The OAuth token request message context. - * @throws IdentityOAuth2Exception If an error occurs while storing the details. - */ - public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessTokenDO, - final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) - throws IdentityOAuth2Exception { - - if (!isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { - log.debug("Request is not a rich authorization request. Skipping storage of token authorization details."); - return; - } - - this.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthTokenReqMessageContext.getAuthorizationDetails()); - } - /** * Stores the authorization details for a given access token and authorization details. * @@ -354,7 +427,7 @@ public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessToken final AuthorizationDetails trimmedAuthorizationDetails = AuthorizationDetailsUtils .getTrimmedAuthorizationDetails(authorizationDetails); - final List authorizationDetailsTokenDTOs = AuthorizationDetailsUtils + final Set authorizationDetailsTokenDTOs = AuthorizationDetailsUtils .getAccessTokenAuthorizationDetailsDTOs(accessTokenDO, trimmedAuthorizationDetails); // Storing the authorization details. @@ -396,27 +469,6 @@ public void storeOrReplaceAccessTokenAuthorizationDetails( oAuthTokenReqMessageContext.getAuthorizationDetails()); } - /** - * Replaces the authorization details for an old access token with the details of a new access token. - * - * @param oldAccessTokenId The old access token ID. - * @param newAccessTokenDO The new access token data object. - * @param oAuthTokenReqMessageContext The OAuth token request message context. - * @throws IdentityOAuth2Exception If an error occurs while replacing the details. - */ - public void replaceAccessTokenAuthorizationDetails(final String oldAccessTokenId, - final AccessTokenDO newAccessTokenDO, - final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) - throws IdentityOAuth2Exception { - - if (!isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { - log.debug("Request is not a rich authorization request. Skipping replacement of authorization details."); - return; - } - this.deleteAccessTokenAuthorizationDetails(oldAccessTokenId, newAccessTokenDO.getTenantID()); - this.storeAccessTokenAuthorizationDetails(newAccessTokenDO, oAuthTokenReqMessageContext); - } - /** * Deletes the authorization details associated with a given access token. * @@ -439,120 +491,107 @@ public void deleteAccessTokenAuthorizationDetails(final String accessTokenId, fi } /** - * Retrieves the consent ID for the given user, client, and tenant. + * Replaces the authorization details for an old access token with the details of a new access token. * - * @param authenticatedUser The authenticated user. - * @param clientId The client ID. - * @param tenantId The tenant ID. - * @return An {@link Optional} containing the consent ID if present. - * @throws IdentityOAuth2Exception if an error occurs related to OAuth2 identity. + * @param oldAccessTokenId The old access token ID. + * @param newAccessTokenDO The new access token data object. + * @param oAuthTokenReqMessageContext The OAuth token request message context. + * @throws IdentityOAuth2Exception If an error occurs while replacing the details. */ - private Optional getConsentId(final AuthenticatedUser authenticatedUser, final String clientId, - final int tenantId) + public void replaceAccessTokenAuthorizationDetails(final String oldAccessTokenId, + final AccessTokenDO newAccessTokenDO, + final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) throws IdentityOAuth2Exception { - final String userId = AuthorizationDetailsUtils.getIdFromAuthenticatedUser(authenticatedUser); - final String appId = AuthorizationDetailsUtils.getApplicationResourceIdFromClientId(clientId); - - return this.getConsentIdByUserIdAndAppId(userId, appId, tenantId); + if (!isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { + log.debug("Request is not a rich authorization request. Skipping replacement of authorization details."); + return; + } + this.deleteAccessTokenAuthorizationDetails(oldAccessTokenId, newAccessTokenDO.getTenantID()); + this.storeAccessTokenAuthorizationDetails(newAccessTokenDO, oAuthTokenReqMessageContext); } /** - * Retrieves the consent ID by user ID and application ID. + * Stores the authorization details for a given access token and OAuth token request context. * - * @param userId The user ID. - * @param appId The application ID. - * @param tenantId The tenant ID. - * @return An {@link Optional} containing the consent ID if present. - * @throws IdentityOAuth2Exception if an error occurs while retrieving the consent ID. + * @param accessTokenDO The access token data object. + * @param oAuthTokenReqMessageContext The OAuth token request message context. + * @throws IdentityOAuth2Exception If an error occurs while storing the details. */ - public Optional getConsentIdByUserIdAndAppId(final String userId, final String appId, final int tenantId) + public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessTokenDO, + final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) throws IdentityOAuth2Exception { - try { - return Optional - .ofNullable(this.authorizationDetailsDAO.getConsentIdByUserIdAndAppId(userId, appId, tenantId)); - } catch (SQLException e) { - log.error(String.format("Error occurred while retrieving user consent by " + - "userId: %s and appId: %s. Caused by, ", userId, appId), e); - throw new IdentityOAuth2Exception("Error occurred while retrieving user consent", e); + if (!isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { + log.debug("Request is not a rich authorization request. Skipping storage of token authorization details."); + return; } + + this.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthTokenReqMessageContext.getAuthorizationDetails()); } - public AuthorizationDetails getConsentRequiredAuthorizationDetails(final AuthenticatedUser authenticatedUser, - final OAuth2Parameters oAuth2Parameters) + /** + * Stores the authorization details for a given authorization code and OAuth authorization request context. + * + * @param authzCodeDO The authorization code data object. + * @param oAuthAuthzReqMessageContext The OAuth authorization request message context. + * @throws IdentityOAuth2Exception If an error occurs while storing the details. + */ + public void storeAuthorizationCodeAuthorizationDetails( + final AuthzCodeDO authzCodeDO, final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) throws IdentityOAuth2Exception { - if (!isRichAuthorizationRequest(oAuth2Parameters)) { - log.debug("Request is not a rich authorization request. Skipping the authorization details retrieval."); - return new AuthorizationDetails(); + if (!isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) { + log.debug("Request is not a rich authorization request. Skipping storage of code authorization details."); + return; } - final Map> consentedAuthorizationDetailsByType = - getUserConsentedAuthorizationDetailsByType(authenticatedUser, oAuth2Parameters); + try { + final int tenantId = + OAuth2Util.getTenantId(oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getTenantDomain()); - final Set consentRequiredAuthorizationDetails = new HashSet<>(); - oAuth2Parameters.getAuthorizationDetails().stream() - .filter(requestedDetail -> - !this.isUserConsentedAuthorizationDetail(consentedAuthorizationDetailsByType, requestedDetail)) - .forEach(consentRequiredAuthorizationDetails::add); + final Set authorizationDetailsCodeDTOs = + AuthorizationDetailsUtils.getCodeAuthorizationDetailsDTOs(authzCodeDO, + oAuthAuthzReqMessageContext.getAuthorizationDetails(), tenantId); - return new AuthorizationDetails(consentRequiredAuthorizationDetails); - } - - private Map> getUserConsentedAuthorizationDetailsByType( - final AuthenticatedUser authenticatedUser, final OAuth2Parameters oAuth2Parameters) - throws IdentityOAuth2Exception { + // Storing the authorization details. + this.authorizationDetailsDAO.addOAuth2CodeAuthorizationDetails(authorizationDetailsCodeDTOs); - return this.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters) - .stream() - .collect(Collectors.groupingBy(AuthorizationDetail::getType, - Collectors.mapping(Function.identity(), Collectors.toSet()))); + if (log.isDebugEnabled()) { + log.debug("Successfully stored authorization code authorization details for code ID: " + + authzCodeDO.getAuthzCodeId()); + } + } catch (SQLException e) { + log.error("Error occurred while storing authorization code authorization details. Caused by, ", e); + throw new IdentityOAuth2Exception("Error occurred while storing authz code authorization details", e); + } } /** - * Checks if the user has already consented to the requested authorization detail. - * - *

This method validates if the requested authorization detail is part of the consented authorization details. - * It uses the appropriate provider to compare the requested detail with the existing consented details.

+ * Retrieves the authorization details associated with a given authorization code Id. * - * @param consentedAuthorizationDetailsByType a map of consented authorization details grouped by type - * @param requestedAuthorizationDetail the authorization detail to be checked - * @return {@code true} if the user has consented to the requested authorization detail, {@code false} otherwise + * @param codeId The authorization code ID. + * @param tenantId The tenant ID. + * @return The authorization code authorization details. + * @throws IdentityOAuth2Exception If an error occurs while retrieving the details. */ - public boolean isUserConsentedAuthorizationDetail( - final Map> consentedAuthorizationDetailsByType, - final AuthorizationDetail requestedAuthorizationDetail) { - - if (!consentedAuthorizationDetailsByType.containsKey(requestedAuthorizationDetail.getType())) { - log.debug("Request is not a rich authorization request. Skipping the validation."); - return false; - } - - final Optional provider = this.authorizationDetailsProviderFactory - .getProviderByType(requestedAuthorizationDetail.getType()); - if (provider.isPresent()) { + public AuthorizationDetails getAuthorizationCodeAuthorizationDetails(final String codeId, final int tenantId) + throws IdentityOAuth2Exception { - if (log.isDebugEnabled()) { - log.debug("Validating equality of requested and existing authorization details " + - "using provider class: " + provider.get().getClass().getSimpleName()); - } + try { + final Set authorizationDetailsCodeDTOs = + this.authorizationDetailsDAO.getOAuth2CodeAuthorizationDetails(codeId, tenantId); - final AuthorizationDetails existingAuthorizationDetails = new AuthorizationDetails( - consentedAuthorizationDetailsByType.get(requestedAuthorizationDetail.getType())); - boolean isEqualOrSubset = provider.get() - .isEqualOrSubset(requestedAuthorizationDetail, existingAuthorizationDetails); + final Set codeAuthorizationDetails = new HashSet<>(); + authorizationDetailsCodeDTOs + .stream() + .map(AuthorizationDetailsCodeDTO::getAuthorizationDetail) + .forEach(codeAuthorizationDetails::add); - if (log.isDebugEnabled() && isEqualOrSubset) { - log.debug("User has already consented for the requested authorization details type: " - + requestedAuthorizationDetail.getType()); - } - return isEqualOrSubset; - } - if (log.isDebugEnabled()) { - log.debug(String.format("Ignores unsupported authorization details type: %s", - requestedAuthorizationDetail.getType())); + return new AuthorizationDetails(codeAuthorizationDetails); + } catch (SQLException e) { + log.error("Error occurred while retrieving authz code authorization details. Caused by, ", e); + throw new IdentityOAuth2Exception("Unable to retrieve authz code authorization details", e); } - return true; } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessor.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessor.java index 44b68875a4..569751a9ba 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessor.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessor.java @@ -27,13 +27,11 @@ /** * The {@code AuthorizationDetailsProcessor} interface defines a contract for implementing - * different types of authorization detail providers in a Service Provider Interface (SPI) setup. + * different types of authorization detail providers in an OSGI setup. *

* Implementing classes are expected to provide mechanisms to validate, enrich, and identify * authorization details specific to various types. *

- * - * @see Java SPI */ public interface AuthorizationDetailsProcessor { diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java new file mode 100644 index 0000000000..a8798b42e2 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth2.rar.core; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.identity.api.resource.mgt.APIResourceMgtException; +import org.wso2.carbon.identity.application.common.model.AuthorizationDetailsType; +import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * A factory class to manage and provide instances of {@link AuthorizationDetailsProcessor} Service Provider Interface. + * This class follows the Singleton pattern to ensure only one instance is created. + * It uses {@link ServiceLoader} to dynamically load and manage {@link AuthorizationDetailsProcessor} implementations. + *

Example usage: + *

 {@code
+ * // Get a specific provider by type
+ * AuthorizationDetailsProviderFactory.getInstance()
+ *     .getProviderByType("customer_information")
+ *     .ifPresentOrElse(
+ *         p -> log.debug("Provider for type " + type + ": " + p.getClass().getName()),
+ *         () -> log.debug("No provider found for type " + type)
+ *     );
+ * } 

+ * + * @see AuthorizationDetailsProcessor AuthorizationDetailsService + * @see + * Request Parameter "authorization_details" + */ +public class AuthorizationDetailsProcessorFactory { + + private static final Log log = LogFactory.getLog(AuthorizationDetailsProcessorFactory.class); + private static volatile AuthorizationDetailsProcessorFactory instance; + private final Map authorizationDetailsProcessors; + + /** + * Private constructor to initialize the factory. + *

This constructor is intentionally private to prevent direct instantiation of the + * {@code AuthorizationDetailsProviderFactory} class. + * Instead, use the {@link #getInstance()} method to obtain the singleton instance.

+ */ + private AuthorizationDetailsProcessorFactory() { + + this.authorizationDetailsProcessors = new HashMap<>(); + } + + /** + * Provides the singleton instance of {@code AuthorizationDetailsProviderFactory}. + * + * @return Singleton instance of {@code AuthorizationDetailsProviderFactory}. + */ + public static AuthorizationDetailsProcessorFactory getInstance() { + + if (instance == null) { + synchronized (AuthorizationDetailsProcessorFactory.class) { + if (instance == null) { + instance = new AuthorizationDetailsProcessorFactory(); + } + } + } + return instance; + } + + /** + * Returns the {@link AuthorizationDetailsProcessor} provider for the given type. + * + * @param type A supported authorization details type. + * @return {@link Optional} containing the {@link AuthorizationDetailsProcessor} if present, otherwise empty. + * @see AuthorizationDetailsProcessor#getType() getAuthorizationDetailsType + */ + public Optional getAuthorizationDetailsProcessorByType(final String type) { + + return Optional.ofNullable(this.authorizationDetailsProcessors.get(type)); + } + + /** + * Checks if a given type has a valid service provider implementation. + * + * @param type The type to check. + * @return {@code true} if the type is supported, {@code false} otherwise. + * @see AuthorizationDetailsProcessor AuthorizationDetailsService + */ + public boolean isSupportedAuthorizationDetailsType(final String type) { + + return this.getSupportedAuthorizationDetailTypes().contains(type); + } + + /** + * Returns an {@link Collections#unmodifiableSet} containing all supported authorization details types. + *

A type is considered "supported" if it has been registered by invoking the + * POST: /api/server/v1/api-resources endpoint.

+ * + * @return An unmodifiable set of supported authorization details types. + */ + public Set getSupportedAuthorizationDetailTypes() { + + final String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + try { + return OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsTypeManager() + .getAuthorizationDetailsTypes(StringUtils.EMPTY, tenantDomain) + .stream() + .map(AuthorizationDetailsType::getType) + .collect(Collectors.toUnmodifiableSet()); + } catch (APIResourceMgtException e) { + if (log.isDebugEnabled()) { + log.debug(String.format("Error occurred while retrieving supported authorization details types " + + "for tenant: %s. Caused by, ", tenantDomain), e); + } + } + return Collections.emptySet(); + } + + /** + * Caches the provided {@link AuthorizationDetailsProcessor} instance by associating it with its corresponding + * authorization details type. This allows efficient retrieval and reuse of processors based on their type. + *

The type of the authorization details processor is obtained using + * {@link AuthorizationDetailsProcessor#getType()}

+ * + * @param authorizationDetailsProcessor Processor instance to be cached, keyed by its authorization details type. + */ + public void setAuthorizationDetailsProcessors(final AuthorizationDetailsProcessor authorizationDetailsProcessor) { + + if (authorizationDetailsProcessor != null && StringUtils.isNotBlank(authorizationDetailsProcessor.getType())) { + final String type = authorizationDetailsProcessor.getType(); + if (log.isDebugEnabled()) { + log.debug(String.format("Registering AuthorizationDetailsProcessor %s against type %s", + authorizationDetailsProcessor.getClass().getSimpleName(), type)); + } + this.authorizationDetailsProcessors.put(type, authorizationDetailsProcessor); + } + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java deleted file mode 100644 index 64ca86d097..0000000000 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProviderFactory.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.oauth2.rar.core; - -import java.util.Collections; -import java.util.Map; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -/** - * A factory class to manage and provide instances of {@link AuthorizationDetailsProcessor} Service Provider Interface. - * This class follows the Singleton pattern to ensure only one instance is created. - * It uses {@link ServiceLoader} to dynamically load and manage {@link AuthorizationDetailsProcessor} implementations. - *

Example usage: - *

 {@code
- * // Get a specific provider by type
- * AuthorizationDetailsProviderFactory.getInstance()
- *     .getProviderByType("customer_information")
- *     .ifPresentOrElse(
- *         p -> log.debug("Provider for type " + type + ": " + p.getClass().getName()),
- *         () -> log.debug("No provider found for type " + type)
- *     );
- * } 

- * - * @see AuthorizationDetailsProcessor AuthorizationDetailsService - * @see - * Request Parameter "authorization_details" - */ -public class AuthorizationDetailsProviderFactory { - - private static volatile AuthorizationDetailsProviderFactory instance; - private final Map supportedAuthorizationDetailsTypes; - - /** - * Private constructor to initialize the factory. - *

This constructor is intentionally private to prevent direct instantiation of the - * {@code AuthorizationDetailsProviderFactory} class. - * Instead, use the {@link #getInstance()} method to obtain the singleton instance.

- */ - private AuthorizationDetailsProviderFactory() { - - this.supportedAuthorizationDetailsTypes = this.loadSupportedAuthorizationDetailsTypes(); - } - - /** - * Loads supported authorization details Processors from the provided {@link ServiceLoader}. - * - * @return Map of authorization details types with their corresponding SPI services. - */ - private Map loadSupportedAuthorizationDetailsTypes() { - - final ServiceLoader serviceLoader = ServiceLoader - .load(AuthorizationDetailsProcessor.class, this.getClass().getClassLoader()); - - return StreamSupport.stream(serviceLoader.spliterator(), false) - .collect(Collectors.toMap(AuthorizationDetailsProcessor::getType, Function.identity())); - } - - /** - * Provides the singleton instance of {@code AuthorizationDetailsProviderFactory}. - * - * @return Singleton instance of {@code AuthorizationDetailsProviderFactory}. - */ - public static AuthorizationDetailsProviderFactory getInstance() { - - if (instance == null) { - synchronized (AuthorizationDetailsProviderFactory.class) { - if (instance == null) { - instance = new AuthorizationDetailsProviderFactory(); - } - } - } - return instance; - } - - /** - * Returns the {@link AuthorizationDetailsProcessor} provider for the given type. - * - * @param type A supported authorization details type. - * @return {@link Optional} containing the {@link AuthorizationDetailsProcessor} if present, otherwise empty. - * @see AuthorizationDetailsProcessor#getType() getAuthorizationDetailsType - */ - public Optional getProviderByType(final String type) { - - return Optional.ofNullable(this.supportedAuthorizationDetailsTypes.get(type)); - } - - /** - * Checks if a given type has a valid service provider implementation. - * - * @param type The type to check. - * @return {@code true} if the type is supported, {@code false} otherwise. - * @see AuthorizationDetailsProcessor AuthorizationDetailsService - */ - public boolean isSupportedAuthorizationDetailsType(final String type) { - - return this.supportedAuthorizationDetailsTypes.containsKey(type); - } - - /** - * Returns a {@link Collections#unmodifiableSet} of all supported authorization details types. - *

To be included as a supported authorization details type, there must be a custom implementation - * of the {@link AuthorizationDetailsProcessor} Service Provider Interface (SPI) available in the classpath - * for the specified type.

- * - * @return A set of supported authorization details types. - */ - public Set getSupportedAuthorizationDetailTypes() { - - return Collections.unmodifiableSet(this.supportedAuthorizationDetailsTypes.keySet()); - } -} diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java index 998ea794ac..893647091c 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetailsContext.java @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.oauth2.rar.model; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.AuthorizationDetailsType; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; @@ -40,10 +41,31 @@ public class AuthorizationDetailsContext { private final AuthenticatedUser authenticatedUser; private final AuthorizationDetail authorizationDetail; + private final AuthorizationDetailsType authorizationDetailsType; private final HttpServletRequestWrapper httpServletRequestWrapper; private final OAuthAppDO oAuthAppDO; private final String[] scopes; + /** + * Constructs a new {@code AuthorizationDetailsContext}. + * + * @param authorizationDetail the specific {@link AuthorizationDetail} to be validated. + * @param oAuthAuthzReqMessageContext the {@link OAuthAuthzReqMessageContext} instance which represent + * the authorization request context. + * @throws NullPointerException if any of the arguments are {@code null}. + */ + public AuthorizationDetailsContext(final AuthorizationDetail authorizationDetail, + final AuthorizationDetailsType authorizationDetailsType, + final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) { + + this(oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getUser(), + authorizationDetail, + authorizationDetailsType, + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getHttpServletRequestWrapper(), + (OAuthAppDO) oAuthAuthzReqMessageContext.getProperty(OAUTH_APP_PROPERTY), + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getScopes()); + } + /** * Constructs a new {@code AuthorizationDetailsContext}. *

@@ -59,36 +81,21 @@ public class AuthorizationDetailsContext { */ public AuthorizationDetailsContext(final AuthenticatedUser authenticatedUser, final AuthorizationDetail authorizationDetail, + final AuthorizationDetailsType authorizationDetailsType, final HttpServletRequestWrapper httpServletRequestWrapper, final OAuthAppDO oAuthAppDO, final String[] scopes) { this.authenticatedUser = Objects.requireNonNull(authenticatedUser, "authenticatedUser cannot be null"); this.authorizationDetail = Objects.requireNonNull(authorizationDetail, "authorizationDetail cannot be null"); - this.httpServletRequestWrapper = Objects - .requireNonNull(httpServletRequestWrapper, "httpServletRequestWrapper cannot be null"); + this.authorizationDetailsType = + Objects.requireNonNull(authorizationDetailsType, "authorizationDetailsType cannot be null"); + this.httpServletRequestWrapper = + Objects.requireNonNull(httpServletRequestWrapper, "httpServletRequestWrapper cannot be null"); this.oAuthAppDO = Objects.requireNonNull(oAuthAppDO, "oAuthAppDO cannot be null"); this.scopes = Objects.requireNonNull(scopes, "scopes cannot be null"); } - /** - * Constructs a new {@code AuthorizationDetailsContext}. - * - * @param authorizationDetail the specific {@link AuthorizationDetail} to be validated. - * @param oAuthAuthzReqMessageContext the {@link OAuthAuthzReqMessageContext} instance which represent - * the authorization request context. - * @throws NullPointerException if any of the arguments are {@code null}. - */ - public AuthorizationDetailsContext(final AuthorizationDetail authorizationDetail, - final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) { - - this(oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getUser(), - authorizationDetail, - oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getHttpServletRequestWrapper(), - (OAuthAppDO) oAuthAuthzReqMessageContext.getProperty(OAUTH_APP_PROPERTY), - oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getScopes()); - } - /** * Constructs a new {@code AuthorizationDetailsContext}. * @@ -98,10 +105,12 @@ public AuthorizationDetailsContext(final AuthorizationDetail authorizationDetail * @throws NullPointerException if any of the arguments are {@code null}. */ public AuthorizationDetailsContext(final AuthorizationDetail authorizationDetail, + final AuthorizationDetailsType authorizationDetailsType, final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) { this(oAuthTokenReqMessageContext.getAuthorizedUser(), authorizationDetail, + authorizationDetailsType, oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getHttpServletRequestWrapper(), (OAuthAppDO) oAuthTokenReqMessageContext.getProperty(OAUTH_APP_PROPERTY), oAuthTokenReqMessageContext.getScope()); @@ -116,12 +125,21 @@ public AuthorizationDetail getAuthorizationDetail() { return this.authorizationDetail; } + /** + * Returns the {@code AuthorizationDetailsType} instance. + * + * @return the {@link AuthorizationDetailsType} instance. + */ + public AuthorizationDetailsType getAuthorizationDetailsType() { + return this.authorizationDetailsType; + } + /** * Returns the OAuth application details. * * @return the {@link OAuthAppDO} instance. */ - public OAuthAppDO getoAuthAppDO() { + public OAuthAppDO getOAuthAppDO() { return this.oAuthAppDO; } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java index e6d3f97244..150cf8de51 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java @@ -10,6 +10,7 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.rar.validator.AuthorizationDetailsValidator; @@ -56,20 +57,25 @@ public Map getIntrospectionData( final OAuth2TokenValidationRequestDTO tokenValidationRequestDTO, final OAuth2IntrospectionResponseDTO introspectionResponseDTO) throws IdentityOAuth2Exception { - final Map introspectionData = new HashMap<>(); - final OAuth2TokenValidationMessageContext tokenValidationMessageContext = - generateOAuth2TokenValidationMessageContext(tokenValidationRequestDTO, introspectionResponseDTO); + try { + final OAuth2TokenValidationMessageContext tokenValidationMessageContext = + generateOAuth2TokenValidationMessageContext(tokenValidationRequestDTO, introspectionResponseDTO); + final Map introspectionData = new HashMap<>(); - if (Objects.nonNull(tokenValidationMessageContext)) { + if (Objects.nonNull(tokenValidationMessageContext)) { - final AuthorizationDetails validatedAuthorizationDetails = this.authorizationDetailsValidator - .getValidatedAuthorizationDetails(tokenValidationMessageContext); - if (AuthorizationDetailsUtils.isRichAuthorizationRequest(validatedAuthorizationDetails)) { + final AuthorizationDetails validatedAuthorizationDetails = this.authorizationDetailsValidator + .getValidatedAuthorizationDetails(tokenValidationMessageContext); - introspectionData.put(AUTHORIZATION_DETAILS, validatedAuthorizationDetails.toSet()); + if (AuthorizationDetailsUtils.isRichAuthorizationRequest(validatedAuthorizationDetails)) { + introspectionData.put(AUTHORIZATION_DETAILS, validatedAuthorizationDetails.toSet()); + } } + return introspectionData; + } catch (AuthorizationDetailsProcessingException e) { + log.error("Authorization details validation failed. Caused by, ", e); + throw new IdentityOAuth2Exception("Authorization details validation failed", e); } - return introspectionData; } /** diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java index ade73ab635..634da17875 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java @@ -13,26 +13,33 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.AuthzCodeDO; import org.wso2.carbon.identity.oauth2.model.CarbonOAuthTokenRequest; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsCodeDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.List; +import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toSet; import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.AUTHORIZATION_DETAILS_ID_PREFIX; /** @@ -55,55 +62,58 @@ public static boolean isRichAuthorizationRequest(final OAuthAuthzReqMessageConte } /** - * Determines if the given {@link OAuthAuthzRequest} object contains {@code authorization_details}. + * Determines if the request is a rich authorization request using provided {@link AuthorizationDetails} object. + *

+ * This method checks if the specified {@link AuthorizationDetails} instance is not {@code null} + * and has a non-empty details set. * - * @param oauthRequest The OAuth Authorization Request to check. - * @return {@code true} if the OAuth authorization request contains a non-blank authorization details parameter, + * @param authorizationDetails The {@link AuthorizationDetails} to check. + * @return {@code true} if the {@link AuthorizationDetails} is not {@code null} and has a non-empty details set, * {@code false} otherwise. */ - public static boolean isRichAuthorizationRequest(final OAuthAuthzRequest oauthRequest) { + public static boolean isRichAuthorizationRequest(final AuthorizationDetails authorizationDetails) { - return StringUtils.isNotBlank(oauthRequest.getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); + return !isEmpty(authorizationDetails); } /** - * Determines if the given {@link CarbonOAuthTokenRequest} object contains {@code authorization_details}. + * Determines if the provided {@link AuthorizationDetails} object is empty or not. + *

+ * This method checks if the specified {@link AuthorizationDetails} instance is not {@code null} + * and has a non-empty details set. * - * @param carbonOAuthTokenRequest The OAuth Token Request to check. - * @return {@code true} if the OAuth token request contains a non-blank authorization details parameter, + * @param authorizationDetails The {@link AuthorizationDetails} to check. + * @return {@code true} if the {@link AuthorizationDetails} is not {@code null} and has a non-empty details set, * {@code false} otherwise. */ - public static boolean isRichAuthorizationRequest(final CarbonOAuthTokenRequest carbonOAuthTokenRequest) { + public static boolean isEmpty(final AuthorizationDetails authorizationDetails) { - return StringUtils - .isNotBlank(carbonOAuthTokenRequest.getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); + return authorizationDetails == null || authorizationDetails.getDetails().isEmpty(); } /** - * Determines if the request is a rich authorization request using provided {@link AuthorizationDetails} object. - *

- * This method checks if the specified {@link AuthorizationDetails} instance is not {@code null} - * and has a non-empty details set. + * Determines if the given {@link OAuthAuthzRequest} object contains {@code authorization_details}. * - * @param authorizationDetails The {@link AuthorizationDetails} to check. - * @return {@code true} if the {@link AuthorizationDetails} is not {@code null} and has a non-empty details set, + * @param oauthRequest The OAuth Authorization Request to check. + * @return {@code true} if the OAuth authorization request contains a non-blank authorization details parameter, * {@code false} otherwise. */ - public static boolean isRichAuthorizationRequest(final AuthorizationDetails authorizationDetails) { + public static boolean isRichAuthorizationRequest(final OAuthAuthzRequest oauthRequest) { - return authorizationDetails != null && !authorizationDetails.getDetails().isEmpty(); + return StringUtils.isNotBlank(oauthRequest.getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); } /** - * Determines if the given {@link OAuth2Parameters} object contains {@link AuthorizationDetails}. + * Determines if the given {@link CarbonOAuthTokenRequest} object contains {@code authorization_details}. * - * @param oAuth2Parameters The requested OAuth2Parameters to check. - * @return {@code true} if the OAuth2Parameters contains non-empty authorization details set, + * @param carbonOAuthTokenRequest The OAuth Token Request to check. + * @return {@code true} if the OAuth token request contains a non-blank authorization details parameter, * {@code false} otherwise. */ - public static boolean isRichAuthorizationRequest(final OAuth2Parameters oAuth2Parameters) { + public static boolean isRichAuthorizationRequest(final CarbonOAuthTokenRequest carbonOAuthTokenRequest) { - return isRichAuthorizationRequest(oAuth2Parameters.getAuthorizationDetails()); + return StringUtils + .isNotBlank(carbonOAuthTokenRequest.getParam(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); } /** @@ -121,18 +131,6 @@ public static boolean isRichAuthorizationRequest(final OAuthTokenReqMessageConte .getOauth2AccessTokenReqDTO().getAuthorizationDetails()); } - /** - * Determines if the given {@link OAuth2AuthorizeReqDTO} object contains {@link AuthorizationDetails}. - * - * @param oAuth2AuthorizeReqDTO The requested oAuth2AuthorizeReqDTO to check. - * @return {@code true} if the oAuth2AuthorizeReqDTO contains non-empty authorization details set, - * {@code false} otherwise. - */ - public static boolean isRichAuthorizationRequest(final OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO) { - - return isRichAuthorizationRequest(oAuth2AuthorizeReqDTO.getAuthorizationDetails()); - } - /** * Retrieves the application resource ID from the client ID. * @@ -169,7 +167,7 @@ public static String getIdFromAuthenticatedUser(final AuthenticatedUser authenti } /** - * Generates a list of {@link AuthorizationDetailsConsentDTO} from the provided consent ID, + * Generates a set of {@link AuthorizationDetailsConsentDTO} from the provided consent ID, * authorization details, and tenant ID. * * @param consentId The consent ID. @@ -177,30 +175,48 @@ public static String getIdFromAuthenticatedUser(final AuthenticatedUser authenti * @param tenantId The tenant ID. * @return A list of {@link AuthorizationDetailsConsentDTO}. */ - public static List getAuthorizationDetailsConsentDTOs( + public static Set getAuthorizationDetailsConsentDTOs( final String consentId, final AuthorizationDetails userConsentedAuthorizationDetails, final int tenantId) { return userConsentedAuthorizationDetails.stream() .map(detail -> new AuthorizationDetailsConsentDTO(consentId, detail, true, tenantId)) - .collect(Collectors.toList()); + .collect(toSet()); } /** - * Generates a list of {@link AuthorizationDetailsTokenDTO} from the provided access token and + * Generates a set of {@link AuthorizationDetailsTokenDTO} from the provided access token and * authorization details. * * @param accessTokenDO The access token data object. * @param authorizationDetails The user-consented authorization details. * @return A list of {@link AuthorizationDetailsTokenDTO}. */ - public static List getAccessTokenAuthorizationDetailsDTOs( + public static Set getAccessTokenAuthorizationDetailsDTOs( final AccessTokenDO accessTokenDO, final AuthorizationDetails authorizationDetails) { return authorizationDetails .stream() .map(authorizationDetail -> new AuthorizationDetailsTokenDTO( accessTokenDO.getTokenId(), authorizationDetail, accessTokenDO.getTenantID())) - .collect(Collectors.toList()); + .collect(toSet()); + } + + /** + * Generates a set of {@link AuthorizationDetailsCodeDTO} from the provided access token and + * authorization details. + * + * @param authzCodeDO The authorization code data object. + * @param authorizationDetails The user-consented authorization details. + * @return A list of {@link AuthorizationDetailsTokenDTO}. + */ + public static Set getCodeAuthorizationDetailsDTOs( + final AuthzCodeDO authzCodeDO, final AuthorizationDetails authorizationDetails, final int tenantId) { + + return authorizationDetails + .stream() + .map(authorizationDetail -> + new AuthorizationDetailsCodeDTO(authzCodeDO.getAuthzCodeId(), authorizationDetail, tenantId)) + .collect(toSet()); } /** @@ -222,16 +238,31 @@ public static AuthorizationDetails extractAuthorizationDetailsFromRequest( final Set consentedAuthorizationDetailIDs = httpServletRequest.getParameterMap().keySet().stream() .filter(parameterName -> parameterName.startsWith(AUTHORIZATION_DETAILS_ID_PREFIX)) .map(parameterName -> parameterName.substring(AUTHORIZATION_DETAILS_ID_PREFIX.length())) - .collect(Collectors.toSet()); + .collect(toSet()); // Filter and collect the consented authorization details - final Set consentedAuthorizationDetails = oAuth2Parameters.getAuthorizationDetails() + final AuthorizationDetails consentedAuthorizationDetails = new AuthorizationDetails(oAuth2Parameters + .getAuthorizationDetails() .stream() .filter(authorizationDetail -> consentedAuthorizationDetailIDs.contains(authorizationDetail.getId())) - .collect(Collectors.toSet()); + .collect(toSet())); log.debug("User consented authorization details extracted successfully."); - return new AuthorizationDetails(consentedAuthorizationDetails); + + oAuth2Parameters.setAuthorizationDetails(consentedAuthorizationDetails); + return consentedAuthorizationDetails; + } + + /** + * Determines if the given {@link OAuth2Parameters} object contains {@link AuthorizationDetails}. + * + * @param oAuth2Parameters The requested OAuth2Parameters to check. + * @return {@code true} if the OAuth2Parameters contains non-empty authorization details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuth2Parameters oAuth2Parameters) { + + return isRichAuthorizationRequest(oAuth2Parameters.getAuthorizationDetails()); } /** @@ -251,7 +282,7 @@ public static AuthorizationDetails getDisplayableAuthorizationDetails( authorizationDetail.setId(protectedAuthorizationDetail.getId()); authorizationDetail.setConsentDescription(protectedAuthorizationDetail.getConsentDescription()); return authorizationDetail; - }).collect(Collectors.toSet()); + }).collect(toSet()); return new AuthorizationDetails(displayableAuthorizationDetails); } @@ -352,6 +383,34 @@ public static void setRARPropertiesToAuthzRequestContext( IdentityTenantUtil.getTenantId(oAuth2AuthorizeReqDTO.getTenantDomain()) ); - oAuthAuthzReqMessageContext.setAuthorizationDetails(authorizationDetails); + if (authorizationDetails != null) { + oAuthAuthzReqMessageContext.setAuthorizationDetails(authorizationDetails); + } + } + + /** + * Determines if the given {@link OAuth2AuthorizeReqDTO} object contains {@link AuthorizationDetails}. + * + * @param oAuth2AuthorizeReqDTO The requested oAuth2AuthorizeReqDTO to check. + * @return {@code true} if the oAuth2AuthorizeReqDTO contains non-empty authorization details set, + * {@code false} otherwise. + */ + public static boolean isRichAuthorizationRequest(final OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO) { + + return isRichAuthorizationRequest(oAuth2AuthorizeReqDTO.getAuthorizationDetails()); + } + + /** + * Converts a list of AuthorizationDetails into a map with the type as the key. + * + * @param authorizationDetails {@link AuthorizationDetails} instance to be converted. + * @return A map where the key is the type and the value is the corresponding AuthorizationDetails object. + */ + public static Map> getAuthorizationDetailsTypesMap( + final AuthorizationDetails authorizationDetails) { + + return authorizationDetails == null ? Collections.emptyMap() + : authorizationDetails.stream() + .collect(groupingBy(AuthorizationDetail::getType, mapping(identity(), toSet()))); } -} +} \ No newline at end of file diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java index 3ea9e29085..809bcfdd49 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java @@ -18,9 +18,13 @@ package org.wso2.carbon.identity.oauth2.rar.validator; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.oltu.oauth2.common.message.types.GrantType; +import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; +import org.wso2.carbon.identity.application.common.model.AuthorizationDetailsType; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException; @@ -28,26 +32,32 @@ 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.rar.AuthorizationDetailsSchemaValidator; import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessorFactory; import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; import org.wso2.carbon.identity.oauth2.rar.model.ValidationResult; -import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; -import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.oauth2.validators.OAuth2TokenValidationMessageContext; +import java.util.Collections; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.TYPE_NOT_SUPPORTED_ERR_FORMAT; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_MSG; + /** * Default implementation class responsible for validating {@link AuthorizationDetails} in different * OAuth2 message contexts. @@ -55,23 +65,26 @@ public class DefaultAuthorizationDetailsValidator implements AuthorizationDetailsValidator { private static final Log log = LogFactory.getLog(DefaultAuthorizationDetailsValidator.class); - private final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory; + private final AuthorizationDetailsProcessorFactory authorizationDetailsProcessorFactory; private final AuthorizationDetailsService authorizationDetailsService; + private final AuthorizationDetailsSchemaValidator authorizationDetailsSchemaValidator; public DefaultAuthorizationDetailsValidator() { - this( - AuthorizationDetailsProviderFactory.getInstance(), - OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsService() + AuthorizationDetailsProcessorFactory.getInstance(), + OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsService(), + AuthorizationDetailsSchemaValidator.getInstance() ); } public DefaultAuthorizationDetailsValidator( - final AuthorizationDetailsProviderFactory authorizationDetailsProviderFactory, - final AuthorizationDetailsService authorizationDetailsService) { + final AuthorizationDetailsProcessorFactory authorizationDetailsProcessorFactory, + final AuthorizationDetailsService authorizationDetailsService, + final AuthorizationDetailsSchemaValidator authorizationDetailsSchemaValidator) { - this.authorizationDetailsProviderFactory = authorizationDetailsProviderFactory; + this.authorizationDetailsProcessorFactory = authorizationDetailsProcessorFactory; this.authorizationDetailsService = authorizationDetailsService; + this.authorizationDetailsSchemaValidator = authorizationDetailsSchemaValidator; } /** @@ -83,12 +96,12 @@ public AuthorizationDetails getValidatedAuthorizationDetails(final OAuthAuthzReq throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { try { + return this.getValidatedAuthorizationDetails( oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getConsumerKey(), - OAuth2Util.getTenantId(oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getTenantDomain()), + oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getTenantDomain(), oAuthAuthzReqMessageContext.getAuthorizationReqDTO().getAuthorizationDetails(), - authorizationDetail -> - new AuthorizationDetailsContext(authorizationDetail, oAuthAuthzReqMessageContext) + (detail, type) -> new AuthorizationDetailsContext(detail, type, oAuthAuthzReqMessageContext) ); } catch (IdentityOAuth2Exception e) { log.error("Unable find the tenant ID of the domain: " + @@ -107,29 +120,104 @@ public AuthorizationDetails getValidatedAuthorizationDetails(final OAuthTokenReq final OAuth2AccessTokenReqDTO accessTokenReqDTO = oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO(); - if (GrantType.AUTHORIZATION_CODE.toString().equals(accessTokenReqDTO.getGrantType())) { + if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(accessTokenReqDTO.getAuthorizationDetails())) { if (log.isDebugEnabled()) { - log.debug("Skipping the authorization_details validation for authorization code flow " + - "as this validation has already happened in the authorize flow."); + log.debug("Client application does not request new authorization details. " + + "Returning previously validated authorization details."); } return oAuthTokenReqMessageContext.getAuthorizationDetails(); } - if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(accessTokenReqDTO.getAuthorizationDetails())) { + if (GrantType.AUTHORIZATION_CODE.toString().equals(accessTokenReqDTO.getGrantType())) { if (log.isDebugEnabled()) { - log.debug("Client application does not request new authorization details. " + - "Returning previously validated authorization details."); - + log.debug("Skipping the authorization_details validation for authorization code flow " + + "as this validation has already happened in the authorize flow."); } return oAuthTokenReqMessageContext.getAuthorizationDetails(); } - return this.getValidatedAuthorizationDetails( + final AuthorizationDetails validatedAuthorizationDetails = this.getValidatedAuthorizationDetails( accessTokenReqDTO.getClientId(), - oAuthTokenReqMessageContext.getTenantID(), + accessTokenReqDTO.getTenantDomain(), accessTokenReqDTO.getAuthorizationDetails(), - authorizationDetail -> new AuthorizationDetailsContext(authorizationDetail, oAuthTokenReqMessageContext) + (detail, type) -> new AuthorizationDetailsContext(detail, type, oAuthTokenReqMessageContext) ); + + if (GrantType.REFRESH_TOKEN.toString().equals(accessTokenReqDTO.getGrantType())) { + return new AuthorizationDetails(this.filterConsentedAuthorizationDetails(validatedAuthorizationDetails, + oAuthTokenReqMessageContext.getAuthorizationDetails())); + } + + return validatedAuthorizationDetails; + } + + /** + * Validates whether the user has consented to the requested authorization details. + * + * @param requestedAuthorizationDetails The requested authorization details. + * @param consentedAuthorizationDetails The consented authorization details. + * @throws AuthorizationDetailsProcessingException If validation fails. + */ + private Set filterConsentedAuthorizationDetails( + final AuthorizationDetails requestedAuthorizationDetails, + final AuthorizationDetails consentedAuthorizationDetails) + throws AuthorizationDetailsProcessingException { + + final Set validAuthorizationDetails = new HashSet<>(); + if (AuthorizationDetailsUtils.isEmpty(requestedAuthorizationDetails)) { + log.debug("No authorization details requested. Using all consented authorization details."); + validAuthorizationDetails.addAll(consentedAuthorizationDetails.getDetails()); + return validAuthorizationDetails; + } + + if (AuthorizationDetailsUtils.isEmpty(consentedAuthorizationDetails)) { + log.debug("Invalid request. No consented authorization details found."); + throw new AuthorizationDetailsProcessingException(VALIDATION_FAILED_ERR_MSG); + } + + // Map consented authorization details by type for quick lookup + final Map> consentedAuthorizationDetailsByType = + AuthorizationDetailsUtils.getAuthorizationDetailsTypesMap(consentedAuthorizationDetails); + + for (AuthorizationDetail requestedAuthorizationDetail : requestedAuthorizationDetails.getDetails()) { + + final String requestedType = requestedAuthorizationDetail.getType(); + if (!consentedAuthorizationDetailsByType.containsKey(requestedType)) { + if (log.isDebugEnabled()) { + log.debug("User hasn't consented to the requested authorization details type: " + requestedType); + } + throw new AuthorizationDetailsProcessingException(VALIDATION_FAILED_ERR_MSG); + } + + final Optional optProcessor = + this.authorizationDetailsProcessorFactory.getAuthorizationDetailsProcessorByType(requestedType); + + if (optProcessor.isPresent()) { + if (log.isDebugEnabled()) { + log.debug("Validating equality of requested and existing authorization details using processor: " + + optProcessor.get().getClass().getSimpleName()); + } + final AuthorizationDetails existingAuthorizationDetails = + new AuthorizationDetails(consentedAuthorizationDetailsByType.get(requestedType)); + + // If the requested authorization details match the consented ones, add to the valid set + if (optProcessor.get().isEqualOrSubset(requestedAuthorizationDetail, existingAuthorizationDetails)) { + validAuthorizationDetails.add(requestedAuthorizationDetail); + } else { + if (log.isDebugEnabled()) { + log.debug("User hasn't consented to requested authorization details type: " + requestedType); + } + throw new AuthorizationDetailsProcessingException(VALIDATION_FAILED_ERR_MSG); + } + } else { + // Cannot process, returning all consented authorization details + if (CollectionUtils.isNotEmpty(consentedAuthorizationDetailsByType.get(requestedType))) { + validAuthorizationDetails.addAll(consentedAuthorizationDetailsByType.get(requestedType)); + } + consentedAuthorizationDetailsByType.put(requestedType, Collections.emptySet()); + } + } + return validAuthorizationDetails; } /** @@ -149,9 +237,9 @@ public AuthorizationDetails getValidatedAuthorizationDetails( if (AuthorizationDetailsUtils.isRichAuthorizationRequest(accessTokenAuthorizationDetails)) { final Set authorizedAuthorizationDetails = - this.getAuthorizedAuthorizationDetails( + this.getValidatedAuthorizationDetails( accessTokenDO.getConsumerKey(), - accessTokenDO.getTenantID(), + IdentityTenantUtil.getTenantDomain(accessTokenDO.getTenantID()), accessTokenAuthorizationDetails); return new AuthorizationDetails(authorizedAuthorizationDetails); } @@ -162,59 +250,92 @@ public AuthorizationDetails getValidatedAuthorizationDetails( return new AuthorizationDetails(); } + private Set getValidatedAuthorizationDetails( + final String clientId, final String tenantDomain, final AuthorizationDetails authorizationDetails) + throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { + + return this.getSchemaCompliantAuthorizationDetails(authorizationDetails, + this.getAuthorizedAuthorizationDetailsTypes(clientId, tenantDomain)); + } + /** * Validates the authorization details for OAuthTokenReqMessageContext. * * @param clientId The client ID. - * @param tenantId The tenant ID. + * @param tenantDomain The tenant domain. * @param authorizationDetails The set of authorization details to validate. * @param contextProvider A lambda function to create the AuthorizationDetailsContext. * @return An {@link AuthorizationDetails} object containing the validated authorization details. * @throws AuthorizationDetailsProcessingException if validation fails. */ private AuthorizationDetails getValidatedAuthorizationDetails( - final String clientId, final int tenantId, final AuthorizationDetails authorizationDetails, - final Function contextProvider) + final String clientId, final String tenantDomain, final AuthorizationDetails authorizationDetails, + BiFunction contextProvider) throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { + final Map authorizedDetailsTypes = + this.getAuthorizedAuthorizationDetailsTypes(clientId, tenantDomain); + final Set validatedAuthorizationDetails = new HashSet<>(); for (final AuthorizationDetail authorizationDetail : - this.getAuthorizedAuthorizationDetails(clientId, tenantId, authorizationDetails)) { + this.getSchemaCompliantAuthorizationDetails(authorizationDetails, authorizedDetailsTypes)) { - if (!isSupportedAuthorizationDetailType(authorizationDetail.getType())) { - throw new AuthorizationDetailsProcessingException(String.format(AuthorizationDetailsConstants - .TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT, authorizationDetail.getType())); - } - - if (log.isDebugEnabled()) { - log.debug("Validation started for authorization detail of type: " + authorizationDetail.getType()); - } - - final AuthorizationDetailsContext authorizationDetailsContext = contextProvider.apply(authorizationDetail); + final AuthorizationDetailsContext authorizationDetailsContext = contextProvider + .apply(authorizationDetail, authorizedDetailsTypes.get(authorizationDetail.getType())); if (this.isValidAuthorizationDetail(authorizationDetailsContext)) { - validatedAuthorizationDetails.add(getEnrichedAuthorizationDetail(authorizationDetailsContext)); + validatedAuthorizationDetails.add(this.getEnrichedAuthorizationDetail(authorizationDetailsContext)); } } - return new AuthorizationDetails(validatedAuthorizationDetails); } - private Set getAuthorizedAuthorizationDetails( - final String clientId, final int tenantId, final AuthorizationDetails authorizationDetails) { + /** + * Retrieves the set of authorized authorization types for the given client and tenant domain. + * + * @param clientId The client ID. + * @param tenantDomain The tenant domain. + * @return A set of strings representing the authorized authorization types. + */ + private Map getAuthorizedAuthorizationDetailsTypes(final String clientId, + final String tenantDomain) + throws IdentityOAuth2ServerException { - final Set authorizedAuthorizationDetailsTypes = - this.getAuthorizedAuthorizationDetailsTypes(clientId, tenantId); + try { + final String appId = AuthorizationDetailsUtils.getApplicationResourceIdFromClientId(clientId); + final List authorizationDetailsTypes = OAuth2ServiceComponentHolder.getInstance() + .getAuthorizedAPIManagementService().getAuthorizedAuthorizationDetailsTypes(appId, tenantDomain); - return authorizationDetails.stream() - .filter(authorizationDetail -> - authorizedAuthorizationDetailsTypes.contains(authorizationDetail.getType())) - .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(authorizationDetailsTypes)) { + return Collections.emptyMap(); + } + return authorizationDetailsTypes.stream() + .collect(Collectors.toMap(AuthorizationDetailsType::getType, Function.identity())); + } catch (IdentityOAuth2Exception | IdentityApplicationManagementException e) { + log.error("Unable to retrieve authorized authorization details types. Caused by, ", e); + throw new IdentityOAuth2ServerException("Unable to retrieve authorized authorization details types", e); + } } - private boolean isSupportedAuthorizationDetailType(final String authorizationDetailType) { + private Set getSchemaCompliantAuthorizationDetails( + final AuthorizationDetails authorizationDetails, + final Map authorizedDetailsTypes) + throws AuthorizationDetailsProcessingException { + + final Set schemaCompliantAuthorizationDetails = new HashSet<>(); + for (final AuthorizationDetail authorizationDetail : authorizationDetails.getDetails()) { + + if (log.isDebugEnabled()) { + log.debug("Schema validation started for authorization details type: " + authorizationDetail.getType()); + } + + this.assertAuthorizationDetailTypeSupported(authorizationDetail.getType()); - return this.authorizationDetailsProviderFactory.isSupportedAuthorizationDetailsType(authorizationDetailType); + if (this.isSchemaCompliant(authorizationDetail.getType(), authorizationDetail, authorizedDetailsTypes)) { + schemaCompliantAuthorizationDetails.add(authorizationDetail); + } + } + return schemaCompliantAuthorizationDetails; } /** @@ -226,23 +347,26 @@ private boolean isSupportedAuthorizationDetailType(final String authorizationDet private boolean isValidAuthorizationDetail(final AuthorizationDetailsContext authorizationDetailsContext) throws AuthorizationDetailsProcessingException, IdentityOAuth2ServerException { - Optional optionalProvider = this.authorizationDetailsProviderFactory - .getProviderByType(authorizationDetailsContext.getAuthorizationDetail().getType()); + final String type = authorizationDetailsContext.getAuthorizationDetail().getType(); + final Optional optProcessor = + this.authorizationDetailsProcessorFactory.getAuthorizationDetailsProcessorByType(type); - if (optionalProvider.isPresent()) { - - final ValidationResult validationResult = optionalProvider.get().validate(authorizationDetailsContext); - if (log.isDebugEnabled() && validationResult.isInvalid()) { - - log.debug(String.format("Authorization details validation failed for type %s. Caused by, %s", - authorizationDetailsContext.getAuthorizationDetail().getType(), validationResult.getReason())); + if (optProcessor.isPresent()) { + final ValidationResult validationResult = optProcessor.get().validate(authorizationDetailsContext); + if (validationResult.isInvalid()) { + if (log.isDebugEnabled()) { + log.debug(String.format("Authorization details validation failed for type: %s. Caused by, %s", + type, validationResult.getReason())); + } + return false; + } + } else { + if (log.isDebugEnabled()) { + log.debug("An authorization details processor implementation is not found for type: " + type); } - return validationResult.isValid(); } - throw new AuthorizationDetailsProcessingException(String.format( - AuthorizationDetailsConstants.TYPE_NOT_SUPPORTED_ERR_MSG_FORMAT, - authorizationDetailsContext.getAuthorizationDetail().getType())); + return true; } /** @@ -254,35 +378,40 @@ private boolean isValidAuthorizationDetail(final AuthorizationDetailsContext aut private AuthorizationDetail getEnrichedAuthorizationDetail( final AuthorizationDetailsContext authorizationDetailsContext) { - return this.authorizationDetailsProviderFactory - .getProviderByType(authorizationDetailsContext.getAuthorizationDetail().getType()) + return this.authorizationDetailsProcessorFactory + .getAuthorizationDetailsProcessorByType(authorizationDetailsContext.getAuthorizationDetail().getType()) .map(authorizationDetailsProcessor -> authorizationDetailsProcessor.enrich(authorizationDetailsContext)) // If provider is missing, return the original authorization detail instance .orElse(authorizationDetailsContext.getAuthorizationDetail()); } - /** - * Retrieves the set of authorized authorization types for the given client and tenant domain. - * - * @param clientId The client ID. - * @param tenantId The tenant ID. - * @return A set of strings representing the authorized authorization types. - */ - private Set getAuthorizedAuthorizationDetailsTypes(final String clientId, final int tenantId) { - -// try { -// final String appId = OAuth2Util -// .getApplicationResourceIDByClientId(clientID, tenantDomain, this.applicationMgtService); -// -//// OAuth2ServiceComponentHolder.getInstance().getAuthorizedAPIManagementService() -// .getAuthorizedAuthorizationDetailsTypes(appId, tenantDomain); -// } catch (IdentityOAuth2Exception e) { -// throw new RuntimeException(e); -// } - Set authorizedAuthorizationDetailsTypes = new HashSet<>(); - authorizedAuthorizationDetailsTypes.add("payment_initiation"); - return authorizedAuthorizationDetailsTypes; + private void assertAuthorizationDetailTypeSupported(final String type) + throws AuthorizationDetailsProcessingException { + + if (!this.authorizationDetailsProcessorFactory.isSupportedAuthorizationDetailsType(type)) { + throw new AuthorizationDetailsProcessingException(String.format(TYPE_NOT_SUPPORTED_ERR_FORMAT, type)); + } } + private boolean isSchemaCompliant(final String type, final AuthorizationDetail authorizationDetail, + final Map authorizedDetailsTypes) + throws AuthorizationDetailsProcessingException { + + if (!authorizedDetailsTypes.containsKey(type)) { + if (log.isDebugEnabled()) { + log.debug("Ignoring unauthorized authorization details type: " + type); + } + return false; + } + if (this.authorizationDetailsSchemaValidator + .isSchemaCompliant(authorizedDetailsTypes.get(type).getSchema(), authorizationDetail)) { + return true; + } + + if (log.isDebugEnabled()) { + log.debug("Ignoring non-schema-compliant authorization details type: " + type); + } + return false; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java index 323160f2c4..9321ba42a0 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java @@ -1240,18 +1240,41 @@ private boolean isFederatedUser(OAuthTokenReqMessageContext tokReqMsgCtx) { return tokReqMsgCtx.getAuthorizedUser().isFederatedUser(); } + /** + * Sets the Rich Authorization Requests (RAR) properties for token generation. + * It retrieves the user-consented authorization details or fallback to code authorization details + * based on the provided OAuth token request context. + * + * @param oAuthTokenReqMessageContext Context of the OAuth token request message. + * @throws IdentityOAuth2Exception If an error occurs while retrieving authorization details. + */ protected void setRARPropertiesForTokenGeneration(final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) throws IdentityOAuth2Exception { - final int tenantId = OAuth2Util - .getTenantId(oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getTenantDomain()); + final int tenantId = + OAuth2Util.getTenantId(oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getTenantDomain()); + + if (log.isDebugEnabled()) { + log.debug("Retrieving user consented authorization details for user: " + + oAuthTokenReqMessageContext.getAuthorizedUser().getLoggableMaskedUserId()); + } - final AuthorizationDetails userConsentedAuthorizationDetails = - this.authorizationDetailsService.getUserConsentedAuthorizationDetails( + AuthorizationDetails authorizationDetails = this.authorizationDetailsService + .getUserConsentedAuthorizationDetails( oAuthTokenReqMessageContext.getAuthorizedUser(), oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getClientId(), tenantId); - oAuthTokenReqMessageContext.setAuthorizationDetails(userConsentedAuthorizationDetails); + // Fallback to code authorization details if user consent is unavailable + if (authorizationDetails == null) { + if (log.isDebugEnabled()) { + log.debug("No user consent is available. Fetching authorization details for code: " + + oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getAuthorizationCode()); + } + + authorizationDetails = this.authorizationDetailsService.getAuthorizationCodeAuthorizationDetails( + oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getAuthorizationCode(), tenantId); + } + oAuthTokenReqMessageContext.setAuthorizationDetails(authorizationDetails); } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java index 4c72935ff5..143ee3fb9a 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java @@ -11,20 +11,26 @@ import org.wso2.carbon.identity.application.common.model.ServiceProvider; import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; import org.wso2.carbon.identity.oauth2.rar.dao.AuthorizationDetailsDAO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; +import org.wso2.carbon.identity.oauth2.rar.model.ValidationResult; import org.wso2.carbon.identity.oauth2.rar.utils.AuthorizationDetailsBaseTest; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import java.sql.SQLException; import java.util.Collections; +import java.util.Optional; import java.util.Set; import java.util.stream.Stream; @@ -32,12 +38,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.testng.Assert.assertNull; import static org.wso2.carbon.identity.oauth2.TestConstants.ACESS_TOKEN_ID; import static org.wso2.carbon.identity.oauth2.TestConstants.CLIENT_ID; import static org.wso2.carbon.identity.oauth2.TestConstants.TENANT_DOMAIN; @@ -78,7 +86,8 @@ public void tearDown() { } @BeforeMethod() - public void setUpMethod() throws SQLException { + public void setUpMethod() + throws SQLException, IdentityOAuth2ServerException, AuthorizationDetailsProcessingException { this.authorizationDetailsDAOMock = Mockito.mock(AuthorizationDetailsDAO.class); when(this.authorizationDetailsDAOMock.getConsentIdByUserIdAndAppId(TEST_USER_ID, TEST_APP_ID, TENANT_ID)) @@ -92,13 +101,23 @@ public void setUpMethod() throws SQLException { .thenReturn(Collections.singleton(new AuthorizationDetailsTokenDTO(ACESS_TOKEN_ID, this.authorizationDetail, TENANT_ID))); - uut = new AuthorizationDetailsService(this.providerFactoryMock, this.authorizationDetailsDAOMock); + AuthorizationDetailsProcessor processor = Mockito.mock(AuthorizationDetailsProcessor.class); + when(processor.isEqualOrSubset(any(AuthorizationDetail.class), any(AuthorizationDetails.class))) + .thenReturn(true); + when(processor.enrich(any(AuthorizationDetailsContext.class))).thenReturn(this.authorizationDetail); + when(processor.getType()).thenReturn(TEST_TYPE); + when(processor.validate(any(AuthorizationDetailsContext.class))).thenReturn(ValidationResult.valid()); + + when(this.processorFactoryMock.getAuthorizationDetailsProcessorByType(TEST_TYPE)) + .thenReturn(Optional.of(processor)); + + uut = new AuthorizationDetailsService(this.processorFactoryMock, this.authorizationDetailsDAOMock); } @BeforeMethod(onlyForGroups = {"error-flow-tests"}, dependsOnMethods = {"setUpMethod"}) public void setUpErrorMethod() throws SQLException { - when(this.authorizationDetailsDAOMock.addUserConsentedAuthorizationDetails(anyList())) + when(this.authorizationDetailsDAOMock.addUserConsentedAuthorizationDetails(anySet())) .thenThrow(SQLException.class); when(this.authorizationDetailsDAOMock.deleteUserConsentedAuthorizationDetails(anyString(), anyInt())) .thenThrow(SQLException.class); @@ -106,12 +125,12 @@ public void setUpErrorMethod() throws SQLException { .thenThrow(SQLException.class); when(this.authorizationDetailsDAOMock.getAccessTokenAuthorizationDetails(anyString(), anyInt())) .thenThrow(SQLException.class); - when(this.authorizationDetailsDAOMock.addAccessTokenAuthorizationDetails(anyList())) + when(this.authorizationDetailsDAOMock.addAccessTokenAuthorizationDetails(anySet())) .thenThrow(SQLException.class); when(this.authorizationDetailsDAOMock.deleteAccessTokenAuthorizationDetails(anyString(), anyInt())) .thenThrow(SQLException.class); - uut = new AuthorizationDetailsService(this.providerFactoryMock, this.authorizationDetailsDAOMock); + uut = new AuthorizationDetailsService(this.processorFactoryMock, this.authorizationDetailsDAOMock); } @Test @@ -121,7 +140,7 @@ public void shouldNotAddUserConsentedAuthorizationDetails_ifNotRichAuthorization uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, new OAuth2Parameters(), authorizationDetails); - verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anySet()); } @Test @@ -134,7 +153,7 @@ public void shouldNotAddUserConsentedAuthorizationDetails_whenConsentIsNotFound( uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters, authorizationDetails); - verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anySet()); } @Test @@ -144,7 +163,7 @@ public void shouldAddUserConsentedAuthorizationDetails_ifRichAuthorizationReques uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters, authorizationDetails); - verify(authorizationDetailsDAOMock, times(1)).addUserConsentedAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(1)).addUserConsentedAuthorizationDetails(anySet()); } @Test @@ -186,7 +205,7 @@ public void shouldReplaceUserConsentedAuthorizationDetails_ifRichAuthorizationRe verify(authorizationDetailsDAOMock, times(1)) .deleteUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TENANT_ID); - verify(authorizationDetailsDAOMock, times(1)).addUserConsentedAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(1)).addUserConsentedAuthorizationDetails(anySet()); } @Test @@ -202,13 +221,12 @@ public void shouldReturnFalse_ifAuthorizationDetailsAlreadyConsented() throws Id } @Test - public void shouldReturnEmptyAuthorizationDetails_whenConsentIsInvalid() throws IdentityOAuth2Exception { + public void shouldReturnNull_whenConsentIsInvalid() throws IdentityOAuth2Exception { AuthenticatedUser invalidUser = new AuthenticatedUser(); invalidUser.setUserId("invalid-user-id"); - assertTrue(uut.getUserConsentedAuthorizationDetails(invalidUser, CLIENT_ID, TENANT_ID) - .getDetails().isEmpty()); + assertNull(uut.getUserConsentedAuthorizationDetails(invalidUser, CLIENT_ID, TENANT_ID)); } @Test @@ -249,7 +267,7 @@ public void shouldNotAddAccessTokenAuthorizationDetails_ifNotRichAuthorizationRe uut.storeAccessTokenAuthorizationDetails(accessTokenDO, new OAuthAuthzReqMessageContext(null)); - verify(authorizationDetailsDAOMock, times(0)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(0)).addAccessTokenAuthorizationDetails(anySet()); } @Test @@ -261,7 +279,7 @@ public void shouldAddAccessTokenAuthorizationDetails_ifRichAuthorizationRequest( uut.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthAuthzReqMessageContext); - verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anySet()); } @Test @@ -271,7 +289,7 @@ public void shouldNotReplaceAccessTokenAuthorizationDetails_ifNotRichAuthorizati uut.storeOrReplaceAccessTokenAuthorizationDetails(accessTokenDO, accessTokenDO, new OAuthTokenReqMessageContext(new OAuth2AccessTokenReqDTO())); - verify(authorizationDetailsDAOMock, times(0)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(0)).addAccessTokenAuthorizationDetails(anySet()); verify(authorizationDetailsDAOMock, times(0)).deleteAccessTokenAuthorizationDetails(anyString(), anyInt()); } @@ -284,7 +302,7 @@ public void shouldNotDeleteAccessTokenAuthorizationDetails_whenOldAccessTokenIsM uut.storeOrReplaceAccessTokenAuthorizationDetails(accessTokenDO, null, messageContext); - verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anySet()); verify(authorizationDetailsDAOMock, times(0)).deleteAccessTokenAuthorizationDetails(anyString(), anyInt()); } @@ -297,7 +315,7 @@ public void shouldReplaceAccessTokenAuthorizationDetails_whenOldAccessTokenIsPre uut.storeOrReplaceAccessTokenAuthorizationDetails(accessTokenDO, accessTokenDO, messageContext); - verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anySet()); verify(authorizationDetailsDAOMock, times(1)).deleteAccessTokenAuthorizationDetails(anyString(), anyInt()); } @@ -313,7 +331,7 @@ public void shouldReplaceAccessTokenAuthorizationDetails_ifRichAuthorizationRequ verify(authorizationDetailsDAOMock, times(1)) .deleteAccessTokenAuthorizationDetails(oldAccessTokenId, TENANT_ID); - verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anyList()); + verify(authorizationDetailsDAOMock, times(1)).addAccessTokenAuthorizationDetails(anySet()); } @Test diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java index c5bcda4332..ec9f84b1d0 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java @@ -10,6 +10,7 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.rar.utils.AuthorizationDetailsBaseTest; import org.wso2.carbon.identity.oauth2.rar.validator.AuthorizationDetailsValidator; @@ -36,7 +37,7 @@ public class IntrospectionRARDataProviderTest extends AuthorizationDetailsBaseTe private IntrospectionRARDataProvider uut; @BeforeClass - public void setUpClass() throws IdentityOAuth2Exception { + public void setUpClass() throws IdentityOAuth2Exception, AuthorizationDetailsProcessingException { this.validatorMock = Mockito.mock(AuthorizationDetailsValidator.class); when(validatorMock.getValidatedAuthorizationDetails(any(OAuth2TokenValidationMessageContext.class))) @@ -55,7 +56,7 @@ public void setUpClass() throws IdentityOAuth2Exception { @Test(priority = 1) public void shouldNotReturnAuthorizationDetails_ifNotRichAuthorizationRequest() - throws IdentityOAuth2Exception { + throws IdentityOAuth2Exception, AuthorizationDetailsProcessingException { when(validatorMock.getValidatedAuthorizationDetails(any(OAuth2TokenValidationMessageContext.class))) .thenReturn(new AuthorizationDetails()); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java index 5108f23f0a..7159bda1be 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java @@ -8,9 +8,10 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsSchemaValidator; import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; -import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProviderFactory; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessorFactory; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants; @@ -49,9 +50,11 @@ public class AuthorizationDetailsBaseTest { protected AccessTokenDO accessTokenDO; protected OAuth2AccessTokenReqDTO accessTokenReqDTO; - protected AuthorizationDetailsProviderFactory providerFactoryMock; + protected AuthorizationDetailsProcessorFactory processorFactoryMock; protected AuthorizationDetailsService serviceMock; + protected AuthorizationDetailsSchemaValidator schemaValidatorMock; + public AuthorizationDetailsBaseTest() { this.authorizationDetail = new AuthorizationDetail(); @@ -95,6 +98,8 @@ public AuthorizationDetailsBaseTest() { mockAuthorizationDetailsProviderFactory(); this.serviceMock = mock(AuthorizationDetailsService.class); + + this.schemaValidatorMock = spy(AuthorizationDetailsSchemaValidator.class); } public static void assertAuthorizationDetailsPresent(final Map attributes) { @@ -111,13 +116,13 @@ public static void assertAuthorizationDetailsMissing(final Map a private void mockAuthorizationDetailsProviderFactory() { - this.providerFactoryMock = spy(AuthorizationDetailsProviderFactory.class); + this.processorFactoryMock = spy(AuthorizationDetailsProcessorFactory.class); try { - Field privateField = AuthorizationDetailsProviderFactory.class - .getDeclaredField("supportedAuthorizationDetailsTypes"); + Field privateField = AuthorizationDetailsProcessorFactory.class + .getDeclaredField("authorizationDetailsProcessors"); privateField.setAccessible(true); - privateField.set(this.providerFactoryMock, new HashMap() {{ + privateField.set(this.processorFactoryMock, new HashMap() {{ put(TEST_TYPE, getAuthorizationDetailsProcessorMock()); }}); } catch (Exception e) { diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java index 6b14dc1bf7..2849f2976b 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java @@ -24,7 +24,7 @@ public void setUp() throws IdentityOAuth2Exception { when(serviceMock.getAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID)) .thenReturn(authorizationDetails); - this.uut = new DefaultAuthorizationDetailsValidator(providerFactoryMock, serviceMock); + this.uut = new DefaultAuthorizationDetailsValidator(processorFactoryMock, serviceMock, schemaValidatorMock); } @Test diff --git a/pom.xml b/pom.xml index e8930fc7c1..fad419f78c 100644 --- a/pom.xml +++ b/pom.xml @@ -413,6 +413,12 @@ auto-service ${com.google.auto.service.version} + + + io.vertx + vertx-json-schema + ${vertx.json.schema.version} + @@ -561,6 +567,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.oauth.rar + provided ${project.version} @@ -1011,6 +1018,7 @@ 5.2 9.2 1.1.1 + 4.5.10 5.1.2 From c3c9fe9d7ae63309b8a082082b366de6a788eef6 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Wed, 9 Oct 2024 10:08:00 +0530 Subject: [PATCH 06/28] Add unit tests to discovery endpoint --- .../builders/ProviderConfigBuilderTest.java | 27 +++++++++------- .../pom.xml | 31 +++---------------- .../dao/AuthorizationDetailsDAOImplTest.java | 3 ++ .../AuthorizationDetailsCommonUtilsTest.java | 1 - .../org.wso2.carbon.identity.oauth/pom.xml | 2 ++ .../rar/util/AuthorizationDetailsUtils.java | 3 +- pom.xml | 2 +- 7 files changed, 26 insertions(+), 43 deletions(-) diff --git a/components/org.wso2.carbon.identity.discovery/src/test/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilderTest.java b/components/org.wso2.carbon.identity.discovery/src/test/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilderTest.java index c4aa460249..f5f14813a8 100644 --- a/components/org.wso2.carbon.identity.discovery/src/test/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilderTest.java +++ b/components/org.wso2.carbon.identity.discovery/src/test/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilderTest.java @@ -42,11 +42,12 @@ import java.net.URISyntaxException; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Collections; import java.util.List; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.spy; @@ -69,9 +70,6 @@ public class ProviderConfigBuilderTest { @Mock private OIDProviderRequest mockOidProviderRequest; -// -// @Mock -// private AuthorizationDetailsProcessorFactory mockAuthorizationDetailsProcessorFactory; @BeforeMethod public void setUp() throws Exception { @@ -90,7 +88,7 @@ public void testBuildOIDProviderConfig() throws Exception { oAuthServerConfiguration.when( OAuthServerConfiguration::getInstance).thenReturn(mockOAuthServerConfiguration); try (MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); - MockedStatic factoryMock = + MockedStatic factoryMockedStatic = mockStatic(AuthorizationDetailsProcessorFactory.class)) { OIDCDiscoveryDataHolder mockOidcDiscoveryDataHolder = spy(new OIDCDiscoveryDataHolder()); @@ -115,12 +113,10 @@ public void testBuildOIDProviderConfig() throws Exception { when(mockOidProviderRequest.getTenantDomain()).thenReturn( MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); - AuthorizationDetailsProcessorFactory processorFactoryMock = - spy(AuthorizationDetailsProcessorFactory.class); - when(processorFactoryMock.getSupportedAuthorizationDetailTypes()).thenReturn(new HashSet() {{ - add("test_type"); - }}); - factoryMock.when(AuthorizationDetailsProcessorFactory::getInstance).thenReturn(processorFactoryMock); + AuthorizationDetailsProcessorFactory factoryMock = spy(AuthorizationDetailsProcessorFactory.class); + doReturn(Collections.emptySet()).when(factoryMock).getSupportedAuthorizationDetailTypes(); + factoryMockedStatic.when(AuthorizationDetailsProcessorFactory::getInstance).thenReturn(factoryMock); + assertNotNull(providerConfigBuilder.buildOIDProviderConfig(mockOidProviderRequest)); } } @@ -208,7 +204,9 @@ public void testBuildOIDProviderConfig4() throws Exception { MockedStatic oidcDiscoveryDataHolder = mockStatic(OIDCDiscoveryDataHolder.class); MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); - MockedStatic discoveryUtil = mockStatic(DiscoveryUtil.class);) { + MockedStatic discoveryUtil = mockStatic(DiscoveryUtil.class); + MockedStatic factoryMockedStatic = + mockStatic(AuthorizationDetailsProcessorFactory.class)) { OAuthServerConfiguration mockOAuthServerConfiguration = mock(OAuthServerConfiguration.class); oAuthServerConfiguration.when( OAuthServerConfiguration::getInstance).thenReturn(mockOAuthServerConfiguration); @@ -237,9 +235,14 @@ public void testBuildOIDProviderConfig4() throws Exception { when(mockOidProviderRequest.getTenantDomain()).thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); when(mockOAuthServerConfiguration.getUserInfoJWTSignatureAlgorithm()).thenReturn(idTokenSignatureAlgorithm); + AuthorizationDetailsProcessorFactory factoryMock = spy(AuthorizationDetailsProcessorFactory.class); + doReturn(Collections.singleton("test_type")).when(factoryMock).getSupportedAuthorizationDetailTypes(); + factoryMockedStatic.when(AuthorizationDetailsProcessorFactory::getInstance).thenReturn(factoryMock); + OIDProviderConfigResponse response = providerConfigBuilder.buildOIDProviderConfig(mockOidProviderRequest); assertNotNull(response); assertEquals(response.getIssuer(), dummyIdIssuer); + assertEquals(response.getAuthorizationDetailsTypesSupported()[0], "test_type"); } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index f9e8deb6bf..ab38e1b73d 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -24,7 +24,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.150-SNAPSHOT + 7.0.162-SNAPSHOT 4.0.0 @@ -85,13 +85,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - - com.github.spotbugs @@ -105,6 +98,7 @@ org.apache.maven.plugins maven-surefire-plugin + ${maven.surefire.plugin.version} src/test/resources/testng.xml @@ -119,6 +113,7 @@ org.jacoco jacoco-maven-plugin + ${jacoco.version} @@ -135,31 +130,13 @@ prepare-agent - - default-instrument - - instrument - - - - default-restore-instrumented-classes - - restore-instrumented-classes - - default-report - prepare-package + verify report - - default-report-integration - - report-integration - - default-check diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java index cc35612769..fb27e90a4c 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java @@ -49,6 +49,9 @@ import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TOKEN_ID; import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TYPE; +/** + * Test class for {@link AuthorizationDetailsDAO}. + */ public class AuthorizationDetailsDAOImplTest { private MockedStatic identityDatabaseUtilMock; diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java index d556e4e9e2..238be9a7b7 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java @@ -57,7 +57,6 @@ public void setUp() throws JsonProcessingException { this.objectMapper = AuthorizationDetailsCommonUtils.getDefaultObjectMapper(); this.mockObjectMapper = Mockito.spy(this.objectMapper); - // mock doThrow(JsonProcessingException.class) .when(this.mockObjectMapper).writeValueAsString(any(TestDAOUtils.TestAuthorizationDetail.class)); doThrow(JsonProcessingException.class).when(this.mockObjectMapper).writeValueAsString(any(Set.class)); diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 64f746df3b..dd724b1977 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -265,6 +265,8 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.oauth.rar + compile + 7.0.162-SNAPSHOT diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java index 634da17875..ef32dcc622 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java @@ -21,7 +21,6 @@ import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; -import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetailsContext; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; @@ -413,4 +412,4 @@ public static Map> getAuthorizationDetailsTypes : authorizationDetails.stream() .collect(groupingBy(AuthorizationDetail::getType, mapping(identity(), toSet()))); } -} \ No newline at end of file +} diff --git a/pom.xml b/pom.xml index 71930900b1..e70893ea39 100644 --- a/pom.xml +++ b/pom.xml @@ -950,7 +950,7 @@ [1.0.1, 2.0.0) - 7.3.62 + 7.3.75-SNAPSHOT [5.25.234, 8.0.0) From 7e5ac327fbda3bf85e82518381964f721da0f371 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 25 Oct 2024 17:00:25 +0530 Subject: [PATCH 07/28] Change schema type to CLOB --- .../AuthorizationDetailsSchemaValidator.java | 61 ++++++++++++------- .../rar/dao/AuthorizationDetailsDAOImpl.java | 5 +- .../identity/oauth2/rar/dao/SQLQueries.java | 22 +++---- .../rar/dto/AuthorizationDetailsDTO.java | 36 ++++++++--- .../oauth2/rar/model/AuthorizationDetail.java | 36 ++++++----- .../rar/model/AuthorizationDetails.java | 10 +-- .../util/AuthorizationDetailsCommonUtils.java | 40 +++++------- ...thorizationDetailsSchemaValidatorTest.java | 33 ++++++++++ .../dao/AuthorizationDetailsDAOImplTest.java | 4 +- .../AuthorizationDetailsCommonUtilsTest.java | 48 ++++----------- .../src/test/resources/dbScripts/h2.sql | 10 +-- .../rar/util/AuthorizationDetailsUtils.java | 20 ++---- .../DefaultAuthorizationDetailsValidator.java | 8 +-- 13 files changed, 171 insertions(+), 162 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidator.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidator.java index b476f62030..904cc76fe2 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidator.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidator.java @@ -30,12 +30,15 @@ import io.vertx.json.schema.SchemaRepository; import io.vertx.json.schema.Validator; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import java.util.Map; + import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.SCHEMA_VALIDATION_FAILED_ERR_MSG_FORMAT; import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.TYPE_VALIDATION_FAILED_ERR_MSG_FORMAT; import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.VALIDATION_FAILED_ERR_MSG; @@ -107,13 +110,15 @@ public boolean isValidSchema(final String schema) throws AuthorizationDetailsPro return false; } - final OutputUnit outputUnit = this.buildOutputUnit(null, this.parseJsonString(schema)); + final OutputUnit outputUnit = this.buildOutputUnit(null, this.parseJsonObject(schema)); try { // Validates the schema itself against the DRAFT202012 schema standard outputUnit.checkValidity(); } catch (JsonSchemaValidationException e) { - logDebugIfEnabled(String.format("Validation failed against DRAFT202012 schema for input: %s. Caused by, ", - schema), e); + if (log.isDebugEnabled()) { + log.debug(String.format("Validation failed against DRAFT202012 schema for input: %s. Caused by, ", + schema), e); + } throw new AuthorizationDetailsProcessingException(String.format(SCHEMA_VALIDATION_FAILED_ERR_MSG_FORMAT, buildSchemaValidationErrorMessage(outputUnit, e)), e); } @@ -137,14 +142,16 @@ private OutputUnit buildOutputUnit(final JsonObject jsonSchema, final JsonObject * @return A {@link JsonObject} created from the input string. * @throws AuthorizationDetailsProcessingException if the input string is not valid JSON. */ - private JsonObject parseJsonString(final String jsonString) throws AuthorizationDetailsProcessingException { + private JsonObject parseJsonObject(final String jsonString) throws AuthorizationDetailsProcessingException { try { return new JsonObject(jsonString); } catch (DecodeException e) { - this.logDebugIfEnabled(String.format("Failed to parse the JSON input: '%s'. Caused by, ", jsonString), e); + if (log.isDebugEnabled()) { + log.debug(String.format("Failed to parse the JSON input: '%s'. Caused by, ", jsonString), e); + } throw new AuthorizationDetailsProcessingException( - String.format("%s. Invalid Json input received.", VALIDATION_FAILED_ERR_MSG), e); + String.format("%s. Invalid JSON input received.", VALIDATION_FAILED_ERR_MSG), e); } } @@ -175,33 +182,45 @@ public boolean isSchemaCompliant(final String schema, final AuthorizationDetail return false; } - final JsonObject jsonSchema = this.parseJsonString(schema); - jsonSchema.put(ADDITIONAL_PROPERTIES, false); // Ensure no unknown fields are allowed + return this.isSchemaCompliant(this.parseJsonObject(schema), authorizationDetail); + } + + public boolean isSchemaCompliant(final JsonObject schema, final AuthorizationDetail authorizationDetail) + throws AuthorizationDetailsProcessingException { + + if (schema == null || authorizationDetail == null) { + log.debug("Schema validation failed. Inputs cannot be null"); + return false; + } final OutputUnit outputUnit = - this.buildOutputUnit(jsonSchema, this.parseJsonString(authorizationDetail.toJsonString())); + this.buildOutputUnit(schema, this.parseJsonObject(authorizationDetail.toJsonString())); + try { // Validates the authorization detail against the schema outputUnit.checkValidity(); } catch (JsonSchemaValidationException e) { - logDebugIfEnabled(String.format("Schema validation failed for authorization details type: %s. Caused by, ", - authorizationDetail.getType()), e); + if (log.isDebugEnabled()) { + log.debug(String.format("Schema validation failed for authorization details type: %s. Caused by, ", + authorizationDetail.getType()), e); + } throw new AuthorizationDetailsProcessingException(String.format(TYPE_VALIDATION_FAILED_ERR_MSG_FORMAT, - authorizationDetail.getType(), buildSchemaValidationErrorMessage(outputUnit, e)), e); + authorizationDetail.getType(), this.buildSchemaValidationErrorMessage(outputUnit, e)), e); } return true; } - /** - * Logs a debug message along with the exception if debug logging is enabled. - * - * @param message The debug message to log. - * @param ex The exception to log along with the message. - */ - private void logDebugIfEnabled(final String message, final Exception ex) { + public boolean isSchemaCompliant(final Map schema, final AuthorizationDetail authorizationDetail) + throws AuthorizationDetailsProcessingException { - if (log.isDebugEnabled()) { - log.debug(message, ex); + if (MapUtils.isEmpty(schema) || authorizationDetail == null) { + log.debug("Schema validation failed. Inputs cannot be null"); + return false; } + + final JsonObject jsonSchema = new JsonObject(schema); + jsonSchema.put(ADDITIONAL_PROPERTIES, false); // Ensure no unknown fields are allowed + + return this.isSchemaCompliant(jsonSchema, authorizationDetail); } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java index a50f8d5f2c..fc9682292e 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java @@ -46,9 +46,8 @@ public int[] addUserConsentedAuthorizationDetails( final Set authorizationDetailsConsentDTOs) throws SQLException { try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); - PreparedStatement ps = connection.getMetaData().getDatabaseProductName().contains("H2") - ? connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS_H2) - : connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { + PreparedStatement ps = + connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) { ps.setString(1, consentDTO.getConsentId()); diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java index cc03a89d62..3582c3babf 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java @@ -28,17 +28,13 @@ private SQLQueries() { // Private constructor to prevent instantiation } - public static final String ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = - "INSERT INTO IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + - "(CONSENT_ID, AUTHORIZATION_DETAILS, CONSENT, TYPE_ID, TENANT_ID) " + - "VALUES (?, ?, ?," + - "(SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; + private static final String SELECT_AUTHORIZATION_DETAILS_ID_BY_TYPE = + "SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE = ? AND TENANT_ID = ?"; - public static final String ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS_H2 = + public static final String ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = "INSERT INTO IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + "(CONSENT_ID, AUTHORIZATION_DETAILS, CONSENT, TYPE_ID, TENANT_ID) " + - "VALUES (?, ? FORMAT JSON, ?," + - "(SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; + "VALUES (?, ?, ?, (" + SELECT_AUTHORIZATION_DETAILS_ID_BY_TYPE + "), ?)"; public static final String GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS = "SELECT ID, TYPE_ID, AUTHORIZATION_DETAILS, CONSENT FROM IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " + @@ -50,8 +46,7 @@ private SQLQueries() { public static final String ADD_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS = "INSERT INTO IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS " + "(TOKEN_ID, AUTHORIZATION_DETAILS, TYPE_ID, TENANT_ID) " + - "VALUES (?, ? FORMAT JSON, " + - "(SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; + "VALUES (?, ?, (" + SELECT_AUTHORIZATION_DETAILS_ID_BY_TYPE + "), ?)"; public static final String DELETE_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS = "DELETE FROM IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS WHERE TOKEN_ID=? AND TENANT_ID=?"; @@ -63,14 +58,13 @@ private SQLQueries() { public static final String ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS = "INSERT INTO IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS" + "(CODE_ID, AUTHORIZATION_DETAILS, TYPE_ID, TENANT_ID) " + - "VALUES (?, ? FORMAT JSON, " + - "(SELECT ID FROM AUTHORIZATION_DETAILS_TYPES WHERE TYPE=? AND TENANT_ID=?), ?)"; + "VALUES (?, ?, (" + SELECT_AUTHORIZATION_DETAILS_ID_BY_TYPE + "), ?)"; public static final String GET_OAUTH2_CODE_AUTHORIZATION_DETAILS_BY_CODE = "SELECT IOAC.CODE_ID, IOACAD.TYPE_ID, IOACAD.AUTHORIZATION_DETAILS " + - "FROM IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS IOACAD " + + "FROM IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS IOACAD " + "INNER JOIN IDN_OAUTH2_AUTHORIZATION_CODE IOAC ON IOACAD.CODE_ID = IOAC.CODE_ID " + - "WHERE IOAC.AUTHORIZATION_CODE=? AND IOACAD.TENANT_ID=?"; + "WHERE IOAC.AUTHORIZATION_CODE=? AND IOACAD.TENANT_ID=?"; public static final String GET_IDN_OAUTH2_USER_CONSENT_CONSENT_ID = "SELECT CONSENT_ID FROM IDN_OAUTH2_USER_CONSENT WHERE USER_ID=? AND APP_ID=? AND TENANT_ID=?"; diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java index 00b705d29e..77b711d377 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dto/AuthorizationDetailsDTO.java @@ -1,9 +1,26 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar.dto; import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; -import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils; -import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils.getDefaultObjectMapper; +import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils.fromJSON; /** * Data Transfer Object (DTO) for representing authorization details. @@ -20,10 +37,10 @@ public class AuthorizationDetailsDTO { /** * Constructs an AuthorizationDetailsDTO with all fields. * - * @param id the ID of the authorization detail DTO. - * @param typeId the type ID of the authorization detail. + * @param id the ID of the authorization detail DTO. + * @param typeId the type ID of the authorization detail. * @param authorizationDetail the authorization detail object. - * @param tenantId the tenant ID. + * @param tenantId the tenant ID. */ public AuthorizationDetailsDTO(final String id, final String typeId, final AuthorizationDetail authorizationDetail, final int tenantId) { @@ -37,16 +54,15 @@ public AuthorizationDetailsDTO(final String id, final String typeId, final Autho /** * Constructs an AuthorizationDetailsDTO from authorization detail JSON string. * - * @param id the ID of the authorization detail DTO. - * @param typeId the type ID of the authorization detail. + * @param id the ID of the authorization detail DTO. + * @param typeId the type ID of the authorization detail. * @param authorizationDetailJson the JSON string of the authorization detail. - * @param tenantId the tenant ID. + * @param tenantId the tenant ID. */ public AuthorizationDetailsDTO(final String id, final String typeId, final String authorizationDetailJson, final int tenantId) { - this(id, typeId, AuthorizationDetailsCommonUtils - .fromJSON(authorizationDetailJson, AuthorizationDetail.class, getDefaultObjectMapper()), tenantId); + this(id, typeId, fromJSON(authorizationDetailJson, AuthorizationDetail.class), tenantId); } /** diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetail.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetail.java index 9d3c87af10..f86599976b 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetail.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetail.java @@ -31,8 +31,6 @@ import java.util.Map; import java.util.function.Function; -import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils.getDefaultObjectMapper; - /** * Represents an individual authorization details object which specifies the authorization requirements for a * specific resource type within the {@code authorization_details} request parameter used in OAuth 2.0 flows @@ -76,8 +74,6 @@ public class AuthorizationDetail implements Serializable { private static final long serialVersionUID = -3928636285264078857L; - @JsonProperty("_id") - private String id; private String type; private List locations; private List actions; @@ -86,7 +82,11 @@ public class AuthorizationDetail implements Serializable { private String identifier; private List privileges; private Map details; - private String consentDescription; + + @JsonProperty("_id") + private String id; + @JsonProperty("_description") + private String description; /** * Gets the unique ID of the authorization detail. @@ -234,7 +234,7 @@ public void setDetails(final Map details) { public void setDetail(final String key, final Object value) { if (this.details == null) { - setDetails(new HashMap<>()); + this.setDetails(new HashMap<>()); } this.details.put(key, value); } @@ -247,21 +247,21 @@ public void setDetail(final String key, final Object value) { * * @return A string representing the consent description of the {@code authorization_details}. */ - public String getConsentDescription() { - return this.consentDescription; + public String getDescription() { + return this.description; } /** * Sets a human-readable sentence that describes the {@code authorization_details}. This sentence is used to * display to the user and obtain their consent for the current {@link AuthorizationDetail AuthorizationDetail}. * - * @param consentDescription A string representing the description of the authorization detail. - * This description should be clear and understandable to the user, - * explaining what they are consenting to. + * @param description A string representing the description of the authorization detail. + * This description should be clear and understandable to the user, + * explaining what they are consenting to. */ - public void setConsentDescription(final String consentDescription) { + public void setDescription(final String description) { - this.consentDescription = consentDescription; + this.description = description; } /** @@ -286,10 +286,9 @@ public void setConsentDescription(final String consentDescription) { * @param defaultFunction the Function that provides a default value if the consent description is not present * @return the consent description if present, otherwise the value from the Function */ - public String getConsentDescriptionOrDefault(Function defaultFunction) { + public String getDescriptionOrDefault(Function defaultFunction) { - return StringUtils.isNotEmpty(this.getConsentDescription()) ? - this.getConsentDescription() : defaultFunction.apply(this); + return StringUtils.isNotEmpty(this.getDescription()) ? this.getDescription() : defaultFunction.apply(this); } /** @@ -299,7 +298,7 @@ public String getConsentDescriptionOrDefault(Function toMap() { - return AuthorizationDetailsCommonUtils.toMap(this, getDefaultObjectMapper()); + return AuthorizationDetailsCommonUtils.toMap(this); } @Override @@ -323,7 +322,6 @@ public String toString() { ", identifier=" + this.identifier + ", privileges=" + this.privileges + ", details=" + this.details + - ", consentDescription=" + this.consentDescription + '}'; } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetails.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetails.java index 11c16e87fb..df1391e49d 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetails.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/model/AuthorizationDetails.java @@ -31,8 +31,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsCommonUtils.getDefaultObjectMapper; - /** * Represents a set of {@link AuthorizationDetail} objects which specifies the authorization requirements for a * specific resource type within the {@code authorization_details} request parameter used in OAuth 2.0 flows @@ -77,8 +75,7 @@ public AuthorizationDetails(final Set authorizationDetails) */ public AuthorizationDetails(final String authorizationDetailsJson) { - this(AuthorizationDetailsCommonUtils.fromJSONArray( - authorizationDetailsJson, AuthorizationDetail.class, getDefaultObjectMapper())); + this(AuthorizationDetailsCommonUtils.fromJSONArray(authorizationDetailsJson, AuthorizationDetail.class)); } /** @@ -124,7 +121,7 @@ public Set getDetailsByType(final String type) { */ public String toJsonString() { - return AuthorizationDetailsCommonUtils.toJSON(this.getDetails(), getDefaultObjectMapper()); + return AuthorizationDetailsCommonUtils.toJSON(this.getDetails()); } /** @@ -136,8 +133,7 @@ public String toJsonString() { public String toReadableText() { return this.stream() - .map(authorizationDetail -> - authorizationDetail.getConsentDescriptionOrDefault(AuthorizationDetail::getType)) + .map(authorizationDetail -> authorizationDetail.getDescriptionOrDefault(AuthorizationDetail::getType)) .collect(Collectors.joining(AuthorizationDetailsConstants.PARAM_SEPARATOR)); } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java index e1e9c3040a..6e2d84090c 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtils.java @@ -45,6 +45,7 @@ public class AuthorizationDetailsCommonUtils { private static final Log log = LogFactory.getLog(AuthorizationDetailsCommonUtils.class); private static volatile ObjectMapper objectMapper; + private static final TypeReference> TYPE_MAP = new TypeReference>() { }; private AuthorizationDetailsCommonUtils() { // Private constructor to prevent instantiation @@ -55,20 +56,19 @@ private AuthorizationDetailsCommonUtils() { * * @param authorizationDetailsJson A JSON string containing authorization details which comes in the * OAuth 2.0 authorization request or token request - * @param objectMapper A Jackson {@link ObjectMapper} used for parsing * @param clazz A Class that extends {@link AuthorizationDetail} to be parsed * @param the type parameter extending {@code AuthorizationDetail} * @return an immutable set of {@link AuthorizationDetail} objects parsed from the given JSON string, * or an empty set if parsing fails * @see AuthorizationDetails */ - public static Set fromJSONArray( - final String authorizationDetailsJson, final Class clazz, final ObjectMapper objectMapper) { + public static Set fromJSONArray(final String authorizationDetailsJson, + final Class clazz) { try { if (StringUtils.isNotEmpty(authorizationDetailsJson)) { - return objectMapper.readValue(authorizationDetailsJson, - objectMapper.getTypeFactory().constructCollectionType(Set.class, clazz)); + return getDefaultObjectMapper().readValue(authorizationDetailsJson, + getDefaultObjectMapper().getTypeFactory().constructCollectionType(Set.class, clazz)); } } catch (JsonProcessingException e) { log.debug("Error occurred while parsing String to AuthorizationDetails. Caused by, ", e); @@ -80,19 +80,18 @@ public static Set fromJSONArray( * Parses the given JSON object string into an {@link AuthorizationDetail} object. * * @param authorizationDetailJson A JSON string containing authorization detail object - * @param objectMapper A Jackson {@link ObjectMapper} used for parsing * @param clazz A Class that extends {@link AuthorizationDetail} to be parsed * @param the type parameter extending {@code AuthorizationDetail} * @return an {@link AuthorizationDetail} objects parsed from the given JSON string, * or null if parsing fails * @see AuthorizationDetail */ - public static T fromJSON( - final String authorizationDetailJson, final Class clazz, final ObjectMapper objectMapper) { + public static T fromJSON(final String authorizationDetailJson, + final Class clazz) { try { if (StringUtils.isNotEmpty(authorizationDetailJson)) { - return objectMapper.readValue(authorizationDetailJson, clazz); + return getDefaultObjectMapper().readValue(authorizationDetailJson, clazz); } } catch (JsonProcessingException e) { log.debug("Error occurred while parsing String to AuthorizationDetails. Caused by, ", e); @@ -108,19 +107,17 @@ public static T fromJSON( *

* * @param authorizationDetails the set of {@code AuthorizationDetail} objects to convert - * @param objectMapper the {@code ObjectMapper} instance to use for serialization * @param the type parameter extending {@code AuthorizationDetail} * @return a JSON string representation of the authorization details set, * or an empty JSON array if null or an error occurs * @see AuthorizationDetail * @see AuthorizationDetails */ - public static String toJSON( - final Set authorizationDetails, final ObjectMapper objectMapper) { + public static String toJSON(final Set authorizationDetails) { try { if (authorizationDetails != null) { - return objectMapper.writeValueAsString(authorizationDetails); + return getDefaultObjectMapper().writeValueAsString(authorizationDetails); } } catch (JsonProcessingException e) { log.debug("Error occurred while parsing AuthorizationDetails to String. Caused by, ", e); @@ -136,19 +133,17 @@ public static String toJSON( *

* * @param authorizationDetail the {@code AuthorizationDetail} object to convert - * @param objectMapper the {@code ObjectMapper} instance to use for serialization * @param the type parameter extending {@code AuthorizationDetail} * @return a JSON string representation of the authorization detail, * or an empty JSON object if null or an error occurs * @see AuthorizationDetail * @see AuthorizationDetails */ - public static String toJSON( - final T authorizationDetail, final ObjectMapper objectMapper) { + public static String toJSON(final T authorizationDetail) { try { if (authorizationDetail != null) { - return objectMapper.writeValueAsString(authorizationDetail); + return getDefaultObjectMapper().writeValueAsString(authorizationDetail); } } catch (JsonProcessingException e) { log.debug("Error occurred while parsing AuthorizationDetail to String. Caused by, ", e); @@ -164,21 +159,16 @@ public static String toJSON( *

* * @param authorizationDetail the {@code AuthorizationDetail} object to convert - * @param objectMapper the {@code ObjectMapper} instance to use for serialization * @param the type parameter extending {@code AuthorizationDetail} * @return a {@code Map} representation of the authorization detail, * or an empty {@code HashMap} if null or an error occurs * @see AuthorizationDetail * @see AuthorizationDetails */ - public static Map toMap( - final T authorizationDetail, final ObjectMapper objectMapper) { + public static Map toMap(final T authorizationDetail) { - if (authorizationDetail != null) { - return objectMapper.convertValue(authorizationDetail, new TypeReference>() { - }); - } - return Collections.emptyMap(); + return (authorizationDetail == null) ? Collections.emptyMap() + : getDefaultObjectMapper().convertValue(authorizationDetail, TYPE_MAP); } /** diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidatorTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidatorTest.java index b078f7ea08..5a283dd1d9 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidatorTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsSchemaValidatorTest.java @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.oauth2.rar; import com.fasterxml.jackson.core.JsonProcessingException; +import io.vertx.core.json.JsonObject; import org.apache.commons.lang3.StringUtils; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -27,6 +28,9 @@ import org.wso2.carbon.identity.oauth2.rar.util.TestDAOUtils; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -54,6 +58,7 @@ public void shouldReturnTrue_whenAuthorizationDetailIsSchemaCompliant() testAuthorizationDetail.setType(TEST_TYPE); assertTrue(this.uut.isSchemaCompliant(TEST_SCHEMA, testAuthorizationDetail)); + assertTrue(this.uut.isSchemaCompliant(this.getTestSchema(), testAuthorizationDetail)); } @Test @@ -61,6 +66,10 @@ public void shouldReturnFalse_whenSchemaIsEmpty() throws AuthorizationDetailsPro assertFalse(this.uut.isSchemaCompliant(StringUtils.EMPTY, new TestDAOUtils.TestAuthorizationDetail())); assertFalse(this.uut.isSchemaCompliant(TEST_SCHEMA, null)); + assertFalse(this.uut.isSchemaCompliant((JsonObject) null, new TestDAOUtils.TestAuthorizationDetail())); + assertFalse(this.uut.isSchemaCompliant(new JsonObject(), null)); + assertFalse(this.uut.isSchemaCompliant((Map) null, new TestDAOUtils.TestAuthorizationDetail())); + assertFalse(this.uut.isSchemaCompliant(this.getTestSchema(), null)); } @Test(expectedExceptions = {AuthorizationDetailsProcessingException.class}) @@ -102,4 +111,28 @@ public void shouldThrowAuthorizationDetailsProcessingException_whenSchemaIsInval assertFalse(this.uut.isValidSchema(invalidSchema)); } + + private Map getTestSchema() { + final Map items = new HashMap<>(); + items.put("type", "string"); + items.put("enum", Collections.singletonList("initiate")); + + final Map actions = new HashMap<>(); + actions.put("type", "array"); + actions.put("items", items); + + final Map type = new HashMap<>(); + type.put("type", "string"); + type.put("enum", Collections.singletonList("test_type_v1")); + + final Map properties = new HashMap<>(); + properties.put("type", type); + properties.put("actions", actions); + + final Map schema = new HashMap<>(); + schema.put("type", "object"); + schema.put("required", Collections.singletonList("type")); + schema.put("properties", properties); + return schema; + } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java index fb27e90a4c..7dd3648d94 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java @@ -205,7 +205,7 @@ public void shouldThrowSQLException_whenAddingConsentedAuthorizationDetailsFails try (Connection connectionMock = Mockito.spy(Connection.class)) { - Mockito.when(connectionMock.getMetaData()).thenThrow(SQLException.class); + Mockito.when(connectionMock.prepareStatement(anyString())).thenThrow(SQLException.class); identityDatabaseUtilMock .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class))) .thenReturn(connectionMock); @@ -235,6 +235,6 @@ public void testGetConsentIdByUserIdAndAppId() throws SQLException { @Test public void shouldReturnNull_whenUserIdOrAppIdInvalid() throws SQLException { - assertNull(this.uut.getConsentIdByUserIdAndAppId("invlid_user_id", "invalid_app_id", TEST_TENANT_ID)); + assertNull(this.uut.getConsentIdByUserIdAndAppId("invalid_user_id", "invalid_app_id", TEST_TENANT_ID)); } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java index 238be9a7b7..44ea42d325 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsCommonUtilsTest.java @@ -18,10 +18,6 @@ package org.wso2.carbon.identity.oauth2.rar.util; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.mockito.Mockito; -import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.collections.Sets; @@ -36,8 +32,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.EMPTY_JSON_ARRAY; import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.EMPTY_JSON_OBJECT; import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_NAME; @@ -48,20 +42,6 @@ */ public class AuthorizationDetailsCommonUtilsTest { - private ObjectMapper objectMapper; - private ObjectMapper mockObjectMapper; - - @BeforeClass - public void setUp() throws JsonProcessingException { - - this.objectMapper = AuthorizationDetailsCommonUtils.getDefaultObjectMapper(); - this.mockObjectMapper = Mockito.spy(this.objectMapper); - - doThrow(JsonProcessingException.class) - .when(this.mockObjectMapper).writeValueAsString(any(TestDAOUtils.TestAuthorizationDetail.class)); - doThrow(JsonProcessingException.class).when(this.mockObjectMapper).writeValueAsString(any(Set.class)); - } - @DataProvider(name = "AuthorizationDetailsCommonUtilsTestDataProvider") public Object[][] provideAuthorizationDetailsCommonUtilsTestData(Method testMethod) { @@ -89,8 +69,8 @@ public Object[][] provideAuthorizationDetailsCommonUtilsTestData(Method testMeth @Test(dataProvider = "AuthorizationDetailsCommonUtilsTestDataProvider") public void shouldReturnCorrectSize_whenJSONArrayIsValid(String inputJson, int expectedSize) { - Set actualAuthorizationDetails = AuthorizationDetailsCommonUtils - .fromJSONArray(inputJson, AuthorizationDetail.class, objectMapper); + Set actualAuthorizationDetails = + AuthorizationDetailsCommonUtils.fromJSONArray(inputJson, AuthorizationDetail.class); assertEquals(expectedSize, actualAuthorizationDetails.size()); } @@ -98,7 +78,7 @@ public void shouldReturnCorrectSize_whenJSONArrayIsValid(String inputJson, int e @Test(dataProvider = "AuthorizationDetailsCommonUtilsTestDataProvider") public void shouldReturnNull_whenJSONIsInvalid(String inputJson, int expectedSize) { - assertNull(AuthorizationDetailsCommonUtils.fromJSON(inputJson, AuthorizationDetail.class, objectMapper)); + assertNull(AuthorizationDetailsCommonUtils.fromJSON(inputJson, AuthorizationDetail.class)); } @Test(dataProvider = "AuthorizationDetailsCommonUtilsTestDataProvider") @@ -106,7 +86,7 @@ public void shouldReturnCorrectType_whenJSONIsVa final String inputJson = "{\"type\": \"" + TEST_TYPE + "\"}"; AuthorizationDetail actualAuthorizationDetail = - AuthorizationDetailsCommonUtils.fromJSON(inputJson, expectedClazz, objectMapper); + AuthorizationDetailsCommonUtils.fromJSON(inputJson, expectedClazz); assertNotNull(actualAuthorizationDetail); assertEquals(TEST_TYPE, actualAuthorizationDetail.getType()); @@ -119,15 +99,12 @@ public void shouldReturnCorrectJson_whenAuthorizationDetailsAreValid() { inputAuthorizationDetail.setType(TEST_TYPE); inputAuthorizationDetail.setName(TEST_NAME); - final String authorizationDetails = AuthorizationDetailsCommonUtils - .toJSON(Sets.newHashSet(inputAuthorizationDetail), objectMapper); + final String authorizationDetails = + AuthorizationDetailsCommonUtils.toJSON(Sets.newHashSet(inputAuthorizationDetail)); assertTrue(authorizationDetails.contains(TEST_TYPE)); assertTrue(authorizationDetails.contains(TEST_NAME)); - assertEquals(EMPTY_JSON_ARRAY, - AuthorizationDetailsCommonUtils.toJSON((Set) null, objectMapper)); - assertEquals(EMPTY_JSON_ARRAY, - AuthorizationDetailsCommonUtils.toJSON(Sets.newHashSet(inputAuthorizationDetail), mockObjectMapper)); + assertEquals(EMPTY_JSON_ARRAY, AuthorizationDetailsCommonUtils.toJSON((Set) null)); } @Test @@ -137,15 +114,14 @@ public void shouldReturnCorrectJson_whenAuthorizationDetailIsValid() { inputAuthorizationDetail.setType(TEST_TYPE); inputAuthorizationDetail.setName(TEST_NAME); - final String authorizationDetail = - AuthorizationDetailsCommonUtils.toJSON(inputAuthorizationDetail, objectMapper); + final String authorizationDetail = AuthorizationDetailsCommonUtils.toJSON(inputAuthorizationDetail); assertTrue(authorizationDetail.contains(TEST_TYPE)); assertTrue(authorizationDetail.contains(TEST_NAME)); assertEquals(EMPTY_JSON_OBJECT, - AuthorizationDetailsCommonUtils.toJSON((TestDAOUtils.TestAuthorizationDetail) null, objectMapper)); + AuthorizationDetailsCommonUtils.toJSON((TestDAOUtils.TestAuthorizationDetail) null)); assertEquals(EMPTY_JSON_OBJECT, - AuthorizationDetailsCommonUtils.toJSON(new TestDAOUtils.TestAuthorizationDetail(), mockObjectMapper)); + AuthorizationDetailsCommonUtils.toJSON(new TestDAOUtils.TestAuthorizationDetail())); } @Test @@ -154,7 +130,7 @@ public void shouldReturnMap_whenAuthorizationDetailIsValid() { TestDAOUtils.TestAuthorizationDetail inputAuthorizationDetail = new TestDAOUtils.TestAuthorizationDetail(); inputAuthorizationDetail.setType(TEST_TYPE); inputAuthorizationDetail.setName(TEST_NAME); - Map map = AuthorizationDetailsCommonUtils.toMap(inputAuthorizationDetail, objectMapper); + Map map = AuthorizationDetailsCommonUtils.toMap(inputAuthorizationDetail); assertTrue(map.containsKey("type")); assertTrue(map.containsKey("name")); @@ -162,6 +138,6 @@ public void shouldReturnMap_whenAuthorizationDetailIsValid() { assertEquals(TEST_NAME, String.valueOf(map.get("name"))); assertEquals(2, map.keySet().size()); - assertFalse(AuthorizationDetailsCommonUtils.toMap(null, objectMapper).containsKey(TEST_TYPE)); + assertFalse(AuthorizationDetailsCommonUtils.toMap(null).containsKey(TEST_TYPE)); } } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql index 7ab96e2b44..abcd4dacab 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS AUTHORIZATION_DETAILS_TYPES( CURSOR_KEY INTEGER DEFAULT 1, NAME VARCHAR(255), DESCRIPTION VARCHAR (255), - JSON_SCHEMA JSON NOT NULL, + JSON_SCHEMA CLOB NOT NULL, TENANT_ID INTEGER DEFAULT -1 ); @@ -12,7 +12,7 @@ CREATE TABLE IF NOT EXISTS IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS ( ID INTEGER NOT NULL AUTO_INCREMENT, CONSENT_ID VARCHAR(255) NOT NULL, TYPE_ID INTEGER NOT NULL, - AUTHORIZATION_DETAILS JSON NOT NULL, + AUTHORIZATION_DETAILS CLOB NOT NULL, CONSENT BOOLEAN NOT NULL DEFAULT 1, TENANT_ID INTEGER NOT NULL DEFAULT -1 ); @@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS ( CREATE TABLE IF NOT EXISTS IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS ( ID INTEGER NOT NULL AUTO_INCREMENT, TYPE_ID INTEGER NOT NULL, - AUTHORIZATION_DETAILS JSON NOT NULL, + AUTHORIZATION_DETAILS CLOB NOT NULL, TOKEN_ID VARCHAR (255), TENANT_ID INTEGER DEFAULT -1 ); @@ -28,7 +28,7 @@ CREATE TABLE IF NOT EXISTS IDN_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS ( CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS ( ID INTEGER NOT NULL AUTO_INCREMENT, TYPE_ID CHAR(36) NOT NULL, - AUTHORIZATION_DETAILS JSON NOT NULL, + AUTHORIZATION_DETAILS CLOB NOT NULL, CODE_ID VARCHAR (255), TENANT_ID INTEGER ); @@ -68,4 +68,4 @@ INSERT INTO IDN_OAUTH2_AUTHORIZATION_CODE (CODE_ID, AUTHORIZATION_CODE, IDP_ID) VALUES ('81197bc6-63f3-4c0f-90dd-1588076ab50f', 'b1b833f0-f605-4f5c-add6-38ea8ce1b969', 1); INSERT INTO IDN_OAUTH2_USER_CONSENT (USER_ID, APP_ID, TENANT_ID, CONSENT_ID) -VALUES ('valid_user_id', 'valid_app_id', 1234, '52481ccd-0927-4d17-8cfc-5110fc4aa009'); \ No newline at end of file +VALUES ('valid_user_id', 'valid_app_id', 1234, '52481ccd-0927-4d17-8cfc-5110fc4aa009'); diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java index ef32dcc622..a3a61ef6e9 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java @@ -266,7 +266,7 @@ public static boolean isRichAuthorizationRequest(final OAuth2Parameters oAuth2Pa /** * Transforms the given {@link AuthorizationDetails} by creating a new set of {@link AuthorizationDetail} objects - * with only the displayable fields ({@code type}, {@code id}, {@code consentDescription}) copied over. + * with only the displayable fields ({@code type}, {@code id}, {@code description}) copied over. * * @param authorizationDetails The original AuthorizationDetails to be transformed. * @return A new {@link AuthorizationDetails} object containing the displayable authorization details. @@ -277,9 +277,9 @@ public static AuthorizationDetails getDisplayableAuthorizationDetails( final Set displayableAuthorizationDetails = authorizationDetails.stream() .map(protectedAuthorizationDetail -> { final AuthorizationDetail authorizationDetail = new AuthorizationDetail(); - authorizationDetail.setType(protectedAuthorizationDetail.getType()); authorizationDetail.setId(protectedAuthorizationDetail.getId()); - authorizationDetail.setConsentDescription(protectedAuthorizationDetail.getConsentDescription()); + authorizationDetail.setType(protectedAuthorizationDetail.getType()); + authorizationDetail.setDescription(protectedAuthorizationDetail.getDescription()); return authorizationDetail; }).collect(toSet()); @@ -297,23 +297,11 @@ public static AuthorizationDetails getTrimmedAuthorizationDetails(final Authoriz authorizationDetails.stream().forEach(authorizationDetail -> { authorizationDetail.setId(null); - authorizationDetail.setConsentDescription(null); + authorizationDetail.setDescription(null); }); return authorizationDetails; } - /** - * Generates an {@link AuthorizationDetails} instance from given JSON string - * and assigns unique IDs for each {@link AuthorizationDetail}. - * - * @param authorizationDetailsJson The JSON string representing the authorization details. - * @return The AuthorizationDetails object with unique IDs assigned to each AuthorizationDetail. - */ - public static AuthorizationDetails generateAndAssignUniqueIDs(final String authorizationDetailsJson) { - - return assignUniqueIDsToAuthorizationDetails(new AuthorizationDetails(authorizationDetailsJson)); - } - /** * Generates unique IDs for each {@link AuthorizationDetail} within the given {@link AuthorizationDetails} object. * diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java index 809bcfdd49..cc42caeb32 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java @@ -306,15 +306,15 @@ private Map getAuthorizedAuthorizationDetailsT final List authorizationDetailsTypes = OAuth2ServiceComponentHolder.getInstance() .getAuthorizedAPIManagementService().getAuthorizedAuthorizationDetailsTypes(appId, tenantDomain); - if (CollectionUtils.isEmpty(authorizationDetailsTypes)) { - return Collections.emptyMap(); + if (CollectionUtils.isNotEmpty(authorizationDetailsTypes)) { + return authorizationDetailsTypes.stream() + .collect(Collectors.toMap(AuthorizationDetailsType::getType, Function.identity())); } - return authorizationDetailsTypes.stream() - .collect(Collectors.toMap(AuthorizationDetailsType::getType, Function.identity())); } catch (IdentityOAuth2Exception | IdentityApplicationManagementException e) { log.error("Unable to retrieve authorized authorization details types. Caused by, ", e); throw new IdentityOAuth2ServerException("Unable to retrieve authorized authorization details types", e); } + return Collections.emptyMap(); } private Set getSchemaCompliantAuthorizationDetails( From ca2f0549d9310cbd71f18e16a08da7a34f7e6e44 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Mon, 28 Oct 2024 11:18:46 +0530 Subject: [PATCH 08/28] Resolve merge conflicts --- .../org.wso2.carbon.identity.oauth/pom.xml | 2 -- .../rar/util/AuthorizationDetailsUtils.java | 10 ++++++---- .../grant/AbstractAuthorizationGrantHandler.java | 3 ++- .../handlers/grant/RefreshGrantHandlerTest.java | 16 +++++++++++++++- pom.xml | 5 +++-- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index b0218bad0d..0f334853fb 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -269,8 +269,6 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.oauth.rar - compile - 7.0.162-SNAPSHOT diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java index a3a61ef6e9..012382d23a 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java @@ -295,10 +295,12 @@ public static AuthorizationDetails getDisplayableAuthorizationDetails( */ public static AuthorizationDetails getTrimmedAuthorizationDetails(final AuthorizationDetails authorizationDetails) { - authorizationDetails.stream().forEach(authorizationDetail -> { - authorizationDetail.setId(null); - authorizationDetail.setDescription(null); - }); + if (authorizationDetails != null) { + authorizationDetails.stream().forEach(authorizationDetail -> { + authorizationDetail.setId(null); + authorizationDetail.setDescription(null); + }); + } return authorizationDetails; } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java index 9321ba42a0..15dd3b7264 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java @@ -1275,6 +1275,7 @@ protected void setRARPropertiesForTokenGeneration(final OAuthTokenReqMessageCont authorizationDetails = this.authorizationDetailsService.getAuthorizationCodeAuthorizationDetails( oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getAuthorizationCode(), tenantId); } - oAuthTokenReqMessageContext.setAuthorizationDetails(authorizationDetails); + oAuthTokenReqMessageContext.setAuthorizationDetails(AuthorizationDetailsUtils + .getTrimmedAuthorizationDetails(authorizationDetails)); } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTest.java index 5dd37ce304..737414b8c7 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/RefreshGrantHandlerTest.java @@ -36,7 +36,10 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.RefreshTokenValidationDataDO; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.test.common.testng.utils.MockAuthenticatedUser; import org.wso2.carbon.identity.user.profile.mgt.association.federation.FederatedAssociationManager; import org.wso2.carbon.identity.user.profile.mgt.association.federation.exception.FederatedAssociationManagerClientException; @@ -47,6 +50,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -54,6 +58,7 @@ import static org.mockito.Mockito.when; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_CHECKING_ACCOUNT_LOCK_STATUS; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_GETTING_USERNAME_ASSOCIATED_WITH_IDP; +import static org.wso2.carbon.identity.oauth2.TestConstants.TENANT_ID; /** * Unit tests for the RefreshGrantHandler class. @@ -66,6 +71,7 @@ public class RefreshGrantHandlerTest { private OAuthServerConfiguration oAuthServerConfiguration; private OAuth2AccessTokenReqDTO oAuth2AccessTokenReqDTO; private OAuth2ServiceComponentHolder oAuth2ServiceComponentHolder; + private AuthorizationDetailsService authorizationDetailsService; @BeforeMethod public void init() { @@ -75,6 +81,7 @@ public void init() { oAuthServerConfiguration = mock(OAuthServerConfiguration.class); oAuth2AccessTokenReqDTO = mock(OAuth2AccessTokenReqDTO.class); oAuth2ServiceComponentHolder = mock(OAuth2ServiceComponentHolder.class); + authorizationDetailsService = mock(AuthorizationDetailsService.class); } @DataProvider(name = "validateGrantWhenUserIsLockedInUserStoreEnd") @@ -143,6 +150,10 @@ public void testValidateGrantWhenUserIsLockedInUserStoreEnd(AuthenticatedUser us isValidateAuthenticatedUserForRefreshGrant); when(oAuth2ServiceComponentHolder.getRefreshTokenGrantProcessor()).thenReturn(refreshTokenGrantProcessor); when(oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO()).thenReturn(oAuth2AccessTokenReqDTO); + when(authorizationDetailsService + .getUserConsentedAuthorizationDetails(any(AuthenticatedUser.class), anyString(), anyInt())) + .thenReturn(new AuthorizationDetails()); + when(oAuth2ServiceComponentHolder.getAuthorizationDetailsService()).thenReturn(authorizationDetailsService); FederatedAssociationManager federatedAssociationManager = mock(FederatedAssociationManager.class); if (federatedAssociationManagerException instanceof FederatedAssociationManagerException) { @@ -169,7 +180,9 @@ public void testValidateGrantWhenUserIsLockedInUserStoreEnd(AuthenticatedUser us OAuthServerConfiguration.class); MockedStatic oAuth2ServiceComponentHolderMockedStatic = mockStatic( OAuth2ServiceComponentHolder.class); - MockedStatic frameworkUtilsMockedStatic = mockStatic(FrameworkUtils.class)) { + MockedStatic frameworkUtilsMockedStatic = mockStatic(FrameworkUtils.class); + MockedStatic oAuth2Util = mockStatic(OAuth2Util.class)) { + oAuth2Util.when(() -> OAuth2Util.getTenantId(anyString())).thenReturn(TENANT_ID); oAuthServerConfigurationMockedStatic.when(OAuthServerConfiguration::getInstance) .thenReturn(oAuthServerConfiguration); oAuth2ServiceComponentHolderMockedStatic.when(OAuth2ServiceComponentHolder::getInstance) @@ -185,6 +198,7 @@ public void testValidateGrantWhenUserIsLockedInUserStoreEnd(AuthenticatedUser us } RefreshGrantHandler refreshGrantHandler = new RefreshGrantHandler(); + refreshGrantHandler.init(); boolean validateResult = refreshGrantHandler.validateGrant(oAuthTokenReqMessageContext); assertTrue(validateResult); } diff --git a/pom.xml b/pom.xml index 29d6b86721..558f5fb95c 100644 --- a/pom.xml +++ b/pom.xml @@ -62,12 +62,12 @@ components/org.wso2.carbon.identity.oauth.client.authn.filter components/org.wso2.carbon.identity.oauth.ciba components/org.wso2.carbon.identity.client.attestation.filter + components/org.wso2.carbon.identity.oauth.rar features/org.wso2.carbon.identity.oauth.common.feature features/org.wso2.carbon.identity.oauth.feature features/org.wso2.carbon.identity.oauth.server.feature features/org.wso2.carbon.identity.oauth.ui.feature features/org.wso2.carbon.identity.oauth.dcr.server.feature - components/org.wso2.carbon.identity.oauth.rar @@ -957,7 +957,8 @@ [1.0.1, 2.0.0) - 7.5.86 + + 7.5.94-SNAPSHOT [5.25.234, 8.0.0) From ffba19a022e4bce2069d2408f009eeae0d39f760 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Mon, 28 Oct 2024 14:13:40 +0530 Subject: [PATCH 09/28] Add license headers --- .../pom.xml | 3 +- .../pom.xml | 2 +- .../src/test/resources/dbScripts/h2.sql | 34 +++++++++---------- .../rar/AuthorizationDetailsService.java | 18 ++++++++++ .../AuthorizationDetailsProcessorFactory.java | 4 +-- .../rar/util/AuthorizationDetailsUtils.java | 18 ++++++++++ .../AuthorizationDetailsValidator.java | 18 ++++++++++ .../rar/AuthorizationDetailsServiceTest.java | 18 ++++++++++ .../AccessTokenResponseRARHandlerTest.java | 18 ++++++++++ .../IntrospectionRARDataProviderTest.java | 18 ++++++++++ .../JWTAccessTokenRARClaimProviderTest.java | 18 ++++++++++ .../utils/AuthorizationDetailsBaseTest.java | 18 ++++++++++ ...aultAuthorizationDetailsValidatorTest.java | 18 ++++++++++ pom.xml | 6 ---- 14 files changed, 183 insertions(+), 28 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index b60ef106f2..2de3921206 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -327,8 +327,7 @@ COMPLEXITY COVEREDRATIO - - 0.47 + 0.48 diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index 99929f0ce5..7b74c4df18 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -24,7 +24,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.174-SNAPSHOT + 7.0.177-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql index abcd4dacab..83f076e4bc 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/resources/dbScripts/h2.sql @@ -34,23 +34,23 @@ CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHZ_CODE_AUTHORIZATION_DETAILS ( ); CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHORIZATION_CODE ( - CODE_ID VARCHAR (255), - AUTHORIZATION_CODE VARCHAR (2048), - CONSUMER_KEY_ID INTEGER, - CALLBACK_URL VARCHAR (2048), - SCOPE VARCHAR(2048), - AUTHZ_USER VARCHAR (100), - TENANT_ID INTEGER, - USER_DOMAIN VARCHAR(50), - TIME_CREATED TIMESTAMP, - VALIDITY_PERIOD BIGINT, - STATE VARCHAR (25) DEFAULT 'ACTIVE', - TOKEN_ID VARCHAR(255), - SUBJECT_IDENTIFIER VARCHAR(255), - PKCE_CODE_CHALLENGE VARCHAR (255), - PKCE_CODE_CHALLENGE_METHOD VARCHAR(128), - AUTHORIZATION_CODE_HASH VARCHAR (512), - IDP_ID INTEGER DEFAULT -1 NOT NULL + CODE_ID VARCHAR (255), + AUTHORIZATION_CODE VARCHAR (2048), + CONSUMER_KEY_ID INTEGER, + CALLBACK_URL VARCHAR (2048), + SCOPE VARCHAR(2048), + AUTHZ_USER VARCHAR (100), + TENANT_ID INTEGER, + USER_DOMAIN VARCHAR(50), + TIME_CREATED TIMESTAMP, + VALIDITY_PERIOD BIGINT, + STATE VARCHAR (25) DEFAULT 'ACTIVE', + TOKEN_ID VARCHAR(255), + SUBJECT_IDENTIFIER VARCHAR(255), + PKCE_CODE_CHALLENGE VARCHAR (255), + PKCE_CODE_CHALLENGE_METHOD VARCHAR(128), + AUTHORIZATION_CODE_HASH VARCHAR (512), + IDP_ID INTEGER DEFAULT -1 NOT NULL ); CREATE TABLE IF NOT EXISTS IDN_OAUTH2_USER_CONSENT ( diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java index f870ae85d1..11e412a9d2 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar; import org.apache.commons.logging.Log; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java index a8798b42e2..3743515386 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java @@ -41,8 +41,8 @@ *

Example usage: *

 {@code
  * // Get a specific provider by type
- * AuthorizationDetailsProviderFactory.getInstance()
- *     .getProviderByType("customer_information")
+ * AuthorizationDetailsProcessorFactory.getInstance()
+ *     .getAuthorizationDetailsProcessorByType("customer_information")
  *     .ifPresentOrElse(
  *         p -> log.debug("Provider for type " + type + ": " + p.getClass().getName()),
  *         () -> log.debug("No provider found for type " + type)
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java
index 012382d23a..5f9cc82d41 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 package org.wso2.carbon.identity.oauth2.rar.util;
 
 import org.apache.commons.lang.StringUtils;
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/AuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/AuthorizationDetailsValidator.java
index 2cdf2afd7f..71e5549e55 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/AuthorizationDetailsValidator.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/AuthorizationDetailsValidator.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 package org.wso2.carbon.identity.oauth2.rar.validator;
 
 import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException;
diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java
index 143ee3fb9a..987da89649 100644
--- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java
+++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 package org.wso2.carbon.identity.oauth2.rar;
 
 import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandlerTest.java
index 26dae1ca6c..53103e1eb4 100644
--- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandlerTest.java
+++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandlerTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 package org.wso2.carbon.identity.oauth2.rar.token;
 
 import org.testng.annotations.BeforeClass;
diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java
index ec9f84b1d0..bb8a935e39 100644
--- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java
+++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 package org.wso2.carbon.identity.oauth2.rar.token;
 
 import org.mockito.MockedStatic;
diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProviderTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProviderTest.java
index 7e8c99e6fc..a4a903d37d 100644
--- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProviderTest.java
+++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProviderTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 package org.wso2.carbon.identity.oauth2.rar.token;
 
 import org.testng.annotations.BeforeClass;
diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java
index 7159bda1be..b8bec6482f 100644
--- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java
+++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 package org.wso2.carbon.identity.oauth2.rar.utils;
 
 import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser;
diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java
index 2849f2976b..67c8e4f942 100644
--- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java
+++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 package org.wso2.carbon.identity.oauth2.rar.validator;
 
 import org.apache.oltu.oauth2.common.message.types.GrantType;
diff --git a/pom.xml b/pom.xml
index 2362c9c2a0..c2446c22de 100644
--- a/pom.xml
+++ b/pom.xml
@@ -415,11 +415,6 @@
                 gson
                 ${com.google.code.gson.version}
             
-            
-                com.google.auto.service
-                auto-service
-                ${com.google.auto.service.version}
-            
             
             
                 io.vertx
@@ -1052,7 +1047,6 @@
         2.4.7
         5.2
         9.2
-        1.1.1
         4.5.10
 
         

From 4c56858466f6f43b6bd9c9ec071f363285fac535 Mon Sep 17 00:00:00 2001
From: vimukthiRajapaksha 
Date: Wed, 13 Nov 2024 17:59:35 +0530
Subject: [PATCH 10/28] Add a config method to check if RAR is enabled

---
 .../builders/ProviderConfigBuilder.java       |   8 +-
 .../endpoint/authz/OAuth2AuthzEndpoint.java   |  12 +-
 .../pom.xml                                   |   6 +
 .../rar/dao/AuthorizationDetailsDAO.java      |  14 +-
 .../rar/dao/AuthorizationDetailsDAOImpl.java  |  81 ++++++++--
 .../identity/oauth2/rar/dao/SQLQueries.java   |   5 +
 .../dao/AuthorizationDetailsDAOImplTest.java  | 113 ++++++++++---
 .../oauth2/rar/util/TestDAOUtils.java         |   8 +
 .../authz/AuthorizationHandlerManager.java    |   2 -
 .../authz/OAuthAuthzReqMessageContext.java    |  44 +++--
 .../handlers/AbstractResponseTypeHandler.java |   2 +-
 .../rar/AuthorizationDetailsService.java      | 151 ++++++++++++------
 .../AuthorizationDetailsProcessorFactory.java |  16 +-
 .../token/AccessTokenResponseRARHandler.java  |   4 +-
 .../token/JWTAccessTokenRARClaimProvider.java |   4 +-
 .../rar/util/AuthorizationDetailsUtils.java   |  31 +---
 .../DefaultAuthorizationDetailsValidator.java |   4 +-
 .../AbstractAuthorizationGrantHandler.java    |  42 +----
 .../grant/AuthorizationCodeGrantHandler.java  |  35 +++-
 .../handlers/grant/RefreshGrantHandler.java   |  33 +++-
 .../rar/AuthorizationDetailsServiceTest.java  |  15 +-
 .../utils/AuthorizationDetailsBaseTest.java   |   3 +-
 22 files changed, 436 insertions(+), 197 deletions(-)

diff --git a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java
index 68b79545e3..d3ac9f6ad1 100644
--- a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java
+++ b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java
@@ -154,11 +154,11 @@ public OIDProviderConfigResponse buildOIDProviderConfig(OIDProviderRequest reque
         providerConfig.setMtlsTokenEndpoint(OAuth2Util.OAuthURL.getOAuth2MTLSTokenEPUrl());
         providerConfig.setMtlsPushedAuthorizationRequestEndpoint(OAuth2Util.OAuthURL.getOAuth2MTLSParEPUrl());
 
-        final Set supportedTypes = AuthorizationDetailsProcessorFactory.getInstance()
+        final Set authorizationDetailTypes = AuthorizationDetailsProcessorFactory.getInstance()
                 .getSupportedAuthorizationDetailTypes();
-        if (supportedTypes != null && !supportedTypes.isEmpty()) {
-            final int size = supportedTypes.size();
-            providerConfig.setAuthorizationDetailsTypesSupported(supportedTypes.toArray(new String[size]));
+        if (authorizationDetailTypes != null && !authorizationDetailTypes.isEmpty()) {
+            //final int size = supportedTypes.size();
+            providerConfig.setAuthorizationDetailsTypesSupported(authorizationDetailTypes.toArray(String[]::new));
         }
         return providerConfig;
     }
diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java
index 296c78eaf0..37b2f67266 100644
--- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java
+++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpoint.java
@@ -1637,6 +1637,7 @@ private String handleUserConsent(OAuthMessage oAuthMessage, String consent, OIDC
                 oAuthMessage.getSessionDataCacheEntry().getAuthzReqMsgCtx();
         oAuthAuthzReqMessageContext.setAuthorizationReqDTO(authzReqDTO);
         oAuthAuthzReqMessageContext.addProperty(OAuthConstants.IS_MTLS_REQUEST, oauth2Params.isMtlsRequest());
+        oAuthAuthzReqMessageContext.setApprovedAuthorizationDetails(oauth2Params.getAuthorizationDetails());
         // authorizing the request
         OAuth2AuthorizeRespDTO authzRespDTO = authorize(oAuthAuthzReqMessageContext);
         if (authzRespDTO != null && authzRespDTO.getCallbackURI() != null) {
@@ -1742,7 +1743,7 @@ private void storeUserConsent(OAuthMessage oAuthMessage, String consent) throws
                             clientId, oauth2Params, userConsentedAuthorizationDetails);
                 } else {
                     EndpointUtil.storeOAuthScopeConsent(loggedInUser, oauth2Params, false);
-                    authorizationDetailsService.storeUserConsentedAuthorizationDetails(loggedInUser,
+                    authorizationDetailsService.storeOrUpdateUserConsentedAuthorizationDetails(loggedInUser,
                             clientId, oauth2Params, userConsentedAuthorizationDetails);
                 }
             }
@@ -4894,15 +4895,14 @@ private void validateAuthorizationDetailsBeforeConsent(final OAuthMessage oAuthM
                     .getAuthorizationDetailsValidator()
                     .getValidatedAuthorizationDetails(oAuthAuthzReqMessageContext);
 
-            // update oAuth2Parameters with validated authorization details
-            oAuth2Parameters.setAuthorizationDetails(AuthorizationDetailsUtils
-                    .assignUniqueIDsToAuthorizationDetails(validatedAuthorizationDetails));
-
             // Update the authorization message context with validated authorization details
-            oAuthAuthzReqMessageContext.setAuthorizationDetails(AuthorizationDetailsUtils
+            oAuthAuthzReqMessageContext.setRequestedAuthorizationDetails(AuthorizationDetailsUtils
                     .assignUniqueIDsToAuthorizationDetails(validatedAuthorizationDetails));
             oAuthMessage.getSessionDataCacheEntry().setAuthzReqMsgCtx(oAuthAuthzReqMessageContext);
 
+            // update oAuth2Parameters with validated authorization details
+            oAuth2Parameters.setAuthorizationDetails(oAuthAuthzReqMessageContext.getRequestedAuthorizationDetails());
+
             if (LoggerUtils.isDiagnosticLogsEnabled()) {
                 DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder(
                         OAuthConstants.LogConstants.OAUTH_INBOUND_SERVICE,
diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml
index 7b74c4df18..5af7f05e05 100644
--- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml
+++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml
@@ -44,6 +44,12 @@
             provided
         
 
+        
+            org.wso2.carbon.identity.framework
+            org.wso2.carbon.identity.api.resource.mgt
+            provided
+        
+
         
             com.fasterxml.jackson.core
             jackson-databind
diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java
index be49e2c822..eddef973d4 100644
--- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java
+++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAO.java
@@ -45,6 +45,18 @@ public interface AuthorizationDetailsDAO {
     int[] addUserConsentedAuthorizationDetails(Set authorizationDetailsConsentDTOs)
             throws SQLException;
 
+    /**
+     * Updates user consented authorization details in the database.
+     *
+     * @param authorizationDetailsConsentDTOs A set of user consented authorization details DTOs.
+     *                                        {@link AuthorizationDetailsConsentDTO }
+     * @return An array of positive integers indicating the number of rows affected for each batch operation,
+     * or negative integers if any of the batch operations fail.
+     * @throws SQLException If a database access error occurs.
+     */
+    int[] updateUserConsentedAuthorizationDetails(Set authorizationDetailsConsentDTOs)
+            throws SQLException;
+
     /**
      * Retrieves user consented authorization details from the database.
      *
@@ -114,7 +126,7 @@ int[] addOAuth2CodeAuthorizationDetails(Set authori
      * Retrieves authorization code authorization details from the database.
      *
      * @param authorizationCode The value of the authorization code.
-     * @param tenantId      The tenant ID.
+     * @param tenantId          The tenant ID.
      * @return A set of authorization code authorization details DTOs.
      * @throws SQLException If a database access error occurs.
      */
diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java
index fc9682292e..4af816fbba 100644
--- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java
+++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java
@@ -30,6 +30,8 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import static org.wso2.carbon.identity.api.resource.mgt.util.AuthorizationDetailsTypesUtil.isRichAuthorizationRequestsDisabled;
+
 /**
  * Implements the {@link AuthorizationDetailsDAO} interface to manage rich authorization requests.
  *
@@ -42,14 +44,18 @@ public class AuthorizationDetailsDAOImpl implements AuthorizationDetailsDAO {
      * {@inheritDoc}
      */
     @Override
-    public int[] addUserConsentedAuthorizationDetails(
-            final Set authorizationDetailsConsentDTOs) throws SQLException {
+    public int[] addUserConsentedAuthorizationDetails(final Set consentDTOs)
+            throws SQLException {
+
+        if (isRichAuthorizationRequestsDisabled()) {
+            return new int[0];
+        }
 
         try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
              PreparedStatement ps =
                      connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) {
 
-            for (AuthorizationDetailsConsentDTO consentDTO : authorizationDetailsConsentDTOs) {
+            for (AuthorizationDetailsConsentDTO consentDTO : consentDTOs) {
                 ps.setString(1, consentDTO.getConsentId());
                 ps.setString(2, consentDTO.getAuthorizationDetail().toJsonString());
                 ps.setBoolean(3, consentDTO.isConsentActive());
@@ -62,6 +68,34 @@ public int[] addUserConsentedAuthorizationDetails(
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int[] updateUserConsentedAuthorizationDetails(final Set consentDTOs)
+            throws SQLException {
+
+        if (isRichAuthorizationRequestsDisabled()) {
+            return new int[0];
+        }
+
+        try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
+             PreparedStatement ps =
+                     connection.prepareStatement(SQLQueries.UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) {
+
+            for (AuthorizationDetailsConsentDTO consentDTO : consentDTOs) {
+                ps.setString(1, consentDTO.getAuthorizationDetail().toJsonString());
+                ps.setBoolean(2, consentDTO.isConsentActive());
+                ps.setString(3, consentDTO.getConsentId());
+                ps.setString(4, consentDTO.getAuthorizationDetail().getType());
+                ps.setInt(5, consentDTO.getTenantId());
+                ps.setInt(6, consentDTO.getTenantId());
+                ps.addBatch();
+            }
+            return ps.executeBatch();
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -70,6 +104,11 @@ public Set getUserConsentedAuthorizationDetails(
                                                                                     final int tenantId)
             throws SQLException {
 
+        final Set authorizationDetailsConsentDTOs = new HashSet<>();
+        if (isRichAuthorizationRequestsDisabled()) {
+            return authorizationDetailsConsentDTOs;
+        }
+
         try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
              final PreparedStatement ps =
                      connection.prepareStatement(SQLQueries.GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) {
@@ -78,7 +117,6 @@ public Set getUserConsentedAuthorizationDetails(
             ps.setInt(2, tenantId);
             try (ResultSet rs = ps.executeQuery()) {
 
-                final Set authorizationDetailsConsentDTOs = new HashSet<>();
                 while (rs.next()) {
                     final String id = rs.getString(1);
                     final String typeId = rs.getString(2);
@@ -100,6 +138,10 @@ public Set getUserConsentedAuthorizationDetails(
     public int deleteUserConsentedAuthorizationDetails(final String consentId, final int tenantId)
             throws SQLException {
 
+        if (isRichAuthorizationRequestsDisabled()) {
+            return -1;
+        }
+
         try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
              final PreparedStatement ps =
                      connection.prepareStatement(SQLQueries.DELETE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) {
@@ -114,13 +156,18 @@ public int deleteUserConsentedAuthorizationDetails(final String consentId, final
      * {@inheritDoc}
      */
     @Override
-    public int[] addAccessTokenAuthorizationDetails(final Set
-                                                            authorizationDetailsTokenDTOs) throws SQLException {
+    public int[] addAccessTokenAuthorizationDetails(final Set tokenDTOs)
+            throws SQLException {
+
+        if (isRichAuthorizationRequestsDisabled()) {
+            return new int[0];
+        }
+
         try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
              final PreparedStatement ps =
                      connection.prepareStatement(SQLQueries.ADD_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) {
 
-            for (AuthorizationDetailsTokenDTO tokenDTO : authorizationDetailsTokenDTOs) {
+            for (AuthorizationDetailsTokenDTO tokenDTO : tokenDTOs) {
                 ps.setString(1, tokenDTO.getAccessTokenId());
                 ps.setString(2, tokenDTO.getAuthorizationDetail().toJsonString());
                 ps.setString(3, tokenDTO.getAuthorizationDetail().getType());
@@ -140,6 +187,11 @@ public Set getAccessTokenAuthorizationDetails(fina
                                                                                 final int tenantId)
             throws SQLException {
 
+        final Set authorizationDetailsTokenDTO = new HashSet<>();
+        if (isRichAuthorizationRequestsDisabled()) {
+            return authorizationDetailsTokenDTO;
+        }
+
         try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
              final PreparedStatement ps =
                      connection.prepareStatement(SQLQueries.GET_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) {
@@ -148,7 +200,6 @@ public Set getAccessTokenAuthorizationDetails(fina
             ps.setInt(2, tenantId);
             try (ResultSet rs = ps.executeQuery()) {
 
-                final Set authorizationDetailsTokenDTO = new HashSet<>();
                 while (rs.next()) {
                     final String id = rs.getString(1);
                     final String typeId = rs.getString(2);
@@ -169,6 +220,10 @@ public Set getAccessTokenAuthorizationDetails(fina
     public int deleteAccessTokenAuthorizationDetails(final String accessTokenId, final int tenantId)
             throws SQLException {
 
+        if (isRichAuthorizationRequestsDisabled()) {
+            return -1;
+        }
+
         try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
              final PreparedStatement ps =
                      connection.prepareStatement(SQLQueries.DELETE_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) {
@@ -186,6 +241,10 @@ public int deleteAccessTokenAuthorizationDetails(final String accessTokenId, fin
     public int[] addOAuth2CodeAuthorizationDetails(final Set authorizationDetailsCodeDTOs)
             throws SQLException {
 
+        if (isRichAuthorizationRequestsDisabled()) {
+            return new int[0];
+        }
+
         try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
              final PreparedStatement ps =
                      connection.prepareStatement(SQLQueries.ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS)) {
@@ -209,6 +268,11 @@ public int[] addOAuth2CodeAuthorizationDetails(final Set getOAuth2CodeAuthorizationDetails(final String authorizationCode,
                                                                               final int tenantId) throws SQLException {
 
+        final Set authorizationDetailsCodeDTOs = new HashSet<>();
+        if (isRichAuthorizationRequestsDisabled()) {
+            return authorizationDetailsCodeDTOs;
+        }
+
         try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false);
              final PreparedStatement ps =
                      connection.prepareStatement(SQLQueries.GET_OAUTH2_CODE_AUTHORIZATION_DETAILS_BY_CODE)) {
@@ -217,7 +281,6 @@ public Set getOAuth2CodeAuthorizationDetails(final
             ps.setInt(2, tenantId);
             try (ResultSet rs = ps.executeQuery()) {
 
-                final Set authorizationDetailsCodeDTOs = new HashSet<>();
                 while (rs.next()) {
                     final String codeId = rs.getString(1);
                     final String typeId = rs.getString(2);
diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java
index 3582c3babf..ef901d0bd9 100644
--- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java
+++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/SQLQueries.java
@@ -36,6 +36,11 @@ private SQLQueries() {
                     "(CONSENT_ID, AUTHORIZATION_DETAILS, CONSENT, TYPE_ID, TENANT_ID) " +
                     "VALUES (?, ?, ?, (" + SELECT_AUTHORIZATION_DETAILS_ID_BY_TYPE + "), ?)";
 
+    public static final String UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS =
+            "UPDATE IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " +
+                    "SET AUTHORIZATION_DETAILS=?, CONSENT=? " +
+                    "WHERE CONSENT_ID=? AND TYPE_ID=(" + SELECT_AUTHORIZATION_DETAILS_ID_BY_TYPE + ") AND TENANT_ID=?";
+
     public static final String GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS =
             "SELECT ID, TYPE_ID, AUTHORIZATION_DETAILS, CONSENT FROM IDN_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS " +
                     "WHERE CONSENT_ID=? AND TENANT_ID=?";
diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java
index 7dd3648d94..f51555d8e6 100644
--- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java
+++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java
@@ -18,12 +18,15 @@
 
 package org.wso2.carbon.identity.oauth2.rar.dao;
 
+import org.apache.commons.lang3.StringUtils;
 import org.mockito.MockedStatic;
 import org.mockito.Mockito;
+import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
+import org.wso2.carbon.identity.api.resource.mgt.util.AuthorizationDetailsTypesUtil;
 import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
 import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsCodeDTO;
 import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO;
@@ -35,6 +38,7 @@
 import java.sql.SQLException;
 import java.util.Collections;
 import java.util.Set;
+import java.util.UUID;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -48,6 +52,7 @@
 import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TENANT_ID;
 import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TOKEN_ID;
 import static org.wso2.carbon.identity.oauth2.rar.util.TestConstants.TEST_TYPE;
+import static org.wso2.carbon.identity.oauth2.rar.util.TestDAOUtils.closeMockedStatic;
 
 /**
  * Test class for {@link AuthorizationDetailsDAO}.
@@ -55,6 +60,7 @@
 public class AuthorizationDetailsDAOImplTest {
 
     private MockedStatic identityDatabaseUtilMock;
+    private MockedStatic authorizationDetailsTypesUtilMock;
     private AuthorizationDetailsDAO uut;
 
     @BeforeClass
@@ -62,22 +68,21 @@ public void setUp() throws SQLException {
         this.uut = new AuthorizationDetailsDAOImpl();
         TestDAOUtils.initializeDataSource(TEST_DB_NAME, TestDAOUtils.getFilePath("h2.sql"));
         this.identityDatabaseUtilMock = Mockito.mockStatic(IdentityDatabaseUtil.class);
+        this.authorizationDetailsTypesUtilMock = Mockito.mockStatic(AuthorizationDetailsTypesUtil.class);
     }
 
     @AfterClass
     public void tearDown() throws SQLException {
 
-        if (this.identityDatabaseUtilMock != null && !this.identityDatabaseUtilMock.isClosed()) {
-            this.identityDatabaseUtilMock.close();
-        }
+        closeMockedStatic(this.identityDatabaseUtilMock);
+        closeMockedStatic(this.authorizationDetailsTypesUtilMock);
     }
 
     @BeforeMethod
     public void setUpBeforeMethod() throws SQLException {
 
-        this.identityDatabaseUtilMock
-                .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class)))
-                .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME));
+        this.mockIdentityDatabaseUtil();
+        this.mockAuthorizationDetailsTypesUtil(true);
     }
 
     @Test
@@ -85,9 +90,7 @@ public void testAddUserConsentedAuthorizationDetails() throws SQLException {
 
         assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size());
 
-        this.identityDatabaseUtilMock
-                .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class)))
-                .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME));
+        this.mockIdentityDatabaseUtil();
 
         AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail();
         testAuthorizationDetail.setType(TEST_TYPE);
@@ -114,13 +117,43 @@ public void testGetUserConsentedAuthorizationDetails() throws SQLException {
     }
 
     @Test(priority = 2)
+    public void testUpdateUserConsentedAuthorizationDetails() throws SQLException {
+
+        final String identifier = UUID.randomUUID().toString();
+        Set existingConsentDTOs =
+                this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID);
+
+        this.mockIdentityDatabaseUtil();
+
+        AuthorizationDetailsConsentDTO existingDTO = existingConsentDTOs.iterator().next();
+        Assert.assertTrue(StringUtils.isEmpty(existingDTO.getAuthorizationDetail().getIdentifier()));
+
+        AuthorizationDetail authorizationDetailToUpdate = existingDTO.getAuthorizationDetail();
+        authorizationDetailToUpdate.setIdentifier(identifier);
+
+        AuthorizationDetailsConsentDTO consentDTO = new AuthorizationDetailsConsentDTO(existingDTO.getConsentId(),
+                authorizationDetailToUpdate, existingDTO.isConsentActive(), existingDTO.getTenantId());
+
+        int[] result = uut.updateUserConsentedAuthorizationDetails(Collections.singleton(consentDTO));
+        assertEquals(1, result.length);
+
+        this.mockIdentityDatabaseUtil();
+
+        Set updatedConsentDTOs =
+                this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID);
+        AuthorizationDetailsConsentDTO updatedDto = updatedConsentDTOs.iterator().next();
+
+        assertEquals(existingConsentDTOs.size(), updatedConsentDTOs.size());
+        assertEquals(existingDTO.getAuthorizationDetail().getType(), updatedDto.getAuthorizationDetail().getType());
+        assertEquals(identifier, updatedDto.getAuthorizationDetail().getIdentifier());
+    }
+
+    @Test(dependsOnMethods = "testUpdateUserConsentedAuthorizationDetails")
     public void testDeleteUserConsentedAuthorizationDetails() throws SQLException {
 
         assertEquals(1, uut.deleteUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID));
 
-        this.identityDatabaseUtilMock
-                .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class)))
-                .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME));
+        this.mockIdentityDatabaseUtil();
 
         assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size());
     }
@@ -129,9 +162,7 @@ public void testDeleteUserConsentedAuthorizationDetails() throws SQLException {
     public void testAddAccessTokenAuthorizationDetails() throws SQLException {
         assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size());
 
-        this.identityDatabaseUtilMock
-                .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class)))
-                .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME));
+        this.mockIdentityDatabaseUtil();
 
         AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail();
         testAuthorizationDetail.setType(TEST_TYPE);
@@ -161,9 +192,7 @@ public void testGetAccessTokenAuthorizationDetails() throws SQLException {
     public void testDeleteAccessTokenAuthorizationDetails() throws SQLException {
         assertEquals(1, uut.deleteAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID));
 
-        this.identityDatabaseUtilMock
-                .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class)))
-                .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME));
+        this.mockIdentityDatabaseUtil();
 
         assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size());
     }
@@ -172,9 +201,7 @@ public void testDeleteAccessTokenAuthorizationDetails() throws SQLException {
     public void testAddOAuth2CodeAuthorizationDetails() throws SQLException {
         assertEquals(0, this.uut.getOAuth2CodeAuthorizationDetails(TEST_CODE_ID, TEST_TENANT_ID).size());
 
-        this.identityDatabaseUtilMock
-                .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class)))
-                .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME));
+        this.mockIdentityDatabaseUtil();
 
         AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail();
         testAuthorizationDetail.setType(TEST_TYPE);
@@ -237,4 +264,48 @@ public void shouldReturnNull_whenUserIdOrAppIdInvalid() throws SQLException {
 
         assertNull(this.uut.getConsentIdByUserIdAndAppId("invalid_user_id", "invalid_app_id", TEST_TENANT_ID));
     }
+
+    @Test
+    public void testUserConsentedAuthorizationDetailsWhenFeatureIsDisabled() throws SQLException {
+
+        this.mockAuthorizationDetailsTypesUtil(false);
+
+        assertEquals(0, this.uut.addUserConsentedAuthorizationDetails(Collections.emptySet()).length);
+        assertEquals(0, this.uut.updateUserConsentedAuthorizationDetails(Collections.emptySet()).length);
+        assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size());
+        assertEquals(-1, this.uut.deleteUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID));
+    }
+
+    @Test
+    public void testAccessTokenAuthorizationDetailsWhenFeatureIsDisabled() throws SQLException {
+
+        this.mockAuthorizationDetailsTypesUtil(false);
+
+        assertEquals(0, uut.addAccessTokenAuthorizationDetails(Collections.emptySet()).length);
+        assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size());
+        assertEquals(-1, this.uut.deleteAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID));
+    }
+
+    @Test
+    public void testOAuth2CodeAuthorizationDetailsWhenFeatureIsDisabled() throws SQLException {
+
+        this.mockAuthorizationDetailsTypesUtil(false);
+
+        assertEquals(0, uut.addOAuth2CodeAuthorizationDetails(Collections.emptySet()).length);
+        assertEquals(0, this.uut.getOAuth2CodeAuthorizationDetails(TEST_AUTHORIZATION_CODE, TEST_TENANT_ID).size());
+    }
+
+    private void mockAuthorizationDetailsTypesUtil(boolean isRichAuthorizationRequestsEnabled) {
+
+        this.authorizationDetailsTypesUtilMock
+                .when(AuthorizationDetailsTypesUtil::isRichAuthorizationRequestsDisabled)
+                .thenReturn(!isRichAuthorizationRequestsEnabled);
+    }
+
+    private void mockIdentityDatabaseUtil() throws SQLException {
+
+        this.identityDatabaseUtilMock
+                .when(() -> IdentityDatabaseUtil.getDBConnection(any(Boolean.class)))
+                .thenReturn(TestDAOUtils.getConnection(TEST_DB_NAME));
+    }
 }
diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java
index fe2e3b0dd8..d9fd51e2f1 100644
--- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java
+++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/util/TestDAOUtils.java
@@ -20,6 +20,7 @@
 
 import org.apache.commons.dbcp.BasicDataSource;
 import org.apache.commons.lang.StringUtils;
+import org.mockito.MockedStatic;
 import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail;
 
 import java.nio.file.Paths;
@@ -66,6 +67,13 @@ public static String getFilePath(String fileName) {
         return null;
     }
 
+    public static void closeMockedStatic(final MockedStatic mockedStatic) {
+
+        if (mockedStatic != null && !mockedStatic.isClosed()) {
+            mockedStatic.close();
+        }
+    }
+
     /**
      * Test authorization detail class which extends AuthorizationDetail
      */
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java
index a9f1307804..c2c0d44ecf 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManager.java
@@ -41,7 +41,6 @@
 import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO;
 import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO;
 import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters;
-import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils;
 import org.wso2.carbon.identity.oauth2.util.AuthzUtil;
 import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
 import org.wso2.carbon.identity.oauth2.validators.DefaultOAuth2ScopeValidator;
@@ -256,7 +255,6 @@ public OAuth2AuthorizeRespDTO handleAuthorization(OAuthAuthzReqMessageContext au
             // set the authorization request context to be used by downstream handlers. This is introduced as a fix for
             // IDENTITY-4111
             OAuth2Util.setAuthzRequestContext(authzReqMsgCtx);
-            AuthorizationDetailsUtils.setRARPropertiesToAuthzRequestContext(authzReqMsgCtx);
             authorizeRespDTO = authzHandler.issue(authzReqMsgCtx);
         } finally {
             // clears authorization request context
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java
index 8b7cc822f4..8b4e677500 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/OAuthAuthzReqMessageContext.java
@@ -57,7 +57,9 @@ public class OAuthAuthzReqMessageContext implements Serializable {
 
     private Properties properties = new Properties();
 
-    private AuthorizationDetails authorizationDetails;
+    private AuthorizationDetails approvedAuthorizationDetails;
+
+    private AuthorizationDetails requestedAuthorizationDetails;
 
     public OAuthAuthzReqMessageContext(OAuth2AuthorizeReqDTO authorizationReqDTO) {
 
@@ -217,24 +219,46 @@ public void setSubjectTokenFlow(boolean subjectTokenFlow) {
     }
 
     /**
-     * Retrieves the current authorization details.
+     * Retrieves the user approved authorization details.
+     *
+     * @return the {@link AuthorizationDetails} instance representing the approved authorization information.
+     * If no authorization details are available, it will return {@code null}.
+     */
+    public AuthorizationDetails getApprovedAuthorizationDetails() {
+
+        return this.approvedAuthorizationDetails;
+    }
+
+    /**
+     * Sets the approved authorization details.
+     * This method updates the approved authorization details with the provided {@link AuthorizationDetails} instance.
+     *
+     * @param approvedAuthorizationDetails the approved {@link AuthorizationDetails} to set.
+     */
+    public void setApprovedAuthorizationDetails(final AuthorizationDetails approvedAuthorizationDetails) {
+
+        this.approvedAuthorizationDetails = approvedAuthorizationDetails;
+    }
+
+    /**
+     * Retrieves the requested authorization details.
      *
-     * @return the {@link AuthorizationDetails} instance representing the current authorization information.
+     * @return the {@link AuthorizationDetails} instance representing the authorization information came in the request.
      * If no authorization details are available, it will return {@code null}.
      */
-    public AuthorizationDetails getAuthorizationDetails() {
+    public AuthorizationDetails getRequestedAuthorizationDetails() {
 
-        return this.authorizationDetails;
+        return this.requestedAuthorizationDetails;
     }
 
     /**
-     * Sets the authorization details.
-     * This method updates the authorization details with the provided {@link AuthorizationDetails} instance.
+     * Sets the requested authorization details.
+     * This method updates the requested authorization details with the provided {@link AuthorizationDetails} instance.
      *
-     * @param authorizationDetails the {@link AuthorizationDetails} to set.
+     * @param requestedAuthorizationDetails the requested {@link AuthorizationDetails} to set.
      */
-    public void setAuthorizationDetails(final AuthorizationDetails authorizationDetails) {
+    public void setRequestedAuthorizationDetails(final AuthorizationDetails requestedAuthorizationDetails) {
 
-        this.authorizationDetails = authorizationDetails;
+        this.requestedAuthorizationDetails = requestedAuthorizationDetails;
     }
 }
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java
index 4be8704f12..89c099d9a2 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/AbstractResponseTypeHandler.java
@@ -225,7 +225,7 @@ public OAuth2AuthorizeRespDTO initResponse(OAuthAuthzReqMessageContext oauthAuth
         OAuth2AuthorizeReqDTO authorizationReqDTO = oauthAuthzMsgCtx.getAuthorizationReqDTO();
         respDTO.setCallbackURI(authorizationReqDTO.getCallbackUrl());
         respDTO.setScope(oauthAuthzMsgCtx.getApprovedScope());
-        respDTO.setAuthorizationDetails(oauthAuthzMsgCtx.getAuthorizationDetails());
+        respDTO.setAuthorizationDetails(oauthAuthzMsgCtx.getApprovedAuthorizationDetails());
         return respDTO;
     }
 
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java
index 11e412a9d2..cf1ad3ea89 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java
@@ -18,6 +18,7 @@
 
 package org.wso2.carbon.identity.oauth2.rar;
 
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
@@ -47,8 +48,8 @@
 import java.util.Optional;
 import java.util.Set;
 
-import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.getAuthorizationDetailsConsentDTOs;
 import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.getAuthorizationDetailsTypesMap;
+import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.isEmpty;
 import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils.isRichAuthorizationRequest;
 
 /**
@@ -94,14 +95,15 @@ public AuthorizationDetailsService() {
     public AuthorizationDetailsService(final AuthorizationDetailsProcessorFactory authorizationDetailsProcessorFactory,
                                        final AuthorizationDetailsDAO authorizationDetailsDAO) {
 
-        this.authorizationDetailsDAO = Objects
-                .requireNonNull(authorizationDetailsDAO, "AuthorizationDetailsDAO must not be null");
+        this.authorizationDetailsDAO =
+                Objects.requireNonNull(authorizationDetailsDAO, "AuthorizationDetailsDAO must not be null");
         this.authorizationDetailsProcessorFactory = Objects.requireNonNull(authorizationDetailsProcessorFactory,
                 "AuthorizationDetailsProviderFactory must not be null");
     }
 
     /**
-     * Stores user-consented authorization details.
+     * Persists or updates user-consented authorization details. If previously stored authorization details are found,
+     * they are updated with the new information.
      *
      * @param authenticatedUser                 The authenticated user.
      * @param clientId                          The client ID.
@@ -109,9 +111,9 @@ public AuthorizationDetailsService(final AuthorizationDetailsProcessorFactory au
      * @param userConsentedAuthorizationDetails User consented authorization details.
      * @throws OAuthSystemException if an error occurs while storing user consented authorization details.
      */
-    public void storeUserConsentedAuthorizationDetails(final AuthenticatedUser authenticatedUser, final String clientId,
-                                                       final OAuth2Parameters oAuth2Parameters,
-                                                       final AuthorizationDetails userConsentedAuthorizationDetails)
+    public void storeOrUpdateUserConsentedAuthorizationDetails(
+            final AuthenticatedUser authenticatedUser, final String clientId, final OAuth2Parameters oAuth2Parameters,
+            final AuthorizationDetails userConsentedAuthorizationDetails)
             throws OAuthSystemException {
 
         if (!isRichAuthorizationRequest(oAuth2Parameters)) {
@@ -121,19 +123,48 @@ public void storeUserConsentedAuthorizationDetails(final AuthenticatedUser authe
 
         try {
             final int tenantId = OAuth2Util.getTenantId(oAuth2Parameters.getTenantDomain());
-            final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId);
+            final Optional optConsentId = this.getConsentId(authenticatedUser, clientId, tenantId);
 
-            if (consentId.isPresent()) {
-                final AuthorizationDetails trimmedAuthorizationDetails = AuthorizationDetailsUtils
-                        .getTrimmedAuthorizationDetails(userConsentedAuthorizationDetails);
+            if (!optConsentId.isPresent()) {
+                if (log.isDebugEnabled()) {
+                    log.debug(String.format("Unable to find a consent for userId %s and appId %s",
+                            authenticatedUser.getLoggableMaskedUserId(), clientId));
+                }
+                return;
+            }
 
-                final Set authorizationDetailsConsentDTOs =
-                        getAuthorizationDetailsConsentDTOs(consentId.get(), trimmedAuthorizationDetails, tenantId);
+            final String consentId = optConsentId.get();
+            final Set authorizationDetailsToBeUpdated = new HashSet<>();
+            final Set authorizationDetailsToBeAdded = new HashSet<>();
 
-                this.authorizationDetailsDAO.addUserConsentedAuthorizationDetails(authorizationDetailsConsentDTOs);
+            final AuthorizationDetails trimmedAuthorizationDetails = AuthorizationDetailsUtils
+                    .getTrimmedAuthorizationDetails(userConsentedAuthorizationDetails);
+            final Map> consentedAuthorizationDetailsByType =
+                    getAuthorizationDetailsTypesMap(this.getUserConsentedAuthorizationDetails(consentId, tenantId));
+
+            // Determine new authorization details to add or update based on the existing user consent
+            trimmedAuthorizationDetails.stream().forEach(authorizationDetail -> {
+                final AuthorizationDetailsConsentDTO authorizationDetailsConsentDTO =
+                        new AuthorizationDetailsConsentDTO(consentId, authorizationDetail, true, tenantId);
+
+                if (isUserConsentedAuthorizationDetailsType(authorizationDetail, consentedAuthorizationDetailsByType)) {
+                    authorizationDetailsToBeUpdated.add(authorizationDetailsConsentDTO);
+                } else {
+                    authorizationDetailsToBeAdded.add(authorizationDetailsConsentDTO);
+                }
+            });
+
+            if (CollectionUtils.isNotEmpty(authorizationDetailsToBeUpdated)) {
+                this.authorizationDetailsDAO.updateUserConsentedAuthorizationDetails(authorizationDetailsToBeUpdated);
                 if (log.isDebugEnabled()) {
-                    log.debug("User consented authorization details stored successfully. consentId: " +
-                            consentId.get());
+                    log.debug("User consented authorization details updated. consentId: " + consentId);
+                }
+            }
+
+            if (CollectionUtils.isNotEmpty(authorizationDetailsToBeAdded)) {
+                this.authorizationDetailsDAO.addUserConsentedAuthorizationDetails(authorizationDetailsToBeAdded);
+                if (log.isDebugEnabled()) {
+                    log.debug("User consented authorization details stored. consentId: " + consentId);
                 }
             }
         } catch (SQLException | IdentityOAuth2Exception e) {
@@ -192,7 +223,7 @@ public void replaceUserConsentedAuthorizationDetails(
             final AuthorizationDetails userConsentedAuthorizationDetails) throws OAuthSystemException {
 
         this.deleteUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters);
-        this.storeUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters,
+        this.storeOrUpdateUserConsentedAuthorizationDetails(authenticatedUser, clientId, oAuth2Parameters,
                 userConsentedAuthorizationDetails);
     }
 
@@ -212,7 +243,7 @@ public boolean isUserAlreadyConsentedForAuthorizationDetails(final Authenticated
             return true;
         }
 
-        return this.getConsentRequiredAuthorizationDetails(authenticatedUser, oAuth2Parameters).getDetails().isEmpty();
+        return isEmpty(this.getConsentRequiredAuthorizationDetails(authenticatedUser, oAuth2Parameters));
     }
 
     public AuthorizationDetails getConsentRequiredAuthorizationDetails(final AuthenticatedUser authenticatedUser,
@@ -224,8 +255,8 @@ public AuthorizationDetails getConsentRequiredAuthorizationDetails(final Authent
             return new AuthorizationDetails();
         }
 
-        final Map> consentedAuthorizationDetailsByType =
-                this.getUserConsentedAuthorizationDetailsByType(authenticatedUser, oAuth2Parameters);
+        Map> consentedAuthorizationDetailsByType = getAuthorizationDetailsTypesMap(
+                this.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters));
 
         final Set consentRequiredAuthorizationDetails = new HashSet<>();
         oAuth2Parameters.getAuthorizationDetails().stream()
@@ -236,14 +267,6 @@ public AuthorizationDetails getConsentRequiredAuthorizationDetails(final Authent
         return new AuthorizationDetails(consentRequiredAuthorizationDetails);
     }
 
-    private Map> getUserConsentedAuthorizationDetailsByType(
-            final AuthenticatedUser authenticatedUser, final OAuth2Parameters oAuth2Parameters)
-            throws IdentityOAuth2Exception {
-
-        return getAuthorizationDetailsTypesMap(
-                this.getUserConsentedAuthorizationDetails(authenticatedUser, oAuth2Parameters));
-    }
-
     /**
      * Checks if the user has already consented to the requested authorization detail.
      *
@@ -258,15 +281,12 @@ private boolean isUserConsentedAuthorizationDetail(
             final AuthorizationDetail requestedAuthorizationDetail,
             final Map> consentedAuthorizationDetailsByType) {
 
-        final String requestedType = requestedAuthorizationDetail.getType();
-        if (!consentedAuthorizationDetailsByType.containsKey(requestedType)) {
-            if (log.isDebugEnabled()) {
-                log.debug(String.format("User hasn't consented for the requested authorization details type '%s'.",
-                        requestedType));
-            }
+        if (!this.isUserConsentedAuthorizationDetailsType(requestedAuthorizationDetail,
+                consentedAuthorizationDetailsByType)) {
             return false;
         }
 
+        final String requestedType = requestedAuthorizationDetail.getType();
         final Optional optProcessor =
                 this.authorizationDetailsProcessorFactory.getAuthorizationDetailsProcessorByType(requestedType);
 
@@ -295,6 +315,20 @@ private boolean isUserConsentedAuthorizationDetail(
         return false;
     }
 
+    private boolean isUserConsentedAuthorizationDetailsType(
+            final AuthorizationDetail requestedAuthorizationDetail,
+            final Map> consentedAuthorizationDetailsByType) {
+
+        if (consentedAuthorizationDetailsByType.containsKey(requestedAuthorizationDetail.getType())) {
+            return true;
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(String.format("User hasn't consented for the requested authorization details type '%s'",
+                    requestedAuthorizationDetail.getType()));
+        }
+        return false;
+    }
+
     /**
      * Retrieves the user consented authorization details for a given user and OAuth2 parameters.
      *
@@ -324,22 +358,28 @@ public AuthorizationDetails getUserConsentedAuthorizationDetails(
             final AuthenticatedUser authenticatedUser, final String clientId, final int tenantId)
             throws IdentityOAuth2Exception {
 
+        final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId);
+        if (consentId.isPresent()) {
+            return this.getUserConsentedAuthorizationDetails(consentId.get(), tenantId);
+        }
+        return null;
+    }
+
+    public AuthorizationDetails getUserConsentedAuthorizationDetails(final String consentId, final int tenantId)
+            throws IdentityOAuth2Exception {
+
         try {
-            final Optional consentId = this.getConsentId(authenticatedUser, clientId, tenantId);
-            if (consentId.isPresent()) {
-                final Set consentedAuthorizationDetails = new HashSet<>();
-                this.authorizationDetailsDAO.getUserConsentedAuthorizationDetails(consentId.get(), tenantId)
-                        .stream()
-                        .filter(AuthorizationDetailsConsentDTO::isConsentActive)
-                        .map(AuthorizationDetailsConsentDTO::getAuthorizationDetail)
-                        .forEach(consentedAuthorizationDetails::add);
-                return new AuthorizationDetails(consentedAuthorizationDetails);
-            }
+            final Set consentedAuthorizationDetails = new HashSet<>();
+            this.authorizationDetailsDAO.getUserConsentedAuthorizationDetails(consentId, tenantId)
+                    .stream()
+                    .filter(AuthorizationDetailsConsentDTO::isConsentActive)
+                    .map(AuthorizationDetailsConsentDTO::getAuthorizationDetail)
+                    .forEach(consentedAuthorizationDetails::add);
+            return new AuthorizationDetails(consentedAuthorizationDetails);
         } catch (SQLException e) {
             log.error("Error occurred while retrieving user consented authorization details. Caused by, ", e);
             throw new IdentityOAuth2Exception("Unable to retrieve user consented authorization details", e);
         }
-        return null;
     }
 
     /**
@@ -422,12 +462,13 @@ public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessToken
                                                      final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext)
             throws IdentityOAuth2Exception {
 
-        if (!isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) {
+        if (!isRichAuthorizationRequest(oAuthAuthzReqMessageContext.getApprovedAuthorizationDetails())) {
             log.debug("Request is not a rich authorization request. Skipping storage of token authorization details.");
             return;
         }
 
-        this.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthAuthzReqMessageContext.getAuthorizationDetails());
+        this.storeAccessTokenAuthorizationDetails(accessTokenDO,
+                oAuthAuthzReqMessageContext.getApprovedAuthorizationDetails());
     }
 
     /**
@@ -441,6 +482,10 @@ public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessToken
                                                      final AuthorizationDetails authorizationDetails)
             throws IdentityOAuth2Exception {
 
+        if (AuthorizationDetailsUtils.isEmpty(authorizationDetails)) {
+            return;
+        }
+
         try {
             final AuthorizationDetails trimmedAuthorizationDetails = AuthorizationDetailsUtils
                     .getTrimmedAuthorizationDetails(authorizationDetails);
@@ -498,8 +543,8 @@ public void deleteAccessTokenAuthorizationDetails(final String accessTokenId, fi
             throws IdentityOAuth2Exception {
 
         try {
-            this.authorizationDetailsDAO.deleteAccessTokenAuthorizationDetails(accessTokenId, tenantId);
-            if (log.isDebugEnabled()) {
+            int result = this.authorizationDetailsDAO.deleteAccessTokenAuthorizationDetails(accessTokenId, tenantId);
+            if (result > 0 && log.isDebugEnabled()) {
                 log.debug("Access token authorization details deleted successfully. accessTokenId: " + accessTokenId);
             }
         } catch (SQLException e) {
@@ -570,7 +615,7 @@ public void storeAuthorizationCodeAuthorizationDetails(
 
             final Set authorizationDetailsCodeDTOs =
                     AuthorizationDetailsUtils.getCodeAuthorizationDetailsDTOs(authzCodeDO,
-                            oAuthAuthzReqMessageContext.getAuthorizationDetails(), tenantId);
+                            oAuthAuthzReqMessageContext.getApprovedAuthorizationDetails(), tenantId);
 
             // Storing the authorization details.
             this.authorizationDetailsDAO.addOAuth2CodeAuthorizationDetails(authorizationDetailsCodeDTOs);
@@ -588,17 +633,17 @@ public void storeAuthorizationCodeAuthorizationDetails(
     /**
      * Retrieves the authorization details associated with a given authorization code Id.
      *
-     * @param codeId   The authorization code ID.
+     * @param code     The authorization code.
      * @param tenantId The tenant ID.
      * @return The authorization code authorization details.
      * @throws IdentityOAuth2Exception If an error occurs while retrieving the details.
      */
-    public AuthorizationDetails getAuthorizationCodeAuthorizationDetails(final String codeId, final int tenantId)
+    public AuthorizationDetails getAuthorizationCodeAuthorizationDetails(final String code, final int tenantId)
             throws IdentityOAuth2Exception {
 
         try {
             final Set authorizationDetailsCodeDTOs =
-                    this.authorizationDetailsDAO.getOAuth2CodeAuthorizationDetails(codeId, tenantId);
+                    this.authorizationDetailsDAO.getOAuth2CodeAuthorizationDetails(code, tenantId);
 
             final Set codeAuthorizationDetails = new HashSet<>();
             authorizationDetailsCodeDTOs
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java
index 3743515386..1c55095726 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/core/AuthorizationDetailsProcessorFactory.java
@@ -28,6 +28,7 @@
 
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.ServiceLoader;
@@ -122,11 +123,16 @@ public Set getSupportedAuthorizationDetailTypes() {
 
         final String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain();
         try {
-            return OAuth2ServiceComponentHolder.getInstance().getAuthorizationDetailsTypeManager()
-                    .getAuthorizationDetailsTypes(StringUtils.EMPTY, tenantDomain)
-                    .stream()
-                    .map(AuthorizationDetailsType::getType)
-                    .collect(Collectors.toUnmodifiableSet());
+
+            final List authorizationDetailsTypes = OAuth2ServiceComponentHolder.getInstance()
+                    .getAuthorizationDetailsTypeManager().getAuthorizationDetailsTypes(StringUtils.EMPTY, tenantDomain);
+
+            if (authorizationDetailsTypes != null) {
+                return authorizationDetailsTypes
+                        .stream()
+                        .map(AuthorizationDetailsType::getType)
+                        .collect(Collectors.toUnmodifiableSet());
+            }
         } catch (APIResourceMgtException e) {
             if (log.isDebugEnabled()) {
                 log.debug(String.format("Error occurred while retrieving supported authorization details types " +
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java
index a6d4baa1cd..f2d618e85a 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java
@@ -38,8 +38,8 @@ public Map getAdditionalTokenResponseAttributes(
         if (isRichAuthorizationRequest(oAuthTokenReqMessageContext.getAuthorizationDetails())) {
 
             if (log.isDebugEnabled()) {
-                log.debug("Processing Rich Authorization Request in token flow. authorization_details: " +
-                        oAuthTokenReqMessageContext.getAuthorizationDetails().toJsonString());
+                log.debug("Adding authorization details into the token response: " + oAuthTokenReqMessageContext
+                        .getAuthorizationDetails().toReadableText());
             }
             additionalAttributes.put(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS,
                     oAuthTokenReqMessageContext.getAuthorizationDetails().toSet());
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java
index d429390131..cdbe9c2425 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java
@@ -36,10 +36,10 @@ public Map getAdditionalClaims(final OAuthAuthzReqMessageContext
         if (AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) {
             if (log.isDebugEnabled()) {
                 log.debug("Processing Rich Authorization Request in authorization flow. authorization_details: " +
-                        oAuthAuthzReqMessageContext.getAuthorizationDetails().toJsonString());
+                        oAuthAuthzReqMessageContext.getRequestedAuthorizationDetails().toJsonString());
             }
             additionalClaims.put(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS,
-                    oAuthAuthzReqMessageContext.getAuthorizationDetails().toSet());
+                    oAuthAuthzReqMessageContext.getApprovedAuthorizationDetails().toSet());
         }
         return additionalClaims;
     }
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java
index 5f9cc82d41..ebd9ebdad5 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/util/AuthorizationDetailsUtils.java
@@ -25,11 +25,9 @@
 import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException;
 import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser;
 import org.wso2.carbon.identity.application.common.model.ServiceProvider;
-import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
 import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
 import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext;
 import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO;
-import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder;
 import org.wso2.carbon.identity.oauth2.model.AccessTokenDO;
 import org.wso2.carbon.identity.oauth2.model.AuthzCodeDO;
 import org.wso2.carbon.identity.oauth2.model.CarbonOAuthTokenRequest;
@@ -75,7 +73,7 @@ public class AuthorizationDetailsUtils {
      */
     public static boolean isRichAuthorizationRequest(final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) {
 
-        return isRichAuthorizationRequest(oAuthAuthzReqMessageContext.getAuthorizationDetails());
+        return isRichAuthorizationRequest(oAuthAuthzReqMessageContext.getRequestedAuthorizationDetails());
     }
 
     /**
@@ -313,7 +311,7 @@ public static AuthorizationDetails getDisplayableAuthorizationDetails(
      */
     public static AuthorizationDetails getTrimmedAuthorizationDetails(final AuthorizationDetails authorizationDetails) {
 
-        if (authorizationDetails != null) {
+        if (!isEmpty(authorizationDetails)) {
             authorizationDetails.stream().forEach(authorizationDetail -> {
                 authorizationDetail.setId(null);
                 authorizationDetail.setDescription(null);
@@ -370,31 +368,6 @@ public static String getUrlDecodedAuthorizationDetails(final String encodedAutho
         return StringUtils.EMPTY;
     }
 
-    public static void setRARPropertiesToAuthzRequestContext(
-            final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) throws IdentityOAuth2Exception {
-
-        OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO = oAuthAuthzReqMessageContext.getAuthorizationReqDTO();
-        if (!AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuth2AuthorizeReqDTO)) {
-            if (log.isDebugEnabled()) {
-                log.debug("Request is not a rich authorization request. " +
-                        "Skips adding authorization details to OAuthAuthzReqMessageContext");
-            }
-            return;
-        }
-
-        final AuthorizationDetails authorizationDetails = OAuth2ServiceComponentHolder.getInstance()
-                .getAuthorizationDetailsService()
-                .getUserConsentedAuthorizationDetails(
-                        oAuth2AuthorizeReqDTO.getUser(),
-                        oAuth2AuthorizeReqDTO.getConsumerKey(),
-                        IdentityTenantUtil.getTenantId(oAuth2AuthorizeReqDTO.getTenantDomain())
-                );
-
-        if (authorizationDetails != null) {
-            oAuthAuthzReqMessageContext.setAuthorizationDetails(authorizationDetails);
-        }
-    }
-
     /**
      * Determines if the given {@link OAuth2AuthorizeReqDTO} object contains {@link AuthorizationDetails}.
      *
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java
index cc42caeb32..6dce155dc5 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidator.java
@@ -399,9 +399,9 @@ private boolean isSchemaCompliant(final String type, final AuthorizationDetail a
 
         if (!authorizedDetailsTypes.containsKey(type)) {
             if (log.isDebugEnabled()) {
-                log.debug("Ignoring unauthorized authorization details type: " + type);
+                log.debug("Request received for unauthorized authorization details type: " + type);
             }
-            return false;
+            throw new AuthorizationDetailsProcessingException(VALIDATION_FAILED_ERR_MSG);
         }
 
         if (this.authorizationDetailsSchemaValidator
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java
index 15dd3b7264..c69bcaf991 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandler.java
@@ -58,7 +58,6 @@
 import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder;
 import org.wso2.carbon.identity.oauth2.model.AccessTokenDO;
 import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService;
-import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails;
 import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils;
 import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
 import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuer;
@@ -433,7 +432,7 @@ private OAuth2AccessTokenRespDTO issueExistingAccessToken(OAuthTokenReqMessageCo
                     existingTokenBean.getTokenId(), true);
         }
 
-        if (AuthorizationDetailsUtils.isRichAuthorizationRequest(tokReqMsgCtx)) {
+        if (AuthorizationDetailsUtils.isRichAuthorizationRequest(tokReqMsgCtx.getAuthorizationDetails())) {
             this.authorizationDetailsService.replaceAccessTokenAuthorizationDetails(existingTokenBean.getTokenId(),
                     existingTokenBean, tokReqMsgCtx);
         }
@@ -1239,43 +1238,4 @@ private boolean isFederatedUser(OAuthTokenReqMessageContext tokReqMsgCtx) {
         }
         return tokReqMsgCtx.getAuthorizedUser().isFederatedUser();
     }
-
-    /**
-     * Sets the Rich Authorization Requests (RAR) properties for token generation.
-     * It retrieves the user-consented authorization details or fallback to code authorization details
-     * based on the provided OAuth token request context.
-     *
-     * @param oAuthTokenReqMessageContext Context of the OAuth token request message.
-     * @throws IdentityOAuth2Exception If an error occurs while retrieving authorization details.
-     */
-    protected void setRARPropertiesForTokenGeneration(final OAuthTokenReqMessageContext oAuthTokenReqMessageContext)
-            throws IdentityOAuth2Exception {
-
-        final int tenantId =
-                OAuth2Util.getTenantId(oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getTenantDomain());
-
-        if (log.isDebugEnabled()) {
-            log.debug("Retrieving user consented authorization details for user: "
-                    + oAuthTokenReqMessageContext.getAuthorizedUser().getLoggableMaskedUserId());
-        }
-
-        AuthorizationDetails authorizationDetails = this.authorizationDetailsService
-                .getUserConsentedAuthorizationDetails(
-                        oAuthTokenReqMessageContext.getAuthorizedUser(),
-                        oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getClientId(),
-                        tenantId);
-
-        // Fallback to code authorization details if user consent is unavailable
-        if (authorizationDetails == null) {
-            if (log.isDebugEnabled()) {
-                log.debug("No user consent is available. Fetching authorization details for code: " +
-                        oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getAuthorizationCode());
-            }
-
-            authorizationDetails = this.authorizationDetailsService.getAuthorizationCodeAuthorizationDetails(
-                    oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getAuthorizationCode(), tenantId);
-        }
-        oAuthTokenReqMessageContext.setAuthorizationDetails(AuthorizationDetailsUtils
-                .getTrimmedAuthorizationDetails(authorizationDetails));
-    }
 }
diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AuthorizationCodeGrantHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AuthorizationCodeGrantHandler.java
index e111552248..6c627cb759 100644
--- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AuthorizationCodeGrantHandler.java
+++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AuthorizationCodeGrantHandler.java
@@ -49,6 +49,8 @@
 import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO;
 import org.wso2.carbon.identity.oauth2.model.AccessTokenDO;
 import org.wso2.carbon.identity.oauth2.model.AuthzCodeDO;
+import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails;
+import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils;
 import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
 import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
 import org.wso2.carbon.utils.DiagnosticLog;
@@ -134,7 +136,7 @@ private void setPropertiesForTokenGeneration(OAuthTokenReqMessageContext tokReqM
         // keep the pre processed authz code as a OAuthTokenReqMessageContext property to avoid
         // calculating it again when issuing the access token.
         tokReqMsgCtx.addProperty(AUTHZ_CODE, tokenReq.getAuthorizationCode());
-        super.setRARPropertiesForTokenGeneration(tokReqMsgCtx);
+        this.setRARPropertiesForTokenGeneration(tokReqMsgCtx);
     }
 
     private boolean validateCallbackUrlFromRequest(String callbackUrlFromRequest,
@@ -672,4 +674,35 @@ private String resolveUserResidentOrganization(Map userAtt
         }
         return null;
     }
+
+    /**
+     * Configures RAR properties for token generation in the OAuth 2.0 flow.
+     * 

+ * It checks if authorization details were included in the authorization code request and whether the + * user has consented to these specific authorization details. Depending on user consent, it selects + * the appropriate authorization details to be included in the token response. + *

+ * + * @param oAuthTokenReqMessageContext Context of the OAuth token request message. + * @throws IdentityOAuth2Exception If an error occurs while retrieving authorization details. + */ + private void setRARPropertiesForTokenGeneration(final OAuthTokenReqMessageContext oAuthTokenReqMessageContext) + throws IdentityOAuth2Exception { + + final int tenantId = + OAuth2Util.getTenantId(oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getTenantDomain()); + + if (log.isDebugEnabled()) { + log.debug("Retrieving user consented authorization details for user: " + + oAuthTokenReqMessageContext.getAuthorizedUser().getLoggableMaskedUserId()); + } + + final AuthorizationDetails authorizationCodeAuthorizationDetails = super.authorizationDetailsService + .getAuthorizationCodeAuthorizationDetails( + oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getAuthorizationCode(), + tenantId); + + oAuthTokenReqMessageContext.setAuthorizationDetails(AuthorizationDetailsUtils + .getTrimmedAuthorizationDetails(authorizationCodeAuthorizationDetails)); + } } 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 858134956f..b69dacdcf9 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 @@ -59,6 +59,8 @@ 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.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsUtils; import org.wso2.carbon.identity.oauth2.token.AccessTokenIssuer; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuer; @@ -221,7 +223,7 @@ public boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) /** * Build and return a string to be used as a lock for synchronous token issuance for refresh token grant type. * - * @param tokReqMsgCtx OAuthTokenReqMessageContext + * @param tokReqMsgCtx OAuthTokenReqMessageContext * @return A string to be used as a lock for synchronous token issuance for refresh token grant type. */ public String buildSyncLockString(OAuthTokenReqMessageContext tokReqMsgCtx) { @@ -253,7 +255,7 @@ private void setPropertiesForTokenGeneration(OAuthTokenReqMessageContext tokReqM // Store the old access token as a OAuthTokenReqMessageContext property, this is already // a preprocessed token. tokReqMsgCtx.addProperty(PREV_ACCESS_TOKEN, validationBean); - super.setRARPropertiesForTokenGeneration(tokReqMsgCtx); + this.setRARPropertiesForTokenGeneration(tokReqMsgCtx, validationBean); } private boolean validateRefreshTokenInRequest(OAuth2AccessTokenReqDTO tokenReq, @@ -894,4 +896,31 @@ private RefreshTokenGrantProcessor getRefreshTokenGrantProcessor() { return OAuth2ServiceComponentHolder.getInstance().getRefreshTokenGrantProcessor(); } + + /** + * Sets the RAR properties for token generation. + *

It retrieves the token authorization details based on the provided OAuth token request context.

+ * + * @param oAuthTokenReqMessageContext Context of the OAuth token request message. + * @param validationBean Refresh token validation data. + * @throws IdentityOAuth2Exception If an error occurs while retrieving authorization details. + */ + private void setRARPropertiesForTokenGeneration(final OAuthTokenReqMessageContext oAuthTokenReqMessageContext, + final RefreshTokenValidationDataDO validationBean) + throws IdentityOAuth2Exception { + + if (log.isDebugEnabled()) { + log.debug("Retrieving token authorization details for user: " + + oAuthTokenReqMessageContext.getAuthorizedUser().getLoggableMaskedUserId()); + } + + final int tenantId = + OAuth2Util.getTenantId(oAuthTokenReqMessageContext.getOauth2AccessTokenReqDTO().getTenantDomain()); + + AuthorizationDetails tokenAuthorizationDetails = super.authorizationDetailsService + .getAccessTokenAuthorizationDetails(validationBean.getTokenId(), tenantId); + + oAuthTokenReqMessageContext.setAuthorizationDetails(AuthorizationDetailsUtils + .getTrimmedAuthorizationDetails(tokenAuthorizationDetails)); + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java index 987da89649..4df6f96e9d 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java @@ -155,7 +155,7 @@ public void setUpErrorMethod() throws SQLException { public void shouldNotAddUserConsentedAuthorizationDetails_ifNotRichAuthorizationRequest() throws OAuthSystemException, SQLException { - uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + uut.storeOrUpdateUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, new OAuth2Parameters(), authorizationDetails); verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anySet()); @@ -168,7 +168,7 @@ public void shouldNotAddUserConsentedAuthorizationDetails_whenConsentIsNotFound( final OAuth2Parameters oAuth2Parameters = new OAuth2Parameters(); oAuth2Parameters.setAuthorizationDetails(authorizationDetails); - uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + uut.storeOrUpdateUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters, authorizationDetails); verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anySet()); @@ -178,7 +178,10 @@ public void shouldNotAddUserConsentedAuthorizationDetails_whenConsentIsNotFound( public void shouldAddUserConsentedAuthorizationDetails_ifRichAuthorizationRequest() throws OAuthSystemException, SQLException { - uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + when(this.authorizationDetailsDAOMock.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TENANT_ID)) + .thenReturn(Collections.emptySet()); + + uut.storeOrUpdateUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters, authorizationDetails); verify(authorizationDetailsDAOMock, times(1)).addUserConsentedAuthorizationDetails(anySet()); @@ -218,6 +221,8 @@ public void shouldDeleteUserConsentedAuthorizationDetails_ifRichAuthorizationReq public void shouldReplaceUserConsentedAuthorizationDetails_ifRichAuthorizationRequest() throws OAuthSystemException, SQLException { + when(this.authorizationDetailsDAOMock.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TENANT_ID)) + .thenReturn(Collections.emptySet()); uut.replaceUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters, authorizationDetails); @@ -293,7 +298,7 @@ public void shouldAddAccessTokenAuthorizationDetails_ifRichAuthorizationRequest( throws SQLException, IdentityOAuth2Exception { OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext = new OAuthAuthzReqMessageContext(null); - oAuthAuthzReqMessageContext.setAuthorizationDetails(authorizationDetails); + oAuthAuthzReqMessageContext.setApprovedAuthorizationDetails(authorizationDetails); uut.storeAccessTokenAuthorizationDetails(accessTokenDO, oAuthAuthzReqMessageContext); @@ -398,7 +403,7 @@ public void shouldReturnConsentRequiredAuthorizationDetails() throws IdentityOAu public void shouldThrowOAuthSystemException_onUserConsentAuthorizationDetailsInsertionFailure() throws OAuthSystemException { - uut.storeUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, + uut.storeOrUpdateUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters, authorizationDetails); } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java index b8bec6482f..8254b42634 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java @@ -86,7 +86,8 @@ public AuthorizationDetailsBaseTest() { authorizeReqDTO.setAuthorizationDetails(this.authorizationDetails); this.authzReqMessageContext = new OAuthAuthzReqMessageContext(authorizeReqDTO); - this.authzReqMessageContext.setAuthorizationDetails(this.authorizationDetails); + this.authzReqMessageContext.setRequestedAuthorizationDetails(this.authorizationDetails); + this.authzReqMessageContext.setApprovedAuthorizationDetails(this.authorizationDetails); this.accessTokenReqDTO = new OAuth2AccessTokenReqDTO(); this.accessTokenReqDTO.setAuthorizationDetails(authorizationDetails); From faa5e3136d6609b39117838443bdcf3ea2066ad6 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Wed, 13 Nov 2024 20:08:37 +0530 Subject: [PATCH 11/28] Fix refresh token introspection issue --- .../token/AccessTokenResponseRARHandler.java | 18 +++++++++ .../token/IntrospectionRARDataProvider.java | 39 +++++++++++++++++-- .../token/JWTAccessTokenRARClaimProvider.java | 26 +++++++++++-- pom.xml | 2 +- 4 files changed, 76 insertions(+), 9 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java index f2d618e85a..516eba5cd3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/AccessTokenResponseRARHandler.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar.token; import org.apache.commons.logging.Log; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java index 150cf8de51..f185e9d2ed 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProvider.java @@ -1,5 +1,24 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar.token; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.oauth.common.OAuthConstants; @@ -22,6 +41,7 @@ import java.util.Objects; import static org.wso2.carbon.identity.oauth2.rar.util.AuthorizationDetailsConstants.AUTHORIZATION_DETAILS; +import static org.wso2.carbon.identity.oauth2.validators.RefreshTokenValidator.TOKEN_TYPE_NAME; /** * Class responsible for modifying the introspection response to include user-consented authorization details. @@ -107,10 +127,8 @@ private OAuth2TokenValidationMessageContext generateOAuth2TokenValidationMessage new OAuth2TokenValidationMessageContext(tokenValidationRequestDTO, generateOAuth2TokenValidationResponseDTO(introspectionResponseDTO)); - final AccessTokenDO accessTokenDO = OAuth2ServiceComponentHolder.getInstance().getTokenProvider() - .getVerifiedAccessToken(tokenValidationRequestDTO.getAccessToken().getIdentifier(), false); - - oAuth2TokenValidationMessageContext.addProperty(OAuthConstants.ACCESS_TOKEN_DO, accessTokenDO); + oAuth2TokenValidationMessageContext.addProperty(OAuthConstants.ACCESS_TOKEN_DO, + this.getVerifiedToken(tokenValidationRequestDTO, introspectionResponseDTO)); return oAuth2TokenValidationMessageContext; } @@ -130,4 +148,17 @@ private OAuth2TokenValidationResponseDTO generateOAuth2TokenValidationResponseDT return tokenValidationResponseDTO; } + + private AccessTokenDO getVerifiedToken(final OAuth2TokenValidationRequestDTO tokenValidationRequestDTO, + final OAuth2IntrospectionResponseDTO introspectionResponseDTO) + throws IdentityOAuth2Exception { + + if (StringUtils.equals(TOKEN_TYPE_NAME, introspectionResponseDTO.getTokenType())) { + return OAuth2ServiceComponentHolder.getInstance().getTokenProvider() + .getVerifiedRefreshToken(tokenValidationRequestDTO.getAccessToken().getIdentifier()); + } else { + return OAuth2ServiceComponentHolder.getInstance().getTokenProvider() + .getVerifiedAccessToken(tokenValidationRequestDTO.getAccessToken().getIdentifier(), false); + } + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java index cdbe9c2425..dc4e10ac45 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/token/JWTAccessTokenRARClaimProvider.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package org.wso2.carbon.identity.oauth2.rar.token; import org.apache.commons.logging.Log; @@ -35,8 +53,8 @@ public Map getAdditionalClaims(final OAuthAuthzReqMessageContext final Map additionalClaims = new HashMap<>(); if (AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) { if (log.isDebugEnabled()) { - log.debug("Processing Rich Authorization Request in authorization flow. authorization_details: " + - oAuthAuthzReqMessageContext.getRequestedAuthorizationDetails().toJsonString()); + log.debug("Adding authorization details into JWT token response in authorization flow: " + + oAuthAuthzReqMessageContext.getRequestedAuthorizationDetails().toReadableText()); } additionalClaims.put(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS, oAuthAuthzReqMessageContext.getApprovedAuthorizationDetails().toSet()); @@ -59,8 +77,8 @@ public Map getAdditionalClaims(final OAuthTokenReqMessageContext final Map additionalClaims = new HashMap<>(); if (AuthorizationDetailsUtils.isRichAuthorizationRequest(oAuthTokenReqMessageContext)) { if (log.isDebugEnabled()) { - log.debug("Processing Rich Authorization Request in token flow.authorization_details: " + - oAuthTokenReqMessageContext.getAuthorizationDetails().toJsonString()); + log.debug("Adding authorization details into JWT token response in token flow: " + + oAuthTokenReqMessageContext.getAuthorizationDetails().toReadableText()); } additionalClaims.put(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS, oAuthTokenReqMessageContext.getAuthorizationDetails().toSet()); diff --git a/pom.xml b/pom.xml index 535ef6a796..dba911544e 100644 --- a/pom.xml +++ b/pom.xml @@ -952,7 +952,7 @@ [1.0.1, 2.0.0) - 7.6.0 + 7.6.8-SNAPSHOT [5.25.234, 8.0.0) From 4b205a490fc6cf0834c7656c1c4aad5dd0fd1db2 Mon Sep 17 00:00:00 2001 From: Shan Chathusanda Jayathilaka Date: Tue, 17 Dec 2024 12:57:58 +0530 Subject: [PATCH 12/28] Improve user authorization check when accessing org is different from resident org --- .../org/wso2/carbon/identity/oauth2/util/AuthzUtil.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/AuthzUtil.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/AuthzUtil.java index 5811e251c0..29620bd069 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/AuthzUtil.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/AuthzUtil.java @@ -255,7 +255,13 @@ public static boolean isUserAuthorized(AuthenticatedUser authenticatedUser, List // Application id is not required for basic authentication flow. List roleIds = getUserRoles(authenticatedUser, null); - List permissions = getAssociatedScopesForRoles(roleIds, authenticatedUser.getTenantDomain()); + String tenantDomain = authenticatedUser.getTenantDomain(); + if (StringUtils.isNotBlank(authenticatedUser.getAccessingOrganization()) && + !authenticatedUser.getAccessingOrganization(). + equals(authenticatedUser.getUserResidentOrganization())) { + tenantDomain = getAccessingTenantDomain(authenticatedUser); + } + List permissions = getAssociatedScopesForRoles(roleIds, tenantDomain); if (OAuthServerConfiguration.getInstance().isUseLegacyPermissionAccessForUserBasedAuth()) { // Handling backward compatibility for previous access level. List internalScopes = getInternalScopes(authenticatedUser.getTenantDomain()); From a8e87fe14365c6877ab774d88363620ed11104f2 Mon Sep 17 00:00:00 2001 From: sandushi Date: Fri, 3 Jan 2025 17:00:22 +0530 Subject: [PATCH 13/28] Fix the issue of password expiry event trigger of PasswordGrantHandler --- .../handlers/grant/PasswordGrantHandler.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/PasswordGrantHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/PasswordGrantHandler.java index bba4046100..5822cd1f35 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/PasswordGrantHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/PasswordGrantHandler.java @@ -169,6 +169,11 @@ private Optional authenticateUserAtUserStore(OAuth2AccessTok if (log.isDebugEnabled()) { log.debug("user " + tokenReq.getResourceOwnerUsername() + " authenticated: " + authenticated); } + triggerPasswordExpiryValidationEvent(PASSWORD_GRANT_POST_AUTHENTICATION_EVENT, tenantAwareUserName, + userTenantDomain, userStoreManager, true); + if (log.isDebugEnabled()) { + log.debug(PASSWORD_GRANT_POST_AUTHENTICATION_EVENT + " event is triggered"); + } if (authenticated) { AuthenticatedUser authenticatedUser = new AuthenticatedUser(authenticationResult.getAuthenticatedUser().get()); @@ -178,11 +183,6 @@ private Optional authenticateUserAtUserStore(OAuth2AccessTok return Optional.of(authenticatedUser); } - triggerPasswordExpiryValidationEvent(PASSWORD_GRANT_POST_AUTHENTICATION_EVENT, tenantAwareUserName, - userTenantDomain, userStoreManager, true); - if (log.isDebugEnabled()) { - log.debug(PASSWORD_GRANT_POST_AUTHENTICATION_EVENT + " event is triggered"); - } return Optional.empty(); } @@ -387,14 +387,14 @@ private AuthenticatedUser validateUserCredentials(OAuth2AccessTokenReqDTO tokenR authenticatedUser = authenticateUserAtUserStore(tokenReq, userId, userStoreManager, tenantAwareUserName, isPublishPasswordGrantLoginEnabled, userTenantDomain, serviceProvider); } - if (authenticatedUser.isPresent()) { - return authenticatedUser.get(); - } triggerPasswordExpiryValidationEvent(PASSWORD_GRANT_POST_AUTHENTICATION_EVENT, tenantAwareUserName, userTenantDomain, userStoreManager, false); if (log.isDebugEnabled()) { log.debug(PASSWORD_GRANT_POST_AUTHENTICATION_EVENT + " event is triggered"); } + if (authenticatedUser.isPresent()) { + return authenticatedUser.get(); + } if (isPublishPasswordGrantLoginEnabled) { publishAuthenticationData(tokenReq, false, serviceProvider); } From 95792de333865a975e864ecf71d3b95dde045553 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 17 Jan 2025 09:39:31 +0530 Subject: [PATCH 14/28] Resolve test failures --- components/org.wso2.carbon.identity.oauth.rar/pom.xml | 2 +- .../identity/oauth2/rar/AuthorizationDetailsServiceTest.java | 2 ++ .../oauth2/rar/token/IntrospectionRARDataProviderTest.java | 4 +--- .../oauth2/rar/utils/AuthorizationDetailsBaseTest.java | 4 ++-- .../validator/DefaultAuthorizationDetailsValidatorTest.java | 5 ++++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index 2e79ffbf4b..20fc5054ee 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -24,7 +24,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.191-SNAPSHOT + 7.0.211-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java index 4df6f96e9d..e62c8b9702 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java @@ -34,6 +34,7 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessor; +import org.wso2.carbon.identity.oauth2.rar.core.AuthorizationDetailsProcessorFactory; import org.wso2.carbon.identity.oauth2.rar.dao.AuthorizationDetailsDAO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsConsentDTO; import org.wso2.carbon.identity.oauth2.rar.dto.AuthorizationDetailsTokenDTO; @@ -126,6 +127,7 @@ public void setUpMethod() when(processor.getType()).thenReturn(TEST_TYPE); when(processor.validate(any(AuthorizationDetailsContext.class))).thenReturn(ValidationResult.valid()); + this.processorFactoryMock = Mockito.mock(AuthorizationDetailsProcessorFactory.class); when(this.processorFactoryMock.getAuthorizationDetailsProcessorByType(TEST_TYPE)) .thenReturn(Optional.of(processor)); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java index bb8a935e39..1a2d0d198e 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/token/IntrospectionRARDataProviderTest.java @@ -79,11 +79,9 @@ public void shouldNotReturnAuthorizationDetails_ifNotRichAuthorizationRequest() when(validatorMock.getValidatedAuthorizationDetails(any(OAuth2TokenValidationMessageContext.class))) .thenReturn(new AuthorizationDetails()); - try (MockedStatic oAuth2UtilMock = Mockito.mockStatic(OAuth2Util.class); - MockedStatic componentHolderMock = + try (MockedStatic componentHolderMock = Mockito.mockStatic(OAuth2ServiceComponentHolder.class)) { - oAuth2UtilMock.when(() -> OAuth2Util.buildScopeArray(any())).thenReturn(new String[0]); componentHolderMock.when(OAuth2ServiceComponentHolder::getInstance) .thenReturn(this.componentHolderMock); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java index 8254b42634..720a6f267c 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/utils/AuthorizationDetailsBaseTest.java @@ -115,7 +115,7 @@ public AuthorizationDetailsBaseTest() { this.accessTokenDO.setTokenId(ACESS_TOKEN_ID); this.accessTokenDO.setTenantID(TENANT_ID); - mockAuthorizationDetailsProviderFactory(); + mockAuthorizationDetailsProcessorFactory(); this.serviceMock = mock(AuthorizationDetailsService.class); this.schemaValidatorMock = spy(AuthorizationDetailsSchemaValidator.class); @@ -133,7 +133,7 @@ public static void assertAuthorizationDetailsMissing(final Map a assertFalse(attributes.containsKey(AuthorizationDetailsConstants.AUTHORIZATION_DETAILS)); } - private void mockAuthorizationDetailsProviderFactory() { + private void mockAuthorizationDetailsProcessorFactory() { this.processorFactoryMock = spy(AuthorizationDetailsProcessorFactory.class); try { diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java index 67c8e4f942..3c63abce05 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/validator/DefaultAuthorizationDetailsValidatorTest.java @@ -24,10 +24,12 @@ import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.IdentityOAuth2ServerException; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; import org.wso2.carbon.identity.oauth2.rar.exception.AuthorizationDetailsProcessingException; import org.wso2.carbon.identity.oauth2.rar.utils.AuthorizationDetailsBaseTest; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.wso2.carbon.identity.oauth2.TestConstants.ACESS_TOKEN_ID; @@ -39,7 +41,8 @@ public class DefaultAuthorizationDetailsValidatorTest extends AuthorizationDetai @BeforeClass public void setUp() throws IdentityOAuth2Exception { - when(serviceMock.getAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID)) + this.serviceMock = mock(AuthorizationDetailsService.class); + when(this.serviceMock.getAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID)) .thenReturn(authorizationDetails); this.uut = new DefaultAuthorizationDetailsValidator(processorFactoryMock, serviceMock, schemaValidatorMock); From 61bf493292788fc06110644798deeadb95f302d4 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 17 Jan 2025 14:04:58 +0530 Subject: [PATCH 15/28] Improve unit tests coverage --- .../authz/OAuth2AuthzEndpointTest.java | 87 +++++++++++++------ .../oauth/endpoint/util/EndpointUtilTest.java | 31 ++++++- .../pom.xml | 2 +- .../OAuth2ServiceComponentHolder.java | 2 + 4 files changed, 93 insertions(+), 29 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpointTest.java index 91535b6212..aba2d95884 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzEndpointTest.java @@ -51,6 +51,7 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.testng.collections.Sets; import org.wso2.carbon.base.CarbonBaseConstants; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.identity.application.authentication.framework.AuthenticatorFlowStatus; @@ -113,6 +114,9 @@ import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; +import org.wso2.carbon.identity.oauth2.rar.validator.AuthorizationDetailsValidator; import org.wso2.carbon.identity.oauth2.responsemode.provider.ResponseModeProvider; import org.wso2.carbon.identity.oauth2.responsemode.provider.impl.DefaultResponseModeProvider; import org.wso2.carbon.identity.oauth2.responsemode.provider.impl.FormPostResponseModeProvider; @@ -287,7 +291,13 @@ public class OAuth2AuthzEndpointTest extends TestOAuthEndpointBase { private CentralLogMgtServiceComponentHolder centralLogMgtServiceComponentHolderMock; @Mock - private AuthorizationDetailsService authorizationDetailsService; + private AuthorizationDetailsService authorizationDetailsServiceMock; + + @Mock + private AuthorizationDetailsValidator authorizationDetailsValidatorMock; + + @Mock + private OAuth2ServiceComponentHolder oAuth2ServiceComponentHolderMock; private static final String ERROR_PAGE_URL = "https://localhost:9443/authenticationendpoint/oauth2_error.do"; private static final String LOGIN_PAGE_URL = "https://localhost:9443/authenticationendpoint/login.do"; @@ -577,8 +587,8 @@ public void testAuthorize(Object flowStatusObject, String[] clientId, String ses SessionDataCacheKey consentDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_CONSENT_VALUE); when(mockSessionDataCache.getValueFromCache(loginDataCacheKey)).thenReturn(loginCacheEntry); when(mockSessionDataCache.getValueFromCache(consentDataCacheKey)).thenReturn(consentCacheEntry); - when(loginCacheEntry.getoAuth2Parameters()).thenReturn(setOAuth2Parameters( - new HashSet<>(Collections.singletonList(OAuthConstants.Scope.OPENID)), APP_NAME, null, null)); + when(loginCacheEntry.getoAuth2Parameters()).thenReturn(setOAuth2Parameters(new HashSet<>(Collections + .singletonList(OAuthConstants.Scope.OPENID)), APP_NAME, null, null, null)); mockEndpointUtil(false, endpointUtil); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); @@ -676,32 +686,39 @@ public void testAuthorize(Object flowStatusObject, String[] clientId, String ses @DataProvider(name = "provideAuthenticatedData") public Object[][] provideAuthenticatedData() { + final AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail(); + testAuthorizationDetail.setType("test_type"); + return addDiagnosticLogStatusToExistingDataProvider(new Object[][]{ {true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), - RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_FOUND}, + null, RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_FOUND}, {false, true, null, null, null, null, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), - RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_FOUND}, + null, RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_FOUND}, - {true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList("scope1")), "not_form_post", - APP_REDIRECT_URL, HttpServletResponse.SC_FOUND}, + {true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList("scope1")), null, + "not_form_post", APP_REDIRECT_URL, HttpServletResponse.SC_FOUND}, {true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), - RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL_JSON, HttpServletResponse.SC_OK}, + null, RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL_JSON, HttpServletResponse.SC_OK}, - {true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList("scope1")), + {true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList("scope1")), null, RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL_JSON, HttpServletResponse.SC_OK}, {true, false, null, OAuth2ErrorCodes.INVALID_REQUEST, null, null, - new HashSet<>(Arrays.asList("scope1")), + new HashSet<>(Arrays.asList("scope1")), null, RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_OK}, {true, false, null, null, "Error!", null, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), - RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_OK}, + null, RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_OK}, {true, false, null, null, null, "http://localhost:8080/error", - new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), RESPONSE_MODE_FORM_POST, - APP_REDIRECT_URL, HttpServletResponse.SC_OK} + new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), null, RESPONSE_MODE_FORM_POST, + APP_REDIRECT_URL, HttpServletResponse.SC_OK}, + + {true, true, new HashMap<>(), null, null, null, Sets.newHashSet("scope1"), + Sets.newHashSet(testAuthorizationDetail), RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL_JSON, + HttpServletResponse.SC_OK} }); } @@ -709,6 +726,7 @@ public Object[][] provideAuthenticatedData() { public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, boolean isAuthenticated, Map attributes, String errorCode, String errorMsg, String errorUri, Set scopes, + Set testAuthorizationDetails, String responseMode, String redirectUri, int expected, boolean diagnosticLogsEnabled) throws Exception { @@ -729,7 +747,9 @@ public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, bo MockedStatic identityUtil = mockStatic(IdentityUtil.class, Mockito.CALLS_REAL_METHODS); MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic serviceComponentHolder = + mockStatic(OAuth2ServiceComponentHolder.class, Mockito.CALLS_REAL_METHODS)) { sessionDataCache.when(SessionDataCache::getInstance).thenReturn(mockSessionDataCache); SessionDataCacheKey loginDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_VALUE); @@ -770,7 +790,8 @@ public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, bo identityUtil.when(() -> IdentityUtil.getServerURL(anyString(), anyBoolean(), anyBoolean())) .thenReturn("https://localhost:9443/carbon"); - OAuth2Parameters oAuth2Params = setOAuth2Parameters(scopes, APP_NAME, responseMode, redirectUri); + OAuth2Parameters oAuth2Params = + setOAuth2Parameters(scopes, APP_NAME, responseMode, redirectUri, testAuthorizationDetails); oAuth2Params.setClientId(CLIENT_ID_VALUE); oAuth2Params.setState(STATE); when(loginCacheEntry.getoAuth2Parameters()).thenReturn(oAuth2Params); @@ -796,6 +817,7 @@ public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, bo authzReqDTO.setResponseType("code"); OAuthAuthzReqMessageContext authzReqMsgCtx = new OAuthAuthzReqMessageContext(authzReqDTO); authzReqMsgCtx.setApprovedScope(new String[]{OAuthConstants.Scope.OPENID}); + authzReqMsgCtx.setApprovedAuthorizationDetails(new AuthorizationDetails(testAuthorizationDetails)); when(oAuth2Service.validateScopesBeforeConsent(any(OAuth2AuthorizeReqDTO.class))).thenReturn( authzReqMsgCtx); when(mockAuthorizationHandlerManager.validateScopesBeforeConsent(any(OAuth2AuthorizeReqDTO.class))) @@ -819,9 +841,18 @@ public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, bo when(oAuth2ScopeService.hasUserProvidedConsentForAllRequestedScopes( anyString(), isNull(), anyInt(), anyList())).thenReturn(true); - when(authorizationDetailsService.isUserAlreadyConsentedForAuthorizationDetails( + when(authorizationDetailsServiceMock.isUserAlreadyConsentedForAuthorizationDetails( any(AuthenticatedUser.class), any(OAuth2Parameters.class))).thenReturn(true); - OAuth2AuthzEndpoint.setAuthorizationDetailsService(authorizationDetailsService); + OAuth2AuthzEndpoint.setAuthorizationDetailsService(authorizationDetailsServiceMock); + + when(authorizationDetailsValidatorMock + .getValidatedAuthorizationDetails(any(OAuthAuthzReqMessageContext.class))) + .thenReturn(new AuthorizationDetails(testAuthorizationDetails)); + + when(oAuth2ServiceComponentHolderMock.getAuthorizationDetailsValidator()) + .thenReturn(authorizationDetailsValidatorMock); + serviceComponentHolder.when(OAuth2ServiceComponentHolder::getInstance) + .thenReturn(oAuth2ServiceComponentHolderMock); mockServiceURLBuilder(serviceURLBuilder); setSupportedResponseModes(); @@ -976,7 +1007,7 @@ public void testUserConsentResponse(String consent, String redirectUrl, Set(), APP_NAME, responseMode, APP_REDIRECT_URL); + setOAuth2Parameters(new HashSet<>(), APP_NAME, responseMode, APP_REDIRECT_URL, null); oAuth2Params.setResponseType(responseType); oAuth2Params.setState(state); oAuth2Params.setClientId(CLIENT_ID_VALUE); @@ -1664,7 +1695,7 @@ public void testHandleUserConsent(boolean isRespDTONull, String consent, boolean OAuthAuthzReqMessageContext authzReqMsgCtx = new OAuthAuthzReqMessageContext(authorizeReqDTO); when(consentCacheEntry.getAuthzReqMsgCtx()).thenReturn(authzReqMsgCtx); - OAuth2AuthzEndpoint.setAuthorizationDetailsService(authorizationDetailsService); + OAuth2AuthzEndpoint.setAuthorizationDetailsService(authorizationDetailsServiceMock); Response response; try { @@ -1760,7 +1791,8 @@ public void testDoUserAuthz(String prompt, String idTokenHint, boolean hasUserAp mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); - OAuth2Parameters oAuth2Params = setOAuth2Parameters(new HashSet<>(), APP_NAME, null, APP_REDIRECT_URL); + OAuth2Parameters oAuth2Params = + setOAuth2Parameters(new HashSet<>(), APP_NAME, null, APP_REDIRECT_URL, null); oAuth2Params.setClientId(CLIENT_ID_VALUE); oAuth2Params.setPrompt(prompt); oAuth2Params.setIDTokenHint(idTokenHint); @@ -1920,7 +1952,7 @@ public void testManageOIDCSessionState(Object cookieObject, Object sessionStateO OAuth2Parameters oAuth2Params = setOAuth2Parameters(new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), - APP_NAME, responseMode, APP_REDIRECT_URL); + APP_NAME, responseMode, APP_REDIRECT_URL, null); oAuth2Params.setClientId(CLIENT_ID_VALUE); oAuth2Params.setPrompt(OAuthConstants.Prompt.LOGIN); @@ -1953,8 +1985,8 @@ public void testManageOIDCSessionState(Object cookieObject, Object sessionStateO , anyString())) .thenReturn("sessionStateValue"); oidcSessionManagementUtil.when( - () -> OIDCSessionManagementUtil.addSessionStateToURL(anyString(), anyString(), - isNull())).thenCallRealMethod(); + () -> OIDCSessionManagementUtil.addSessionStateToURL(anyString(), anyString(), + isNull())).thenCallRealMethod(); sessionDataCache.when(SessionDataCache::getInstance).thenReturn(mockSessionDataCache); SessionDataCacheKey loginDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_VALUE); @@ -2685,11 +2717,11 @@ private void mockEndpointUtil(boolean isConsentMgtEnabled, MockedStatic EndpointUtil.getUserConsentURL(any(OAuth2Parameters.class), - anyString(), anyString(), any(OAuthMessage.class), anyString())).thenReturn(USER_CONSENT_URL); + anyString(), anyString(), any(OAuthMessage.class), anyString())).thenReturn(USER_CONSENT_URL); endpointUtil.when(EndpointUtil::getRequestObjectService).thenReturn(requestObjectService); endpointUtil.when(() -> EndpointUtil.getLoginPageURL(anyString(), anyString(), anyBoolean(), - anyBoolean(), anySet(), anyMap(), any())).thenReturn(LOGIN_PAGE_URL); + anyBoolean(), anySet(), anyMap(), any())).thenReturn(LOGIN_PAGE_URL); EndpointUtil.setOAuthAdminService(oAuthAdminService); EndpointUtil.setOAuth2ScopeService(oAuth2ScopeService); @@ -2734,13 +2766,14 @@ private AuthenticationResult setAuthenticationResult(boolean isAuthenticated, Ma } private OAuth2Parameters setOAuth2Parameters(Set scopes, String appName, String responseMode, - String redirectUri) { + String redirectUri, Set authorizationDetails) { OAuth2Parameters oAuth2Parameters = new OAuth2Parameters(); oAuth2Parameters.setScopes(scopes); oAuth2Parameters.setResponseMode(responseMode); oAuth2Parameters.setRedirectURI(redirectUri); oAuth2Parameters.setApplicationName(appName); + oAuth2Parameters.setAuthorizationDetails(new AuthorizationDetails(authorizationDetails)); return oAuth2Parameters; } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtilTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtilTest.java index 188c294385..58af26b813 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtilTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/util/EndpointUtilTest.java @@ -38,6 +38,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; +import org.testng.collections.Sets; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.ServerConfiguration; import org.wso2.carbon.context.PrivilegedCarbonContext; @@ -71,8 +72,12 @@ import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; import org.wso2.carbon.identity.oauth2.bean.Scope; +import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.model.OAuth2ScopeConsentResponse; +import org.wso2.carbon.identity.oauth2.rar.AuthorizationDetailsService; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetail; +import org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.openidconnect.RequestObjectService; import org.wso2.carbon.identity.webfinger.DefaultWebFingerProcessor; @@ -159,9 +164,15 @@ public class EndpointUtilTest { @Mock OAuth2ScopeService oAuth2ScopeService; + @Mock + private AuthorizationDetailsService authorizationDetailsServiceMock; + @Mock FileBasedConfigurationBuilder mockFileBasedConfigurationBuilder; + @Mock + private OAuth2ServiceComponentHolder oAuth2ServiceComponentHolderMock; + private static final String COMMONAUTH_URL = "https://localhost:9443/commonauth"; private static final String OIDC_CONSENT_PAGE_URL = "https://localhost:9443/authenticationendpoint/oauth2_consent.do"; @@ -196,6 +207,14 @@ public class EndpointUtilTest { private String clientId; private AuthenticatedUser user; private OAuth2ScopeConsentResponse oAuth2ScopeConsentResponse; + private final AuthorizationDetails testAuthorizationDetails; + + public EndpointUtilTest() { + + final AuthorizationDetail testAuthorizationDetail = new AuthorizationDetail(); + testAuthorizationDetail.setType("test_type"); + this.testAuthorizationDetails = new AuthorizationDetails(Sets.newHashSet(testAuthorizationDetail)); + } @BeforeMethod public void setUp() { @@ -245,6 +264,7 @@ public Object[][] provideDataForUserConsentURL() { params.setClientId("testClientId"); params.setTenantDomain("testTenantDomain"); params.setScopes(new HashSet(Arrays.asList("scope1", "scope2", "internal_login"))); + params.setAuthorizationDetails(testAuthorizationDetails); OAuth2Parameters paramsOIDC = new OAuth2Parameters(); paramsOIDC.setApplicationName("TestApplication"); @@ -291,7 +311,9 @@ public void testGetUserConsentURL(Object oAuth2ParamObject, boolean isOIDC, bool MockedStatic oAuthURL = mockStatic(OAuth2Util.OAuthURL.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic sessionDataCache = mockStatic(SessionDataCache.class);) { + MockedStatic sessionDataCache = mockStatic(SessionDataCache.class); + MockedStatic serviceComponentHolder = + mockStatic(OAuth2ServiceComponentHolder.class, Mockito.CALLS_REAL_METHODS)) { EndpointUtil.setOauthServerConfiguration(mockedOAuthServerConfiguration); lenient().when(mockedOAuthServerConfiguration.isDropUnregisteredScopes()).thenReturn(false); @@ -344,6 +366,13 @@ public void testGetUserConsentURL(Object oAuth2ParamObject, boolean isOIDC, bool lenient().when(mockedOAuthAdminService.getRegisteredOIDCScope(anyString())) .thenReturn(Arrays.asList("openid", "email", "profile", "groups")); + lenient().when(authorizationDetailsServiceMock.getConsentRequiredAuthorizationDetails(user, parameters)) + .thenReturn(testAuthorizationDetails); + lenient().when(oAuth2ServiceComponentHolderMock.getAuthorizationDetailsService()) + .thenReturn(authorizationDetailsServiceMock); + serviceComponentHolder.when(OAuth2ServiceComponentHolder::getInstance) + .thenReturn(oAuth2ServiceComponentHolderMock); + String consentUrl; try { consentUrl = EndpointUtil.getUserConsentURL(parameters, username, sessionDataKey, isOIDC); diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index 20fc5054ee..ac4fa5d2d0 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -24,7 +24,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.211-SNAPSHOT + 7.0.215-SNAPSHOT 4.0.0 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 5c3a68c1b2..ada9ba8480 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 @@ -979,6 +979,8 @@ public AuthorizationDetailsTypeManager getAuthorizationDetailsTypeManager() { /** * set an {@link AuthorizationDetailsTypeManager} instance. + * + * @param authorizationDetailsTypeManager An {@link AuthorizationDetailsTypeManager} instance. */ public void setAuthorizationDetailsTypeManager(AuthorizationDetailsTypeManager authorizationDetailsTypeManager) { From f52306142aaba78cc433a914dc201263312263f7 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 17 Jan 2025 14:12:35 +0530 Subject: [PATCH 16/28] bump carbon.identity.framework.version to support authorization details --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0f05a18987..a7cc63d959 100644 --- a/pom.xml +++ b/pom.xml @@ -957,7 +957,7 @@ [1.0.1, 2.0.0) - 7.7.49 + 7.7.90 [5.25.234, 8.0.0) [2.0.0, 3.0.0) From be2070a72128e1f37952c2c2e60606e0a68c906b Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 17 Jan 2025 15:52:49 +0530 Subject: [PATCH 17/28] Add logic to check RAR is enabled --- .../builders/ProviderConfigBuilder.java | 4 +- .../rar/dao/AuthorizationDetailsDAOImpl.java | 44 ++-------------- .../dao/AuthorizationDetailsDAOImplTest.java | 30 ----------- .../dao/OAuthTokenPersistenceFactory.java | 2 +- .../rar/AuthorizationDetailsService.java | 44 ++++++++++++---- .../rar/AuthorizationDetailsServiceTest.java | 51 ++++++++++++++++++- 6 files changed, 90 insertions(+), 85 deletions(-) diff --git a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java index d3ac9f6ad1..c44c689683 100644 --- a/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java +++ b/components/org.wso2.carbon.identity.discovery/src/main/java/org/wso2/carbon/identity/discovery/builders/ProviderConfigBuilder.java @@ -157,8 +157,8 @@ public OIDProviderConfigResponse buildOIDProviderConfig(OIDProviderRequest reque final Set authorizationDetailTypes = AuthorizationDetailsProcessorFactory.getInstance() .getSupportedAuthorizationDetailTypes(); if (authorizationDetailTypes != null && !authorizationDetailTypes.isEmpty()) { - //final int size = supportedTypes.size(); - providerConfig.setAuthorizationDetailsTypesSupported(authorizationDetailTypes.toArray(String[]::new)); + providerConfig + .setAuthorizationDetailsTypesSupported(authorizationDetailTypes.stream().toArray(String[]::new)); } return providerConfig; } diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java index 4af816fbba..a4508e880c 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/main/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImpl.java @@ -30,8 +30,6 @@ import java.util.HashSet; import java.util.Set; -import static org.wso2.carbon.identity.api.resource.mgt.util.AuthorizationDetailsTypesUtil.isRichAuthorizationRequestsDisabled; - /** * Implements the {@link AuthorizationDetailsDAO} interface to manage rich authorization requests. * @@ -47,10 +45,6 @@ public class AuthorizationDetailsDAOImpl implements AuthorizationDetailsDAO { public int[] addUserConsentedAuthorizationDetails(final Set consentDTOs) throws SQLException { - if (isRichAuthorizationRequestsDisabled()) { - return new int[0]; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); PreparedStatement ps = connection.prepareStatement(SQLQueries.ADD_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { @@ -75,10 +69,6 @@ public int[] addUserConsentedAuthorizationDetails(final Set consentDTOs) throws SQLException { - if (isRichAuthorizationRequestsDisabled()) { - return new int[0]; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); PreparedStatement ps = connection.prepareStatement(SQLQueries.UPDATE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { @@ -104,11 +94,6 @@ public Set getUserConsentedAuthorizationDetails( final int tenantId) throws SQLException { - final Set authorizationDetailsConsentDTOs = new HashSet<>(); - if (isRichAuthorizationRequestsDisabled()) { - return authorizationDetailsConsentDTOs; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = connection.prepareStatement(SQLQueries.GET_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { @@ -117,6 +102,7 @@ public Set getUserConsentedAuthorizationDetails( ps.setInt(2, tenantId); try (ResultSet rs = ps.executeQuery()) { + final Set authorizationDetailsConsentDTOs = new HashSet<>(); while (rs.next()) { final String id = rs.getString(1); final String typeId = rs.getString(2); @@ -138,10 +124,6 @@ public Set getUserConsentedAuthorizationDetails( public int deleteUserConsentedAuthorizationDetails(final String consentId, final int tenantId) throws SQLException { - if (isRichAuthorizationRequestsDisabled()) { - return -1; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = connection.prepareStatement(SQLQueries.DELETE_OAUTH2_USER_CONSENTED_AUTHORIZATION_DETAILS)) { @@ -159,10 +141,6 @@ public int deleteUserConsentedAuthorizationDetails(final String consentId, final public int[] addAccessTokenAuthorizationDetails(final Set tokenDTOs) throws SQLException { - if (isRichAuthorizationRequestsDisabled()) { - return new int[0]; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = connection.prepareStatement(SQLQueries.ADD_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) { @@ -187,11 +165,6 @@ public Set getAccessTokenAuthorizationDetails(fina final int tenantId) throws SQLException { - final Set authorizationDetailsTokenDTO = new HashSet<>(); - if (isRichAuthorizationRequestsDisabled()) { - return authorizationDetailsTokenDTO; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = connection.prepareStatement(SQLQueries.GET_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) { @@ -200,6 +173,7 @@ public Set getAccessTokenAuthorizationDetails(fina ps.setInt(2, tenantId); try (ResultSet rs = ps.executeQuery()) { + final Set authorizationDetailsTokenDTO = new HashSet<>(); while (rs.next()) { final String id = rs.getString(1); final String typeId = rs.getString(2); @@ -220,10 +194,6 @@ public Set getAccessTokenAuthorizationDetails(fina public int deleteAccessTokenAuthorizationDetails(final String accessTokenId, final int tenantId) throws SQLException { - if (isRichAuthorizationRequestsDisabled()) { - return -1; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = connection.prepareStatement(SQLQueries.DELETE_OAUTH2_ACCESS_TOKEN_AUTHORIZATION_DETAILS)) { @@ -241,10 +211,6 @@ public int deleteAccessTokenAuthorizationDetails(final String accessTokenId, fin public int[] addOAuth2CodeAuthorizationDetails(final Set authorizationDetailsCodeDTOs) throws SQLException { - if (isRichAuthorizationRequestsDisabled()) { - return new int[0]; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = connection.prepareStatement(SQLQueries.ADD_OAUTH2_CODE_AUTHORIZATION_DETAILS)) { @@ -268,11 +234,6 @@ public int[] addOAuth2CodeAuthorizationDetails(final Set getOAuth2CodeAuthorizationDetails(final String authorizationCode, final int tenantId) throws SQLException { - final Set authorizationDetailsCodeDTOs = new HashSet<>(); - if (isRichAuthorizationRequestsDisabled()) { - return authorizationDetailsCodeDTOs; - } - try (final Connection connection = IdentityDatabaseUtil.getDBConnection(false); final PreparedStatement ps = connection.prepareStatement(SQLQueries.GET_OAUTH2_CODE_AUTHORIZATION_DETAILS_BY_CODE)) { @@ -281,6 +242,7 @@ public Set getOAuth2CodeAuthorizationDetails(final ps.setInt(2, tenantId); try (ResultSet rs = ps.executeQuery()) { + final Set authorizationDetailsCodeDTOs = new HashSet<>(); while (rs.next()) { final String codeId = rs.getString(1); final String typeId = rs.getString(2); diff --git a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java index f51555d8e6..a5fe74cf90 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java +++ b/components/org.wso2.carbon.identity.oauth.rar/src/test/java/org/wso2/carbon/identity/oauth2/rar/dao/AuthorizationDetailsDAOImplTest.java @@ -265,36 +265,6 @@ public void shouldReturnNull_whenUserIdOrAppIdInvalid() throws SQLException { assertNull(this.uut.getConsentIdByUserIdAndAppId("invalid_user_id", "invalid_app_id", TEST_TENANT_ID)); } - @Test - public void testUserConsentedAuthorizationDetailsWhenFeatureIsDisabled() throws SQLException { - - this.mockAuthorizationDetailsTypesUtil(false); - - assertEquals(0, this.uut.addUserConsentedAuthorizationDetails(Collections.emptySet()).length); - assertEquals(0, this.uut.updateUserConsentedAuthorizationDetails(Collections.emptySet()).length); - assertEquals(0, this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID).size()); - assertEquals(-1, this.uut.deleteUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TEST_TENANT_ID)); - } - - @Test - public void testAccessTokenAuthorizationDetailsWhenFeatureIsDisabled() throws SQLException { - - this.mockAuthorizationDetailsTypesUtil(false); - - assertEquals(0, uut.addAccessTokenAuthorizationDetails(Collections.emptySet()).length); - assertEquals(0, this.uut.getAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID).size()); - assertEquals(-1, this.uut.deleteAccessTokenAuthorizationDetails(TEST_TOKEN_ID, TEST_TENANT_ID)); - } - - @Test - public void testOAuth2CodeAuthorizationDetailsWhenFeatureIsDisabled() throws SQLException { - - this.mockAuthorizationDetailsTypesUtil(false); - - assertEquals(0, uut.addOAuth2CodeAuthorizationDetails(Collections.emptySet()).length); - assertEquals(0, this.uut.getOAuth2CodeAuthorizationDetails(TEST_AUTHORIZATION_CODE, TEST_TENANT_ID).size()); - } - private void mockAuthorizationDetailsTypesUtil(boolean isRichAuthorizationRequestsEnabled) { this.authorizationDetailsTypesUtilMock 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 3737e52311..e38b6ad272 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 @@ -116,7 +116,7 @@ public OAuthUserConsentedScopesDAO getOAuthUserConsentedScopesDAO() { * Retrieves the DAO for authorization details. *

* This method returns an {@link AuthorizationDetailsDAO} singleton instance that provides access to the - * {@link org.wso2.carbon.identity.oauth2.rar.common.model.AuthorizationDetails} data. This DAO is used to interact + * {@link org.wso2.carbon.identity.oauth2.rar.model.AuthorizationDetails} data. This DAO is used to interact * with the underlying data store to fetch and manipulate authorization information. *

* @return the {@link AuthorizationDetailsDAO} instance that provides access to authorization details data. diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java index cf1ad3ea89..2bb41ca418 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsService.java @@ -22,6 +22,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.wso2.carbon.identity.api.resource.mgt.util.AuthorizationDetailsTypesUtil; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; @@ -68,6 +69,7 @@ public class AuthorizationDetailsService { private static final Log log = LogFactory.getLog(AuthorizationDetailsService.class); private final AuthorizationDetailsDAO authorizationDetailsDAO; private final AuthorizationDetailsProcessorFactory authorizationDetailsProcessorFactory; + private final boolean isRichAuthorizationRequestsDisabled; /** * Default constructor that initializes the service with the default {@link AuthorizationDetailsDAO} and @@ -81,7 +83,8 @@ public AuthorizationDetailsService() { this( AuthorizationDetailsProcessorFactory.getInstance(), - OAuthTokenPersistenceFactory.getInstance().getAuthorizationDetailsDAO() + OAuthTokenPersistenceFactory.getInstance().getAuthorizationDetailsDAO(), + AuthorizationDetailsTypesUtil.isRichAuthorizationRequestsEnabled() ); } @@ -93,12 +96,14 @@ public AuthorizationDetailsService() { * handling authorization details persistence. Must not be {@code null}. */ public AuthorizationDetailsService(final AuthorizationDetailsProcessorFactory authorizationDetailsProcessorFactory, - final AuthorizationDetailsDAO authorizationDetailsDAO) { + final AuthorizationDetailsDAO authorizationDetailsDAO, + final boolean isRichAuthorizationRequestsEnabled) { this.authorizationDetailsDAO = Objects.requireNonNull(authorizationDetailsDAO, "AuthorizationDetailsDAO must not be null"); this.authorizationDetailsProcessorFactory = Objects.requireNonNull(authorizationDetailsProcessorFactory, "AuthorizationDetailsProviderFactory must not be null"); + this.isRichAuthorizationRequestsDisabled = !isRichAuthorizationRequestsEnabled; } /** @@ -116,7 +121,7 @@ public void storeOrUpdateUserConsentedAuthorizationDetails( final AuthorizationDetails userConsentedAuthorizationDetails) throws OAuthSystemException { - if (!isRichAuthorizationRequest(oAuth2Parameters)) { + if (this.isRichAuthorizationRequestsDisabled || !isRichAuthorizationRequest(oAuth2Parameters)) { log.debug("Request is not a rich authorization request. Skipping storage of authorization details."); return; } @@ -185,7 +190,7 @@ public void deleteUserConsentedAuthorizationDetails(final AuthenticatedUser auth final String clientId, final OAuth2Parameters oAuth2Parameters) throws OAuthSystemException { - if (!isRichAuthorizationRequest(oAuth2Parameters)) { + if (this.isRichAuthorizationRequestsDisabled || !isRichAuthorizationRequest(oAuth2Parameters)) { log.debug("Request is not a rich authorization request. Skipping deletion of authorization details."); return; } @@ -239,7 +244,7 @@ public boolean isUserAlreadyConsentedForAuthorizationDetails(final Authenticated final OAuth2Parameters oAuth2Parameters) throws IdentityOAuth2Exception { - if (!isRichAuthorizationRequest(oAuth2Parameters)) { + if (this.isRichAuthorizationRequestsDisabled || !isRichAuthorizationRequest(oAuth2Parameters)) { return true; } @@ -250,7 +255,7 @@ public AuthorizationDetails getConsentRequiredAuthorizationDetails(final Authent final OAuth2Parameters oAuth2Parameters) throws IdentityOAuth2Exception { - if (!isRichAuthorizationRequest(oAuth2Parameters)) { + if (this.isRichAuthorizationRequestsDisabled || !isRichAuthorizationRequest(oAuth2Parameters)) { log.debug("Request is not a rich authorization request. Skipping the authorization details retrieval."); return new AuthorizationDetails(); } @@ -368,6 +373,11 @@ public AuthorizationDetails getUserConsentedAuthorizationDetails( public AuthorizationDetails getUserConsentedAuthorizationDetails(final String consentId, final int tenantId) throws IdentityOAuth2Exception { + if (this.isRichAuthorizationRequestsDisabled) { + log.debug("Rich authorization requests is disabled. Skip retrieving consented authorization details."); + return new AuthorizationDetails(); + } + try { final Set consentedAuthorizationDetails = new HashSet<>(); this.authorizationDetailsDAO.getUserConsentedAuthorizationDetails(consentId, tenantId) @@ -413,6 +423,10 @@ private Optional getConsentId(final AuthenticatedUser authenticatedUser, public Optional getConsentIdByUserIdAndAppId(final String userId, final String appId, final int tenantId) throws IdentityOAuth2Exception { + if (this.isRichAuthorizationRequestsDisabled) { + log.debug("Rich authorization requests is disabled. Skip retrieving consents."); + return Optional.empty(); + } try { return Optional .ofNullable(this.authorizationDetailsDAO.getConsentIdByUserIdAndAppId(userId, appId, tenantId)); @@ -434,6 +448,10 @@ public Optional getConsentIdByUserIdAndAppId(final String userId, final public AuthorizationDetails getAccessTokenAuthorizationDetails(final String accessTokenId, final int tenantId) throws IdentityOAuth2Exception { + if (this.isRichAuthorizationRequestsDisabled) { + log.debug("Rich authorization requests is disabled. Skip retrieving token authorization details."); + return new AuthorizationDetails(); + } try { final Set authorizationDetailsTokenDTOs = this.authorizationDetailsDAO.getAccessTokenAuthorizationDetails(accessTokenId, tenantId); @@ -482,10 +500,10 @@ public void storeAccessTokenAuthorizationDetails(final AccessTokenDO accessToken final AuthorizationDetails authorizationDetails) throws IdentityOAuth2Exception { - if (AuthorizationDetailsUtils.isEmpty(authorizationDetails)) { + if (this.isRichAuthorizationRequestsDisabled || AuthorizationDetailsUtils.isEmpty(authorizationDetails)) { + log.debug("Request is not a rich authorization request. Skipping storage of token authorization details."); return; } - try { final AuthorizationDetails trimmedAuthorizationDetails = AuthorizationDetailsUtils .getTrimmedAuthorizationDetails(authorizationDetails); @@ -542,6 +560,10 @@ public void storeOrReplaceAccessTokenAuthorizationDetails( public void deleteAccessTokenAuthorizationDetails(final String accessTokenId, final int tenantId) throws IdentityOAuth2Exception { + if (this.isRichAuthorizationRequestsDisabled) { + log.debug("Rich authorization requests is disabled. Skip persisting token authorization details."); + return; + } try { int result = this.authorizationDetailsDAO.deleteAccessTokenAuthorizationDetails(accessTokenId, tenantId); if (result > 0 && log.isDebugEnabled()) { @@ -604,7 +626,7 @@ public void storeAuthorizationCodeAuthorizationDetails( final AuthzCodeDO authzCodeDO, final OAuthAuthzReqMessageContext oAuthAuthzReqMessageContext) throws IdentityOAuth2Exception { - if (!isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) { + if (this.isRichAuthorizationRequestsDisabled || !isRichAuthorizationRequest(oAuthAuthzReqMessageContext)) { log.debug("Request is not a rich authorization request. Skipping storage of code authorization details."); return; } @@ -641,6 +663,10 @@ public void storeAuthorizationCodeAuthorizationDetails( public AuthorizationDetails getAuthorizationCodeAuthorizationDetails(final String code, final int tenantId) throws IdentityOAuth2Exception { + if (this.isRichAuthorizationRequestsDisabled) { + log.debug("Rich authorization requests is disabled. Skip retrieving code authorization details."); + return new AuthorizationDetails(); + } try { final Set authorizationDetailsCodeDTOs = this.authorizationDetailsDAO.getOAuth2CodeAuthorizationDetails(code, tenantId); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java index e62c8b9702..355752747b 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/rar/AuthorizationDetailsServiceTest.java @@ -131,7 +131,7 @@ public void setUpMethod() when(this.processorFactoryMock.getAuthorizationDetailsProcessorByType(TEST_TYPE)) .thenReturn(Optional.of(processor)); - uut = new AuthorizationDetailsService(this.processorFactoryMock, this.authorizationDetailsDAOMock); + uut = new AuthorizationDetailsService(this.processorFactoryMock, this.authorizationDetailsDAOMock, true); } @BeforeMethod(onlyForGroups = {"error-flow-tests"}, dependsOnMethods = {"setUpMethod"}) @@ -150,7 +150,13 @@ public void setUpErrorMethod() throws SQLException { when(this.authorizationDetailsDAOMock.deleteAccessTokenAuthorizationDetails(anyString(), anyInt())) .thenThrow(SQLException.class); - uut = new AuthorizationDetailsService(this.processorFactoryMock, this.authorizationDetailsDAOMock); + uut = new AuthorizationDetailsService(this.processorFactoryMock, this.authorizationDetailsDAOMock, true); + } + + @BeforeMethod(onlyForGroups = {"feature-disabled-flow-tests"}, dependsOnMethods = {"setUpErrorMethod"}) + public void setUpFeatureDisabledMethod() { + + uut = new AuthorizationDetailsService(this.processorFactoryMock, this.authorizationDetailsDAOMock, false); } @Test @@ -443,4 +449,45 @@ public void shouldThrowIdentityOAuth2Exception_onAccessTokenAuthorizationDetails uut.deleteAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID); } + + @Test(groups = {"feature-disabled-flow-tests"}) + public void testUserConsentedAuthorizationDetailsWhenFeatureIsDisabled() + throws OAuthSystemException, SQLException, IdentityOAuth2Exception { + + this.uut.storeOrUpdateUserConsentedAuthorizationDetails(authenticatedUser, CLIENT_ID, oAuth2Parameters, + new AuthorizationDetails()); + verify(authorizationDetailsDAOMock, times(0)).addUserConsentedAuthorizationDetails(anySet()); + verify(authorizationDetailsDAOMock, times(0)).updateUserConsentedAuthorizationDetails(anySet()); + + this.uut.getUserConsentedAuthorizationDetails(TEST_CONSENT_ID, TENANT_ID); + verify(authorizationDetailsDAOMock, times(0)).getUserConsentedAuthorizationDetails(anyString(), anyInt()); + + this.uut.deleteUserConsentedAuthorizationDetails(authenticatedUser, TEST_CONSENT_ID, oAuth2Parameters); + verify(authorizationDetailsDAOMock, times(0)).deleteUserConsentedAuthorizationDetails(anyString(), anyInt()); + } + + @Test(groups = {"feature-disabled-flow-tests"}) + public void testAccessTokenAuthorizationDetailsWhenFeatureIsDisabled() + throws SQLException, IdentityOAuth2Exception { + + this.uut.storeAccessTokenAuthorizationDetails(accessTokenDO, authorizationDetails); + verify(authorizationDetailsDAOMock, times(0)).addAccessTokenAuthorizationDetails(anySet()); + + this.uut.getAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID); + verify(authorizationDetailsDAOMock, times(0)).getAccessTokenAuthorizationDetails(anyString(), anyInt()); + + this.uut.deleteAccessTokenAuthorizationDetails(ACESS_TOKEN_ID, TENANT_ID); + verify(authorizationDetailsDAOMock, times(0)).getAccessTokenAuthorizationDetails(anyString(), anyInt()); + } + + @Test(groups = {"feature-disabled-flow-tests"}) + public void testOAuth2CodeAuthorizationDetailsWhenFeatureIsDisabled() throws SQLException, IdentityOAuth2Exception { + + uut.storeAuthorizationCodeAuthorizationDetails(null, new OAuthAuthzReqMessageContext(null)); + verify(authorizationDetailsDAOMock, times(0)).addOAuth2CodeAuthorizationDetails(anySet()); + + this.uut.getAuthorizationCodeAuthorizationDetails("", TENANT_ID); + verify(authorizationDetailsDAOMock, times(0)).getOAuth2CodeAuthorizationDetails(anyString(), anyInt()); + } + } From 0c03aa3f9fbbdae33850e11178697d0db1061d91 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 17 Jan 2025 17:27:07 +0530 Subject: [PATCH 18/28] Update license to 2025 --- .../AuthorizationDetailsServiceFactory.java | 2 +- .../org.wso2.carbon.identity.oauth.rar/pom.xml | 2 +- .../AuthorizationDetailsSchemaValidator.java | 2 +- .../rar/dao/AuthorizationDetailsDAO.java | 2 +- .../rar/dao/AuthorizationDetailsDAOImpl.java | 2 +- .../identity/oauth2/rar/dao/SQLQueries.java | 2 +- .../rar/dto/AuthorizationDetailsCodeDTO.java | 18 ++++++++++++++++++ .../dto/AuthorizationDetailsConsentDTO.java | 18 ++++++++++++++++++ .../rar/dto/AuthorizationDetailsDTO.java | 2 +- .../rar/dto/AuthorizationDetailsTokenDTO.java | 18 ++++++++++++++++++ ...uthorizationDetailsProcessingException.java | 18 ++++++++++++++++++ .../oauth2/rar/model/AuthorizationDetail.java | 2 +- .../oauth2/rar/model/AuthorizationDetails.java | 2 +- .../oauth2/rar/model/ValidationResult.java | 2 +- .../util/AuthorizationDetailsCommonUtils.java | 2 +- .../util/AuthorizationDetailsConstants.java | 2 +- ...uthorizationDetailsSchemaValidatorTest.java | 2 +- .../dao/AuthorizationDetailsDAOImplTest.java | 2 +- .../AuthorizationDetailsCommonUtilsTest.java | 2 +- .../oauth2/rar/util/TestConstants.java | 2 +- .../identity/oauth2/rar/util/TestDAOUtils.java | 2 +- .../src/test/resources/testng.xml | 2 +- .../rar/AuthorizationDetailsService.java | 2 +- .../core/AuthorizationDetailsProcessor.java | 2 +- .../AuthorizationDetailsProcessorFactory.java | 2 +- .../rar/model/AuthorizationDetailsContext.java | 2 +- .../token/AccessTokenResponseRARHandler.java | 2 +- .../token/IntrospectionRARDataProvider.java | 2 +- .../token/JWTAccessTokenRARClaimProvider.java | 2 +- .../rar/util/AuthorizationDetailsUtils.java | 2 +- .../AuthorizationDetailsValidator.java | 2 +- .../DefaultAuthorizationDetailsValidator.java | 2 +- .../rar/AuthorizationDetailsServiceTest.java | 2 +- .../AccessTokenResponseRARHandlerTest.java | 2 +- .../IntrospectionRARDataProviderTest.java | 2 +- .../JWTAccessTokenRARClaimProviderTest.java | 2 +- .../utils/AuthorizationDetailsBaseTest.java | 2 +- ...faultAuthorizationDetailsValidatorTest.java | 2 +- 38 files changed, 106 insertions(+), 34 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/AuthorizationDetailsServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/AuthorizationDetailsServiceFactory.java index f33588a722..af195571c7 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/AuthorizationDetailsServiceFactory.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/AuthorizationDetailsServiceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2025, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index ac4fa5d2d0..5d491ddac4 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -1,6 +1,6 @@ - io.vertx + org.wso2.orbit.io.vertx vertx-json-schema - ${vertx.json.schema.version} + ${vertx.json.schema.wso2.osgi.version} + + + org.wso2.orbit.io.netty + netty-all + ${netty-all.wso2.osgi.version} @@ -1055,7 +1060,9 @@ 2.4.7 5.2 9.2 - 4.5.11 + 4.5.11.wso2v1 + [4.5.11, 5.0.0) + 4.1.115.wso2v1 5.1.2 From 4959016ab05d3bf410ac77dbe2b06266dc4dd951 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Thu, 23 Jan 2025 08:59:40 +0530 Subject: [PATCH 22/28] Bump RAR version to 7.0.219-SNAPSHOT --- components/org.wso2.carbon.identity.oauth.rar/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.server.feature/pom.xml | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index be72db8d59..f83136d649 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -24,7 +24,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.215-SNAPSHOT + 7.0.219-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml index 11f6468f88..71b475b8f0 100644 --- a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml @@ -120,10 +120,6 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.client.attestation.filter
- - org.wso2.orbit.io.vertx - vertx-json-schema - From 16cd35043be929230f3452a79c1e76318968e5ad Mon Sep 17 00:00:00 2001 From: WSO2 Builder Date: Thu, 23 Jan 2025 07:10:10 +0000 Subject: [PATCH 23/28] [WSO2 Release] [Jenkins #5172] [Release 7.0.219] prepare release v7.0.219 --- components/org.wso2.carbon.identity.api.server.dcr/pom.xml | 4 ++-- .../org.wso2.carbon.identity.api.server.oauth.scope/pom.xml | 4 ++-- .../pom.xml | 2 +- components/org.wso2.carbon.identity.discovery/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ciba/pom.xml | 2 +- .../pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.common/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.extension/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.par/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.rar/pom.xml | 6 ++---- .../org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.stub/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ui/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.session/pom.xml | 2 +- components/org.wso2.carbon.identity.webfinger/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.feature/pom.xml | 2 +- .../pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml | 2 +- pom.xml | 4 ++-- .../org.wso2.carbon.claim.metadata.mgt.stub/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.testng/pom.xml | 2 +- 28 files changed, 32 insertions(+), 34 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml index e2e44506b7..b0ce46621b 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219-SNAPSHOT + 7.0.219 ../../pom.xml org.wso2.carbon.identity.api.server.dcr - 7.0.219-SNAPSHOT + 7.0.219 WSO2 Carbon - User DCR Rest API WSO2 Carbon - User DCR Rest API diff --git a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml index 73a1943011..7b3910c784 100644 --- a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219-SNAPSHOT + 7.0.219 ../.. org.wso2.carbon.identity.api.server.oauth.scope - 7.0.219-SNAPSHOT + 7.0.219 WSO2 Carbon - Identity OAuth 2.0 Scope Rest APIs Rest APIs for OAuth 2.0 Scope Handling diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml index bf2d312be5..88f5073bf6 100644 --- a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml +++ b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219-SNAPSHOT + 7.0.219 ../../pom.xml diff --git a/components/org.wso2.carbon.identity.discovery/pom.xml b/components/org.wso2.carbon.identity.discovery/pom.xml index 6c3bc0d82e..b6921ca62f 100644 --- a/components/org.wso2.carbon.identity.discovery/pom.xml +++ b/components/org.wso2.carbon.identity.discovery/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml index b1ce812487..7c3e4ddb9e 100644 --- a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml @@ -20,7 +20,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.219-SNAPSHOT + 7.0.219 ../../pom.xml diff --git a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml index 2539660e24..8a272954d0 100644 --- a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.common/pom.xml b/components/org.wso2.carbon.identity.oauth.common/pom.xml index 7dd72856aa..f28fdbb5da 100644 --- a/components/org.wso2.carbon.identity.oauth.common/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.common/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml index 72daea93b2..239c0419a6 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml @@ -6,7 +6,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index 82df845436..9d1eb0dc57 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index b7965ec57a..b1bf0865b7 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.extension/pom.xml b/components/org.wso2.carbon.identity.oauth.extension/pom.xml index 5092392fe5..57c269c09e 100644 --- a/components/org.wso2.carbon.identity.oauth.extension/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.extension/pom.xml @@ -19,7 +19,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.219-SNAPSHOT + 7.0.219 ../../pom.xml 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.par/pom.xml b/components/org.wso2.carbon.identity.oauth.par/pom.xml index 4676d51a1d..ef0a7b103e 100644 --- a/components/org.wso2.carbon.identity.oauth.par/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.par/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index f83136d649..6dc1a03f60 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -16,15 +16,13 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml index aacebc802f..1fd2a54ae7 100644 --- a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.stub/pom.xml b/components/org.wso2.carbon.identity.oauth.stub/pom.xml index af88724432..66b4cac263 100644 --- a/components/org.wso2.carbon.identity.oauth.stub/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.stub/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ui/pom.xml b/components/org.wso2.carbon.identity.oauth.ui/pom.xml index 61b3254601..b33405f3b1 100644 --- a/components/org.wso2.carbon.identity.oauth.ui/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ui/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 1c4267e9c5..26300b8106 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml index 7f3f2bf5ed..b37f6559f8 100644 --- a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.session/pom.xml b/components/org.wso2.carbon.identity.oidc.session/pom.xml index b054c08ef8..de893379a9 100644 --- a/components/org.wso2.carbon.identity.oidc.session/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.session/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/components/org.wso2.carbon.identity.webfinger/pom.xml b/components/org.wso2.carbon.identity.webfinger/pom.xml index bf0ea5fbf6..3b19e4b51f 100644 --- a/components/org.wso2.carbon.identity.webfinger/pom.xml +++ b/components/org.wso2.carbon.identity.webfinger/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml index ebb8e3e44d..c26d6a6e6f 100644 --- a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml index 2f70c712db..3022f5a495 100644 --- a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.feature/pom.xml index f5ea737204..3c0919b9ca 100644 --- a/features/org.wso2.carbon.identity.oauth.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml index 71b475b8f0..338c35d2ee 100644 --- a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml index 72047250dd..e1395f4fab 100644 --- a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 diff --git a/pom.xml b/pom.xml index add9f3bf7f..94632131c1 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ 4.0.0 org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219-SNAPSHOT + 7.0.219 pom WSO2 Carbon OAuth module http://wso2.org @@ -37,7 +37,7 @@ https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git - HEAD + v7.0.219 diff --git a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml index 4c7c603a6c..1f58c459e8 100644 --- a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml +++ b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219-SNAPSHOT + 7.0.219 ../../pom.xml diff --git a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml index c118e9217e..ef9950b2e2 100644 --- a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml +++ b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219-SNAPSHOT + 7.0.219 4.0.0 From 209b7eaaf5a494d864d0cffaf0e322ec2f4df426 Mon Sep 17 00:00:00 2001 From: WSO2 Builder Date: Thu, 23 Jan 2025 07:10:13 +0000 Subject: [PATCH 24/28] [WSO2 Release] [Jenkins #5172] [Release 7.0.219] prepare for next development iteration --- components/org.wso2.carbon.identity.api.server.dcr/pom.xml | 4 ++-- .../org.wso2.carbon.identity.api.server.oauth.scope/pom.xml | 4 ++-- .../pom.xml | 2 +- components/org.wso2.carbon.identity.discovery/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ciba/pom.xml | 2 +- .../pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.common/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.extension/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.par/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.rar/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.stub/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ui/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.session/pom.xml | 2 +- components/org.wso2.carbon.identity.webfinger/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml | 2 +- pom.xml | 4 ++-- service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.testng/pom.xml | 2 +- 28 files changed, 31 insertions(+), 31 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml index b0ce46621b..a64882ab66 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219 + 7.0.220-SNAPSHOT ../../pom.xml org.wso2.carbon.identity.api.server.dcr - 7.0.219 + 7.0.220-SNAPSHOT WSO2 Carbon - User DCR Rest API WSO2 Carbon - User DCR Rest API diff --git a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml index 7b3910c784..0a2a4ff341 100644 --- a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219 + 7.0.220-SNAPSHOT ../.. org.wso2.carbon.identity.api.server.oauth.scope - 7.0.219 + 7.0.220-SNAPSHOT WSO2 Carbon - Identity OAuth 2.0 Scope Rest APIs Rest APIs for OAuth 2.0 Scope Handling diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml index 88f5073bf6..7f82d0e55c 100644 --- a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml +++ b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219 + 7.0.220-SNAPSHOT ../../pom.xml diff --git a/components/org.wso2.carbon.identity.discovery/pom.xml b/components/org.wso2.carbon.identity.discovery/pom.xml index b6921ca62f..fc304c5a25 100644 --- a/components/org.wso2.carbon.identity.discovery/pom.xml +++ b/components/org.wso2.carbon.identity.discovery/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml index 7c3e4ddb9e..ff30d5326a 100644 --- a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml @@ -20,7 +20,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.219 + 7.0.220-SNAPSHOT ../../pom.xml diff --git a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml index 8a272954d0..ec1c3548cb 100644 --- a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.common/pom.xml b/components/org.wso2.carbon.identity.oauth.common/pom.xml index f28fdbb5da..674aadb49a 100644 --- a/components/org.wso2.carbon.identity.oauth.common/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.common/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml index 239c0419a6..8d554f6c05 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml @@ -6,7 +6,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index 9d1eb0dc57..fcbfbf1a15 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index b1bf0865b7..08e0170718 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.extension/pom.xml b/components/org.wso2.carbon.identity.oauth.extension/pom.xml index 57c269c09e..5dd749dd2c 100644 --- a/components/org.wso2.carbon.identity.oauth.extension/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.extension/pom.xml @@ -19,7 +19,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.219 + 7.0.220-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.par/pom.xml b/components/org.wso2.carbon.identity.oauth.par/pom.xml index ef0a7b103e..e76683d3f8 100644 --- a/components/org.wso2.carbon.identity.oauth.par/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.par/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index 6dc1a03f60..6be36573f2 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml index 1fd2a54ae7..0f1261ab65 100644 --- a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.stub/pom.xml b/components/org.wso2.carbon.identity.oauth.stub/pom.xml index 66b4cac263..2262fd45d8 100644 --- a/components/org.wso2.carbon.identity.oauth.stub/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.stub/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ui/pom.xml b/components/org.wso2.carbon.identity.oauth.ui/pom.xml index b33405f3b1..56f4d1fc85 100644 --- a/components/org.wso2.carbon.identity.oauth.ui/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ui/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 26300b8106..2cd71c4ce4 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml index b37f6559f8..38ccf1578c 100644 --- a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.session/pom.xml b/components/org.wso2.carbon.identity.oidc.session/pom.xml index de893379a9..6f2b41bf3d 100644 --- a/components/org.wso2.carbon.identity.oidc.session/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.session/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.webfinger/pom.xml b/components/org.wso2.carbon.identity.webfinger/pom.xml index 3b19e4b51f..ae83e6987d 100644 --- a/components/org.wso2.carbon.identity.webfinger/pom.xml +++ b/components/org.wso2.carbon.identity.webfinger/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml index c26d6a6e6f..180478d064 100644 --- a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml index 3022f5a495..a3bb61d6bd 100644 --- a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.feature/pom.xml index 3c0919b9ca..533190ce72 100644 --- a/features/org.wso2.carbon.identity.oauth.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml index 338c35d2ee..d7c24d24d1 100644 --- a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml index e1395f4fab..f4cde2b86d 100644 --- a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 94632131c1..769dd5f252 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ 4.0.0 org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219 + 7.0.220-SNAPSHOT pom WSO2 Carbon OAuth module http://wso2.org @@ -37,7 +37,7 @@ https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git - v7.0.219 + HEAD diff --git a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml index 1f58c459e8..a01a62636b 100644 --- a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml +++ b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.219 + 7.0.220-SNAPSHOT ../../pom.xml diff --git a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml index ef9950b2e2..d6ca2f995e 100644 --- a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml +++ b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.219 + 7.0.220-SNAPSHOT 4.0.0 From 9319df356f68e46fdc2af9204ca5bc6457661af8 Mon Sep 17 00:00:00 2001 From: WSO2 Builder Date: Thu, 23 Jan 2025 07:39:31 +0000 Subject: [PATCH 25/28] [WSO2 Release] [Jenkins #5174] [Release 7.0.220] prepare release v7.0.220 --- components/org.wso2.carbon.identity.api.server.dcr/pom.xml | 4 ++-- .../org.wso2.carbon.identity.api.server.oauth.scope/pom.xml | 4 ++-- .../pom.xml | 2 +- components/org.wso2.carbon.identity.discovery/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ciba/pom.xml | 2 +- .../pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.common/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.extension/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.par/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.rar/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.stub/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ui/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.session/pom.xml | 2 +- components/org.wso2.carbon.identity.webfinger/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml | 2 +- pom.xml | 4 ++-- service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.testng/pom.xml | 2 +- 28 files changed, 31 insertions(+), 31 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml index a64882ab66..8636abd2bf 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220-SNAPSHOT + 7.0.220 ../../pom.xml org.wso2.carbon.identity.api.server.dcr - 7.0.220-SNAPSHOT + 7.0.220 WSO2 Carbon - User DCR Rest API WSO2 Carbon - User DCR Rest API diff --git a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml index 0a2a4ff341..12741e0b6f 100644 --- a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220-SNAPSHOT + 7.0.220 ../.. org.wso2.carbon.identity.api.server.oauth.scope - 7.0.220-SNAPSHOT + 7.0.220 WSO2 Carbon - Identity OAuth 2.0 Scope Rest APIs Rest APIs for OAuth 2.0 Scope Handling diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml index 7f82d0e55c..36336bb869 100644 --- a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml +++ b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220-SNAPSHOT + 7.0.220 ../../pom.xml diff --git a/components/org.wso2.carbon.identity.discovery/pom.xml b/components/org.wso2.carbon.identity.discovery/pom.xml index fc304c5a25..710438ad93 100644 --- a/components/org.wso2.carbon.identity.discovery/pom.xml +++ b/components/org.wso2.carbon.identity.discovery/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml index ff30d5326a..6769926bc3 100644 --- a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml @@ -20,7 +20,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.220-SNAPSHOT + 7.0.220 ../../pom.xml diff --git a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml index ec1c3548cb..65d8088e85 100644 --- a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.common/pom.xml b/components/org.wso2.carbon.identity.oauth.common/pom.xml index 674aadb49a..9092af0662 100644 --- a/components/org.wso2.carbon.identity.oauth.common/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.common/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml index 8d554f6c05..03c7fe6110 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml @@ -6,7 +6,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index fcbfbf1a15..62032826b3 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index 08e0170718..d2cdca196f 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.extension/pom.xml b/components/org.wso2.carbon.identity.oauth.extension/pom.xml index 5dd749dd2c..74b0370d27 100644 --- a/components/org.wso2.carbon.identity.oauth.extension/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.extension/pom.xml @@ -19,7 +19,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.220-SNAPSHOT + 7.0.220 ../../pom.xml 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.par/pom.xml b/components/org.wso2.carbon.identity.oauth.par/pom.xml index e76683d3f8..e799a7c1af 100644 --- a/components/org.wso2.carbon.identity.oauth.par/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.par/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index 6be36573f2..68ffd97bd7 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml index 0f1261ab65..32a6b275a0 100644 --- a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.stub/pom.xml b/components/org.wso2.carbon.identity.oauth.stub/pom.xml index 2262fd45d8..d8e89bf9b9 100644 --- a/components/org.wso2.carbon.identity.oauth.stub/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.stub/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ui/pom.xml b/components/org.wso2.carbon.identity.oauth.ui/pom.xml index 56f4d1fc85..67f9813be8 100644 --- a/components/org.wso2.carbon.identity.oauth.ui/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ui/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 2cd71c4ce4..f2b12495e4 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml index 38ccf1578c..c53df5fd5f 100644 --- a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.session/pom.xml b/components/org.wso2.carbon.identity.oidc.session/pom.xml index 6f2b41bf3d..9b6f8e36ca 100644 --- a/components/org.wso2.carbon.identity.oidc.session/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.session/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/components/org.wso2.carbon.identity.webfinger/pom.xml b/components/org.wso2.carbon.identity.webfinger/pom.xml index ae83e6987d..8167aa854d 100644 --- a/components/org.wso2.carbon.identity.webfinger/pom.xml +++ b/components/org.wso2.carbon.identity.webfinger/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml index 180478d064..f6d5a34f92 100644 --- a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml index a3bb61d6bd..f29cf508dd 100644 --- a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.feature/pom.xml index 533190ce72..45f722e5de 100644 --- a/features/org.wso2.carbon.identity.oauth.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml index d7c24d24d1..699aba5473 100644 --- a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml index f4cde2b86d..98e0f78946 100644 --- a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 diff --git a/pom.xml b/pom.xml index 769dd5f252..bac9a996b6 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ 4.0.0 org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220-SNAPSHOT + 7.0.220 pom WSO2 Carbon OAuth module http://wso2.org @@ -37,7 +37,7 @@ https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git - HEAD + v7.0.220 diff --git a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml index a01a62636b..04357fe87a 100644 --- a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml +++ b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220-SNAPSHOT + 7.0.220 ../../pom.xml diff --git a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml index d6ca2f995e..c56e4425c9 100644 --- a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml +++ b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220-SNAPSHOT + 7.0.220 4.0.0 From e64fd7dcf89f32be3c94c981cb27b98f63899f8d Mon Sep 17 00:00:00 2001 From: WSO2 Builder Date: Thu, 23 Jan 2025 07:39:33 +0000 Subject: [PATCH 26/28] [WSO2 Release] [Jenkins #5174] [Release 7.0.220] prepare for next development iteration --- components/org.wso2.carbon.identity.api.server.dcr/pom.xml | 4 ++-- .../org.wso2.carbon.identity.api.server.oauth.scope/pom.xml | 4 ++-- .../pom.xml | 2 +- components/org.wso2.carbon.identity.discovery/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ciba/pom.xml | 2 +- .../pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.common/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.extension/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.par/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.rar/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.stub/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ui/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.session/pom.xml | 2 +- components/org.wso2.carbon.identity.webfinger/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml | 2 +- pom.xml | 4 ++-- service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.testng/pom.xml | 2 +- 28 files changed, 31 insertions(+), 31 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml index 8636abd2bf..4e0d52d30d 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220 + 7.0.221-SNAPSHOT ../../pom.xml org.wso2.carbon.identity.api.server.dcr - 7.0.220 + 7.0.221-SNAPSHOT WSO2 Carbon - User DCR Rest API WSO2 Carbon - User DCR Rest API diff --git a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml index 12741e0b6f..7379022b9d 100644 --- a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220 + 7.0.221-SNAPSHOT ../.. org.wso2.carbon.identity.api.server.oauth.scope - 7.0.220 + 7.0.221-SNAPSHOT WSO2 Carbon - Identity OAuth 2.0 Scope Rest APIs Rest APIs for OAuth 2.0 Scope Handling diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml index 36336bb869..88b16104a2 100644 --- a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml +++ b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220 + 7.0.221-SNAPSHOT ../../pom.xml diff --git a/components/org.wso2.carbon.identity.discovery/pom.xml b/components/org.wso2.carbon.identity.discovery/pom.xml index 710438ad93..7426828081 100644 --- a/components/org.wso2.carbon.identity.discovery/pom.xml +++ b/components/org.wso2.carbon.identity.discovery/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml index 6769926bc3..b3d1164f03 100644 --- a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml @@ -20,7 +20,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.220 + 7.0.221-SNAPSHOT ../../pom.xml diff --git a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml index 65d8088e85..c219e81be7 100644 --- a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.common/pom.xml b/components/org.wso2.carbon.identity.oauth.common/pom.xml index 9092af0662..0085ee7a3c 100644 --- a/components/org.wso2.carbon.identity.oauth.common/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.common/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml index 03c7fe6110..48b4eccc19 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml @@ -6,7 +6,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index 62032826b3..d87535581d 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index d2cdca196f..d1b500dca3 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.extension/pom.xml b/components/org.wso2.carbon.identity.oauth.extension/pom.xml index 74b0370d27..bbcc9c297e 100644 --- a/components/org.wso2.carbon.identity.oauth.extension/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.extension/pom.xml @@ -19,7 +19,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.220 + 7.0.221-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.par/pom.xml b/components/org.wso2.carbon.identity.oauth.par/pom.xml index e799a7c1af..c12b26d353 100644 --- a/components/org.wso2.carbon.identity.oauth.par/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.par/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index 68ffd97bd7..56d4f19c10 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml index 32a6b275a0..535d77a8a3 100644 --- a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.stub/pom.xml b/components/org.wso2.carbon.identity.oauth.stub/pom.xml index d8e89bf9b9..e03a1a5a27 100644 --- a/components/org.wso2.carbon.identity.oauth.stub/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.stub/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ui/pom.xml b/components/org.wso2.carbon.identity.oauth.ui/pom.xml index 67f9813be8..5f80835e08 100644 --- a/components/org.wso2.carbon.identity.oauth.ui/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ui/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index f2b12495e4..ada1b8ee86 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml index c53df5fd5f..56180f1500 100644 --- a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.session/pom.xml b/components/org.wso2.carbon.identity.oidc.session/pom.xml index 9b6f8e36ca..bbd4c84a05 100644 --- a/components/org.wso2.carbon.identity.oidc.session/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.session/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.webfinger/pom.xml b/components/org.wso2.carbon.identity.webfinger/pom.xml index 8167aa854d..afcfd84e61 100644 --- a/components/org.wso2.carbon.identity.webfinger/pom.xml +++ b/components/org.wso2.carbon.identity.webfinger/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml index f6d5a34f92..63b6dc026f 100644 --- a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml index f29cf508dd..0c8570e2b2 100644 --- a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.feature/pom.xml index 45f722e5de..497b2a9631 100644 --- a/features/org.wso2.carbon.identity.oauth.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml index 699aba5473..a838be3132 100644 --- a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml index 98e0f78946..69dea60e28 100644 --- a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index bac9a996b6..c649707371 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ 4.0.0 org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220 + 7.0.221-SNAPSHOT pom WSO2 Carbon OAuth module http://wso2.org @@ -37,7 +37,7 @@ https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git - v7.0.220 + HEAD diff --git a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml index 04357fe87a..3b6120cfa2 100644 --- a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml +++ b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.220 + 7.0.221-SNAPSHOT ../../pom.xml diff --git a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml index c56e4425c9..c2f217653f 100644 --- a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml +++ b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.220 + 7.0.221-SNAPSHOT 4.0.0 From 11826d55347f5ada81aad9e16afb4f7ece049409 Mon Sep 17 00:00:00 2001 From: WSO2 Builder Date: Thu, 23 Jan 2025 09:13:56 +0000 Subject: [PATCH 27/28] [WSO2 Release] [Jenkins #5176] [Release 7.0.221] prepare release v7.0.221 --- components/org.wso2.carbon.identity.api.server.dcr/pom.xml | 4 ++-- .../org.wso2.carbon.identity.api.server.oauth.scope/pom.xml | 4 ++-- .../pom.xml | 2 +- components/org.wso2.carbon.identity.discovery/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ciba/pom.xml | 2 +- .../pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.common/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.extension/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.par/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.rar/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.stub/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ui/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.session/pom.xml | 2 +- components/org.wso2.carbon.identity.webfinger/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml | 2 +- pom.xml | 4 ++-- service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.testng/pom.xml | 2 +- 28 files changed, 31 insertions(+), 31 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml index 4e0d52d30d..20d651a27f 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221-SNAPSHOT + 7.0.221 ../../pom.xml org.wso2.carbon.identity.api.server.dcr - 7.0.221-SNAPSHOT + 7.0.221 WSO2 Carbon - User DCR Rest API WSO2 Carbon - User DCR Rest API diff --git a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml index 7379022b9d..4ce1d5726f 100644 --- a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221-SNAPSHOT + 7.0.221 ../.. org.wso2.carbon.identity.api.server.oauth.scope - 7.0.221-SNAPSHOT + 7.0.221 WSO2 Carbon - Identity OAuth 2.0 Scope Rest APIs Rest APIs for OAuth 2.0 Scope Handling diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml index 88b16104a2..7eb433b2f2 100644 --- a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml +++ b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221-SNAPSHOT + 7.0.221 ../../pom.xml diff --git a/components/org.wso2.carbon.identity.discovery/pom.xml b/components/org.wso2.carbon.identity.discovery/pom.xml index 7426828081..0497b8b97c 100644 --- a/components/org.wso2.carbon.identity.discovery/pom.xml +++ b/components/org.wso2.carbon.identity.discovery/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml index b3d1164f03..7540be594e 100644 --- a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml @@ -20,7 +20,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.221-SNAPSHOT + 7.0.221 ../../pom.xml diff --git a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml index c219e81be7..4354b2844a 100644 --- a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.common/pom.xml b/components/org.wso2.carbon.identity.oauth.common/pom.xml index 0085ee7a3c..bd22927189 100644 --- a/components/org.wso2.carbon.identity.oauth.common/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.common/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml index 48b4eccc19..0f36137766 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml @@ -6,7 +6,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index d87535581d..0122bab97e 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index d1b500dca3..f9283ba2e9 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.extension/pom.xml b/components/org.wso2.carbon.identity.oauth.extension/pom.xml index bbcc9c297e..fb1bd19517 100644 --- a/components/org.wso2.carbon.identity.oauth.extension/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.extension/pom.xml @@ -19,7 +19,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.221-SNAPSHOT + 7.0.221 ../../pom.xml 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.par/pom.xml b/components/org.wso2.carbon.identity.oauth.par/pom.xml index c12b26d353..54c1af08b6 100644 --- a/components/org.wso2.carbon.identity.oauth.par/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.par/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index 56d4f19c10..d8eee0d701 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml index 535d77a8a3..7acf157a2a 100644 --- a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.stub/pom.xml b/components/org.wso2.carbon.identity.oauth.stub/pom.xml index e03a1a5a27..587bb90e35 100644 --- a/components/org.wso2.carbon.identity.oauth.stub/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.stub/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ui/pom.xml b/components/org.wso2.carbon.identity.oauth.ui/pom.xml index 5f80835e08..e4f436023e 100644 --- a/components/org.wso2.carbon.identity.oauth.ui/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ui/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index ada1b8ee86..129bb33c0d 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml index 56180f1500..304769b1cc 100644 --- a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.session/pom.xml b/components/org.wso2.carbon.identity.oidc.session/pom.xml index bbd4c84a05..8a4239a37f 100644 --- a/components/org.wso2.carbon.identity.oidc.session/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.session/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/components/org.wso2.carbon.identity.webfinger/pom.xml b/components/org.wso2.carbon.identity.webfinger/pom.xml index afcfd84e61..15266777d0 100644 --- a/components/org.wso2.carbon.identity.webfinger/pom.xml +++ b/components/org.wso2.carbon.identity.webfinger/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml index 63b6dc026f..47b7daef1b 100644 --- a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml index 0c8570e2b2..6128c1fa29 100644 --- a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.feature/pom.xml index 497b2a9631..9a8304740d 100644 --- a/features/org.wso2.carbon.identity.oauth.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml index a838be3132..3369bcd727 100644 --- a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml index 69dea60e28..ca6b142222 100644 --- a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 diff --git a/pom.xml b/pom.xml index c649707371..f3fc4a5a22 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ 4.0.0 org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221-SNAPSHOT + 7.0.221 pom WSO2 Carbon OAuth module http://wso2.org @@ -37,7 +37,7 @@ https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git - HEAD + v7.0.221 diff --git a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml index 3b6120cfa2..0883399bb6 100644 --- a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml +++ b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221-SNAPSHOT + 7.0.221 ../../pom.xml diff --git a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml index c2f217653f..f432126bc5 100644 --- a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml +++ b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221-SNAPSHOT + 7.0.221 4.0.0 From a22fe6d70688b2628195478b32f5c83b926dea61 Mon Sep 17 00:00:00 2001 From: WSO2 Builder Date: Thu, 23 Jan 2025 09:13:58 +0000 Subject: [PATCH 28/28] [WSO2 Release] [Jenkins #5176] [Release 7.0.221] prepare for next development iteration --- components/org.wso2.carbon.identity.api.server.dcr/pom.xml | 4 ++-- .../org.wso2.carbon.identity.api.server.oauth.scope/pom.xml | 4 ++-- .../pom.xml | 2 +- components/org.wso2.carbon.identity.discovery/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ciba/pom.xml | 2 +- .../pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.common/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.extension/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.par/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.rar/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.stub/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth.ui/pom.xml | 2 +- components/org.wso2.carbon.identity.oauth/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.dcr/pom.xml | 2 +- components/org.wso2.carbon.identity.oidc.session/pom.xml | 2 +- components/org.wso2.carbon.identity.webfinger/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.feature/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.server.feature/pom.xml | 2 +- features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml | 2 +- pom.xml | 4 ++-- service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml | 2 +- .../org.wso2.carbon.identity.oauth.common.testng/pom.xml | 2 +- 28 files changed, 31 insertions(+), 31 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml index 20d651a27f..b1baab8e02 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.dcr/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221 + 7.0.222-SNAPSHOT ../../pom.xml org.wso2.carbon.identity.api.server.dcr - 7.0.221 + 7.0.222-SNAPSHOT WSO2 Carbon - User DCR Rest API WSO2 Carbon - User DCR Rest API diff --git a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml index 4ce1d5726f..79b06403cb 100644 --- a/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.oauth.scope/pom.xml @@ -23,12 +23,12 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221 + 7.0.222-SNAPSHOT ../.. org.wso2.carbon.identity.api.server.oauth.scope - 7.0.221 + 7.0.222-SNAPSHOT WSO2 Carbon - Identity OAuth 2.0 Scope Rest APIs Rest APIs for OAuth 2.0 Scope Handling diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml index 7eb433b2f2..588d3bcd58 100644 --- a/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml +++ b/components/org.wso2.carbon.identity.client.attestation.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221 + 7.0.222-SNAPSHOT ../../pom.xml diff --git a/components/org.wso2.carbon.identity.discovery/pom.xml b/components/org.wso2.carbon.identity.discovery/pom.xml index 0497b8b97c..6157f7646b 100644 --- a/components/org.wso2.carbon.identity.discovery/pom.xml +++ b/components/org.wso2.carbon.identity.discovery/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml index 7540be594e..06993486fc 100644 --- a/components/org.wso2.carbon.identity.oauth.ciba/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ciba/pom.xml @@ -20,7 +20,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.221 + 7.0.222-SNAPSHOT ../../pom.xml diff --git a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml index 4354b2844a..d23605575c 100644 --- a/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.client.authn.filter/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.common/pom.xml b/components/org.wso2.carbon.identity.oauth.common/pom.xml index bd22927189..378948f89c 100644 --- a/components/org.wso2.carbon.identity.oauth.common/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.common/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml index 0f36137766..486120eb3a 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/pom.xml @@ -6,7 +6,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index 0122bab97e..b2a688c39e 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index f9283ba2e9..8ed421354c 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.extension/pom.xml b/components/org.wso2.carbon.identity.oauth.extension/pom.xml index fb1bd19517..77081413ec 100644 --- a/components/org.wso2.carbon.identity.oauth.extension/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.extension/pom.xml @@ -19,7 +19,7 @@ identity-inbound-auth-oauth org.wso2.carbon.identity.inbound.auth.oauth2 - 7.0.221 + 7.0.222-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.par/pom.xml b/components/org.wso2.carbon.identity.oauth.par/pom.xml index 54c1af08b6..0d7c04fdd7 100644 --- a/components/org.wso2.carbon.identity.oauth.par/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.par/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.rar/pom.xml b/components/org.wso2.carbon.identity.oauth.rar/pom.xml index d8eee0d701..0abc113005 100644 --- a/components/org.wso2.carbon.identity.oauth.rar/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.rar/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml index 7acf157a2a..4f8f56dd8b 100644 --- a/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.scope.endpoint/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.stub/pom.xml b/components/org.wso2.carbon.identity.oauth.stub/pom.xml index 587bb90e35..6e7b1b9029 100644 --- a/components/org.wso2.carbon.identity.oauth.stub/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.stub/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth.ui/pom.xml b/components/org.wso2.carbon.identity.oauth.ui/pom.xml index e4f436023e..2f1e638143 100644 --- a/components/org.wso2.carbon.identity.oauth.ui/pom.xml +++ b/components/org.wso2.carbon.identity.oauth.ui/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oauth/pom.xml b/components/org.wso2.carbon.identity.oauth/pom.xml index 129bb33c0d..26158431a6 100644 --- a/components/org.wso2.carbon.identity.oauth/pom.xml +++ b/components/org.wso2.carbon.identity.oauth/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml index 304769b1cc..f62669a8eb 100644 --- a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.oidc.session/pom.xml b/components/org.wso2.carbon.identity.oidc.session/pom.xml index 8a4239a37f..120eab8fa3 100644 --- a/components/org.wso2.carbon.identity.oidc.session/pom.xml +++ b/components/org.wso2.carbon.identity.oidc.session/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/components/org.wso2.carbon.identity.webfinger/pom.xml b/components/org.wso2.carbon.identity.webfinger/pom.xml index 15266777d0..1187078c7b 100644 --- a/components/org.wso2.carbon.identity.webfinger/pom.xml +++ b/components/org.wso2.carbon.identity.webfinger/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml index 47b7daef1b..7e84cb5cb1 100644 --- a/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.common.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml index 6128c1fa29..7746f0d1fe 100644 --- a/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.dcr.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.feature/pom.xml index 9a8304740d..fc94e58d5d 100644 --- a/features/org.wso2.carbon.identity.oauth.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml index 3369bcd727..405785f51b 100644 --- a/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.server.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml index ca6b142222..d95c879597 100644 --- a/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml +++ b/features/org.wso2.carbon.identity.oauth.ui.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index f3fc4a5a22..6951d0e3d5 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ 4.0.0 org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221 + 7.0.222-SNAPSHOT pom WSO2 Carbon OAuth module http://wso2.org @@ -37,7 +37,7 @@ https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git scm:git:https://github.com/wso2-extensions/identity-inbound-auth-oauth.git - v7.0.221 + HEAD diff --git a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml index 0883399bb6..fc7fb5af05 100644 --- a/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml +++ b/service-stubs/org.wso2.carbon.claim.metadata.mgt.stub/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth - 7.0.221 + 7.0.222-SNAPSHOT ../../pom.xml diff --git a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml index f432126bc5..62a7bb22ea 100644 --- a/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml +++ b/test-utils/org.wso2.carbon.identity.oauth.common.testng/pom.xml @@ -23,7 +23,7 @@ org.wso2.carbon.identity.inbound.auth.oauth2 identity-inbound-auth-oauth ../../pom.xml - 7.0.221 + 7.0.222-SNAPSHOT 4.0.0