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 413f30b0df6..8c3dce5a3df 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.191-SNAPSHOT + 7.0.214-SNAPSHOT ../../pom.xml org.wso2.carbon.identity.api.server.dcr - 7.0.191-SNAPSHOT + 7.0.214-SNAPSHOT WSO2 Carbon - User DCR Rest API WSO2 Carbon - User DCR Rest API @@ -48,11 +48,6 @@ jackson-databind provided - - org.springframework - spring-web - provided - junit junit @@ -151,6 +146,10 @@ jaxp-ri test + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.testutil + diff --git a/components/org.wso2.carbon.identity.api.server.dcr/src/gen/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/factories/RegisterApiServiceFactory.java b/components/org.wso2.carbon.identity.api.server.dcr/src/gen/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/factories/RegisterApiServiceFactory.java index 59bf0f207ac..7c48e314b10 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/src/gen/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/factories/RegisterApiServiceFactory.java +++ b/components/org.wso2.carbon.identity.api.server.dcr/src/gen/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/factories/RegisterApiServiceFactory.java @@ -5,10 +5,10 @@ public class RegisterApiServiceFactory { - private final static RegisterApiService service = new RegisterApiServiceImpl(); + private static final RegisterApiService SERVICE = new RegisterApiServiceImpl(); public static RegisterApiService getRegisterApi() { - return service; + return SERVICE; } } diff --git a/components/org.wso2.carbon.identity.api.server.dcr/src/main/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/factory/OAuth2DCRMServiceFactory.java b/components/org.wso2.carbon.identity.api.server.dcr/src/main/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/factory/OAuth2DCRMServiceFactory.java deleted file mode 100644 index ae8bc997340..00000000000 --- a/components/org.wso2.carbon.identity.api.server.dcr/src/main/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/factory/OAuth2DCRMServiceFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.oauth2.dcr.endpoint.factory; - -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.oauth.dcr.service.DCRMService; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the DCRMService type of object inside the container. - */ -public class OAuth2DCRMServiceFactory extends AbstractFactoryBean { - - private DCRMService oAuth2DCRMService; - - @Override - public Class getObjectType() { - - return DCRMService.class; - } - - @Override - protected DCRMService createInstance() throws Exception { - - if (this.oAuth2DCRMService == null) { - DCRMService oAuth2DCRMService = (DCRMService) PrivilegedCarbonContext. - getThreadLocalCarbonContext().getOSGiService(DCRMService.class, null); - if (oAuth2DCRMService != null) { - this.oAuth2DCRMService = oAuth2DCRMService; - } - } - return this.oAuth2DCRMService; - } -} diff --git a/components/org.wso2.carbon.identity.api.server.dcr/src/main/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/util/DCRMUtils.java b/components/org.wso2.carbon.identity.api.server.dcr/src/main/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/util/DCRMUtils.java index 35e56919384..331780788da 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/src/main/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/util/DCRMUtils.java +++ b/components/org.wso2.carbon.identity.api.server.dcr/src/main/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/util/DCRMUtils.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2017-2024, WSO2 LLC. (http://www.wso2.org). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -20,6 +20,7 @@ import org.apache.commons.logging.Log; import org.slf4j.MDC; +import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.oauth.dcr.DCRMConstants; import org.wso2.carbon.identity.oauth.dcr.bean.Application; import org.wso2.carbon.identity.oauth.dcr.bean.ApplicationRegistrationRequest; @@ -44,16 +45,15 @@ public class DCRMUtils { private static final String NOT_FOUND_STATUS = "NOT_FOUND_"; private static final String FORBIDDEN_STATUS = "FORBIDDEN_"; - private static DCRMService oAuth2DCRMService; + private static class OAuth2DCRMServiceHolder { - public static void setOAuth2DCRMService(DCRMService oAuth2DCRMService) { - - DCRMUtils.oAuth2DCRMService = oAuth2DCRMService; + private static final DCRMService SERVICE = (DCRMService) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(DCRMService.class, null); } public static DCRMService getOAuth2DCRMService() { - return oAuth2DCRMService; + return OAuth2DCRMServiceHolder.SERVICE; } public static ApplicationRegistrationRequest getApplicationRegistrationRequest( @@ -307,5 +307,4 @@ private static DCRMEndpointException buildDCRMEndpointException(Response.Status return new DCRMEndpointException(status, errorDTO); } } - } diff --git a/components/org.wso2.carbon.identity.api.server.dcr/src/main/resources/META-INF/cxf/oauth2-dcr-v1-1-cxf.xml b/components/org.wso2.carbon.identity.api.server.dcr/src/main/resources/META-INF/cxf/oauth2-dcr-v1-1-cxf.xml deleted file mode 100644 index e88978d4d65..00000000000 --- a/components/org.wso2.carbon.identity.api.server.dcr/src/main/resources/META-INF/cxf/oauth2-dcr-v1-1-cxf.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - diff --git a/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/impl/RegisterApiServiceImplExceptionTest.java b/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/impl/RegisterApiServiceImplExceptionTest.java index 18cf707512e..47edaa66c5b 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/impl/RegisterApiServiceImplExceptionTest.java +++ b/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/impl/RegisterApiServiceImplExceptionTest.java @@ -33,6 +33,7 @@ import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.oauth.dcr.exception.DCRMException; import org.wso2.carbon.identity.oauth.dcr.internal.DCRDataHolder; import org.wso2.carbon.identity.oauth.dcr.service.DCRMService; @@ -40,7 +41,6 @@ import org.wso2.carbon.identity.oauth2.dcr.endpoint.dto.RegistrationRequestDTO; import org.wso2.carbon.identity.oauth2.dcr.endpoint.dto.UpdateRequestDTO; import org.wso2.carbon.identity.oauth2.dcr.endpoint.exceptions.DCRMEndpointException; -import org.wso2.carbon.identity.oauth2.dcr.endpoint.util.DCRMUtils; import java.util.ArrayList; import java.util.List; @@ -49,11 +49,13 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; +@WithCarbonHome @Listeners(MockitoTestNGListener.class) public class RegisterApiServiceImplExceptionTest { @@ -70,13 +72,22 @@ public class RegisterApiServiceImplExceptionTest { ApplicationManagementService applicationManagementService; @Mock - DCRMService mockedDCRMService; + PrivilegedCarbonContext privilegedCarbonContext; MockedConstruction mockedConstruction; + private MockedStatic mockedPrivilegedCarbonContext; @BeforeMethod public void setUp() throws Exception { + if (mockedPrivilegedCarbonContext != null) { + mockedPrivilegedCarbonContext.close(); + } + mockedPrivilegedCarbonContext = mockStatic(PrivilegedCarbonContext.class); + when(PrivilegedCarbonContext.getThreadLocalCarbonContext()).thenReturn(privilegedCarbonContext); + lenient().when(PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getOSGiService(DCRMService.class, null)).thenReturn(mock(DCRMService.class)); + // Initializing variables. registerApiService = new RegisterApiServiceImpl(); @@ -104,7 +115,6 @@ public void tearDown() { public void testDeleteApplicationClientException() throws Exception { try { - DCRMUtils.setOAuth2DCRMService(mockedDCRMService); registerApiService.deleteApplication(""); } catch (DCRMEndpointException e) { assertEquals(e.getResponse().getStatus(), Response.Status.BAD_REQUEST.getStatusCode()); @@ -126,7 +136,6 @@ public void testDeleteApplicationThrowableException() throws DCRMException { public void testGetApplicationClientException() throws Exception { try { - DCRMUtils.setOAuth2DCRMService(mockedDCRMService); registerApiService.getApplication(""); } catch (DCRMEndpointException e) { assertEquals(e.getResponse().getStatus(), Response.Status.BAD_REQUEST.getStatusCode()); @@ -155,7 +164,6 @@ public void testRegisterApplicationClientException() throws DCRMException { registrationRequestDTO.setClientName("Test App"); registrationRequestDTO.setGrantTypes(granttypes); registrationRequestDTO.setRedirectUris(redirectUris); - DCRMUtils.setOAuth2DCRMService(mockedDCRMService); dcrDataHolder.when(DCRDataHolder::getInstance).thenReturn(dataHolder); lenient().when(dataHolder.getApplicationManagementService()).thenReturn(applicationManagementService); @@ -180,7 +188,6 @@ public void testRegisterApplicationServerException() throws DCRMException, Ident registrationRequestDTO.setGrantTypes(granttypes); registrationRequestDTO.setRedirectUris(redirectUris); - DCRMUtils.setOAuth2DCRMService(mockedDCRMService); dcrDataHolder.when(DCRDataHolder::getInstance).thenReturn(dataHolder); lenient().when(dataHolder.getApplicationManagementService()).thenReturn(applicationManagementService); lenient().when(applicationManagementService.getServiceProvider(any(String.class), any(String.class))). @@ -218,7 +225,6 @@ public void testUpdateApplicationClientException() throws DCRMException { updateRequestDTO.setClientName("Test App"); updateRequestDTO.setGrantTypes(granttypes); updateRequestDTO.setRedirectUris(redirectUris); - DCRMUtils.setOAuth2DCRMService(mockedDCRMService); dcrDataHolder.when(DCRDataHolder::getInstance).thenReturn(dataHolder); lenient().when(dataHolder.getApplicationManagementService()).thenReturn(applicationManagementService); diff --git a/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/impl/RegisterApiServiceImplTest.java b/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/impl/RegisterApiServiceImplTest.java index feb6af16d6b..cb56642834f 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/impl/RegisterApiServiceImplTest.java +++ b/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/impl/RegisterApiServiceImplTest.java @@ -20,6 +20,7 @@ import org.mockito.Mock; import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; import org.mockito.testng.MockitoTestNGListener; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; @@ -30,6 +31,7 @@ import org.testng.annotations.Test; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.internal.OSGiDataHolder; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.oauth.dcr.bean.Application; import org.wso2.carbon.identity.oauth.dcr.bean.ApplicationRegistrationRequest; import org.wso2.carbon.identity.oauth.dcr.bean.ApplicationUpdateRequest; @@ -40,7 +42,6 @@ import org.wso2.carbon.identity.oauth2.dcr.endpoint.dto.RegistrationRequestDTO; import org.wso2.carbon.identity.oauth2.dcr.endpoint.dto.UpdateRequestDTO; import org.wso2.carbon.identity.oauth2.dcr.endpoint.exceptions.DCRMEndpointException; -import org.wso2.carbon.identity.oauth2.dcr.endpoint.util.DCRMUtils; import java.util.ArrayList; import java.util.List; @@ -49,11 +50,13 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; +@WithCarbonHome @Listeners(MockitoTestNGListener.class) public class RegisterApiServiceImplTest { @@ -69,10 +72,20 @@ public class RegisterApiServiceImplTest { @Mock private DCRMService dcrmService; + @Mock + PrivilegedCarbonContext privilegedCarbonContext; + MockedConstruction mockedConstruction; + private MockedStatic mockedPrivilegedCarbonContext; @BeforeMethod public void setUp() throws Exception { + + mockedPrivilegedCarbonContext = mockStatic(PrivilegedCarbonContext.class); + lenient().when(PrivilegedCarbonContext.getThreadLocalCarbonContext()).thenReturn(privilegedCarbonContext); + lenient().when(PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getOSGiService(DCRMService.class, null)).thenReturn(mock(DCRMService.class)); + //Initializing variables. registerApiService = new RegisterApiServiceImpl(); validclientId = "N2QqQluzQuL5X6CtM3KZwqzLQhUa"; @@ -101,16 +114,15 @@ public void tearDown() { mockedConstruction.close(); PrivilegedCarbonContext.endTenantFlow(); + mockedPrivilegedCarbonContext.close(); } @Test public void testDeleteApplication() throws Exception { - DCRMUtils.setOAuth2DCRMService(dcrmService); - doNothing().when(dcrmService).deleteApplication(validclientId); + lenient().doNothing().when(dcrmService).deleteApplication(validclientId); Assert.assertEquals(registerApiService.deleteApplication(validclientId).getStatus(), Response.Status.NO_CONTENT.getStatusCode()); - } @Test @@ -127,8 +139,7 @@ public void testDeleteApplicationServerException() throws Exception { @Test public void testGetApplication() throws Exception { - DCRMUtils.setOAuth2DCRMService(dcrmService); - when(dcrmService.getApplication(validclientId)).thenReturn(application); + lenient().when(dcrmService.getApplication(validclientId)).thenReturn(application); Assert.assertEquals(registerApiService.getApplication(validclientId).getStatus(), Response.Status.OK.getStatusCode()); @@ -153,8 +164,7 @@ public void testRegisterApplication() throws Exception { RegistrationRequestDTO registrationRequestDTO = new RegistrationRequestDTO(); registrationRequestDTO.setClientName("app1"); - DCRMUtils.setOAuth2DCRMService(dcrmService); - when(dcrmService.registerApplication(any(ApplicationRegistrationRequest.class))) + lenient().when(dcrmService.registerApplication(any(ApplicationRegistrationRequest.class))) .thenReturn(application); Assert.assertEquals(registerApiService.registerApplication(registrationRequestDTO) .getStatus(), Response.Status.CREATED.getStatusCode()); @@ -179,8 +189,7 @@ public void testUpdateApplication() throws Exception { UpdateRequestDTO updateRequestDTO1 = new UpdateRequestDTO(); updateRequestDTO1.setClientName("Client1"); String clientID = "clientID1"; - DCRMUtils.setOAuth2DCRMService(dcrmService); - when(dcrmService.updateApplication + lenient().when(dcrmService.updateApplication (any(ApplicationUpdateRequest.class), anyString())) .thenReturn(application); Assert.assertEquals(registerApiService.updateApplication(updateRequestDTO1, clientID) diff --git a/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/util/DCRMUtilsTest.java b/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/util/DCRMUtilsTest.java index 0a1a17abe24..269fd02187a 100644 --- a/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/util/DCRMUtilsTest.java +++ b/components/org.wso2.carbon.identity.api.server.dcr/src/test/java/org/wso2/carbon/identity/oauth2/dcr/endpoint/util/DCRMUtilsTest.java @@ -18,11 +18,19 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.testng.MockitoTestNGListener; import org.testng.Assert; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; +import org.testng.annotations.Listeners; import org.testng.annotations.Test; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.oauth.dcr.exception.DCRMException; +import org.wso2.carbon.identity.oauth.dcr.service.DCRMService; import org.wso2.carbon.identity.oauth2.dcr.endpoint.dto.RegistrationRequestDTO; import org.wso2.carbon.identity.oauth2.dcr.endpoint.dto.UpdateRequestDTO; import org.wso2.carbon.identity.oauth2.dcr.endpoint.exceptions.DCRMEndpointException; @@ -32,19 +40,42 @@ import javax.ws.rs.core.Response; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +@WithCarbonHome +@Listeners(MockitoTestNGListener.class) public class DCRMUtilsTest { private List redirectUris = new ArrayList<>(); private List grantTypes = new ArrayList<>(); private final String clientName = "Application"; + @Mock + PrivilegedCarbonContext privilegedCarbonContext; + + private MockedStatic mockedPrivilegedCarbonContext; + @BeforeMethod public void setUp() throws Exception { + mockedPrivilegedCarbonContext = mockStatic(PrivilegedCarbonContext.class); + when(PrivilegedCarbonContext.getThreadLocalCarbonContext()).thenReturn(privilegedCarbonContext); + lenient().when(PrivilegedCarbonContext.getThreadLocalCarbonContext().getOSGiService(DCRMService.class, null)) + .thenReturn(mock(DCRMService.class)); + redirectUris.add("https://op.certification.openid.net:60845/authz_cb"); grantTypes.add("authorization_code"); } + @AfterMethod + public void tearDown() { + + mockedPrivilegedCarbonContext.close(); + } + @Test public void testGetApplicationRegistrationRequest() throws Exception { diff --git a/components/org.wso2.carbon.identity.api.server.dcr/src/test/resources/repository/conf/carbon.xml b/components/org.wso2.carbon.identity.api.server.dcr/src/test/resources/repository/conf/carbon.xml new file mode 100644 index 00000000000..faae9528f41 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.server.dcr/src/test/resources/repository/conf/carbon.xml @@ -0,0 +1,684 @@ + + + + + + + + WSO2 Identity Server + + + IS + + + 5.3.0 + + + localhost + + + localhost + + + local:/${carbon.context}/services/ + + + + + + + IdentityServer + + + + + + + org.wso2.carbon + + + / + + + + + + + + + 15 + + + + + + + + + 0 + + + + + 9999 + + 11111 + + + + + + 10389 + + 8000 + + + + + + 10500 + + + + + + + + + org.wso2.carbon.tomcat.jndi.CarbonJavaURLContextFactory + + + + + + + + + java + + + + + + + + + + false + + + false + + + 600 + + + + false + + + + + + + + 30 + + + + + + + + + 15 + + + + + + ${carbon.home}/repository/deployment/server/ + + + 15 + + + ${carbon.home}/repository/conf/axis2/axis2.xml + + + 30000 + + + ${carbon.home}/repository/deployment/client/ + + ${carbon.home}/repository/conf/axis2/axis2_client.xml + + false + + + + + + + + + + admin + Default Administrator Role + + + user + Default User Role + + + + + false + + + + + + + ${carbon.home}/repository/resources/security/wso2carbon.jks + + JKS + + wso2carbon + + wso2carbon + + wso2carbon + + + + + + ${carbon.home}/repository/resources/security/client-truststore.jks + + JKS + + wso2carbon + + + + + + + + + + + + + + + + + + + UserManager + + + false + + org.wso2.carbon.identity.provider.AttributeCallbackHandler + + + org.wso2.carbon.identity.sts.store.DBTokenStore + + + true + allow + + + + + + +claim_mgt_menu +identity_mgt_emailtemplate_menu +identity_security_questions_menu + + + + ${carbon.home}/tmp/work + + + + + + true + + + 10 + + + 30 + + + + + + 100 + + + + keystore + certificate + * + + org.wso2.carbon.ui.transports.fileupload.AnyFileUploadExecutor + + + + + jarZip + + org.wso2.carbon.ui.transports.fileupload.JarZipUploadExecutor + + + + dbs + + org.wso2.carbon.ui.transports.fileupload.DBSFileUploadExecutor + + + + tools + + org.wso2.carbon.ui.transports.fileupload.ToolsFileUploadExecutor + + + + toolsAny + + org.wso2.carbon.ui.transports.fileupload.ToolsAnyFileUploadExecutor + + + + + + + + + + info + org.wso2.carbon.core.transports.util.InfoProcessor + + + wsdl + org.wso2.carbon.core.transports.util.Wsdl11Processor + + + wsdl2 + org.wso2.carbon.core.transports.util.Wsdl20Processor + + + xsd + org.wso2.carbon.core.transports.util.XsdProcessor + + + + + + false + false + true + svn + http://svnrepo.example.com/repos/ + username + password + true + + + + + + + + + + + + + + + ${require.carbon.servlet} + + + + + true + + + + + + + default repository + http://product-dist.wso2.com/p2/carbon/releases/wilkes/ + + + + + + + + true + + + + + + true + + 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 03a3dd40972..64699f2d52c 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 @@ -1,6 +1,6 @@ - - - - - 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 067644ec1b2..c0b59585ae0 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.191-SNAPSHOT + 7.0.214-SNAPSHOT ../../pom.xml @@ -46,11 +46,6 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.oauth - - org.springframework - spring-web - provided - org.wso2.carbon.identity.framework org.wso2.carbon.identity.base diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/ClientAttestationProxy.java b/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/ClientAttestationProxy.java index 4e17820081c..204dc068d9f 100644 --- a/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/ClientAttestationProxy.java +++ b/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/ClientAttestationProxy.java @@ -115,7 +115,7 @@ public void handleMessage(Message message) { // Attestation validation should be performed only if API-based authentication is enabled. if (serviceProvider.isAPIBasedAuthenticationEnabled()) { // Validate the attestation header and obtain client attestation context - clientAttestationContext = ClientAttestationServiceHolder.getInstance() + clientAttestationContext = ClientAttestationServiceHolder .getClientAttestationService().validateAttestation(attestationHeader, serviceProvider.getApplicationResourceId(), IdentityTenantUtil.resolveTenantDomain()); @@ -265,7 +265,7 @@ private ServiceProvider getServiceProvider(String clientId, String tenantDomain) ServiceProvider serviceProvider; try { - serviceProvider = ClientAttestationServiceHolder.getInstance().getApplicationManagementService() + serviceProvider = ClientAttestationServiceHolder.getApplicationManagementService() .getServiceProviderByClientId(clientId, OAUTH2, tenantDomain); } catch (IdentityApplicationManagementClientException e) { throw new WebApplicationException( diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/ClientAttestationServiceHolder.java b/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/ClientAttestationServiceHolder.java index 57f6f01e246..6a0aa1f4d2e 100644 --- a/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/ClientAttestationServiceHolder.java +++ b/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/ClientAttestationServiceHolder.java @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.client.attestation.filter; +import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.client.attestation.mgt.services.ClientAttestationService; @@ -29,43 +30,32 @@ */ public class ClientAttestationServiceHolder { - // Singleton instance - private static ClientAttestationServiceHolder instance = new ClientAttestationServiceHolder(); - // Service instances - private ClientAttestationService clientAttestationService; - private ApplicationManagementService applicationManagementService; - // Private constructor to enforce Singleton pattern - private ClientAttestationServiceHolder() {} - - /** - * Returns the singleton instance of the ClientAttestationServiceHolder. - * - * @return The singleton instance. - */ - public static ClientAttestationServiceHolder getInstance() { + private static class ClientAttestationHolder { - return instance; + static final ClientAttestationService SERVICE = (ClientAttestationService) + PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getOSGiService(ClientAttestationService.class, null); } - /** - * Gets the instance of the Client Attestation Service. - * - * @return The Client Attestation Service instance. - */ - public ClientAttestationService getClientAttestationService() { + private static class ApplicationManagementHolder { - return ClientAttestationServiceHolder.getInstance().clientAttestationService; + static final ApplicationManagementService SERVICE = (ApplicationManagementService) + PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getOSGiService(ApplicationManagementService.class, null); } /** - * Sets the instance of the Client Attestation Service. + * Gets the instance of the Client Attestation Service. * - * @param clientAttestationService The Client Attestation Service instance to set. + * @return The Client Attestation Service instance. */ - public void setClientAttestationService(ClientAttestationService clientAttestationService) { + public static ClientAttestationService getClientAttestationService() { - ClientAttestationServiceHolder.getInstance().clientAttestationService = clientAttestationService; + if (ClientAttestationHolder.SERVICE == null) { + throw new IllegalStateException("ClientAttestationService is not available from OSGI context."); + } + return ClientAttestationHolder.SERVICE; } /** @@ -73,18 +63,11 @@ public void setClientAttestationService(ClientAttestationService clientAttestati * * @return The Application Management Service instance. */ - public ApplicationManagementService getApplicationManagementService() { - - return ClientAttestationServiceHolder.getInstance().applicationManagementService; - } - - /** - * Sets the instance of the Application Management Service. - * - * @param applicationManagementService The Application Management Service instance to set. - */ - public void setApplicationManagementService(ApplicationManagementService applicationManagementService) { + public static ApplicationManagementService getApplicationManagementService() { - ClientAttestationServiceHolder.getInstance().applicationManagementService = applicationManagementService; + if (ApplicationManagementHolder.SERVICE == null) { + throw new IllegalStateException("ApplicationManagementService is not available from OSGI context."); + } + return ApplicationManagementHolder.SERVICE; } } diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/factory/ApplicationManagementServiceFactory.java b/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/factory/ApplicationManagementServiceFactory.java deleted file mode 100644 index 79e17064f31..00000000000 --- a/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/factory/ApplicationManagementServiceFactory.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.wso2.carbon.identity.client.attestation.filter.factory; - -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the ApplicationManagementService type of object inside the container. - */ -public class ApplicationManagementServiceFactory extends AbstractFactoryBean { - - public ApplicationManagementService applicationManagementService; - - - @Override - public Class getObjectType() { - - return ApplicationManagementService.class; - } - - @Override - protected ApplicationManagementService createInstance() throws Exception { - - if (this.applicationManagementService != null) { - return this.applicationManagementService; - } else { - ApplicationManagementService applicationManagementService = - (ApplicationManagementService) PrivilegedCarbonContext - .getThreadLocalCarbonContext().getOSGiService(ApplicationManagementService.class, null); - if (applicationManagementService != null) { - this.applicationManagementService = applicationManagementService; - } - return applicationManagementService; - } - } -} diff --git a/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/factory/ClientAttestationServiceFactory.java b/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/factory/ClientAttestationServiceFactory.java deleted file mode 100644 index 517da3f082d..00000000000 --- a/components/org.wso2.carbon.identity.client.attestation.filter/src/main/java/org/wso2/carbon/identity/client/attestation/filter/factory/ClientAttestationServiceFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.wso2.carbon.identity.client.attestation.filter.factory; - -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.client.attestation.mgt.services.ClientAttestationService; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the ClientAttestationService type of object inside the container. - */ -public class ClientAttestationServiceFactory extends AbstractFactoryBean { - - public ClientAttestationService clientAttestationService; - - @Override - public Class getObjectType() { - - return ClientAttestationService.class; - } - - @Override - protected ClientAttestationService createInstance() throws Exception { - - if (this.clientAttestationService != null) { - return this.clientAttestationService; - } else { - ClientAttestationService clientAttestationService = (ClientAttestationService) PrivilegedCarbonContext - .getThreadLocalCarbonContext().getOSGiService(ClientAttestationService.class, null); - if (clientAttestationService != null) { - this.clientAttestationService = clientAttestationService; - } - return clientAttestationService; - } - } -} diff --git a/components/org.wso2.carbon.identity.discovery/pom.xml b/components/org.wso2.carbon.identity.discovery/pom.xml index 2c641bcb07c..3d51245f526 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.191-SNAPSHOT + 7.0.214-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 e155302d75a..3d08bf7559c 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.191-SNAPSHOT + 7.0.214-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 92f248f0475..b5da02cf474 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0 @@ -45,11 +45,6 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.oauth - - org.springframework - spring-web - provided - diff --git a/components/org.wso2.carbon.identity.oauth.client.authn.filter/src/main/java/org/wso2/carbon/identity/oauth/client/authn/filter/OAuthClientAuthenticatorProxy.java b/components/org.wso2.carbon.identity.oauth.client.authn.filter/src/main/java/org/wso2/carbon/identity/oauth/client/authn/filter/OAuthClientAuthenticatorProxy.java index cad84aadd7f..d1229ed2296 100644 --- a/components/org.wso2.carbon.identity.oauth.client.authn.filter/src/main/java/org/wso2/carbon/identity/oauth/client/authn/filter/OAuthClientAuthenticatorProxy.java +++ b/components/org.wso2.carbon.identity.oauth.client.authn.filter/src/main/java/org/wso2/carbon/identity/oauth/client/authn/filter/OAuthClientAuthenticatorProxy.java @@ -30,7 +30,6 @@ import org.wso2.carbon.identity.oauth.common.OAuth2ErrorCodes; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; -import org.wso2.carbon.identity.oauth2.client.authentication.OAuthClientAuthnService; import java.util.Arrays; import java.util.HashMap; @@ -51,7 +50,6 @@ public class OAuthClientAuthenticatorProxy extends AbstractPhaseInterceptor PROXY_ENDPOINT_LIST = Arrays.asList("/oauth2/token", "/oauth2/revoke", "/oauth2/device_authorize", "/oauth2/ciba", "/oauth2/par", "/oauth2/authorize"); - private OAuthClientAuthnService oAuthClientAuthnService; private static final String SLASH = "/"; public OAuthClientAuthenticatorProxy() { @@ -60,16 +58,6 @@ public OAuthClientAuthenticatorProxy() { super(Phase.PRE_INVOKE); } - public OAuthClientAuthnService getOAuthClientAuthnService() { - - return oAuthClientAuthnService; - } - - public void setOAuthClientAuthnService(OAuthClientAuthnService oAuthClientAuthnService) { - - this.oAuthClientAuthnService = oAuthClientAuthnService; - } - /** * Handles the incoming JAX-RS message for the purpose of OAuth2 client authentication. * @@ -82,8 +70,8 @@ public void handleMessage(Message message) { HttpServletRequest request = ((HttpServletRequest) message.get(HTTP_REQUEST)); if (canHandle(message)) { try { - OAuthClientAuthnContext oAuthClientAuthnContext = oAuthClientAuthnService - .authenticateClient(request, bodyContentParams); + OAuthClientAuthnContext oAuthClientAuthnContext = OAuthClientAuthnServiceFactory + .getOAuthClientAuthnService().authenticateClient(request, bodyContentParams); if (!oAuthClientAuthnContext.isPreviousAuthenticatorEngaged()) { /* If the previous authenticator is not engaged it means that either client authentication flow failed or no supported authenticaiton mechanism was found.If the error details are already diff --git a/components/org.wso2.carbon.identity.oauth.client.authn.filter/src/main/java/org/wso2/carbon/identity/oauth/client/authn/filter/OAuthClientAuthnServiceFactory.java b/components/org.wso2.carbon.identity.oauth.client.authn.filter/src/main/java/org/wso2/carbon/identity/oauth/client/authn/filter/OAuthClientAuthnServiceFactory.java index 8cf4955e76d..8bb57472b36 100644 --- a/components/org.wso2.carbon.identity.oauth.client.authn.filter/src/main/java/org/wso2/carbon/identity/oauth/client/authn/filter/OAuthClientAuthnServiceFactory.java +++ b/components/org.wso2.carbon.identity.oauth.client.authn.filter/src/main/java/org/wso2/carbon/identity/oauth/client/authn/filter/OAuthClientAuthnServiceFactory.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2019-2024, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -18,37 +18,29 @@ package org.wso2.carbon.identity.oauth.client.authn.filter; -import org.springframework.beans.factory.config.AbstractFactoryBean; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.oauth2.client.authentication.OAuthClientAuthnService; /** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the OAuthClientAuthnService type of object inside the container. + * Factory class to get OAuthClientAuthnService OSGI service. */ -public class OAuthClientAuthnServiceFactory extends AbstractFactoryBean { +public class OAuthClientAuthnServiceFactory { - public OAuthClientAuthnService oAuthClientAuthnService; + private static final OAuthClientAuthnService SERVICE; + static { + OAuthClientAuthnService oAuthClientAuthnService = (OAuthClientAuthnService) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(OAuthClientAuthnService.class, null); - @Override - public Class getObjectType() { + if (oAuthClientAuthnService == null) { + throw new IllegalStateException("OAuthClientAuthnService is not available from OSGI context."); + } - return OAuthClientAuthnService.class; + SERVICE = oAuthClientAuthnService; } - @Override - protected OAuthClientAuthnService createInstance() throws Exception { - - if (this.oAuthClientAuthnService != null) { - return this.oAuthClientAuthnService; - } else { - OAuthClientAuthnService oAuthClientAuthnService = (OAuthClientAuthnService) PrivilegedCarbonContext - .getThreadLocalCarbonContext().getOSGiService(OAuthClientAuthnService.class, null); - if (oAuthClientAuthnService != null) { - this.oAuthClientAuthnService = oAuthClientAuthnService; - } - return oAuthClientAuthnService; - } + public static OAuthClientAuthnService getOAuthClientAuthnService() { + + return SERVICE; } } diff --git a/components/org.wso2.carbon.identity.oauth.common/pom.xml b/components/org.wso2.carbon.identity.oauth.common/pom.xml index 54b269b6b00..69e0752a0db 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0 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 7ee3e18fa16..f4466f49f57 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 @@ -117,6 +117,8 @@ public final class OAuthConstants { public static final String READ_AMR_VALUE_FROM_IDP = "OAuth.ReplaceDefaultAMRValuesWithIDPSentValues"; + public static final String OAUTH_APP = "OAuthAppDO"; + public static final String CNF = "cnf"; public static final String MTLS_AUTH_HEADER = "MutualTLS.ClientCertificateHeader"; public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----"; @@ -579,6 +581,7 @@ public static class OIDCClaims { public static final String EMAIL_VERIFIED = "email_verified"; public static final String ADDRESS = "address"; public static final String ROLES = "roles"; + public static final String APP_ROLES = "application_roles"; public static final String CUSTOM = "custom"; public static final String AZP = "azp"; public static final String AUTH_TIME = "auth_time"; 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 22550842e46..a3ca06d917a 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0 @@ -31,11 +31,6 @@ jackson-databind provided - - org.springframework - spring-web - provided - io.swagger swagger-jaxrs diff --git a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/src/main/webapp/WEB-INF/web.xml b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/src/main/webapp/WEB-INF/web.xml index 3dc8da7d2f3..98dd7589942 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr.endpoint/src/main/webapp/WEB-INF/web.xml +++ b/components/org.wso2.carbon.identity.oauth.dcr.endpoint/src/main/webapp/WEB-INF/web.xml @@ -49,28 +49,30 @@ * - - contextConfigLocation - WEB-INF/beans.xml - - - - org.springframework.web.context.ContextLoaderListener - - - CXFServlet - org.apache.cxf.transport.servlet.CXFServlet + org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet 1 - + + + jaxrs.serviceClasses + + org.wso2.carbon.identity.oauth2.dcr.endpoint.RegisterApi + + - - CXFServlet - /* - + + jaxrs.providers + + com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider, + org.wso2.carbon.identity.oauth2.dcr.endpoint.exmapper.JsonProcessingExceptionMapper, + com.fasterxml.jackson.jaxrs.base.JsonMappingExceptionMapper, + com.fasterxml.jackson.jaxrs.base.JsonParseExceptionMapper + + + 60 diff --git a/components/org.wso2.carbon.identity.oauth.dcr/pom.xml b/components/org.wso2.carbon.identity.oauth.dcr/pom.xml index e96c26a8bdb..e8b7e935466 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0 @@ -126,7 +126,10 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.configuration.mgt.core - + + org.wso2.carbon.identity.organization.management.core + org.wso2.carbon.identity.organization.management.service + @@ -165,6 +168,8 @@ org.wso2.carbon.identity.application.common.model;version="${carbon.identity.framework.imp.pkg.version.range}", org.wso2.carbon.identity.application.mgt.*;version="${carbon.identity.framework.imp.pkg.version.range}", org.wso2.carbon.identity.application.authentication.framework.*;version="${carbon.identity.framework.imp.pkg.version.range}", + org.wso2.carbon.identity.organization.management.service; version="${carbon.identity.organization.management.core.version.range}", + org.wso2.carbon.identity.organization.management.service.exception; version="${carbon.identity.organization.management.core.version.range}", javax.servlet.http; version="${imp.pkg.version.javax.servlet}", org.wso2.carbon.user.api; version="${carbon.user.api.imp.pkg.version.range}", org.wso2.carbon.identity.oauth.*;version="${identity.inbound.auth.oauth.imp.pkg.version.range}", diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/DCRMConstants.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/DCRMConstants.java index 83b32bb5e0d..8eabb696ce1 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/DCRMConstants.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/DCRMConstants.java @@ -60,7 +60,8 @@ public enum ErrorMessages { SIGNATURE_VALIDATION_FAILED("Signature validation failed for the software statement"), MANDATORY_SOFTWARE_STATEMENT("Mandatory software statement is missing"), FAILED_TO_READ_SSA("Error occurred while reading the software statement"), - ADDITIONAL_ATTRIBUTE_ERROR("Error occurred while handling additional attributes"); + ADDITIONAL_ATTRIBUTE_ERROR("Error occurred while handling additional attributes"), + FAILED_TO_RESOLVE_TENANT_DOMAIN("Error while resolving tenant domain from the organization id: %s"); private final String message; private final String errorCode; diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRDataHolder.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRDataHolder.java index eaaf88e4f68..25bf98dbe34 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRDataHolder.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRDataHolder.java @@ -23,6 +23,7 @@ import org.wso2.carbon.identity.oauth.dcr.handler.RegistrationHandler; import org.wso2.carbon.identity.oauth.dcr.handler.UnRegistrationHandler; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; import java.util.ArrayList; import java.util.List; @@ -33,7 +34,6 @@ * This was deprecated as part of deprecating the legacy identity/register DCR endpoint. * The recommendation is to use /identity/oauth2/dcr/v1.1 instead. */ -@Deprecated public class DCRDataHolder { private static DCRDataHolder thisInstance = new DCRDataHolder(); @@ -42,6 +42,7 @@ public class DCRDataHolder { private List unRegistrationHandlerList = new ArrayList<>(); private List tokenBinders = new ArrayList<>(); private ConfigurationManager configurationManager; + private OrganizationManager organizationManager; private DCRDataHolder() { @@ -111,4 +112,14 @@ public void setConfigurationManager(ConfigurationManager configurationManager) { this.configurationManager = configurationManager; } + + public OrganizationManager getOrganizationManager() { + + return organizationManager; + } + + public void setOrganizationManager(OrganizationManager organizationManager) { + + this.organizationManager = organizationManager; + } } diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRServiceComponent.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRServiceComponent.java index fedd5a94b7f..6a0b63318a1 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRServiceComponent.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/internal/DCRServiceComponent.java @@ -42,6 +42,7 @@ import org.wso2.carbon.identity.oauth.dcr.processor.DCRProcessor; import org.wso2.carbon.identity.oauth.dcr.service.DCRMService; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; /** * OAuth DCRM service component. @@ -52,7 +53,6 @@ name = "identity.oauth.dcr", immediate = true ) -@Deprecated public class DCRServiceComponent { private static final Log log = LogFactory.getLog(DCRServiceComponent.class); @@ -254,4 +254,23 @@ protected void unregisterConfigurationManager(ConfigurationManager configuration log.debug("Unregistering the ConfigurationManager in DCR Service Component."); DCRDataHolder.getInstance().setConfigurationManager(null); } + + @Reference( + name = "organization.service", + service = OrganizationManager.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetOrganizationManager" + ) + protected void setOrganizationManager(OrganizationManager organizationManager) { + + DCRDataHolder.getInstance().setOrganizationManager(organizationManager); + log.debug("Set the organization management service."); + } + + protected void unsetOrganizationManager(OrganizationManager organizationManager) { + + DCRDataHolder.getInstance().setOrganizationManager(null); + log.debug("Unset organization management service."); + } } diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMService.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMService.java index 8e2c9c147f7..ae87ca10fe5 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMService.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMService.java @@ -64,6 +64,7 @@ import org.wso2.carbon.identity.oauth2.OAuth2Constants; import org.wso2.carbon.identity.oauth2.util.JWTSignatureValidationUtils; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; import org.wso2.carbon.user.api.UserStoreException; import java.lang.reflect.InvocationTargetException; @@ -105,12 +106,12 @@ public class DCRMService { */ public Application getApplication(String clientId) throws DCRMException { - validateRequestTenantDomain(clientId); + String tenantDomain = getTenantDomain(); + validateRequestTenantDomain(clientId, tenantDomain); OAuthConsumerAppDTO consumerAppDTO = getApplicationById( - clientId, DCRMUtils.isApplicationRolePermissionRequired()); + clientId, DCRMUtils.isApplicationRolePermissionRequired(), tenantDomain); // Get the jwksURI from the service provider. String applicationName = consumerAppDTO.getApplicationName(); - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); ServiceProvider serviceProvider = getServiceProvider(applicationName, tenantDomain); String jwksURI = serviceProvider.getJwksUri(); if (StringUtils.isNotEmpty(jwksURI)) { @@ -156,7 +157,7 @@ public Application getApplicationByName(String clientName) throws DCRMException DCRMConstants.ErrorMessages.BAD_REQUEST_INSUFFICIENT_DATA, null); } - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getTenantDomain(); if (!isServiceProviderExist(clientName, tenantDomain)) { throw DCRMUtils.generateClientException( DCRMConstants.ErrorMessages.NOT_FOUND_APPLICATION_WITH_NAME, clientName); @@ -203,10 +204,10 @@ public Application registerApplication(ApplicationRegistrationRequest registrati */ public void deleteApplication(String clientId) throws DCRMException { - validateRequestTenantDomain(clientId); - OAuthConsumerAppDTO appDTO = getApplicationById(clientId); + String tenantDomain = getTenantDomain(); + validateRequestTenantDomain(clientId, tenantDomain); + OAuthConsumerAppDTO appDTO = getApplicationById(clientId, tenantDomain); String applicationOwner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); String spName; try { spName = DCRDataHolder.getInstance().getApplicationManagementService() @@ -241,9 +242,9 @@ public void deleteApplication(String clientId) throws DCRMException { */ public Application updateApplication(ApplicationUpdateRequest updateRequest, String clientId) throws DCRMException { - validateRequestTenantDomain(clientId); - OAuthConsumerAppDTO appDTO = getApplicationById(clientId); - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getTenantDomain(); + validateRequestTenantDomain(clientId, tenantDomain); + OAuthConsumerAppDTO appDTO = getApplicationById(clientId, tenantDomain); String applicationOwner = StringUtils.isNotBlank(updateRequest.getExtApplicationOwner()) ? updateRequest.getExtApplicationOwner() : PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); @@ -309,13 +310,24 @@ public Application updateApplication(ApplicationUpdateRequest updateRequest, Str sp.setJwksUri(updateRequest.getJwksURI()); } // Todo: validate version input. Create a function at app mgt. - sp.setApplicationVersion(applicationVersion); - // Need to create a deep clone, since modifying the fields of the original object, - // will modify the cached SP object. - ServiceProvider clonedSP = cloneServiceProvider(sp); + if (StringUtils.isNotBlank(applicationVersion)) { + sp.setApplicationVersion(applicationVersion); + } + } + if (StringUtils.isNotEmpty(updateRequest.getExtAllowedAudience()) && + (updateRequest.getExtAllowedAudience().equalsIgnoreCase(ORG_ROLE_AUDIENCE) + || updateRequest.getExtAllowedAudience().equalsIgnoreCase(APP_ROLE_AUDIENCE))) { + AssociatedRolesConfig associatedRolesConfig = new AssociatedRolesConfig(); + associatedRolesConfig.setAllowedAudience(updateRequest.getExtAllowedAudience().toLowerCase()); + sp.setAssociatedRolesConfig(associatedRolesConfig); + } + // Need to create a deep clone, since modifying the fields of the original object, + // will modify the cached SP object. + ServiceProvider clonedSP = cloneServiceProvider(sp); + if (StringUtils.isNotEmpty(clientName)) { clonedSP.setApplicationName(clientName); - updateServiceProvider(clonedSP, tenantDomain, applicationOwner); } + updateServiceProvider(clonedSP, tenantDomain, applicationOwner); // Update application try { @@ -412,21 +424,13 @@ public Application updateApplication(ApplicationUpdateRequest updateRequest, Str appDTO.setPkceSupportPlain(updateRequest.isExtPkceSupportPlain()); appDTO.setBypassClientCredentials(updateRequest.isExtPublicClient()); oAuthAdminService.updateConsumerApplication(appDTO); - - if (StringUtils.isNotEmpty(updateRequest.getExtAllowedAudience()) && - (updateRequest.getExtAllowedAudience().equalsIgnoreCase(ORG_ROLE_AUDIENCE) - || updateRequest.getExtAllowedAudience().equalsIgnoreCase(APP_ROLE_AUDIENCE))) { - AssociatedRolesConfig associatedRolesConfig = new AssociatedRolesConfig(); - associatedRolesConfig.setAllowedAudience(updateRequest.getExtAllowedAudience().toLowerCase()); - sp.setAssociatedRolesConfig(associatedRolesConfig); - } } catch (IdentityOAuthClientException e) { throw new DCRMClientException(DCRMConstants.ErrorCodes.INVALID_CLIENT_METADATA, e.getMessage(), e); } catch (IdentityOAuthAdminException e) { throw DCRMUtils.generateServerException( DCRMConstants.ErrorMessages.FAILED_TO_UPDATE_APPLICATION, clientId, e); } - OAuthConsumerAppDTO oAuthConsumerAppDTO = getApplicationById(clientId); + OAuthConsumerAppDTO oAuthConsumerAppDTO = getApplicationById(clientId, tenantDomain); // Setting the jwksURI to be sent in the response. oAuthConsumerAppDTO.setJwksURI(updateRequest.getJwksURI()); Application application = buildResponse(oAuthConsumerAppDTO, tenantDomain); @@ -489,12 +493,13 @@ private String getDisplayNameProperty(ServiceProvider serviceProvider) { return displayNameProperty.map(ServiceProviderProperty::getValue).orElse(null); } - private OAuthConsumerAppDTO getApplicationById(String clientId) throws DCRMException { + private OAuthConsumerAppDTO getApplicationById(String clientId, String tenantDomain) throws DCRMException { - return getApplicationById(clientId, true); + return getApplicationById(clientId, true, tenantDomain); } - private OAuthConsumerAppDTO getApplicationById(String clientId, boolean isApplicationRolePermissionRequired) + private OAuthConsumerAppDTO getApplicationById(String clientId, boolean isApplicationRolePermissionRequired, + String tenantDomain) throws DCRMException { if (StringUtils.isEmpty(clientId)) { @@ -504,7 +509,7 @@ private OAuthConsumerAppDTO getApplicationById(String clientId, boolean isApplic } try { - OAuthConsumerAppDTO dto = oAuthAdminService.getOAuthApplicationData(clientId); + OAuthConsumerAppDTO dto = oAuthAdminService.getOAuthApplicationData(clientId, tenantDomain); if (dto == null || StringUtils.isEmpty(dto.getApplicationName())) { throw DCRMUtils.generateClientException( DCRMConstants.ErrorMessages.NOT_FOUND_APPLICATION_WITH_ID, clientId); @@ -529,8 +534,7 @@ private Application createOAuthApplication(ApplicationRegistrationRequest regist String applicationOwner = StringUtils.isNotBlank(registrationRequest.getExtApplicationOwner()) ? registrationRequest.getExtApplicationOwner() : PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); - - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getTenantDomain(); /* * ApplicationOwner will be null and a server error is thrown when creating an app, if the api authentication/ @@ -566,7 +570,7 @@ private Application createOAuthApplication(ApplicationRegistrationRequest regist } if (StringUtils.isNotEmpty(registrationRequest.getConsumerKey()) && isClientIdExist( - registrationRequest.getConsumerKey())) { + registrationRequest.getConsumerKey(), tenantDomain)) { throw DCRMUtils.generateClientException(DCRMConstants.ErrorMessages.CONFLICT_EXISTING_CLIENT_ID, registrationRequest.getConsumerKey()); } @@ -941,10 +945,10 @@ private boolean isServiceProviderExist(String serviceProviderName, String tenant * @return true if application exists with the client id. * @throws DCRMException in case of failure. */ - private boolean isClientIdExist(String clientId) throws DCRMException { + private boolean isClientIdExist(String clientId, String tenantDomain) throws DCRMException { try { - OAuthConsumerAppDTO dto = oAuthAdminService.getOAuthApplicationData(clientId); + OAuthConsumerAppDTO dto = oAuthAdminService.getOAuthApplicationData(clientId, tenantDomain); return dto != null && StringUtils.isNotBlank(dto.getApplicationName()); } catch (IdentityOAuthAdminException e) { if (e.getCause() instanceof InvalidOAuthClientException) { @@ -1144,7 +1148,7 @@ private String escapeQueryParamsIfPresent(String redirectURI) { private boolean isUserAuthorized(String clientId) throws DCRMServerException { try { - String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getTenantDomain(); String spName = DCRDataHolder.getInstance().getApplicationManagementService() .getServiceProviderNameByClientId(clientId, DCRMConstants.OAUTH2, tenantDomain); String threadLocalUserName = CarbonContext.getThreadLocalCarbonContext().getUsername(); @@ -1176,10 +1180,10 @@ private static boolean clientIdMatchesRegex(String clientId, String clientIdVali * @param clientId Consumer key of application. * @throws DCRMException DCRMException */ - private void validateRequestTenantDomain(String clientId) throws DCRMException { + private void validateRequestTenantDomain(String clientId, String tenantDomain) throws DCRMException { try { - String tenantDomainOfApp = OAuth2Util.getTenantDomainOfOauthApp(clientId); + String tenantDomainOfApp = OAuth2Util.getTenantDomainOfOauthApp(clientId, tenantDomain); OAuth2Util.validateRequestTenantDomain(tenantDomainOfApp); } catch (InvalidOAuthClientException e) { throw new DCRMClientException(DCRMConstants.ErrorMessages.TENANT_DOMAIN_MISMATCH.getErrorCode(), @@ -1275,4 +1279,21 @@ private void addSPProperties(Map spProperties, ServiceProvider s } serviceProvider.setSpProperties(serviceProviderProperties); } + + private static String getTenantDomain() throws DCRMServerException { + + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = DCRDataHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw DCRMUtils.generateServerException( + DCRMConstants.ErrorMessages.FAILED_TO_RESOLVE_TENANT_DOMAIN, applicationResidentOrgId, e); + } + } + return tenantDomain; + } } diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/util/DCRMUtils.java b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/util/DCRMUtils.java index 7e2df76179e..beb611f1de1 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/util/DCRMUtils.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/main/java/org/wso2/carbon/identity/oauth/dcr/util/DCRMUtils.java @@ -37,7 +37,6 @@ * This was deprecated as part of deprecating the legacy identity/register DCR endpoint. * The recommendation is to use /identity/oauth2/dcr/v1.1 instead. */ -@Deprecated public class DCRMUtils { private static final Log log = LogFactory.getLog(DCRMUtils.class); diff --git a/components/org.wso2.carbon.identity.oauth.dcr/src/test/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMServiceTest.java b/components/org.wso2.carbon.identity.oauth.dcr/src/test/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMServiceTest.java index 87c456aaf23..8edaea61d9c 100644 --- a/components/org.wso2.carbon.identity.oauth.dcr/src/test/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMServiceTest.java +++ b/components/org.wso2.carbon.identity.oauth.dcr/src/test/java/org/wso2/carbon/identity/oauth/dcr/service/DCRMServiceTest.java @@ -108,6 +108,7 @@ public class DCRMServiceTest { private String dummyCallbackUrl = "dummyCallbackUrl"; private final String dummyTemplateName = "dummyTemplateName"; private final String dummyBackchannelLogoutUri = "http://backchannel.com/"; + private static final String ORG_ROLE_AUDIENCE = "organization"; @Mock private OAuthConsumerAppDTO dto; @@ -199,12 +200,12 @@ public void getApplicationEmptyClientIdTest() throws DCRMException { public void getApplicationNullDTOTest(String dtoStatus) throws Exception { if (dtoStatus == null) { - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(null); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(null); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()).thenReturn(new OAuthConsumerAppDTO[0]); } else { OAuthConsumerAppDTO dto = new OAuthConsumerAppDTO(); dto.setApplicationName(""); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()) .thenReturn(new OAuthConsumerAppDTO[]{dto}); } @@ -222,7 +223,7 @@ public void getApplicationNullDTOTest(String dtoStatus) throws Exception { public void getApplicationDTOTestWithIOAException() throws Exception { doThrow(new IdentityOAuthAdminException("")).when(mockOAuthAdminService) - .getOAuthApplicationData(dummyConsumerKey); + .getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()).thenReturn(new OAuthConsumerAppDTO[0]); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); @@ -239,7 +240,7 @@ public void getApplicationDTOTestWithIOAException() throws Exception { public void getApplicationDTOTestWithIOCException() throws Exception { doThrow(new IdentityOAuthAdminException("", new InvalidOAuthClientException(""))).when(mockOAuthAdminService) - .getOAuthApplicationData(dummyConsumerKey); + .getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()).thenReturn(new OAuthConsumerAppDTO[0]); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); @@ -256,7 +257,7 @@ public void getApplicationDTOTestWithIOCException() throws Exception { public void getApplicationDTOTestUserUnauthorized() throws Exception { setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); when(dto.getApplicationName()).thenReturn(dummyClientName); try { @@ -276,7 +277,7 @@ public void isUserAuthorizedTestWithIAMException() throws IdentityOAuthAdminExce UserStoreException, NoSuchFieldException, IllegalAccessException { setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); when(dto.getApplicationName()).thenReturn(dummyClientName); try { @@ -304,7 +305,7 @@ public void getApplicationDTOTest(String roleAudience) throws Exception { dto.setCallbackUrl(dummyCallbackUrl); dto.setUsername(dummyUserName.concat("@").concat(dummyTenantDomain)); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUserRealm(mockedUserRealm); when(mockedUserRealm.getUserStoreManager()).thenReturn(mockedUserStoreManager); @@ -328,7 +329,8 @@ public void getApplicationDTOTest(String roleAudience) throws Exception { public void validateRequestTenantDomainTestWitInvalidOAuthClientException() throws IdentityOAuth2Exception, InvalidOAuthClientException { - when(OAuth2Util.getTenantDomainOfOauthApp(dummyConsumerKey)).thenThrow(new InvalidOAuthClientException("")); + when(OAuth2Util.getTenantDomainOfOauthApp(dummyConsumerKey, dummyTenantDomain)). + thenThrow(new InvalidOAuthClientException("")); try { dcrmService.getApplication(dummyConsumerKey); } catch (DCRMException ex) { @@ -343,7 +345,8 @@ public void validateRequestTenantDomainTestWitInvalidOAuthClientException() public void validateRequestTenantDomainTestWitIdentityOAuth2Exception() throws IdentityOAuth2Exception, InvalidOAuthClientException { - when(OAuth2Util.getTenantDomainOfOauthApp(dummyConsumerKey)).thenThrow(new IdentityOAuth2Exception("")); + when(OAuth2Util.getTenantDomainOfOauthApp(dummyConsumerKey, dummyTenantDomain)). + thenThrow(new IdentityOAuth2Exception("")); try { dcrmService.getApplication(dummyConsumerKey); } catch (DCRMException ex) { @@ -535,7 +538,7 @@ public void registerApplicationTestWithExistClientId() throws Exception { applicationRegistrationRequest.setGrantTypes(dummyGrantTypes); applicationRegistrationRequest.setConsumerKey(dummyConsumerKey); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)) + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)) .thenReturn(dto); when(dto.getApplicationName()).thenReturn(dummyClientName); @@ -915,7 +918,8 @@ public void isClientIdExistTestWithIdentityOAuthAdminException() throws Exceptio setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); IdentityOAuthAdminException identityOAuthAdminException = mock(IdentityOAuthAdminException.class); - doThrow(identityOAuthAdminException).when(mockOAuthAdminService).getOAuthApplicationData(dummyConsumerKey); + doThrow(identityOAuthAdminException).when(mockOAuthAdminService).getOAuthApplicationData(dummyConsumerKey, + dummyTenantDomain); try { dcrmService.registerApplication(applicationRegistrationRequest); } catch (IdentityException ex) { @@ -974,7 +978,7 @@ private OAuthConsumerAppDTO registerApplicationTestWithFailedToUpdateSP() throws lenient().when(mockOAuthAdminService .getOAuthApplicationDataByAppName(dummyClientName)).thenReturn(oAuthConsumerApp); lenient().when(mockOAuthAdminService - .getOAuthApplicationData("dummyConsumerKey")).thenReturn(oAuthConsumerApp); + .getOAuthApplicationData("dummyConsumerKey", dummyTenantDomain)).thenReturn(oAuthConsumerApp); lenient().when(mockOAuthAdminService.getAllOAuthApplicationData()) .thenReturn(new OAuthConsumerAppDTO[]{oAuthConsumerApp}); lenient().when(mockOAuthAdminService.registerAndRetrieveOAuthApplicationData(any(OAuthConsumerAppDTO.class))). @@ -1004,6 +1008,7 @@ public void updateApplicationTest(List redirectUri1, String roleAudience assertEquals(application.getClientId(), dummyConsumerKey); assertEquals(application.getClientName(), dummyClientName); assertEquals(application.getClientSecret(), dummyConsumerSecret); + assertEquals(application.getExtAllowedAudience(), roleAudience); } @Test @@ -1107,7 +1112,7 @@ private OAuthConsumerAppDTO updateApplication() dto.setCallbackUrl(dummyCallbackUrl); dto.setUsername(dummyUserName.concat("@").concat(dummyTenantDomain)); - when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey)).thenReturn(dto); + when(mockOAuthAdminService.getOAuthApplicationData(dummyConsumerKey, dummyTenantDomain)).thenReturn(dto); setInternalState(dcrmService, "oAuthAdminService", mockOAuthAdminService); ServiceProvider serviceProvider = new ServiceProvider(); diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml b/components/org.wso2.carbon.identity.oauth.endpoint/pom.xml index da49b25e9b4..907932139ec 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0 @@ -146,6 +146,14 @@ org.wso2.carbon.identity.oidc.session provided + + org.apache.httpcomponents.wso2 + httpcore + + + org.wso2.orbit.org.apache.httpcomponents + httpclient + com.google.code.gson gson @@ -161,11 +169,6 @@ org.wso2.carbon.identity.client.attestation.filter provided - - org.springframework - spring-web - provided - com.fasterxml.jackson.core jackson-databind @@ -323,7 +326,7 @@ COMPLEXITY COVEREDRATIO - 0.48 + 0.47 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 fe628a50698..b12082cac57 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 @@ -136,7 +136,6 @@ import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; 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; import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.oauth2.util.RequestUtil; @@ -144,7 +143,6 @@ import org.wso2.carbon.identity.oidc.session.util.OIDCSessionManagementUtil; import org.wso2.carbon.identity.openidconnect.OIDCConstants; import org.wso2.carbon.identity.openidconnect.OIDCRequestObjectUtil; -import org.wso2.carbon.identity.openidconnect.OpenIDConnectClaimFilterImpl; import org.wso2.carbon.identity.openidconnect.model.RequestObject; import org.wso2.carbon.identity.openidconnect.model.RequestedClaim; import org.wso2.carbon.utils.CarbonUtils; @@ -211,12 +209,13 @@ import static org.wso2.carbon.identity.oauth.endpoint.state.OAuthAuthorizeState.USER_CONSENT_RESPONSE; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getErrorPageURL; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getLoginPageURL; -import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getOAuth2Service; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getOAuthAuthzRequest; -import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getOAuthServerConfiguration; -import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getSSOConsentService; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.retrieveStateForErrorURL; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.validateParams; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory.getOAuth2Service; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuthServerConfigurationFactory.getOAuthServerConfiguration; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.RequestObjectServiceFactory.getRequestObjectService; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.SSOConsentServiceFactory.getSSOConsentService; import static org.wso2.carbon.identity.oauth2.OAuth2Constants.TokenBinderType.CLIENT_REQUEST; import static org.wso2.carbon.identity.oauth2.util.OAuth2Util.ACCESS_TOKEN_JS_OBJECT; import static org.wso2.carbon.identity.oauth2.util.OAuth2Util.DYNAMIC_TOKEN_DATA_FUNCTION; @@ -276,37 +275,11 @@ public class OAuth2AuthzEndpoint { private static final String OIDC_DIALECT = "http://wso2.org/oidc/claim"; - private static OpenIDConnectClaimFilterImpl openIDConnectClaimFilter; - - private static ScopeMetadataService scopeMetadataService; - private static DeviceAuthService deviceAuthService; 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(); - public static OpenIDConnectClaimFilterImpl getOpenIDConnectClaimFilter() { - - return openIDConnectClaimFilter; - } - - public static void setOpenIDConnectClaimFilter(OpenIDConnectClaimFilterImpl openIDConnectClaimFilter) { - - OAuth2AuthzEndpoint.openIDConnectClaimFilter = openIDConnectClaimFilter; - } - - public static ScopeMetadataService getScopeMetadataService() { - - return scopeMetadataService; - } - - public static void setScopeMetadataService(ScopeMetadataService scopeMetadataService) { - - OAuth2AuthzEndpoint.scopeMetadataService = scopeMetadataService; - } - - private static Class oAuthAuthzRequestClass; - @GET @Path("/") @Consumes("application/x-www-form-urlencoded") @@ -421,6 +394,36 @@ private void addFederatedTokensToSessionCache(OAuthMessage oAuthMessage, } } + /** + * Add mapped remote claims to session cache. + * + * @param oAuthMessage The OAuthMessage with the session data cache entry. + * @param authenticationResult The authentication result of authorization call. + */ + private void addMappedRemoteClaimsToSessionCache(OAuthMessage oAuthMessage, + AuthenticationResult authenticationResult) { + + Optional> mappedRemoteClaims = authenticationResult.getMappedRemoteClaims(); + if (!mappedRemoteClaims.isPresent()) { + return; + } + + SessionDataCacheEntry sessionDataCacheEntry = oAuthMessage.getSessionDataCacheEntry(); + if (sessionDataCacheEntry == null || mappedRemoteClaims.get().isEmpty()) { + return; + } + Map mappedRemoteClaimsMap = new HashMap<>(); + mappedRemoteClaims.get().forEach( + (key, value) -> mappedRemoteClaimsMap.put(ClaimMapping.build(key, key, null, + false), value)); + sessionDataCacheEntry.setMappedRemoteClaims(mappedRemoteClaimsMap); + if (log.isDebugEnabled() && authenticationResult.getSubject() != null) { + log.debug("Added the mapped remote claims to the session data cache. " + + "Session context identifier: " + sessionDataCacheEntry.getSessionContextIdentifier() + + " for the user: " + authenticationResult.getSubject().getLoggableMaskedUserId()); + } + } + /** * This method creates a list of FederatedTokenDO objects from the list of FederatedToken objects. * @@ -534,9 +537,7 @@ private Response handleOAuthSystemException(OAuthMessage oAuthMessage, OAuthSyst if (oAuthMessage.getSessionDataCacheEntry() != null) { params = oAuthMessage.getSessionDataCacheEntry().getoAuth2Parameters(); } - if (log.isDebugEnabled()) { - log.debug("Server error occurred while performing authorization", e); - } + log.error("Server error occurred while performing authorization", e); OAuthProblemException ex = OAuthProblemException.error(OAuth2ErrorCodes.SERVER_ERROR, "Server error occurred while performing authorization"); return Response.status(HttpServletResponse.SC_FOUND).location(new URI( @@ -547,14 +548,15 @@ private Response handleIdentityException(HttpServletRequest request, IdentityExc throws URISyntaxException { if (OAuth2ErrorCodes.SERVER_ERROR.equals(e.getErrorCode())) { - if (log.isDebugEnabled()) { - log.debug("Server error occurred while performing authorization", e); - } + log.error("Server error occurred while performing authorization", e); OAuthProblemException ex = OAuthProblemException.error(OAuth2ErrorCodes.SERVER_ERROR, "Server error occurred while performing authorization"); return Response.status(HttpServletResponse.SC_FOUND).location(new URI( EndpointUtil.getErrorRedirectURL(request, ex, null))).build(); } + if (log.isDebugEnabled()) { + log.debug("Invalid authorization request", e); + } return Response.status(HttpServletResponse.SC_FOUND).location(new URI(EndpointUtil.getErrorPageURL(request, e.getErrorCode(), OAuth2ErrorCodes.OAuth2SubErrorCodes.INVALID_AUTHORIZATION_REQUEST, e.getMessage(), null))).build(); @@ -976,9 +978,11 @@ private ConsentClaimsData getConsentRequiredClaims(AuthenticatedUser user, Servi if (hasPromptContainsConsent(oAuth2Parameters)) { // Ignore all previous consents and get consent required claims - return getSSOConsentService().getConsentRequiredClaimsWithoutExistingConsents(serviceProvider, user); + return getSSOConsentService().getConsentRequiredClaimsWithoutExistingConsents( + serviceProvider, user); } else { - return getSSOConsentService().getConsentRequiredClaimsWithExistingConsents(serviceProvider, user); + return getSSOConsentService().getConsentRequiredClaimsWithExistingConsents( + serviceProvider, user); } } @@ -1118,7 +1122,7 @@ private void handleDeniedConsent(OAuthMessage oAuthMessage, AuthorizationRespons getOauth2Params(oAuthMessage).getApplicationName(), false, oauth2Params.getClientId()); - OAuthErrorDTO oAuthErrorDTO = EndpointUtil.getOAuth2Service().handleUserConsentDenial(oauth2Params); + OAuthErrorDTO oAuthErrorDTO = getOAuth2Service().handleUserConsentDenial(oauth2Params); OAuthProblemException consentDenialException = buildConsentDenialException(oAuthErrorDTO); if (ResponseModeProvider.AuthResponseType.POST_RESPONSE.equals(responseModeProvider.getAuthResponseType())) { @@ -1355,7 +1359,7 @@ private Response handleFailedAuthentication(OAuthMessage oAuthMessage, OAuth2Par AuthorizationResponseDTO authorizationResponseDTO) throws URISyntaxException { - OAuthErrorDTO oAuthErrorDTO = EndpointUtil.getOAuth2Service().handleAuthenticationFailure(oauth2Params); + OAuthErrorDTO oAuthErrorDTO = getOAuth2Service().handleAuthenticationFailure(oauth2Params); OAuthProblemException oauthException = buildOAuthProblemException(authnResult, oAuthErrorDTO); return handleFailedState(oAuthMessage, oauth2Params, oauthException, authorizationResponseDTO); } @@ -1390,6 +1394,9 @@ private void addToAuthenticationResultDetailsToOAuthMessage(OAuthMessage oAuthMe authnResult.getProperty(FrameworkConstants.AnalyticsAttributes.SESSION_ID)); // Adding federated tokens come with the authentication result of the authorization call. addFederatedTokensToSessionCache(oAuthMessage, authnResult); + // Adding mapped remoted claims come with the authentication result to resolve access token claims in + // federated flow. + addMappedRemoteClaimsToSessionCache(oAuthMessage, authnResult); } private void updateAuthTimeInSessionDataCacheEntry(OAuthMessage oAuthMessage) { @@ -2144,6 +2151,10 @@ private void addUserAttributesToOAuthMessage(OAuthMessage oAuthMessage, String c authorizationGrantCacheEntry.setRequestObjectFlow(isRequestObjectFlow); authorizationGrantCacheEntry.setFederatedTokens(sessionDataCacheEntry.getFederatedTokens()); sessionDataCacheEntry.setFederatedTokens(null); + Map mappedRemoteClaims = sessionDataCacheEntry.getMappedRemoteClaims(); + if (mappedRemoteClaims != null) { + authorizationGrantCacheEntry.setMappedRemoteClaims(mappedRemoteClaims); + } oAuthMessage.setAuthorizationGrantCacheEntry(authorizationGrantCacheEntry); } @@ -2319,9 +2330,9 @@ private void persistRequestObject(OAuth2Parameters params, RequestObject request throws RequestObjectException { String sessionDataKey = params.getSessionDataKey(); - if (EndpointUtil.getRequestObjectService() != null) { + if (getRequestObjectService() != null) { if (requestObject != null && MapUtils.isNotEmpty(requestObject.getRequestedClaims())) { - EndpointUtil.getRequestObjectService().addRequestObject(params.getClientId(), sessionDataKey, + getRequestObjectService().addRequestObject(params.getClientId(), sessionDataKey, new ArrayList(requestObject.getRequestedClaims().values())); params.setRequestObjectFlow(true); } @@ -3407,16 +3418,17 @@ private List getRequestedOidcClaimsList(ConsentClaimsData claimsF // Get the claims uri list of all the requested scopes. Eg:- country, email. List claimListOfScopes = - openIDConnectClaimFilter.getClaimsFilteredByOIDCScopes(oauth2Params.getScopes(), spTenantDomain); + OAuth2AuthzServiceFactory.getOpenIdClaimFilterImpl().getClaimsFilteredByOIDCScopes( + oauth2Params.getScopes(), spTenantDomain); List essentialRequestedClaims = new ArrayList<>(); if (oauth2Params.isRequestObjectFlow()) { // Get the requested claims came through request object. - List requestedClaimsOfIdToken = EndpointUtil.getRequestObjectService() + List requestedClaimsOfIdToken = getRequestObjectService() .getRequestedClaimsForSessionDataKey(oauth2Params.getSessionDataKey(), false); - List requestedClaimsOfUserInfo = EndpointUtil.getRequestObjectService() + List requestedClaimsOfUserInfo = getRequestObjectService() .getRequestedClaimsForSessionDataKey(oauth2Params.getSessionDataKey(), true); @@ -3786,6 +3798,7 @@ private OAuth2AuthorizeReqDTO buildAuthRequest(OAuth2Parameters oauth2Params, Se authzReqDTO.setState(oauth2Params.getState()); authzReqDTO.setHttpServletRequestWrapper(new HttpServletRequestWrapper(request)); authzReqDTO.setRequestedSubjectId(oauth2Params.getRequestedSubjectId()); + authzReqDTO.setMappedRemoteClaims(sessionDataCacheEntry.getMappedRemoteClaims()); if (sessionDataCacheEntry.getParamMap() != null && sessionDataCacheEntry.getParamMap().get(OAuthConstants .AMR) != null) { @@ -4521,6 +4534,10 @@ private void addUserAttributesToCache(SessionDataCacheEntry sessionDataCacheEntr DeviceAuthorizationGrantCacheKey cacheKey = new DeviceAuthorizationGrantCacheKey(deviceCode); DeviceAuthorizationGrantCacheEntry cacheEntry = new DeviceAuthorizationGrantCacheEntry(sessionDataCacheEntry.getLoggedInUser().getUserAttributes()); + if (sessionDataCacheEntry.getMappedRemoteClaims() != null) { + cacheEntry.setMappedRemoteClaims(sessionDataCacheEntry + .getMappedRemoteClaims()); + } DeviceAuthorizationGrantCache.getInstance().addToCache(cacheKey, cacheEntry); } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzServiceFactory.java new file mode 100644 index 00000000000..661e12843aa --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/authz/OAuth2AuthzServiceFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth.endpoint.authz; + +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.identity.openidconnect.OpenIDConnectClaimFilterImpl; + +/** + * Service holder for managing instances of OAuth2 Authorization related services. + */ +public class OAuth2AuthzServiceFactory { + + private static final OpenIDConnectClaimFilterImpl SERVICE; + + static { + OpenIDConnectClaimFilterImpl openIDConnectClaimFilter = (OpenIDConnectClaimFilterImpl) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(OpenIDConnectClaimFilterImpl.class, null); + if (openIDConnectClaimFilter == null) { + throw new IllegalStateException("OpenIDConnectClaimFilterImpl is not available from OSGi context."); + } + SERVICE = openIDConnectClaimFilter; + } + + public static OpenIDConnectClaimFilterImpl getOpenIdClaimFilterImpl() { + + return SERVICE; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/ciba/OAuth2CibaEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/ciba/OAuth2CibaEndpoint.java index e1da2d43456..c8d409a976c 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/ciba/OAuth2CibaEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/ciba/OAuth2CibaEndpoint.java @@ -35,7 +35,7 @@ import org.wso2.carbon.identity.oauth.endpoint.OAuthRequestWrapper; import org.wso2.carbon.identity.oauth.endpoint.exception.CibaAuthFailureException; import org.wso2.carbon.identity.oauth.endpoint.exception.InvalidRequestException; -import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.CibaAuthServiceFactory; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.RequestObjectException; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; @@ -161,7 +161,8 @@ private CibaAuthCodeResponse getCibaAuthCodeResponse(CibaAuthCodeRequest cibaAut throws CibaAuthFailureException { try { - cibaAuthCodeResponse = EndpointUtil.getCibaAuthService().generateAuthCodeResponse(cibaAuthCodeRequest); + cibaAuthCodeResponse = CibaAuthServiceFactory.getCibaAuthService() + .generateAuthCodeResponse(cibaAuthCodeRequest); } catch (CibaCoreException | CibaClientException e) { throw new CibaAuthFailureException(OAuth2ErrorCodes.SERVER_ERROR, "Error while generating " + "authentication response.", e); diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceEndpoint.java index 266da80b216..79d577d33bd 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceEndpoint.java @@ -32,11 +32,11 @@ import org.wso2.carbon.identity.oauth.common.OAuth2ErrorCodes; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; +import org.wso2.carbon.identity.oauth.endpoint.OAuthRequestWrapper; import org.wso2.carbon.identity.oauth.endpoint.exception.TokenEndpointBadRequestException; import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; -import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthService; import org.wso2.carbon.identity.oauth2.device.codegenerator.GenerateKeys; import org.wso2.carbon.identity.oauth2.device.constants.Constants; import org.wso2.carbon.identity.oauth2.device.util.DeviceFlowUtil; @@ -60,12 +60,6 @@ @InInterceptors(classes = OAuthClientAuthenticatorProxy.class) public class DeviceEndpoint { private static final Log log = LogFactory.getLog(DeviceEndpoint.class); - private DeviceAuthService deviceAuthService; - - public void setDeviceAuthService(DeviceAuthService deviceAuthService) { - - this.deviceAuthService = deviceAuthService; - } @POST @Path("/") @@ -81,6 +75,9 @@ public Response authorize(@Context HttpServletRequest request, MultivaluedMap paramMap) diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceServiceFactory.java new file mode 100644 index 00000000000..f6bb6170ac9 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceServiceFactory.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth.endpoint.device; + +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthService; +import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthServiceImpl; + +/** + * Service holder for managing instances of Device Authentication related services. + */ +public class DeviceServiceFactory { + + private static final DeviceAuthServiceImpl SERVICE; + + static { + DeviceAuthServiceImpl deviceAuthService = (DeviceAuthServiceImpl) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(DeviceAuthServiceImpl.class, null); + if (deviceAuthService == null) { + throw new IllegalStateException("DeviceAuthService is not available from OSGi context."); + } + SERVICE = deviceAuthService; + } + + public static DeviceAuthService getDeviceAuthService() { + + return SERVICE; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/UserAuthenticationEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/UserAuthenticationEndpoint.java index 127a7aa3105..afff573f89c 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/UserAuthenticationEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/device/UserAuthenticationEndpoint.java @@ -33,7 +33,6 @@ import org.wso2.carbon.identity.oauth.endpoint.exception.InvalidRequestParentException; import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; -import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthService; import org.wso2.carbon.identity.oauth2.device.constants.Constants; import org.wso2.carbon.identity.oauth2.device.dao.DeviceFlowPersistenceFactory; import org.wso2.carbon.identity.oauth2.device.model.DeviceFlowDO; @@ -63,12 +62,6 @@ public class UserAuthenticationEndpoint { public static final String INVALID_CODE_ERROR_KEY = "invalid.code"; private OAuth2AuthzEndpoint oAuth2AuthzEndpoint = new OAuth2AuthzEndpoint(); private DeviceFlowDO deviceFlowDO = new DeviceFlowDO(); - private DeviceAuthService deviceAuthService; - - public void setDeviceAuthService(DeviceAuthService deviceAuthService) { - - this.deviceAuthService = deviceAuthService; - } @POST @Path("/") @@ -89,10 +82,10 @@ public Response deviceAuthorize(@Context HttpServletRequest request, @Context Ht return Response.status(HttpServletResponse.SC_FOUND).location(URI.create(error)).build(); } DeviceFlowDO deviceFlowDODetails = - deviceAuthService.getDetailsByUserCode(userCode); + DeviceServiceFactory.getDeviceAuthService().getDetailsByUserCode(userCode); if (!isExpiredUserCode(deviceFlowDODetails)) { String clientId = deviceFlowDODetails.getConsumerKey(); - deviceAuthService.setAuthenticationStatus(userCode); + DeviceServiceFactory.getDeviceAuthService().setAuthenticationStatus(userCode); CommonAuthRequestWrapper commonAuthRequestWrapper = new CommonAuthRequestWrapper(request); commonAuthRequestWrapper.setParameter(Constants.CLIENT_ID, clientId); commonAuthRequestWrapper.setParameter(Constants.RESPONSE_TYPE, Constants.RESPONSE_TYPE_DEVICE); diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/CibaServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/CibaServiceFactory.java deleted file mode 100644 index a46e71617de..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/CibaServiceFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.oauth.ciba.api.CibaAuthService; -import org.wso2.carbon.identity.oauth.ciba.api.CibaAuthServiceImpl; - -/** - * This class is used to register CibaAuthService as a factory bean. - */ -public class CibaServiceFactory extends AbstractFactoryBean { - - private CibaAuthServiceImpl cibaAuthService; - - @Override - public Class getObjectType() { - - return CibaAuthServiceImpl.class; - } - - @Override - protected CibaAuthServiceImpl createInstance() throws Exception { - - if (cibaAuthService != null) { - return cibaAuthService; - } else { - CibaAuthServiceImpl cibaAuthService = (CibaAuthServiceImpl) - PrivilegedCarbonContext.getThreadLocalCarbonContext(). - getOSGiService(CibaAuthService.class, null); - if (cibaAuthService != null) { - this.cibaAuthService = cibaAuthService; - } - return cibaAuthService; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/DeviceAuthServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/DeviceAuthServiceFactory.java deleted file mode 100644 index e3c737bcb37..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/DeviceAuthServiceFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.oauth2.device.api.DeviceAuthService; - -/** - * This class is used to register DeviceAuthService as a factory bean. - */ -public class DeviceAuthServiceFactory extends AbstractFactoryBean { - - private DeviceAuthService deviceAuthService; - - @Override - public Class getObjectType() { - - return DeviceAuthService.class; - } - - @Override - protected DeviceAuthService createInstance() throws Exception { - - if (this.deviceAuthService != null) { - return this.deviceAuthService; - } else { - DeviceAuthService deviceAuthService = (DeviceAuthService) - PrivilegedCarbonContext.getThreadLocalCarbonContext(). - getOSGiService(DeviceAuthService.class, null); - if (deviceAuthService != null) { - this.deviceAuthService = deviceAuthService; - } - return deviceAuthService; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/IDPManagerFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/IDPManagerFactory.java deleted file mode 100644 index a91b038495e..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/IDPManagerFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021, 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.idp.mgt.IdpManager; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the IDP Management service type of object inside the container. - */ -public class IDPManagerFactory extends AbstractFactoryBean { - - private IdpManager idpManager; - - @Override - public Class getObjectType() { - - return IdpManager.class; - } - - @Override - protected IdpManager createInstance() throws Exception { - - if (this.idpManager != null) { - return idpManager; - } else { - IdpManager idpManager = (IdpManager) PrivilegedCarbonContext.getThreadLocalCarbonContext() - .getOSGiService(IdpManager.class, null); - if (idpManager != null) { - this.idpManager = idpManager; - } - return idpManager; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuth2ScopeServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuth2ScopeServiceFactory.java deleted file mode 100644 index 6cc13c943ec..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuth2ScopeServiceFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021, 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.oauth2.OAuth2ScopeService; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the OAuth2ScopeService type of object inside the container. - */ -public class OAuth2ScopeServiceFactory extends AbstractFactoryBean { - - private OAuth2ScopeService oAuth2ScopeService; - - @Override - public Class getObjectType() { - - return OAuth2ScopeService.class; - } - - @Override - protected OAuth2ScopeService createInstance() throws Exception { - - if (this.oAuth2ScopeService != null) { - return this.oAuth2ScopeService; - } else { - OAuth2ScopeService oAuth2ScopeService = (OAuth2ScopeService) PrivilegedCarbonContext - .getThreadLocalCarbonContext().getOSGiService(OAuth2ScopeService.class, null); - if (oAuth2ScopeService != null) { - this.oAuth2ScopeService = oAuth2ScopeService; - } - return oAuth2ScopeService; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuth2ServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuth2ServiceFactory.java deleted file mode 100644 index 57b9aabcf01..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuth2ServiceFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.oauth2.OAuth2Service; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the OAuth2Service type of object inside the container. - */ -public class OAuth2ServiceFactory extends AbstractFactoryBean { - - private OAuth2Service oauth2Service; - - @Override - public Class getObjectType() { - - return OAuth2Service.class; - } - - @Override - protected OAuth2Service createInstance() throws Exception { - - if (this.oauth2Service != null) { - return this.oauth2Service; - } else { - OAuth2Service oauth2Service = (OAuth2Service) PrivilegedCarbonContext - .getThreadLocalCarbonContext().getOSGiService(OAuth2Service.class, null); - if (oauth2Service != null) { - this.oauth2Service = oauth2Service; - } - return oauth2Service; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuthAdminServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuthAdminServiceFactory.java deleted file mode 100644 index 0d80643ff15..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuthAdminServiceFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021, 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the OAuthAdminService type of object inside the container. - */ -public class OAuthAdminServiceFactory extends AbstractFactoryBean { - - private OAuthAdminServiceImpl oAuthAdminService; - - @Override - public Class getObjectType() { - - return OAuthAdminServiceImpl.class; - } - - @Override - protected OAuthAdminServiceImpl createInstance() throws Exception { - - if (this.oAuthAdminService != null) { - return this.oAuthAdminService; - } else { - OAuthAdminServiceImpl oAuthAdminService = (OAuthAdminServiceImpl) PrivilegedCarbonContext - .getThreadLocalCarbonContext().getOSGiService(OAuthAdminServiceImpl.class, null); - if (oAuthAdminService != null) { - this.oAuthAdminService = oAuthAdminService; - } - return oAuthAdminService; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuthServerConfigurationFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuthServerConfigurationFactory.java deleted file mode 100644 index 75250a7ef7c..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OAuthServerConfigurationFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the OAuthServerConfiguration type of object inside the container. - */ -public class OAuthServerConfigurationFactory extends AbstractFactoryBean { - - private OAuthServerConfiguration oAuthServerConfiguration; - - @Override - public Class getObjectType() { - - return OAuthServerConfiguration.class; - } - - @Override - protected OAuthServerConfiguration createInstance() throws Exception { - - if (this.oAuthServerConfiguration != null) { - return this.oAuthServerConfiguration; - } else { - OAuthServerConfiguration oAuthServerConfiguration = (OAuthServerConfiguration) PrivilegedCarbonContext. - getThreadLocalCarbonContext().getOSGiService(OAuthServerConfiguration.class, null); - if (oAuthServerConfiguration != null) { - this.oAuthServerConfiguration = oAuthServerConfiguration; - } - return oAuthServerConfiguration; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OpenIDConnectClaimFilterFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OpenIDConnectClaimFilterFactory.java deleted file mode 100644 index a865e317d14..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/OpenIDConnectClaimFilterFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.openidconnect.OpenIDConnectClaimFilter; -import org.wso2.carbon.identity.openidconnect.OpenIDConnectClaimFilterImpl; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the OpenIDConnectClaimFilterImpl type of object inside the container. - */ -public class OpenIDConnectClaimFilterFactory extends AbstractFactoryBean { - - private OpenIDConnectClaimFilterImpl openIDConnectClaimFilter; - - @Override - public Class getObjectType() { - - return OpenIDConnectClaimFilterImpl.class; - } - - @Override - protected OpenIDConnectClaimFilterImpl createInstance() throws Exception { - - if (this.openIDConnectClaimFilter != null) { - return this.openIDConnectClaimFilter; - } else { - OpenIDConnectClaimFilterImpl openIDConnectClaimFilter = (OpenIDConnectClaimFilterImpl) - PrivilegedCarbonContext.getThreadLocalCarbonContext(). - getOSGiService(OpenIDConnectClaimFilter.class, null); - if (openIDConnectClaimFilter != null) { - this.openIDConnectClaimFilter = openIDConnectClaimFilter; - } - return openIDConnectClaimFilter; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/ParServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/ParServiceFactory.java deleted file mode 100644 index 64c060c442b..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/ParServiceFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.oauth.endpoint.factory; - -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.oauth.par.core.ParAuthService; - -/** - * PAR Service Factory. - */ -public class ParServiceFactory extends AbstractFactoryBean { - private ParAuthService parAuthService; - - @Override - public Class getObjectType() { - - return ParAuthService.class; - } - - @Override - protected ParAuthService createInstance() throws Exception { - - if (parAuthService != null) { - return parAuthService; - } - - ParAuthService parAuthService = (ParAuthService) - PrivilegedCarbonContext.getThreadLocalCarbonContext(). - getOSGiService(ParAuthService.class, null); - if (parAuthService != null) { - this.parAuthService = parAuthService; - } - return parAuthService; - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/RequestObjectServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/RequestObjectServiceFactory.java deleted file mode 100644 index cb9465cc3bc..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/RequestObjectServiceFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.openidconnect.RequestObjectService; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the RequestObjectService type of object inside the container. - */ -public class RequestObjectServiceFactory extends AbstractFactoryBean { - - private RequestObjectService requestObjectService; - - @Override - public Class getObjectType() { - - return RequestObjectService.class; - } - - @Override - protected RequestObjectService createInstance() throws Exception { - - if (this.requestObjectService != null) { - return this.requestObjectService; - } else { - RequestObjectService requestObjectService = (RequestObjectService) PrivilegedCarbonContext. - getThreadLocalCarbonContext().getOSGiService(RequestObjectService.class, null); - if (requestObjectService != null) { - this.requestObjectService = requestObjectService; - } - return requestObjectService; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/SSOConsentServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/SSOConsentServiceFactory.java deleted file mode 100644 index 7523727293b..00000000000 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/factory/SSOConsentServiceFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.consent.SSOConsentService; - -/** - * Factory Beans serves as a factory for creating other beans within the IOC container. This factory bean is used to - * instantiate the SSOConsentService type of object inside the container. - */ -public class SSOConsentServiceFactory extends AbstractFactoryBean { - - private SSOConsentService ssoConsentService; - - @Override - public Class getObjectType() { - - return SSOConsentService.class; - } - - @Override - protected SSOConsentService createInstance() throws Exception { - - if (this.ssoConsentService != null) { - return this.ssoConsentService; - } else { - SSOConsentService ssoConsentService = (SSOConsentService) PrivilegedCarbonContext. - getThreadLocalCarbonContext().getOSGiService(SSOConsentService.class, null); - if (ssoConsentService != null) { - this.ssoConsentService = ssoConsentService; - } - return ssoConsentService; - } - } -} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryEndpoint.java index 87b0088cc43..359fdb8eddc 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryEndpoint.java @@ -21,7 +21,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.ServerConfigurationException; import org.wso2.carbon.identity.core.util.IdentityUtil; @@ -29,7 +28,7 @@ import org.wso2.carbon.identity.discovery.OIDCProcessor; import org.wso2.carbon.identity.discovery.builders.OIDProviderResponseBuilder; import org.wso2.carbon.identity.oauth.common.OAuthConstants; -import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OIDCProviderServiceFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -97,9 +96,9 @@ private boolean isValidIssuer(String issuer) { private Response getResponse(HttpServletRequest request, String tenant) { String response; - OIDCProcessor processor = EndpointUtil.getOIDCService(); + OIDCProcessor processor = OIDCProviderServiceFactory.getOIDCService(); try { - OIDProviderResponseBuilder responseBuilder = getOidProviderResponseBuilder(); + OIDProviderResponseBuilder responseBuilder = OIDCDiscoveryServiceFactory.getOIDProviderResponseBuilder(); response = responseBuilder.getOIDProviderConfigString(processor.getResponse(request, tenant)); } catch (OIDCDiscoveryEndPointException e) { Response.ResponseBuilder errorResponse = Response.status(processor.handleError(e)); @@ -112,15 +111,4 @@ private Response getResponse(HttpServletRequest request, String tenant) { Response.ResponseBuilder responseBuilder = Response.status(HttpServletResponse.SC_OK); return responseBuilder.entity(response).build(); } - - @Autowired - public void setOidProviderResponseBuilder(OIDProviderResponseBuilder oidProviderResponseBuilder) { - - this.oidProviderResponseBuilder = oidProviderResponseBuilder; - } - - public OIDProviderResponseBuilder getOidProviderResponseBuilder() { - - return this.oidProviderResponseBuilder; - } } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryServiceFactory.java new file mode 100644 index 00000000000..d9fd4c64285 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryServiceFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth.endpoint.oidcdiscovery; + +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.identity.discovery.builders.OIDProviderResponseBuilder; + +/** + * Service holder for managing instances of OIDC Discovery related services. + */ +public class OIDCDiscoveryServiceFactory { + + private static final OIDProviderResponseBuilder SERVICE; + + static { + OIDProviderResponseBuilder oidProviderResponseBuilder = (OIDProviderResponseBuilder) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(OIDProviderResponseBuilder.class, null); + if (oidProviderResponseBuilder == null) { + throw new IllegalStateException("OIDProviderResponseBuilder is not available from OSGi context."); + } + SERVICE = oidProviderResponseBuilder; + } + + public static OIDProviderResponseBuilder getOIDProviderResponseBuilder() { + + return SERVICE; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/par/OAuth2ParEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/par/OAuth2ParEndpoint.java index 4f4479cb0a0..0b3f2886979 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/par/OAuth2ParEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/par/OAuth2ParEndpoint.java @@ -77,11 +77,11 @@ import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OAuth20Params.RESPONSE_MODE; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OAuth20Params.RESPONSE_TYPE; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OAuth20Params.SCOPE; -import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getOAuth2Service; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getOAuthAuthzRequest; -import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getParAuthService; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getSPTenantDomainFromClientId; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.validateParams; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory.getOAuth2Service; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.ParAuthServiceFactory.getParAuthService; /** * REST implementation for OAuth2 PAR endpoint. diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/revoke/OAuthRevocationEndpoint.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/revoke/OAuthRevocationEndpoint.java index 2643328de7b..b97fd313e41 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/revoke/OAuthRevocationEndpoint.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/revoke/OAuthRevocationEndpoint.java @@ -69,9 +69,9 @@ import static org.wso2.carbon.identity.oauth.common.OAuthConstants.HTTP_RESP_HEADER_VAL_CACHE_CONTROL_NO_STORE; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.HTTP_RESP_HEADER_VAL_PRAGMA_NO_CACHE; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.extractCredentialsFromAuthzHeader; -import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getOAuth2Service; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getRealmInfo; import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.validateParams; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory.getOAuth2Service; /** * Rest implementation for oauth revocation endpoint. diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/state/OAuthRequestStateValidator.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/state/OAuthRequestStateValidator.java index aa2ae22854c..a06d69fe4f5 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/state/OAuthRequestStateValidator.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/state/OAuthRequestStateValidator.java @@ -36,7 +36,7 @@ import static org.wso2.carbon.identity.oauth.endpoint.state.OAuthAuthorizeState.AUTHENTICATION_RESPONSE; import static org.wso2.carbon.identity.oauth.endpoint.state.OAuthAuthorizeState.INITIAL_REQUEST; import static org.wso2.carbon.identity.oauth.endpoint.state.OAuthAuthorizeState.USER_CONSENT_RESPONSE; -import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getOAuth2Service; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory.getOAuth2Service; /** * This class validate the OAuth request state. 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 acff55c6e87..7120aa71608 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 @@ -42,6 +42,7 @@ import org.wso2.carbon.identity.oauth.endpoint.exception.InvalidRequestParentException; import org.wso2.carbon.identity.oauth.endpoint.exception.TokenEndpointBadRequestException; import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory; import org.wso2.carbon.identity.oauth2.ResponseHeader; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; @@ -383,7 +384,7 @@ private OAuth2AccessTokenRespDTO issueAccessToken(CarbonOAuthTokenRequest oauthR OAuth2AccessTokenReqDTO tokenReqDTO = buildAccessTokenReqDTO(oauthRequest, httpServletRequestWrapper, httpServletResponseWrapper); - return EndpointUtil.getOAuth2Service().issueAccessToken(tokenReqDTO); + return OAuth2ServiceFactory.getOAuth2Service().issueAccessToken(tokenReqDTO); } private OAuth2AccessTokenReqDTO buildAccessTokenReqDTO(CarbonOAuthTokenRequest oauthRequest, diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoISAccessTokenValidator.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoISAccessTokenValidator.java index c54f13bebb7..ecac085e6b6 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoISAccessTokenValidator.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoISAccessTokenValidator.java @@ -20,7 +20,7 @@ import org.apache.commons.lang.ArrayUtils; import org.apache.oltu.oauth2.common.error.OAuthError; import org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthClientException; -import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2TokenValidatorServiceFactory; import org.wso2.carbon.identity.oauth.user.UserInfoAccessTokenValidator; import org.wso2.carbon.identity.oauth.user.UserInfoEndpointException; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; @@ -61,7 +61,8 @@ public OAuth2TokenValidationResponseDTO validateToken(String accessTokenIdentifi accessToken.setTokenType("bearer"); accessToken.setIdentifier(accessTokenIdentifier); dto.setAccessToken(accessToken); - OAuth2TokenValidationResponseDTO response = EndpointUtil.getOAuth2TokenValidationService().validate(dto); + OAuth2TokenValidationResponseDTO response = OAuth2TokenValidatorServiceFactory + .getOAuth2TokenValidatorService().validate(dto); AccessTokenDO accessTokenDO; // invalid access token diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoUserStoreClaimRetriever.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoUserStoreClaimRetriever.java index da07eb1999a..054e80c9980 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoUserStoreClaimRetriever.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoUserStoreClaimRetriever.java @@ -20,6 +20,7 @@ import org.apache.commons.collections.MapUtils; import org.wso2.carbon.identity.application.common.model.ClaimMapping; import org.wso2.carbon.identity.core.util.IdentityCoreConstants; +import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.endpoint.util.ClaimUtil; import org.wso2.carbon.identity.oauth.user.UserInfoClaimRetriever; @@ -43,7 +44,10 @@ public Map getClaimsMap(Map userAttributes } String claimValue = entry.getValue(); String claimUri = entry.getKey().getRemoteClaim().getClaimUri(); - if (ClaimUtil.isMultiValuedAttribute(claimUri, claimValue)) { + boolean isMultiValueSupportEnabledForUserinfoResponse = OAuthServerConfiguration.getInstance() + .getUserInfoMultiValueSupportEnabled(); + if (isMultiValueSupportEnabledForUserinfoResponse && + ClaimUtil.isMultiValuedAttribute(claimUri, claimValue)) { String[] attributeValues = ClaimUtil.processMultiValuedAttribute(claimValue); claims.put(entry.getKey().getRemoteClaim().getClaimUri(), attributeValues); } else { diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/ClaimUtil.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/ClaimUtil.java index 2d5f52d215b..ab7bdd3dd6f 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/ClaimUtil.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/ClaimUtil.java @@ -190,7 +190,10 @@ public static Map getClaimsFromUserStore(OAuth2TokenValidationRe continue; } } - if (isMultiValuedAttribute(oidcClaimUri, claimValue)) { + boolean isMultiValueSupportEnabledForUserinfoResponse = OAuthServerConfiguration + .getInstance().getUserInfoMultiValueSupportEnabled(); + if (isMultiValueSupportEnabledForUserinfoResponse && + isMultiValuedAttribute(oidcClaimUri, claimValue)) { String[] attributeValues = processMultiValuedAttribute(claimValue); mappedAppClaims.put(oidcClaimUri, attributeValues); } else { 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 2c7fa73ccfb..6bfbb91868d 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 @@ -44,7 +44,6 @@ import org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationRequestCacheEntry; import org.wso2.carbon.identity.application.authentication.framework.config.builder.FileBasedConfigurationBuilder; import org.wso2.carbon.identity.application.authentication.framework.exception.UserIdNotFoundException; -import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.consent.SSOConsentService; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticationRequest; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants; @@ -62,19 +61,13 @@ import org.wso2.carbon.identity.core.URLBuilderException; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; -import org.wso2.carbon.identity.discovery.DefaultOIDCProcessor; -import org.wso2.carbon.identity.discovery.OIDCProcessor; -import org.wso2.carbon.identity.discovery.builders.DefaultOIDCProviderRequestBuilder; -import org.wso2.carbon.identity.discovery.builders.OIDCProviderRequestBuilder; import org.wso2.carbon.identity.event.IdentityEventException; import org.wso2.carbon.identity.event.event.Event; import org.wso2.carbon.identity.event.services.IdentityEventService; import org.wso2.carbon.identity.oauth.IdentityOAuthAdminException; -import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl; import org.wso2.carbon.identity.oauth.cache.SessionDataCache; import org.wso2.carbon.identity.oauth.cache.SessionDataCacheEntry; import org.wso2.carbon.identity.oauth.cache.SessionDataCacheKey; -import org.wso2.carbon.identity.oauth.ciba.api.CibaAuthServiceImpl; import org.wso2.carbon.identity.oauth.common.OAuth2ErrorCodes; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthClientException; @@ -86,16 +79,13 @@ import org.wso2.carbon.identity.oauth.endpoint.exception.InvalidRequestException; import org.wso2.carbon.identity.oauth.endpoint.exception.TokenEndpointBadRequestException; import org.wso2.carbon.identity.oauth.endpoint.message.OAuthMessage; -import org.wso2.carbon.identity.oauth.par.core.ParAuthService; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory; import org.wso2.carbon.identity.oauth.par.exceptions.ParClientException; import org.wso2.carbon.identity.oauth.user.UserInfoEndpointException; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.IdentityOAuth2ScopeConsentException; import org.wso2.carbon.identity.oauth2.IdentityOAuth2ScopeException; import org.wso2.carbon.identity.oauth2.IdentityOAuth2ScopeServerException; -import org.wso2.carbon.identity.oauth2.OAuth2ScopeService; -import org.wso2.carbon.identity.oauth2.OAuth2Service; -import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; import org.wso2.carbon.identity.oauth2.Oauth2ScopeConstants; import org.wso2.carbon.identity.oauth2.RequestObjectException; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; @@ -106,20 +96,15 @@ import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.model.OAuth2ScopeConsentResponse; import org.wso2.carbon.identity.oauth2.scopeservice.OAuth2Resource; -import org.wso2.carbon.identity.oauth2.scopeservice.ScopeMetadataService; import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.openidconnect.OIDCRequestObjectUtil; import org.wso2.carbon.identity.openidconnect.RequestObjectBuilder; -import org.wso2.carbon.identity.openidconnect.RequestObjectService; import org.wso2.carbon.identity.openidconnect.RequestObjectValidator; import org.wso2.carbon.identity.openidconnect.internal.OpenIDConnectServiceComponentHolder; import org.wso2.carbon.identity.openidconnect.model.RequestObject; -import org.wso2.carbon.identity.webfinger.DefaultWebFingerProcessor; -import org.wso2.carbon.identity.webfinger.WebFingerProcessor; import org.wso2.carbon.idp.mgt.IdentityProviderManagementException; import org.wso2.carbon.idp.mgt.IdentityProviderManager; -import org.wso2.carbon.idp.mgt.IdpManager; import org.wso2.carbon.utils.DiagnosticLog; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; @@ -157,6 +142,10 @@ import static org.wso2.carbon.identity.oauth.common.OAuthConstants.HTTP_REQ_HEADER_AUTH_METHOD_BASIC; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OauthAppStates.APP_STATE_ACTIVE; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.ResponseModes.JWT; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuthAdminServiceFactory.getOAuthAdminService; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuthServerConfigurationFactory.getOAuthServerConfiguration; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.Oauth2ScopeServiceFactory.getOAuth2ScopeService; +import static org.wso2.carbon.identity.oauth.endpoint.util.factory.ScopeMetadataServiceFactory.getScopeMetadataService; import static org.wso2.carbon.identity.oauth.par.common.ParConstants.PRE_HANDLE_PAR_REQUEST; import static org.wso2.carbon.identity.oauth.par.common.ParConstants.REQUEST_HEADERS; import static org.wso2.carbon.identity.oauth.par.common.ParConstants.REQUEST_PARAMETERS; @@ -185,154 +174,15 @@ public class EndpointUtil { private static final String REQUEST_URI = "request_uri"; private static final String NOT_AVAILABLE = "N/A"; private static final String UNKNOWN_ERROR = "unknown_error"; - private static OAuth2Service oAuth2Service; - private static OAuth2ScopeService oAuth2ScopeService; - private static OAuthAdminServiceImpl oAuthAdminService; - private static ScopeMetadataService scopeMetadataService; - private static SSOConsentService ssoConsentService; - private static OAuthServerConfiguration oauthServerConfiguration; - private static RequestObjectService requestObjectService; - private static CibaAuthServiceImpl cibaAuthService; - private static ParAuthService parAuthService; - private static IdpManager idpManager; private static final String ALLOW_ADDITIONAL_PARAMS_FROM_ERROR_URL = "OAuth.AllowAdditionalParamsFromErrorUrl"; private static final String KEEP_OIDC_SCOPES_IN_CONSENT_URL = "OAuth.KeepOIDCScopesInConsentURL"; private static final String IDP_ENTITY_ID = "IdPEntityId"; private static Class oAuthAuthzRequestClass; - public static void setIdpManager(IdpManager idpManager) { - - EndpointUtil.idpManager = idpManager; - } - - public static void setOAuth2Service(OAuth2Service oAuth2Service) { - - EndpointUtil.oAuth2Service = oAuth2Service; - } - - public static void setOAuth2ScopeService(OAuth2ScopeService oAuth2ScopeService) { - - EndpointUtil.oAuth2ScopeService = oAuth2ScopeService; - } - - public static void setOAuthAdminService(OAuthAdminServiceImpl oAuthAdminService) { - - EndpointUtil.oAuthAdminService = oAuthAdminService; - } - - public static void setSSOConsentService(SSOConsentService ssoConsentService) { - - EndpointUtil.ssoConsentService = ssoConsentService; - } - - public static void setOauthServerConfiguration(OAuthServerConfiguration oauthServerConfiguration) { - - EndpointUtil.oauthServerConfiguration = oauthServerConfiguration; - } - - public static void setRequestObjectService(RequestObjectService requestObjectService) { - - EndpointUtil.requestObjectService = requestObjectService; - } - - public static ScopeMetadataService getScopeMetadataService() { - - return scopeMetadataService; - } - - public static void setScopeMetadataService(ScopeMetadataService scopeMetadataService) { - - EndpointUtil.scopeMetadataService = scopeMetadataService; - } - private EndpointUtil() { } - /** - * Returns the registered {@code {@link SSOConsentService}} instance - * - * @return - */ - public static SSOConsentService getSSOConsentService() { - - return ssoConsentService; - } - - /** - * Returns the {@code DefaultWebFingerProcessor} instance - * - * @return DefaultWebFingerProcessor - */ - public static DefaultWebFingerProcessor getWebFingerService() { - - return (DefaultWebFingerProcessor) PrivilegedCarbonContext.getThreadLocalCarbonContext().getOSGiService - (WebFingerProcessor.class, null); - } - - /** - * Returns the {@code OIDCProviderRequestBuilder} instance - * - * @return DefaultOIDCProviderRequestBuilder - */ - public static DefaultOIDCProviderRequestBuilder getOIDProviderRequestValidator() { - - return (DefaultOIDCProviderRequestBuilder) PrivilegedCarbonContext.getThreadLocalCarbonContext().getOSGiService - (OIDCProviderRequestBuilder.class, null); - } - - /** - * Returns the {@code DefaultOIDCProcessor} instance - * - * @return DefaultOIDCProcessor - */ - public static DefaultOIDCProcessor getOIDCService() { - - return (DefaultOIDCProcessor) PrivilegedCarbonContext.getThreadLocalCarbonContext().getOSGiService - (OIDCProcessor.class, null); - } - - /** - * Returns the {@code RequestObjectService} instance - * - * @return RequestObjectService - */ - public static RequestObjectService getRequestObjectService() { - - return requestObjectService; - } - - /** - * Returns the {@code OAuth2Service} instance - * - * @return OAuth2Service - */ - public static OAuth2Service getOAuth2Service() { - - return oAuth2Service; - } - - /** - * Returns the {@code OAuthServerConfiguration} instance - * - * @return OAuthServerConfiguration - */ - public static OAuthServerConfiguration getOAuthServerConfiguration() { - - return oauthServerConfiguration; - } - - /** - * Returns the {@code OAuthServerConfiguration} instance - * - * @return OAuth2TokenValidationService - */ - public static OAuth2TokenValidationService getOAuth2TokenValidationService() { - - return (OAuth2TokenValidationService) PrivilegedCarbonContext.getThreadLocalCarbonContext() - .getOSGiService(OAuth2TokenValidationService.class, null); - } - /** * Returns the request validator class name * @@ -922,7 +772,7 @@ private static ServiceProvider getServiceProvider(OAuth2Parameters params) throw private static String getScopeMetadataQueryParam(Set scopes, String tenantDomain) { try { - List oidcScopeList = oAuthAdminService.getRegisteredOIDCScope(tenantDomain); + List oidcScopeList = getOAuthAdminService().getRegisteredOIDCScope(tenantDomain); List nonOidcScopeList = new ArrayList<>(); oidcScopeList.retainAll(scopes); nonOidcScopeList.addAll(scopes.stream().filter(scope -> @@ -931,7 +781,7 @@ private static String getScopeMetadataQueryParam(Set scopes, String tena if (nonOidcScopeList.isEmpty()) { return null; } - List scopesMetaData = scopeMetadataService.getMetadata(nonOidcScopeList); + List scopesMetaData = getScopeMetadataService().getMetadata(nonOidcScopeList); String scopeMetadata = new Gson().toJson(scopesMetaData); return "scopeMetadata=" + URLEncoder.encode(scopeMetadata, UTF_8); } catch (Exception e) { @@ -1067,7 +917,7 @@ public static boolean isUserAlreadyConsentedForOAuthScopes(AuthenticatedUser use } String userId = getUserIdOfAuthenticatedUser(user); String appId = getAppIdFromClientId(oAuth2Parameters.getClientId()); - return oAuth2ScopeService.hasUserProvidedConsentForAllRequestedScopes(userId, appId, + return getOAuth2ScopeService().hasUserProvidedConsentForAllRequestedScopes(userId, appId, IdentityTenantUtil.getTenantId(user.getTenantDomain()), scopesToBeConsented); } @@ -1107,25 +957,25 @@ public static void storeOAuthScopeConsent(AuthenticatedUser user, OAuth2Paramete log.debug("Overriding existing consents of the user : " + userId + " for application : " + appId); } - oAuth2ScopeService.addUserConsentForApplication(userId, appId, + getOAuth2ScopeService().addUserConsentForApplication(userId, appId, IdentityTenantUtil.getTenantId(user.getTenantDomain()), userApprovedScopes, null); } else { - boolean isUserConsentExist = oAuth2ScopeService.isUserHasAnExistingConsentForApp( + boolean isUserConsentExist = getOAuth2ScopeService().isUserHasAnExistingConsentForApp( userId, appId, IdentityTenantUtil.getTenantId(user.getTenantDomain())); if (isUserConsentExist) { if (log.isDebugEnabled()) { log.debug("Updating existing consents of the user : " + userId + " for application : " + appId); } - oAuth2ScopeService.updateUserConsentForApplication(userId, appId, + getOAuth2ScopeService().updateUserConsentForApplication(userId, appId, IdentityTenantUtil.getTenantId(user.getTenantDomain()), userApprovedScopes, null); } else { if (log.isDebugEnabled()) { log.debug("Adding new consent to the user : " + userId + " for application : " + appId); } - oAuth2ScopeService.addUserConsentForApplication(userId, appId, + getOAuth2ScopeService().addUserConsentForApplication(userId, appId, IdentityTenantUtil.getTenantId(user.getTenantDomain()), userApprovedScopes, null); } @@ -1165,7 +1015,7 @@ public static void storeOAuthScopeConsent(AuthenticatedUser user, OAuth2Paramete private static List getOIDCScopeNames() throws IdentityOAuthAdminException { - return Arrays.asList(ArrayUtils.nullToEmpty(oAuthAdminService.getScopeNames())); + return Arrays.asList(ArrayUtils.nullToEmpty(getOAuthAdminService().getScopeNames())); } /** @@ -1192,7 +1042,7 @@ private static List getRequestedOIDCScopes(OAuth2Parameters params) List requestedOIDCScopes = new ArrayList<>(); try { // Get registered OIDC scopes. - List oidcScopeList = oAuthAdminService.getRegisteredOIDCScope(params.getTenantDomain()); + List oidcScopeList = getOAuthAdminService().getRegisteredOIDCScope(params.getTenantDomain()); for (String scope : allowedScopes) { if (oidcScopeList.contains(scope)) { requestedOIDCScopes.add(scope.toLowerCase()); @@ -1222,7 +1072,7 @@ private static List dropOIDCAndUnregisteredScopesFromConsentRequiredScop /* If DropUnregisteredScopes scopes config is enabled then any unregistered scopes(excluding internal scopes and allowed scopes) will be dropped. Therefore, they will not be shown in the user consent screen.*/ - if (oauthServerConfiguration.isDropUnregisteredScopes()) { + if (getOAuthServerConfiguration().isDropUnregisteredScopes()) { if (log.isDebugEnabled()) { log.debug("DropUnregisteredScopes config is enabled. Attempting to drop unregistered scopes."); } @@ -1234,7 +1084,7 @@ private static List dropOIDCAndUnregisteredScopesFromConsentRequiredScop allowedRegisteredScopes.addAll(allowedScopes); } else { // Get registered OIDC scopes. - String[] oidcScopes = oAuthAdminService.getScopeNames(); + String[] oidcScopes = getOAuthAdminService().getScopeNames(); List oidcScopeList = new ArrayList<>(Arrays.asList(oidcScopes)); for (String scope : allowedScopes) { if (!oidcScopeList.contains(scope)) { @@ -1265,7 +1115,7 @@ private static List filterConsentRequiredScopes(AuthenticatedUser user, if (user != null && !isPromptContainsConsent(params)) { String userId = getUserIdOfAuthenticatedUser(user); String appId = getAppIdFromClientId(params.getClientId()); - OAuth2ScopeConsentResponse existingUserConsent = oAuth2ScopeService.getUserConsentForApp( + OAuth2ScopeConsentResponse existingUserConsent = getOAuth2ScopeService().getUserConsentForApp( userId, appId, IdentityTenantUtil.getTenantId(user.getTenantDomain())); if (existingUserConsent != null) { if (CollectionUtils.isNotEmpty(existingUserConsent.getApprovedScopes())) { @@ -1327,7 +1177,7 @@ private static Set dropUnregisteredScopes(OAuth2Parameters params) throw Set requestedScopes = new HashSet<>(params.getScopes()); Set registeredScopes = getRegisteredScopes(requestedScopes, params.getTenantDomain()); - List allowedScopesFromConfig = oauthServerConfiguration.getAllowedScopes(); + List allowedScopesFromConfig = getOAuthServerConfiguration().getAllowedScopes(); Set filteredScopes = new HashSet<>(); // Filtering allowed scopes. @@ -1360,7 +1210,8 @@ private static Set getRegisteredScopes(Set requestedScopes, Stri try { String requestedScopesStr = StringUtils.join(requestedScopes, " "); Set registeredScopes = new HashSet<>(); - Set registeredScopeSet = oAuth2ScopeService.getScopes(null, null, true, requestedScopesStr); + Set registeredScopeSet = getOAuth2ScopeService().getScopes(null, null, + true, requestedScopesStr); registeredScopeSet.forEach(scope -> registeredScopes.add(scope.getName())); if (!AuthzUtil.isLegacyAuthzRuntime()) { List registeredAPIScopes = getRegisteredAPIScopes(requestedScopes, tenantDomain); @@ -1544,7 +1395,7 @@ public static void startSuperTenantFlow() { */ public static void validateOauthApplication(String consumerKey) throws InvalidApplicationClientException { - String appState = EndpointUtil.getOAuth2Service().getOauthApplicationState(consumerKey); + String appState = OAuth2ServiceFactory.getOAuth2Service().getOauthApplicationState(consumerKey); DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = null; if (LoggerUtils.isDiagnosticLogsEnabled()) { @@ -1807,36 +1658,6 @@ private static void addStringToMap(String name, String value, Map { +public class ScopeMetadataServiceFactory { - private ScopeMetadataService scopeMetadataService; + private static final ScopeMetadataService SERVICE; - private static final Log log = LogFactory.getLog(ScopeServiceFactory.class); + private static final Log LOG = LogFactory.getLog(ScopeMetadataServiceFactory.class); - @Override - public Class getObjectType() { + static { + ScopeMetadataService scopeMetadataService = setScopeMetadataService(); - return ScopeMetadataService.class; + if (scopeMetadataService == null) { + throw new IllegalStateException("ScopeMetadataService is not available from OSGi context."); + } + SERVICE = scopeMetadataService; } - @Override - protected ScopeMetadataService createInstance() throws Exception { - - if (this.scopeMetadataService != null) { - return this.scopeMetadataService; - } + private static ScopeMetadataService setScopeMetadataService() { - ScopeMetadataService scopeMetadataService = getScopeMetadataService(); + ScopeMetadataService scopeMetadataService = getScopeMetadataServiceFromConfig(); if (scopeMetadataService != null) { - this.scopeMetadataService = scopeMetadataService; - return this.scopeMetadataService; + return scopeMetadataService; } + // Get the OSGi services registered for ScopeService interface. List scopeServices = PrivilegedCarbonContext .getThreadLocalCarbonContext().getOSGiServices(ScopeMetadataService.class, null); @@ -79,13 +75,12 @@ protected ScopeMetadataService createInstance() throws Exception { } if (scopeMetadataService == null) { - throw new IdentityOAuth2ServerException("ScopeMetadataService is not available."); + throw new IllegalStateException("ScopeMetadataService is not available from OSGi context."); } - this.scopeMetadataService = scopeMetadataService; - return this.scopeMetadataService; + return scopeMetadataService; } - private ScopeMetadataService getScopeMetadataService() { + private static ScopeMetadataService getScopeMetadataServiceFromConfig() { String scopeMetadataServiceClassName = OAuthServerConfiguration.getInstance() .getScopeMetadataExtensionImpl(); @@ -97,19 +92,24 @@ private ScopeMetadataService getScopeMetadataService() { if (obj instanceof ScopeMetadataService) { return (ScopeMetadataService) obj; } else { - log.error(scopeMetadataServiceClassName + " is not an instance of " + + LOG.error(scopeMetadataServiceClassName + " is not an instance of " + ScopeMetadataService.class.getName()); } } catch (ClassNotFoundException e) { - log.error("ClassNotFoundException while trying to find class " + scopeMetadataServiceClassName); + LOG.error("ClassNotFoundException while trying to find class " + scopeMetadataServiceClassName); } catch (InstantiationException e) { - log.error("InstantiationException while trying to instantiate class " + + LOG.error("InstantiationException while trying to instantiate class " + scopeMetadataServiceClassName); } catch (IllegalAccessException e) { - log.error("IllegalAccessException while trying to instantiate class " + + LOG.error("IllegalAccessException while trying to instantiate class " + scopeMetadataServiceClassName); } } return null; } + + public static ScopeMetadataService getScopeMetadataService() { + + return SERVICE; + } } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/factory/WebFingerServiceFactory.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/factory/WebFingerServiceFactory.java new file mode 100644 index 00000000000..e530993538b --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/java/org/wso2/carbon/identity/oauth/endpoint/util/factory/WebFingerServiceFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth.endpoint.util.factory; + +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.identity.webfinger.DefaultWebFingerProcessor; +import org.wso2.carbon.identity.webfinger.WebFingerProcessor; + +/** + * Factory class for WebFingerService. + */ +public class WebFingerServiceFactory { + + private static final WebFingerProcessor SERVICE; + + static { + WebFingerProcessor webFingerService = (DefaultWebFingerProcessor) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(WebFingerProcessor.class, null); + + if (webFingerService == null) { + throw new IllegalStateException("WebFingerService is not available from OSGI context."); + } + SERVICE = webFingerService; + } + + public static WebFingerProcessor getWebFingerService() { + + return SERVICE; + } +} diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/webapp/WEB-INF/cxf-servlet.xml index 912d5458a4e..4c5a34b03d9 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -68,8 +68,6 @@ - - diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/webapp/WEB-INF/web.xml b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/webapp/WEB-INF/web.xml index 5e45661d5fb..468487abc50 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/main/webapp/WEB-INF/web.xml +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/main/webapp/WEB-INF/web.xml @@ -75,9 +75,44 @@ OAuth2Endpoints - org.apache.cxf.transport.servlet.CXFServlet + org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet 1 + + jaxrs.serviceClasses + + org.wso2.carbon.identity.oauth.endpoint.authz.OAuth2AuthzEndpoint, + org.wso2.carbon.identity.oauth.endpoint.token.OAuth2TokenEndpoint, + org.wso2.carbon.identity.oauth.endpoint.introspection.OAuth2IntrospectionEndpoint, + org.wso2.carbon.identity.oauth.endpoint.revoke.OAuthRevocationEndpoint, + org.wso2.carbon.identity.oauth.endpoint.user.OpenIDConnectUserEndpoint, + org.wso2.carbon.identity.oauth.endpoint.jwks.JwksEndpoint, + org.wso2.carbon.identity.oauth.endpoint.oidcdiscovery.OIDCDiscoveryEndpoint, + org.wso2.carbon.identity.oauth.endpoint.device.DeviceEndpoint, + org.wso2.carbon.identity.oauth.endpoint.device.UserAuthenticationEndpoint, + org.wso2.carbon.identity.oauth.endpoint.ciba.OAuth2CibaEndpoint, + org.wso2.carbon.identity.oauth.endpoint.api.auth.ApiAuthnEndpoint, + org.wso2.carbon.identity.oauth.endpoint.par.OAuth2ParEndpoint + + + + jaxrs.address + / + + + jaxrs.providers + + org.wso2.carbon.identity.oauth.endpoint.expmapper.InvalidRequestExceptionMapper + + + + + jaxrs.inInterceptors + + org.wso2.carbon.identity.oauth.client.authn.filter.OAuthClientAuthenticatorProxy + + + 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 145f6b2795b..66ad92c7e30 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 @@ -1,7 +1,7 @@ /* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2017-2024, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -15,6 +15,7 @@ * specific language governing permissions and limitations * under the License. */ + package org.wso2.carbon.identity.oauth.endpoint.authz; import com.nimbusds.jose.JOSEException; @@ -39,11 +40,17 @@ import org.apache.oltu.oauth2.common.message.types.ResponseType; import org.apache.oltu.oauth2.common.validators.OAuthValidator; import org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; @@ -53,6 +60,8 @@ import org.testng.annotations.Test; import org.wso2.carbon.base.CarbonBaseConstants; import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.identity.application.authentication.framework.AuthenticatorFlowStatus; import org.wso2.carbon.identity.application.authentication.framework.CommonAuthenticationHandler; import org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationResultCacheEntry; @@ -60,6 +69,7 @@ import org.wso2.carbon.identity.application.authentication.framework.handler.request.RequestCoordinator; import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.consent.ConsentClaimsData; import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.consent.SSOConsentService; +import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.consent.exception.SSOConsentServiceException; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticationResult; import org.wso2.carbon.identity.application.authentication.framework.model.CommonAuthRequestWrapper; @@ -99,11 +109,18 @@ import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; import org.wso2.carbon.identity.oauth.endpoint.util.OpenIDConnectUserRPStore; import org.wso2.carbon.identity.oauth.endpoint.util.TestOAuthEndpointBase; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2TokenValidatorServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuthAdminServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuthServerConfigurationFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.Oauth2ScopeServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.SSOConsentServiceFactory; import org.wso2.carbon.identity.oauth.tokenprocessor.TokenPersistenceProcessor; import org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.OAuth2ScopeService; import org.wso2.carbon.identity.oauth2.OAuth2Service; +import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; import org.wso2.carbon.identity.oauth2.RequestObjectException; import org.wso2.carbon.identity.oauth2.authz.AuthorizationHandlerManager; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; @@ -181,16 +198,18 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; @@ -203,6 +222,7 @@ public class OAuth2AuthzEndpointTest extends TestOAuthEndpointBase { + private static final Logger log = LoggerFactory.getLogger(OAuth2AuthzEndpointTest.class); @Mock HttpServletRequest httpServletRequest; @@ -254,7 +274,6 @@ public class OAuth2AuthzEndpointTest extends TestOAuthEndpointBase { @Mock OIDCSessionManager oidcSessionManager; - @Mock OAuthMessage oAuthMessage; @@ -285,6 +304,17 @@ public class OAuth2AuthzEndpointTest extends TestOAuthEndpointBase { @Mock private CentralLogMgtServiceComponentHolder centralLogMgtServiceComponentHolderMock; + @Mock + SSOConsentService mockedSSOConsentService; + + @Mock + OAuth2TokenValidationService oAuth2TokenValidator; + + @Mock + BundleContext bundleContext; + + MockedConstruction mockedConstruction; + 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 = @@ -335,7 +365,8 @@ public void setUp() throws Exception { // ignore } try { - createOAuthApp(INACTIVE_CLIENT_ID_VALUE, "dummySecret", USERNAME, INACTIVE_APP_NAME, "INACTIVE"); + createOAuthApp(INACTIVE_CLIENT_ID_VALUE, "dummySecret", USERNAME, INACTIVE_APP_NAME, + "INACTIVE"); } catch (JdbcSQLIntegrityConstraintViolationException e) { // ignore } @@ -350,24 +381,63 @@ public void setUp() throws Exception { @BeforeMethod public void setUpMethod() { - initMocks(this); + MockitoAnnotations.openMocks(this); identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); mockDatabase(identityDatabaseUtil); IdentityEventService identityEventService = mock(IdentityEventService.class); CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(identityEventService); - } - @AfterClass - public void tearDown() throws Exception { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); - super.cleanData(); - CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(null); + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(OAuth2Service.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oAuth2Service}); + } + if (argumentCaptor.getValue().contains(OpenIDConnectClaimFilterImpl.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{openIDConnectClaimFilter}); + } + if (argumentCaptor.getValue().contains(SSOConsentService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{mockedSSOConsentService}); + } + if (argumentCaptor.getValue().contains(RequestObjectService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{requestObjectService}); + } + if (argumentCaptor.getValue().contains(OAuthAdminServiceImpl.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oAuthAdminService}); + } + if (argumentCaptor.getValue().contains(OAuth2ScopeService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oAuth2ScopeService}); + } + if (argumentCaptor.getValue().contains(OAuthServerConfiguration.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{mockOAuthServerConfiguration}); + } + if (argumentCaptor.getValue().contains(OAuth2TokenValidationService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oAuth2TokenValidator}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); } @AfterMethod public void tearDownMethod() { - identityDatabaseUtil.close(); + if (identityDatabaseUtil != null) { + identityDatabaseUtil.close(); + } + Mockito.reset(oAuth2ScopeService); + mockedConstruction.close(); + PrivilegedCarbonContext.endTenantFlow(); + } + + @AfterClass + public void tearDown() throws Exception { + + super.cleanData(); + CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(null); } @DataProvider(name = "providePostParams") @@ -403,6 +473,7 @@ public void testAuthorizePost(Object paramObject, Map requestP try (MockedStatic oAuthServerConfiguration = mockStatic( OAuthServerConfiguration.class);) { + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic loggerUtils = mockStatic(LoggerUtils.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); @@ -516,7 +587,12 @@ public void testAuthorize(Object flowStatusObject, String[] clientId, String ses Mockito.CALLS_REAL_METHODS); MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class); MockedStatic endpointUtil = mockStatic(EndpointUtil.class, - Mockito.CALLS_REAL_METHODS);) { + Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class); + MockedStatic oAuthAdminServiceFactory = + mockStatic(OAuthAdminServiceFactory.class); + MockedStatic oAuth2TokenValidatorServiceFactory = + mockStatic(OAuth2TokenValidatorServiceFactory.class);) { AuthenticatorFlowStatus flowStatus = (AuthenticatorFlowStatus) flowStatusObject; Map requestParams = new HashMap<>(); @@ -577,6 +653,13 @@ public void testAuthorize(Object flowStatusObject, String[] clientId, String ses new HashSet<>(Collections.singletonList(OAuthConstants.Scope.OPENID)), APP_NAME, null, null)); mockEndpointUtil(false, endpointUtil); + + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); + oAuthAdminServiceFactory.when(OAuthAdminServiceFactory::getOAuthAdminService) + .thenReturn(oAuthAdminService); + oAuth2TokenValidatorServiceFactory.when(OAuth2TokenValidatorServiceFactory + ::getOAuth2TokenValidatorService) + .thenReturn(oAuth2TokenValidator); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); doCallRealMethod().when(oAuth2Service).validateInputParameters(httpServletRequest); if (ArrayUtils.isNotEmpty(clientId) && (clientId[0].equalsIgnoreCase("invalidId") || clientId[0] @@ -710,7 +793,8 @@ public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, bo throws Exception { try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + OAuthServerConfiguration.class)) { + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic sessionDataCache = mockStatic(SessionDataCache.class); MockedStatic loggerUtils = mockStatic(LoggerUtils.class); @@ -725,8 +809,13 @@ 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 oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class); + MockedStatic oAuth2ScopeServiceFactory = + mockStatic(Oauth2ScopeServiceFactory.class);) { + oAuth2ScopeServiceFactory.when(Oauth2ScopeServiceFactory::getOAuth2ScopeService) + .thenReturn(oAuth2ScopeService); sessionDataCache.when(SessionDataCache::getInstance).thenReturn(mockSessionDataCache); SessionDataCacheKey loginDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_VALUE); when(mockSessionDataCache.getValueFromCache(loginDataCacheKey)).thenReturn(loginCacheEntry); @@ -806,11 +895,11 @@ public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, bo thenReturn(true); mockEndpointUtil(false, endpointUtil); + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); mockApplicationManagementService(); - mockEndpointUtil(false, endpointUtil); when(oAuth2Service.handleAuthenticationFailure(oAuth2Params)).thenReturn(oAuthErrorDTO); when(oAuth2ScopeService.hasUserProvidedConsentForAllRequestedScopes( anyString(), isNull(), anyInt(), anyList())).thenReturn(true); @@ -908,9 +997,9 @@ public void testUserConsentResponse(String consent, String redirectUrl, Set oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + OAuthServerConfiguration.class)) { + mockSSOConsentService(true); mockOAuthServerConfiguration(oAuthServerConfiguration); - try (MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); MockedStatic loggerUtils = mockStatic(LoggerUtils.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); @@ -920,7 +1009,8 @@ public void testUserConsentResponse(String consent, String redirectUrl, Set openIDConnectUserRPStore = mockStatic(OpenIDConnectUserRPStore.class); MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = + mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS);) { when(authCookie.getValue()).thenReturn("dummyValue"); frameworkUtils.when(() -> FrameworkUtils.getAuthCookie(any())).thenReturn(authCookie); @@ -939,7 +1029,6 @@ public void testUserConsentResponse(String consent, String redirectUrl, Set mappings = new HashSet<>(); ExternalClaim claim = new ExternalClaim(OIDC_DIALECT, "country", "http://wso2.org/country"); @@ -1149,7 +1238,8 @@ public void testHandleOAuthAuthorizationRequest(String clientId, String redirect throws Exception { try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + OAuthServerConfiguration.class)) { + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class, Mockito.CALLS_REAL_METHODS); @@ -1160,8 +1250,10 @@ public void testHandleOAuthAuthorizationRequest(String clientId, String redirect MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); MockedStatic oAuthURL = mockStatic(OAuth2Util.OAuthURL.class); MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class);) { + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); Map requestParams = new HashMap(); Map requestAttributes = new HashMap(); @@ -1299,7 +1391,7 @@ public void testHandleOAuthAuthorizationRequest(String clientId, String redirect @DataProvider(name = "provideRequestParams") public Object[][] provideRequestParams() { - initMocks(this); + MockitoAnnotations.openMocks(this); return addDiagnosticLogStatusToExistingDataProvider(new Object[][]{ {AuthenticatorFlowStatus.SUCCESS_COMPLETED, "sample_scope", HttpServletResponse.SC_FOUND} }); @@ -1310,7 +1402,7 @@ public void testTestAuthorize(Object flowStatusObject, String scope, int expecte boolean diagnosticLogsEnabled) throws Exception { try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + OAuthServerConfiguration.class)) { mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class, Mockito.CALLS_REAL_METHODS); @@ -1325,8 +1417,14 @@ public void testTestAuthorize(Object flowStatusObject, String scope, int expecte MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); - MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class);) { + MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class); + MockedStatic oauth2ScopeServiceFactory = mockStatic( + Oauth2ScopeServiceFactory.class);) { + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); + oauth2ScopeServiceFactory.when(Oauth2ScopeServiceFactory::getOAuth2ScopeService).thenReturn( + oAuth2ScopeService); Map requestParams = new HashMap<>(); Map requestAttributes = new HashMap<>(); @@ -1342,7 +1440,8 @@ public void testTestAuthorize(Object flowStatusObject, String scope, int expecte (AuthenticatorFlowStatus) flowStatusObject); requestAttributes.put(FrameworkConstants.SESSION_DATA_KEY, SESSION_DATA_KEY_VALUE); requestParams.put(REDIRECT_URI, new String[]{APP_REDIRECT_URL}); - AuthenticationResult result = setAuthenticationResult(true, null, null, null, null); + AuthenticationResult result = setAuthenticationResult(true, null, null, + null, null); result.getSubject().setAuthenticatedSubjectIdentifier("Impersonator"); requestAttributes.put(FrameworkConstants.RequestAttribute.AUTH_RESULT, result); @@ -1350,7 +1449,8 @@ public void testTestAuthorize(Object flowStatusObject, String scope, int expecte oAuthURL.when(OAuth2Util.OAuthURL::getOAuth2ErrorPageUrl).thenReturn(ERROR_PAGE_URL); - frameworkUtils.when(() -> FrameworkUtils.startTenantFlow(anyString())).thenAnswer(invocation -> null); + frameworkUtils.when(() -> FrameworkUtils.startTenantFlow(anyString())).thenAnswer( + invocation -> null); frameworkUtils.when(FrameworkUtils::endTenantFlow).thenAnswer(invocation -> null); loggerUtils.when(LoggerUtils::isDiagnosticLogsEnabled).thenReturn(diagnosticLogsEnabled); identityTenantUtil.when(() -> IdentityTenantUtil.getTenantDomain(anyInt())).thenReturn( @@ -1404,7 +1504,7 @@ public void testTestAuthorize(Object flowStatusObject, String scope, int expecte when(loginCacheEntry.getAuthzReqMsgCtx()).thenReturn(authzReqMsgCtx); when(oAuth2ScopeService.hasUserProvidedConsentForAllRequestedScopes( - anyString(), anyString(), anyInt(), anyList())).thenReturn(true); + anyString(), isNull(), anyInt(), anyList())).thenReturn(true); oAuth2Util.when(() -> OAuth2Util.getServiceProvider(CLIENT_ID_VALUE)).thenReturn(new ServiceProvider()); when(mockOAuthServerConfiguration.getOpenIDConnectSkipeUserConsentConfig()).thenReturn(true); @@ -1448,7 +1548,8 @@ public void testTestAuthorize(Object flowStatusObject, String scope, int expecte public void testErrorWhenPARMandated() throws Exception { try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + OAuthServerConfiguration.class)) { + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class, Mockito.CALLS_REAL_METHODS); @@ -1459,7 +1560,10 @@ public void testErrorWhenPARMandated() throws Exception { MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); MockedStatic oAuthURL = mockStatic(OAuth2Util.OAuthURL.class); MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class);) { + + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); Map requestParams = new HashMap<>(); Map requestAttributes = new HashMap<>(); @@ -1579,7 +1683,8 @@ public void testHandleUserConsent(boolean isRespDTONull, String consent, boolean String expectedLocation) throws Exception { try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { + mockStatic(OAuthServerConfiguration.class)) { + mockSSOConsentService(false); oAuthServerConfiguration.when( OAuthServerConfiguration::getInstance).thenReturn(mockOAuthServerConfiguration); when(mockOAuthServerConfiguration.getAuthorizationCodeValidityPeriodInSeconds()).thenReturn(300L); @@ -1592,7 +1697,8 @@ public void testHandleUserConsent(boolean isRespDTONull, String consent, boolean MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class, Mockito.CALLS_REAL_METHODS); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class)) { Map requestParams = new HashMap<>(); Map requestAttributes = new HashMap<>(); @@ -1635,6 +1741,7 @@ public void testHandleUserConsent(boolean isRespDTONull, String consent, boolean } } mockEndpointUtil(false, endpointUtil); + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); when(oAuth2Service.authorize(any(OAuthAuthzReqMessageContext.class))).thenReturn(authzRespDTO); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); @@ -1645,7 +1752,7 @@ public void testHandleUserConsent(boolean isRespDTONull, String consent, boolean oAuth2Util.when(() -> OAuth2Util.getServiceProvider(CLIENT_ID_VALUE)).thenReturn(new ServiceProvider()); mockApplicationManagementService(); - frameworkUtils.when(()-> FrameworkUtils.startTenantFlow(anyString())).thenAnswer(invocation -> null); + frameworkUtils.when(() -> FrameworkUtils.startTenantFlow(anyString())).thenAnswer(invocation -> null); frameworkUtils.when(FrameworkUtils::endTenantFlow).thenAnswer(invocation -> null); identityTenantUtil.when(() -> IdentityTenantUtil.getTenantDomain(anyInt())).thenReturn( MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); @@ -1718,8 +1825,13 @@ public void testDoUserAuthz(String prompt, String idTokenHint, boolean hasUserAp boolean idTokenHintValid, String loggedInUser, String idTokenHintSubject, String errorCode) throws Exception { - try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + try (MockedStatic oAuthServerConfiguration = + mockStatic(OAuthServerConfiguration.class); + MockedStatic ssoConsentServiceFactory = + mockStatic(SSOConsentServiceFactory.class)) { + ssoConsentServiceFactory.when(SSOConsentServiceFactory::getSSOConsentService) + .thenReturn(mockedSSOConsentService); + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic sessionDataCache = mockStatic(SessionDataCache.class); MockedStatic openIDConnectUserRPStore = @@ -1732,9 +1844,12 @@ public void testDoUserAuthz(String prompt, String idTokenHint, boolean hasUserAp Mockito.CALLS_REAL_METHODS); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class, Mockito.CALLS_REAL_METHODS); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class)) { - AuthenticationResult result = setAuthenticationResult(true, null, null, null, null); + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); + AuthenticationResult result = setAuthenticationResult(true, null, null, + null, null); result.getSubject().setAuthenticatedSubjectIdentifier(loggedInUser); Map requestParams = new HashMap<>(); @@ -1750,7 +1865,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); oAuth2Params.setClientId(CLIENT_ID_VALUE); oAuth2Params.setPrompt(prompt); oAuth2Params.setIDTokenHint(idTokenHint); @@ -1804,7 +1920,8 @@ public void testDoUserAuthz(String prompt, String idTokenHint, boolean hasUserAp frameworkUtils.when(() -> FrameworkUtils.resolveUserIdFromUsername(anyInt(), anyString(), anyString())) .thenReturn("sample"); - frameworkUtils.when(() -> FrameworkUtils.startTenantFlow(anyString())).thenAnswer(invocation -> null); + frameworkUtils.when(() -> FrameworkUtils.startTenantFlow(anyString())).thenAnswer( + invocation -> null); frameworkUtils.when(FrameworkUtils::endTenantFlow).thenAnswer(invocation -> null); identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(nullable(String.class))) @@ -1831,7 +1948,7 @@ public void testDoUserAuthz(String prompt, String idTokenHint, boolean hasUserAp "Location header not found in the response"); String location = String.valueOf(responseMetadata.get(HTTPConstants.HEADER_LOCATION).get(0)); assertFalse(location.isEmpty(), "Redirect URL is empty"); - + log.info("Redirect URL: " + location); if (errorCode != null) { assertTrue(location.contains(errorCode), "Expected error code not found in URL"); } @@ -1874,7 +1991,8 @@ public void testManageOIDCSessionState(Object cookieObject, Object sessionStateO throws Exception { try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + OAuthServerConfiguration.class)) { + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic oAuthURL = mockStatic(OAuth2Util.OAuthURL.class); MockedStatic oidcSessionManagementUtil = @@ -1888,11 +2006,17 @@ public void testManageOIDCSessionState(Object cookieObject, Object sessionStateO Mockito.CALLS_REAL_METHODS); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class, Mockito.CALLS_REAL_METHODS); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuthServerConfigurationFactory = + mockStatic(OAuthServerConfigurationFactory.class); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class)) { + + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); Cookie opBrowserStateCookie = (Cookie) cookieObject; Cookie newOpBrowserStateCookie = new Cookie("opbs", "f6454r678776gffdgdsfafa"); OIDCSessionState previousSessionState = (OIDCSessionState) sessionStateObject; - AuthenticationResult result = setAuthenticationResult(true, null, null, null, null); + AuthenticationResult result = setAuthenticationResult(true, null, null, + null, null); Map requestParams = new HashMap<>(); Map requestAttributes = new HashMap<>(); @@ -1915,7 +2039,8 @@ public void testManageOIDCSessionState(Object cookieObject, Object sessionStateO oAuth2Params.setPrompt(OAuthConstants.Prompt.LOGIN); mockEndpointUtil(false, endpointUtil); - + oAuthServerConfigurationFactory.when(OAuthServerConfigurationFactory::getOAuthServerConfiguration) + .thenReturn(mockOAuthServerConfiguration); when(mockOAuthServerConfiguration.getOpenIDConnectSkipeUserConsentConfig()).thenReturn(true); OAuth2AuthorizeRespDTO authzRespDTO = new OAuth2AuthorizeRespDTO(); @@ -1943,8 +2068,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); @@ -2333,18 +2458,34 @@ public void testHandleOAuthAuthorizationRequest1(boolean showDisplayName, Object boolean diagnosticLogsEnabled) throws Exception { - try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + try (MockedStatic oAuthServerConfiguration = + mockStatic(OAuthServerConfiguration.class); + MockedStatic oAuthServerConfigurationFactory = + mockStatic(OAuthServerConfigurationFactory.class); + MockedStatic ssoConsentServiceFactory = + mockStatic(SSOConsentServiceFactory.class)) { + ssoConsentServiceFactory.when(SSOConsentServiceFactory::getSSOConsentService) + .thenReturn(mockedSSOConsentService); + oAuthServerConfigurationFactory.when(OAuthServerConfigurationFactory::getOAuthServerConfiguration) + .thenReturn(mockOAuthServerConfiguration); + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); MockedStatic loggerUtils = mockStatic(LoggerUtils.class); MockedStatic centralLogMgtServiceComponentMock = mockStatic(CentralLogMgtServiceComponentHolder.class); MockedStatic sessionDataCache = mockStatic(SessionDataCache.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class); + MockedStatic oAuth2ScopeServiceFactory = + mockStatic(Oauth2ScopeServiceFactory.class)) { + + oAuth2ScopeServiceFactory.when(Oauth2ScopeServiceFactory::getOAuth2ScopeService) + .thenReturn(oAuth2ScopeService); ServiceProvider sp = (ServiceProvider) spObj; sp.setApplicationName(APP_NAME); + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); mockApplicationManagementService(sp); mockEndpointUtil(false, endpointUtil); @@ -2454,7 +2595,8 @@ public void testHandleOIDCRequestObjectForFAPI(boolean withRequestObject, Object String testName) throws Exception { try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + OAuthServerConfiguration.class)) { + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic loggerUtils = mockStatic(LoggerUtils.class); MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); @@ -2585,12 +2727,21 @@ private static JWTClaimsSet getJwtClaimsSet(String issuer, String subject, Strin public void testIdentityOAuthAdminException() throws Exception { try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class);) { + OAuthServerConfiguration.class); + MockedStatic oAuthServerConfigurationFactory = + mockStatic(OAuthServerConfigurationFactory.class);) { + + oAuthServerConfigurationFactory.when(OAuthServerConfigurationFactory::getOAuthServerConfiguration) + .thenReturn(mockOAuthServerConfiguration); + mockSSOConsentService(false); mockOAuthServerConfiguration(oAuthServerConfiguration); try (MockedStatic loggerUtils = mockStatic(LoggerUtils.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); MockedStatic oAuthURL = mockStatic(OAuth2Util.OAuthURL.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class)) { + + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); //OAuthAdminException will not occur due to introduce a new Service to get the App State instead // directly use dao Map requestParams = new HashMap<>(); @@ -2666,39 +2817,14 @@ private void mockHttpRequest(final Map requestParams, when(httpServletRequest.getHeader("Authorization")).thenReturn(authHeader); } - private void mockEndpointUtil(boolean isConsentMgtEnabled, MockedStatic endpointUtil) - throws Exception { + private void mockEndpointUtil(boolean isConsentMgtEnabled, MockedStatic endpointUtil) { - endpointUtil.when(EndpointUtil::getOAuth2Service).thenReturn(oAuth2Service); endpointUtil.when(() -> EndpointUtil.getSPTenantDomainFromClientId(anyString())) .thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); - - endpointUtil.when(EndpointUtil::getOAuthServerConfiguration).thenReturn(mockOAuthServerConfiguration); endpointUtil.when(() -> EndpointUtil.getUserConsentURL(any(OAuth2Parameters.class), - anyString(), anyString(), any(OAuthMessage.class), anyString())).thenReturn(USER_CONSENT_URL); - - endpointUtil.when(EndpointUtil::getRequestObjectService).thenReturn(requestObjectService); + anyString(), anyString(), any(OAuthMessage.class), anyString())).thenReturn(USER_CONSENT_URL); endpointUtil.when(() -> EndpointUtil.getLoginPageURL(anyString(), anyString(), anyBoolean(), - anyBoolean(), anySet(), anyMap(), any())).thenReturn(LOGIN_PAGE_URL); - EndpointUtil.setOAuthAdminService(oAuthAdminService); - EndpointUtil.setOAuth2ScopeService(oAuth2ScopeService); - - // TODO: Remove mocking consentUtil and test the consent flow as well - // https://github.com/wso2/product-is/issues/2679 - SSOConsentService ssoConsentService = mock(SSOConsentService.class); - when(ssoConsentService - .getConsentRequiredClaimsWithExistingConsents(any(ServiceProvider.class), any(AuthenticatedUser.class))) - .thenReturn(new ConsentClaimsData()); - - when(ssoConsentService - .getConsentRequiredClaimsWithoutExistingConsents(any(ServiceProvider.class), - any(AuthenticatedUser.class))) - .thenReturn(new ConsentClaimsData()); - - when(ssoConsentService.isSSOConsentManagementEnabled(any())).thenReturn(isConsentMgtEnabled); - - endpointUtil.when(EndpointUtil::getSSOConsentService).thenReturn(ssoConsentService); - + anyBoolean(), anySet(), anyMap(), any())).thenReturn(LOGIN_PAGE_URL); } private AuthenticationResult setAuthenticationResult(boolean isAuthenticated, Map attributes, @@ -3043,4 +3169,19 @@ private void setSupportedResponseModes() throws ClassNotFoundException, Instanti OAuth2ServiceComponentHolder.setResponseModeProviders(supportedResponseModeProviders); OAuth2ServiceComponentHolder.setDefaultResponseModeProvider(defaultResponseModeProvider); } + + private void mockSSOConsentService(boolean isConsentMgtEnabled) throws SSOConsentServiceException { + + // TODO: Remove mocking consentUtil and test the consent flow as well + // https://github.com/wso2/product-is/issues/2679 +// SSOConsentService ssoConsentService = mock(SSOConsentService.class); + when(mockedSSOConsentService + .getConsentRequiredClaimsWithExistingConsents(any(ServiceProvider.class), any(AuthenticatedUser.class))) + .thenReturn(new ConsentClaimsData()); + when(mockedSSOConsentService + .getConsentRequiredClaimsWithoutExistingConsents(any(ServiceProvider.class), + any(AuthenticatedUser.class))).thenReturn(new ConsentClaimsData()); + + when(mockedSSOConsentService.isSSOConsentManagementEnabled(any())).thenReturn(isConsentMgtEnabled); + } } diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/ciba/OAuth2CibaEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/ciba/OAuth2CibaEndpointTest.java index 7c68c442afe..9cb9bde922a 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/ciba/OAuth2CibaEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/ciba/OAuth2CibaEndpointTest.java @@ -19,22 +19,30 @@ package org.wso2.carbon.identity.oauth.endpoint.ciba; import org.junit.Assert; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.testng.MockitoTestNGListener; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.wso2.carbon.base.CarbonBaseConstants; import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.core.ServiceURL; import org.wso2.carbon.identity.core.ServiceURLBuilder; import org.wso2.carbon.identity.core.URLBuilderException; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.identity.oauth.ciba.api.CibaAuthService; import org.wso2.carbon.identity.oauth.ciba.api.CibaAuthServiceImpl; import org.wso2.carbon.identity.oauth.ciba.common.CibaConstants; import org.wso2.carbon.identity.oauth.ciba.model.CibaAuthCodeResponse; @@ -43,6 +51,7 @@ import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; import org.wso2.carbon.identity.oauth.endpoint.authz.OAuth2AuthzEndpoint; import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.CibaAuthServiceFactory; import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.openidconnect.CIBARequestObjectValidatorImpl; @@ -64,11 +73,14 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @WithCarbonHome @@ -99,7 +111,9 @@ public class OAuth2CibaEndpointTest { Response response; @Mock - CIBARequestObjectValidatorImpl cibaRequestObjectValidator; + BundleContext bundleContext; + + MockedConstruction mockedConstruction; private MockedStatic oAuthServerConfiguration; private MockedStatic oAuth2Util; @@ -121,13 +135,20 @@ public class OAuth2CibaEndpointTest { CibaAuthCodeResponse authCodeResponse = new CibaAuthCodeResponse(); String[] scopes = new String[]{"scope1", "scope2", OAuthConstants.Scope.OPENID}; + @BeforeClass + public void setUpClass() { + + System.setProperty(CarbonBaseConstants.CARBON_HOME, Paths.get(System.getProperty("user.dir"), + "src", "test", "resources").toString()); + } + @BeforeMethod public void setUp() throws Exception { System.setProperty( CarbonBaseConstants.CARBON_HOME, Paths.get(System.getProperty("user.dir"), "src", "test", "resources").toString() - ); + ); oAuth2CibaEndpoint = new OAuth2CibaEndpoint(); oAuthServerConfiguration = mockStatic(OAuthServerConfiguration.class); @@ -150,6 +171,19 @@ public void setUp() throws Exception { .thenReturn("https://localhost:9443/oauth2/token"); serviceURLBuilder = mockStatic(ServiceURLBuilder.class); + + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(CibaAuthService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{authService}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); } @AfterMethod @@ -159,6 +193,7 @@ public void tearDown() { oAuth2Util.close(); endpointUtil.close(); serviceURLBuilder.close(); + mockedConstruction.close(); } @DataProvider(name = "provideRequestParamsForBadRequest") @@ -324,20 +359,23 @@ public void testCibaForProperRequest() throws Exception { "suBggOdBCjn1NyprpJoEg"}); try (MockedStatic loggerUtils = mockStatic(LoggerUtils.class); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) { + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic cibaAuthServiceFactory = + mockStatic(CibaAuthServiceFactory.class);) { loggerUtils.when(LoggerUtils::isDiagnosticLogsEnabled).thenReturn(true); identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(anyString())) .thenReturn(MultitenantConstants.SUPER_TENANT_ID); - when(httpServletRequest.getParameterNames()).thenReturn(Collections.enumeration(requestParams.keySet())); + when(httpServletRequest.getParameterNames()).thenReturn(Collections.enumeration( + requestParams.keySet())); when(httpServletRequest.getParameter(REQUEST_ATTRIBUTE)).thenReturn( - "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJaenhtRHFxSzhZWWZqdGxPaDl2dzg1cW5OVm9hIiwiYXVkIjoiaHR0cHM6Ly9sb2Nh" + - "bGhvc3Q6OTQ0My9vYXV0aDIvY2liYSIsImJpbmRpbmdfbWVzc2FnZSI6InRyeSIsImxvZ2luX2hpbnQiOiJ2aXZlayI" + - "sInNjb3BlIjoib3BlbmlkIHNjb3BlMSBzY29wZXgiLCJpYXQiOjExMjg3MTQyMTksImV4cCI6OTYyODcxNDIxOSwib" + - "mJmIjoxMTI4NzE0MjE5LCJhY3IiOiI1Nzg4ODc4OCIsImp0aSI6IjlmZjg0NWI5LTIwYmYtNDAzMy05ZWQzLTNjY2M" + - "2M2Y1MjA0YyIsInRyYW5zYWN0aW9uX2NvbnRleHQiOnsidXNlciI6InVzZXIiLCJhbW91bnQiOjEwMDAsInNob3AiO" + - "iJXU08yIENJQkEgREVNTyBDT05TT0xFIiwiYXBwbGljYXRpb24iOiJQYXlIZXJlIn19.Sx_MjjautinmOV9vvP8yhu" + - "suBggOdBCjn1NyprpJoEg"); + "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJaenhtRHFxSzhZWWZqdGxPaDl2dzg1cW5OVm9hIiwiYXVkIjoiaHR0cHM" + + "6Ly9sb2NhbGhvc3Q6OTQ0My9vYXV0aDIvY2liYSIsImJpbmRpbmdfbWVzc2FnZSI6InRyeSIsImxvZ2luX2" + + "hpbnQiOiJ2aXZlayIsInNjb3BlIjoib3BlbmlkIHNjb3BlMSBzY29wZXgiLCJpYXQiOjExMjg3MTQyMTksI" + + "mV4cCI6OTYyODcxNDIxOSwibmJmIjoxMTI4NzE0MjE5LCJhY3IiOiI1Nzg4ODc4OCIsImp0aSI6IjlmZjg0" + + "NWI5LTIwYmYtNDAzMy05ZWQzLTNjY2M2M2Y1MjA0YyIsInRyYW5zYWN0aW9uX2NvbnRleHQiOnsidXNlciI" + + "6InVzZXIiLCJhbW91bnQiOjEwMDAsInNob3AiOiJXU08yIENJQkEgREVNTyBDT05TT0xFIiwiYXBwbGljYX" + + "Rpb24iOiJQYXlIZXJlIn19.Sx_MjjautinmOV9vvP8yhusuBggOdBCjn1NyprpJoEg"); OAuthClientAuthnContext oAuthClientAuthnContext = new OAuthClientAuthnContext(); oAuthClientAuthnContext.setAuthenticated(true); oAuthClientAuthnContext.setClientId("ZzxmDqqK8YYfjtlOh9vw85qnNVoa"); @@ -358,15 +396,15 @@ public void testCibaForProperRequest() throws Exception { when(oauthServerConfigurationMock.getCIBARequestObjectValidator()).thenReturn(requestObjectValidator); doReturn(true).when(requestObjectValidator).validateSignature(any(), any()); - RequestParamRequestObjectBuilder requestParamRequestObjectBuilder = new RequestParamRequestObjectBuilder(); + RequestParamRequestObjectBuilder requestParamRequestObjectBuilder = + new RequestParamRequestObjectBuilder(); Map requestObjectBuilderMap = new HashMap<>(); requestObjectBuilderMap.put(REQUEST_PARAM_VALUE_BUILDER, requestParamRequestObjectBuilder); when((oauthServerConfigurationMock.getRequestObjectBuilders())).thenReturn(requestObjectBuilderMap); mockServiceURLBuilder(serviceURLBuilder); - endpointUtil.when(EndpointUtil::getCibaAuthService).thenReturn(authService); - endpointUtil.when(EndpointUtil::getCibaAuthService).thenReturn(authService); + cibaAuthServiceFactory.when(CibaAuthServiceFactory::getCibaAuthService).thenReturn(authService); when(authService.generateAuthCodeResponse(any())).thenReturn(authCodeResponse); CibaAuthzHandler cibaAuthzHandler = new CibaAuthzHandler(); @@ -379,6 +417,7 @@ public void testCibaForProperRequest() throws Exception { Response response = oAuth2CibaEndpoint.ciba(httpServletRequest, httpServletResponse, new MultivaluedHashMap()); Assert.assertEquals(200, response.getStatus()); + } } @@ -387,6 +426,7 @@ private void mockServiceURLBuilder(MockedStatic serviceURLBui ServiceURLBuilder builder = new ServiceURLBuilder() { String path = ""; + @Override public ServiceURLBuilder addPath(String... strings) { diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceEndpointTest.java index 045402bee88..57b5d05e506 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/device/DeviceEndpointTest.java @@ -21,12 +21,16 @@ import org.apache.oltu.oauth2.common.OAuth; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.junit.Assert; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.mockito.testng.MockitoTestNGListener; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; @@ -34,6 +38,8 @@ import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.wso2.carbon.base.CarbonBaseConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; import org.wso2.carbon.identity.core.ServiceURL; import org.wso2.carbon.identity.core.ServiceURLBuilder; @@ -54,6 +60,7 @@ import java.lang.reflect.Method; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Enumeration; import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -66,9 +73,13 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; /** * Use for unit tests in device end-point. @@ -91,12 +102,20 @@ public class DeviceEndpointTest extends TestOAuthEndpointBase { @Mock DeviceFlowPersistenceFactory deviceFlowPersistenceFactory; + @Mock + DeviceAuthServiceImpl deviceAuthService; + @Mock DeviceFlowDAO deviceFlowDAO; @Mock HttpServletRequest request; + @Mock + BundleContext bundleContext; + + MockedConstruction mockedConstruction; + private static final String CLIENT_ID_VALUE = "ca19a540f544777860e44e75f605d927"; private static final String TEST_URL = "testURL"; @@ -118,6 +137,19 @@ public void setUp() throws Exception { loggerUtils.when(LoggerUtils::isDiagnosticLogsEnabled).thenReturn(true); identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); mockDatabase(identityDatabaseUtil); + + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(DeviceAuthServiceImpl.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{deviceAuthService}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); } @AfterMethod @@ -125,6 +157,8 @@ public void tearDown() { loggerUtils.close(); identityDatabaseUtil.close(); + mockedConstruction.close(); + PrivilegedCarbonContext.endTenantFlow(); } @DataProvider(name = "provideValues") @@ -183,7 +217,7 @@ public static Object[][] errorResponseValues() { * @param expectedStatus Expected status for response. * @param status Status of user code. * @throws IdentityOAuth2Exception If failed at device endpoint - * @throws OAuthSystemException If failed at device endpoint. + * @throws OAuthSystemException If failed at device endpoint. */ @Test(dataProvider = "dataValues") public void testDevice(String clientId, int expectedStatus, boolean status) @@ -194,7 +228,7 @@ public void testDevice(String clientId, int expectedStatus, boolean status) MockedStatic deviceFlowPersistenceFactory = mockStatic(DeviceFlowPersistenceFactory.class); MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { + mockStatic(OAuthServerConfiguration.class)) { DeviceEndpoint deviceEndpoint = spy(new DeviceEndpoint()); mockOAuthServerConfiguration(oAuthServerConfiguration); @@ -211,8 +245,6 @@ public void testDevice(String clientId, int expectedStatus, boolean status) oAuthClientAuthnContext.setClientId(clientId); oAuthClientAuthnContext.setAuthenticated(status); lenient().when(request.getAttribute(anyString())).thenReturn(oAuthClientAuthnContext); - DeviceAuthServiceImpl deviceAuthService = new DeviceAuthServiceImpl(); - deviceEndpoint.setDeviceAuthService(deviceAuthService); lenient().when(httpServletRequest.getParameter(anyString())).thenReturn(clientId); lenient().when(httpServletRequest.getAttribute(OAuthConstants.CLIENT_AUTHN_CONTEXT)) @@ -225,6 +257,19 @@ public void testDevice(String clientId, int expectedStatus, boolean status) DeviceFlowPersistenceFactory::getInstance).thenReturn(this.deviceFlowPersistenceFactory); lenient().when(this.deviceFlowPersistenceFactory.getDeviceFlowDAO()).thenReturn(deviceFlowDAO); lenient().when(deviceFlowDAO.checkClientIdExist(anyString())).thenReturn(status); + + lenient().when(httpServletRequest.getParameterNames()).thenReturn(new Enumeration() { + @Override + public boolean hasMoreElements() { + return false; // Return false to simulate no parameter names + } + + @Override + public String nextElement() { + return null; // Return null as there's no next element + } + }); + response = deviceEndpoint.authorize(httpServletRequest, new MultivaluedHashMap<>(), httpServletResponse); Assert.assertEquals(expectedStatus, response.getStatus()); diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/device/UserAuthenticationEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/device/UserAuthenticationEndpointTest.java index 2855ed65c01..0ddf4f105f8 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/device/UserAuthenticationEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/device/UserAuthenticationEndpointTest.java @@ -31,6 +31,7 @@ import org.testng.annotations.Test; import org.wso2.carbon.base.CarbonBaseConstants; import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.application.authentication.framework.model.CommonAuthRequestWrapper; import org.wso2.carbon.identity.core.ServiceURL; import org.wso2.carbon.identity.core.ServiceURLBuilder; @@ -110,6 +111,9 @@ public class UserAuthenticationEndpointTest extends TestOAuthEndpointBase { @Mock ServiceURL serviceURL; + @Mock + PrivilegedCarbonContext mockPrivilegedCarbonContext; + private static final String TEST_USER_CODE = "testUserCode"; private static final String TEST_URL = "testURL"; private static final String PENDING = "PENDING"; @@ -148,6 +152,7 @@ public void setUp() throws Exception { public void tearDown() throws Exception { cleanData(); + PrivilegedCarbonContext.endTenantFlow(); } @BeforeMethod @@ -189,9 +194,17 @@ public void testDeviceAuthorize(String userCode, String clientId, int expectedVa throws Exception { try (MockedStatic oAuthServerConfiguration = mockStatic( - OAuthServerConfiguration.class)) { - mockOAuthServerConfiguration(oAuthServerConfiguration); + OAuthServerConfiguration.class); + MockedStatic privilegedCarbonContext + = mockStatic(PrivilegedCarbonContext.class)) { + DeviceAuthServiceImpl deviceAuthService = new DeviceAuthServiceImpl(); + privilegedCarbonContext.when( + PrivilegedCarbonContext::getThreadLocalCarbonContext).thenReturn(mockPrivilegedCarbonContext); + lenient().when(mockPrivilegedCarbonContext.getOSGiService(DeviceAuthServiceImpl.class, null)) + .thenReturn(deviceAuthService); + + mockOAuthServerConfiguration(oAuthServerConfiguration); setInternalState(userAuthenticationEndpoint, "oAuth2AuthzEndpoint", oAuth2AuthzEndpoint); try (MockedStatic deviceFlowPersistenceFactory = @@ -224,9 +237,7 @@ public void testDeviceAuthorize(String userCode, String clientId, int expectedVa lenient().when(oAuth2AuthzEndpoint.authorize(any(CommonAuthRequestWrapper.class), any(HttpServletResponse.class))).thenReturn(response); - DeviceAuthServiceImpl deviceAuthService = new DeviceAuthServiceImpl(); userAuthenticationEndpoint = new UserAuthenticationEndpoint(); - userAuthenticationEndpoint.setDeviceAuthService(deviceAuthService); setInternalState(userAuthenticationEndpoint, "oAuth2AuthzEndpoint", oAuth2AuthzEndpoint); response1 = userAuthenticationEndpoint.deviceAuthorize(httpServletRequest, httpServletResponse); Assert.assertNotNull(response1); @@ -282,7 +293,8 @@ public void testDeviceAuthorizeForURLBuilderExceptionPath(String userCode, Strin mockStatic(DeviceFlowPersistenceFactory.class); MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class);) { + MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class); + MockedStatic deviceServiceHolder = mockStatic(DeviceServiceFactory.class);) { deviceFlowPersistenceFactory.when( DeviceFlowPersistenceFactory::getInstance).thenReturn(mockDeviceFlowPersistenceFactory); @@ -310,8 +322,10 @@ public void testDeviceAuthorizeForURLBuilderExceptionPath(String userCode, Strin any(HttpServletResponse.class))). thenReturn(response); DeviceAuthServiceImpl deviceAuthService = new DeviceAuthServiceImpl(); + deviceServiceHolder.when(DeviceServiceFactory::getDeviceAuthService).thenReturn(deviceAuthService); + userAuthenticationEndpoint = new UserAuthenticationEndpoint(); - userAuthenticationEndpoint.setDeviceAuthService(deviceAuthService); + setInternalState(userAuthenticationEndpoint, "oAuth2AuthzEndpoint", oAuth2AuthzEndpoint); response1 = userAuthenticationEndpoint.deviceAuthorize(httpServletRequest, httpServletResponse); if (expectedValue == HttpServletResponse.SC_ACCEPTED) { @@ -356,7 +370,9 @@ public void testDeviceAuthorizeForIOExceptionPath(String userCode, String client mockStatic(DeviceFlowPersistenceFactory.class); MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class);) { + MockedStatic serviceURLBuilder = mockStatic(ServiceURLBuilder.class); + MockedStatic deviceServiceHolder = mockStatic(DeviceServiceFactory.class);) { + deviceFlowPersistenceFactory.when( DeviceFlowPersistenceFactory::getInstance).thenReturn(mockDeviceFlowPersistenceFactory); when(mockDeviceFlowPersistenceFactory.getDeviceFlowDAO()).thenReturn(deviceFlowDAO); @@ -381,9 +397,11 @@ public void testDeviceAuthorizeForIOExceptionPath(String userCode, String client lenient().when(oAuth2AuthzEndpoint.authorize(any(CommonAuthRequestWrapper.class), any(HttpServletResponse.class))).thenReturn(response); + DeviceAuthServiceImpl deviceAuthService = new DeviceAuthServiceImpl(); + deviceServiceHolder.when(DeviceServiceFactory::getDeviceAuthService).thenReturn(deviceAuthService); + userAuthenticationEndpoint = new UserAuthenticationEndpoint(); - userAuthenticationEndpoint.setDeviceAuthService(deviceAuthService); setInternalState(userAuthenticationEndpoint, "oAuth2AuthzEndpoint", oAuth2AuthzEndpoint); response1 = userAuthenticationEndpoint.deviceAuthorize(httpServletRequest, httpServletResponse); if (expectedValue == HttpServletResponse.SC_ACCEPTED) { diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryEndpointTest.java index 6f9e92dcf23..230ff4c6c02 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/oidcdiscovery/OIDCDiscoveryEndpointTest.java @@ -1,37 +1,49 @@ /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2019-2024, WSO2 LLC. (http://www.wso2.com). * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. * You may obtain a copy of the License at * * 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. + * 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.oidcdiscovery; import org.junit.Assert; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.testng.MockitoTestNGListener; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.identity.discovery.DefaultOIDCProcessor; import org.wso2.carbon.identity.discovery.OIDCDiscoveryEndPointException; +import org.wso2.carbon.identity.discovery.OIDCProcessor; import org.wso2.carbon.identity.discovery.OIDProviderConfigResponse; +import org.wso2.carbon.identity.discovery.builders.OIDProviderResponseBuilder; import org.wso2.carbon.identity.oauth.common.OAuthConstants; -import org.wso2.carbon.identity.oauth.endpoint.oidcdiscovery.impl.OIDProviderJSONResponseBuilder; -import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OIDCProviderServiceFactory; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -44,12 +56,17 @@ import javax.ws.rs.core.Response; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; /** * This class does unit test coverage for OIDCDiscoveryEndpoint class. */ +@WithCarbonHome @Listeners(MockitoTestNGListener.class) public class OIDCDiscoveryEndpointTest { @@ -62,6 +79,14 @@ public class OIDCDiscoveryEndpointTest { @Mock DefaultOIDCProcessor defaultOIDCProcessor; + @Mock + OIDProviderResponseBuilder oidProviderResponseBuilder; + + @Mock + BundleContext bundleContext; + + MockedConstruction mockedConstruction; + private OIDCDiscoveryEndpoint oidcDiscoveryEndpoint; private Object identityUtilObj; @@ -73,6 +98,33 @@ public void setUp() throws Exception { identityUtilObj = clazz.newInstance(); } + @BeforeMethod + public void setUpMethod() { + + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(OIDProviderResponseBuilder.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oidProviderResponseBuilder}); + } + if (argumentCaptor.getValue().contains(OIDCProcessor.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{defaultOIDCProcessor}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); + } + + @AfterMethod + public void tearDown() { + + mockedConstruction.close(); + PrivilegedCarbonContext.endTenantFlow(); + } + @DataProvider(name = "provideDataForGetOIDProviderConfigurationTokenEndpoint") public Object[][] provideDataGetOIDProviderConfigurationTokenEndpoint() { @@ -118,18 +170,24 @@ protected Map initialValue() { threadLocalPropertiesField.setAccessible(true); threadLocalPropertiesField.set(identityUtilObj, threadLocalProperties); - try (MockedStatic endpointUtil = mockStatic(EndpointUtil.class)) { - endpointUtil.when(EndpointUtil::getOIDCService).thenReturn(defaultOIDCProcessor); - lenient().when(defaultOIDCProcessor.getResponse(any(HttpServletRequest.class), any(String.class))) - .thenReturn(oidProviderConfigResponse); + try (MockedStatic oidcProviderServiceFactory = + mockStatic(OIDCProviderServiceFactory.class); + MockedStatic oidcDiscoveryServiceFactory = + mockStatic(OIDCDiscoveryServiceFactory.class)) { + + oidcDiscoveryServiceFactory.when(OIDCDiscoveryServiceFactory::getOIDProviderResponseBuilder) + .thenReturn(oidProviderResponseBuilder); + oidcProviderServiceFactory.when(OIDCProviderServiceFactory::getOIDCService) + .thenReturn(defaultOIDCProcessor); + lenient().when(defaultOIDCProcessor.getResponse(any(), any())).thenReturn(oidProviderConfigResponse); lenient().when(oidProviderConfigResponse.getConfigMap()).thenReturn(configMap); lenient().when(defaultOIDCProcessor.handleError(any(OIDCDiscoveryEndPointException.class))) .thenReturn(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - oidcDiscoveryEndpoint.setOidProviderResponseBuilder(new OIDProviderJSONResponseBuilder()); Response response = oidcDiscoveryEndpoint.getOIDProviderConfiguration(tokenEp, httpServletRequest); Assert.assertEquals(expectedResponse, response.getStatus()); threadLocalProperties.get().remove(OAuthConstants.TENANT_NAME_FROM_CONTEXT); } + } private Map getSampleConfigMap() { diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/par/OAuth2ParEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/par/OAuth2ParEndpointTest.java index ac6ca0462ed..dc4ed562aae 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/par/OAuth2ParEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/par/OAuth2ParEndpointTest.java @@ -24,10 +24,14 @@ import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.validators.OAuthValidator; import org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.testng.MockitoTestNGListener; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; @@ -36,6 +40,8 @@ import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.wso2.carbon.base.CarbonBaseConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; @@ -47,7 +53,10 @@ import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; import org.wso2.carbon.identity.oauth.endpoint.util.TestOAuthEndpointBase; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.ParAuthServiceFactory; import org.wso2.carbon.identity.oauth.par.core.OAuthParRequestWrapper; +import org.wso2.carbon.identity.oauth.par.core.ParAuthService; import org.wso2.carbon.identity.oauth.par.core.ParAuthServiceImpl; import org.wso2.carbon.identity.oauth.par.model.ParAuthData; import org.wso2.carbon.identity.oauth.tokenprocessor.TokenPersistenceProcessor; @@ -75,10 +84,14 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -107,6 +120,11 @@ public class OAuth2ParEndpointTest extends TestOAuthEndpointBase { @Mock private ParAuthData parAuthData; + @Mock + BundleContext bundleContext; + + MockedConstruction mockedConstruction; + private static final String CLIENT_ID_VALUE = "ca19a540f544777860e44e75f605d927"; private static final String APP_NAME = "myApp"; private static final String INACTIVE_CLIENT_ID_VALUE = "inactiveId"; @@ -157,12 +175,30 @@ public void setUpBeforeMethod() { identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); mockDatabase(identityDatabaseUtil); + + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(OAuth2Service.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oAuth2Service}); + } + if (argumentCaptor.getValue().contains(ParAuthService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{parAuthService}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); } @AfterMethod public void tearDownAfterMethod() { + mockedConstruction.close(); identityDatabaseUtil.close(); + PrivilegedCarbonContext.endTenantFlow(); } @DataProvider(name = "testParDataProvider") @@ -190,7 +226,7 @@ public Object[][] testParDataProvider() { Map requestParams7 = createRequestParamsMap(new String[]{CLIENT_ID_VALUE}, new String[]{"http://localhost:8080" + - "/invalid-redirect"}, new String[]{RESPONSE_TYPE_CODE}); + "/invalid-redirect"}, new String[]{RESPONSE_TYPE_CODE}); Map requestParams8 = createRequestParamsMap(new String[]{CLIENT_ID_VALUE}, new String[]{APP_REDIRECT_URL}, new String[]{RESPONSE_TYPE_CODE}); @@ -350,8 +386,7 @@ public void testPar(Object requestParamsObj, Object paramMapObj, Object oAuthCli throws Exception { try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class)) { - + mockStatic(OAuthServerConfiguration.class)) { MultivaluedMap paramMap = (MultivaluedMap) paramMapObj; Map requestParams = (Map) requestParamsObj; OAuthClientAuthnContext oAuthClientAuthnContext = (OAuthClientAuthnContext) oAuthClientAuthnContextObj; @@ -362,8 +397,12 @@ public void testPar(Object requestParamsObj, Object paramMapObj, Object oAuthCli MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); MockedStatic identityUtil = mockStatic(IdentityUtil.class, Mockito.CALLS_REAL_METHODS); MockedStatic oidcRequestObjectUtil = mockStatic(OIDCRequestObjectUtil.class); - MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class); + MockedStatic parAuthServiceFactory = mockStatic(ParAuthServiceFactory.class)) { + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); + parAuthServiceFactory.when(ParAuthServiceFactory::getParAuthService).thenReturn(parAuthService); identityTenantUtil.when(IdentityTenantUtil::getLoginTenantId).thenReturn(-1234); identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId("carbon.super")).thenReturn(-1234); @@ -385,11 +424,8 @@ public void testPar(Object requestParamsObj, Object paramMapObj, Object oAuthCli .thenReturn(SERVER_BASE_PATH); request.setAttribute(OAuthConstants.TRANSPORT_ENDPOINT_ADDRESS, PAR_EP_URL); - endpointUtil.when(EndpointUtil::getOAuth2Service).thenReturn(oAuth2Service); - lenient().doCallRealMethod().when(oAuth2Service).validateInputParameters(request); lenient().doCallRealMethod().when(oAuth2Service).validateClientInfo(any(OAuthParRequestWrapper.class)); - endpointUtil.when(EndpointUtil::getParAuthService).thenReturn(parAuthService); if (testOAuthSystemException) { endpointUtil.when(() -> EndpointUtil.getOAuthAuthzRequest(any())) .thenThrow(new OAuthSystemException()); diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/revoke/OAuthRevocationEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/revoke/OAuthRevocationEndpointTest.java index c819acb3291..841709fe077 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/revoke/OAuthRevocationEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/revoke/OAuthRevocationEndpointTest.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2017-2024, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -15,23 +15,29 @@ * specific language governing permissions and limitations * under the License. */ + package org.wso2.carbon.identity.oauth.endpoint.revoke; import org.apache.axiom.util.base64.Base64Utils; import org.apache.commons.collections.iterators.IteratorEnumeration; import org.apache.commons.lang.StringUtils; import org.apache.oltu.oauth2.common.OAuth; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.MockedStatic; -import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.wso2.carbon.base.CarbonBaseConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.oauth.common.OAuth2ErrorCodes; @@ -39,8 +45,7 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.endpoint.exception.InvalidRequestParentException; import org.wso2.carbon.identity.oauth.endpoint.expmapper.InvalidRequestExceptionMapper; -import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; -import org.wso2.carbon.identity.oauth.tokenprocessor.TokenPersistenceProcessor; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory; import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.ResponseHeader; import org.wso2.carbon.identity.oauth2.dto.OAuthRevocationRequestDTO; @@ -59,9 +64,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; import static org.testng.Assert.assertEquals; @@ -73,15 +81,17 @@ public class OAuthRevocationEndpointTest { @Mock OAuthServerConfiguration mockOAuthServerConfiguration; - @Mock - TokenPersistenceProcessor tokenPersistenceProcessor; - @Mock OAuthRevocationResponseDTO oAuthRevocationResponseDTO; @Mock OAuth2Service oAuth2Service; + @Mock + BundleContext bundleContext; + + MockedConstruction mockedConstruction; + private static final String TOKEN_PARAM = "token"; private static final String TOKEN_TYPE_HINT_PARAM = "token_type_hint"; private static final String CALLBACK_PARAM = "callback"; @@ -104,7 +114,7 @@ public void setUp() { System.setProperty( CarbonBaseConstants.CARBON_HOME, Paths.get(System.getProperty("user.dir"), "src", "test", "resources").toString() - ); + ); revocationEndpoint = new OAuthRevocationEndpoint(); } @@ -114,12 +124,27 @@ public void setUpBeforeMethod() { initMocks(this); oAuthServerConfiguration = mockStatic(OAuthServerConfiguration.class); oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance).thenReturn(mockOAuthServerConfiguration); + + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(OAuth2Service.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oAuth2Service}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); } @AfterMethod public void tearDown() { oAuthServerConfiguration.close(); + mockedConstruction.close(); + PrivilegedCarbonContext.endTenantFlow(); } @DataProvider(name = "testRevokeAccessTokenDataProvider") @@ -220,7 +245,7 @@ public void testRevokeAccessToken(String authzHeader, boolean addReqParams, Stri try (MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); MockedStatic loggerUtils = mockStatic(LoggerUtils.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic oauth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class)) { MultivaluedMap parameterMap = new MultivaluedHashMap<>(); ResponseHeader[] responseHeaders = (ResponseHeader[]) headerObj; parameterMap.add(TOKEN_PARAM, token); @@ -239,7 +264,7 @@ public void testRevokeAccessToken(String authzHeader, boolean addReqParams, Stri HttpServletRequest request = mockHttpRequest(requestedParams, new HashMap<>()); when(request.getHeader(OAuthConstants.HTTP_REQ_HEADER_AUTHZ)).thenReturn(authzHeader); - endpointUtil.when(EndpointUtil::getOAuth2Service).thenReturn(oAuth2Service); + oauth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); final OAuthRevocationRequestDTO[] revokeReqDTO; revokeReqDTO = new OAuthRevocationRequestDTO[1]; diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/token/OAuth2TokenEndpointTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/token/OAuth2TokenEndpointTest.java index e2833a9ce9d..b03c892ebe0 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/token/OAuth2TokenEndpointTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/token/OAuth2TokenEndpointTest.java @@ -28,12 +28,16 @@ import org.apache.oltu.oauth2.common.message.types.GrantType; import org.apache.oltu.oauth2.common.validators.OAuthValidator; import org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.mockito.testng.MockitoTestNGListener; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; @@ -43,6 +47,7 @@ import org.testng.annotations.Test; import org.wso2.carbon.base.CarbonBaseConstants; import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; @@ -55,6 +60,7 @@ import org.wso2.carbon.identity.oauth.endpoint.expmapper.InvalidRequestExceptionMapper; import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; import org.wso2.carbon.identity.oauth.endpoint.util.TestOAuthEndpointBase; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory; import org.wso2.carbon.identity.oauth.tokenprocessor.TokenPersistenceProcessor; import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.ResponseHeader; @@ -83,10 +89,13 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -107,6 +116,11 @@ public class OAuth2TokenEndpointTest extends TestOAuthEndpointBase { @Mock OAuth2AccessTokenRespDTO oAuth2AccessTokenRespDTO; + @Mock + BundleContext bundleContext; + + MockedConstruction mockedConstruction; + private static final String SQL_ERROR = "sql_error"; private static final String TOKEN_ERROR = "token_error"; private static final String CLIENT_ID_VALUE = "ca19a540f544777860e44e75f605d927"; @@ -162,12 +176,27 @@ public void setUpBeforeMethod() { identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); mockDatabase(identityDatabaseUtil); + + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(OAuth2Service.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oAuth2Service}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); } @AfterMethod public void tearDownAfterMethod() { identityDatabaseUtil.close(); + mockedConstruction.close(); + PrivilegedCarbonContext.endTenantFlow(); } @DataProvider(name = "testIssueAccessTokenDataProvider") @@ -264,7 +293,8 @@ public void testIssueAccessToken(String clientId, String authzHeader, Object par mockStatic(OAuthServerConfiguration.class); MockedStatic loggerUtils = mockStatic(LoggerUtils.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS);) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oauth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class);) { MultivaluedMap paramMap = (MultivaluedMap) paramMapObj; ResponseHeader[] responseHeaders = (ResponseHeader[]) headerObj; Map customResponseParameters = (Map) customResponseParamObj; @@ -296,7 +326,7 @@ public void testIssueAccessToken(String clientId, String authzHeader, Object par }})); endpointUtil.when(EndpointUtil::getRealmInfo).thenReturn(REALM); - endpointUtil.when(EndpointUtil::getOAuth2Service).thenReturn(oAuth2Service); + oauth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); lenient().when(oAuth2Service.issueAccessToken(any(OAuth2AccessTokenReqDTO.class))).thenReturn( oAuth2AccessTokenRespDTO); @@ -385,7 +415,9 @@ public void testTokenErrorResponse(String errorCode, Object headerObj, int expec mockStatic(OAuthServerConfiguration.class); MockedStatic loggerUtils = mockStatic(LoggerUtils.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS);) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class);) { + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); ResponseHeader[] responseHeaders = (ResponseHeader[]) headerObj; Map requestParams = new HashMap<>(); @@ -407,7 +439,6 @@ public void testTokenErrorResponse(String errorCode, Object headerObj, int expec }})); endpointUtil.when(EndpointUtil::getRealmInfo).thenReturn(REALM); - endpointUtil.when(EndpointUtil::getOAuth2Service).thenReturn(oAuth2Service); when(oAuth2Service.issueAccessToken(any(OAuth2AccessTokenReqDTO.class))).thenReturn( oAuth2AccessTokenRespDTO); @@ -450,7 +481,8 @@ public void testIssueAccessTokenWithInvalidClientSecret() throws Exception { mockStatic(OAuthServerConfiguration.class); MockedStatic loggerUtils = mockStatic(LoggerUtils.class); MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS);) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class);) { ResponseHeader[] responseHeaders = new ResponseHeader[]{null}; Map requestParams = new HashMap<>(); requestParams.put(OAuth.OAUTH_GRANT_TYPE, new String[]{GrantType.CLIENT_CREDENTIALS.toString()}); @@ -472,7 +504,7 @@ public void testIssueAccessTokenWithInvalidClientSecret() throws Exception { }})); endpointUtil.when(EndpointUtil::getRealmInfo).thenReturn(REALM); - endpointUtil.when(EndpointUtil::getOAuth2Service).thenReturn(oAuth2Service); + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); mockOAuthServerConfiguration(oAuthServerConfiguration); Map>> grantTypeValidators = new Hashtable<>(); grantTypeValidators.put(GrantType.CLIENT_CREDENTIALS.toString(), PasswordValidator.class); @@ -519,7 +551,8 @@ public void testGetAccessToken(String grantType, String additionalParameters) th try (MockedStatic oAuthServerConfiguration = mockStatic(OAuthServerConfiguration.class); - MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS);) { + MockedStatic endpointUtil = mockStatic(EndpointUtil.class, Mockito.CALLS_REAL_METHODS); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class);) { Map requestParams = new HashMap<>(); requestParams.put(OAuth.OAUTH_CLIENT_ID, new String[]{CLIENT_ID_VALUE}); requestParams.put(OAuth.OAUTH_GRANT_TYPE, new String[]{grantType}); @@ -562,7 +595,7 @@ public void testGetAccessToken(String grantType, String additionalParameters) th mockOAuthServerConfiguration(oAuthServerConfiguration); when(mockOAuthServerConfiguration.getSupportedGrantTypeValidators()).thenReturn(grantTypeValidators); - endpointUtil.when(EndpointUtil::getOAuth2Service).thenReturn(oAuth2Service); + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(oAuth2Service); final Map parametersSetToRequest = new HashMap<>(); doAnswer(new Answer() { @Override diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoISAccessTokenValidatorTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoISAccessTokenValidatorTest.java index 4134c1bb3c5..b4380adb6d5 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoISAccessTokenValidatorTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoISAccessTokenValidatorTest.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2017-2024, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -18,14 +18,23 @@ package org.wso2.carbon.identity.oauth.endpoint.user.impl; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.testng.MockitoTestNGListener; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; -import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; +import org.wso2.carbon.base.CarbonBaseConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2TokenValidatorServiceFactory; import org.wso2.carbon.identity.oauth.user.UserInfoEndpointException; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO; @@ -33,16 +42,21 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Paths; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.HttpHeaders; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; import static org.testng.Assert.assertEquals; @Listeners(MockitoTestNGListener.class) @@ -50,8 +64,15 @@ public class UserInfoISAccessTokenValidatorTest { @Mock private HttpServletRequest httpServletRequest; + @Mock private OAuth2TokenValidationService oAuth2TokenValidationService; + + @Mock + BundleContext bundleContext; + + MockedConstruction mockedConstruction; + private UserInforRequestDefaultValidator userInforRequestDefaultValidator; private UserInfoISAccessTokenValidator userInfoISAccessTokenValidator; private final String token = "ZWx1c3VhcmlvOnlsYWNsYXZl"; @@ -61,8 +82,40 @@ public class UserInfoISAccessTokenValidatorTest { @BeforeClass public void setup() { + System.setProperty(CarbonBaseConstants.CARBON_HOME, Paths.get(System.getProperty("user.dir"), + "src", "test", "resources").toString()); + userInforRequestDefaultValidator = new UserInforRequestDefaultValidator(); userInfoISAccessTokenValidator = new UserInfoISAccessTokenValidator(); + if (mockedConstruction != null) { + mockedConstruction.close(); + } + } + + @BeforeMethod + public void setUp() { + + initMocks(this); + + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(OAuth2TokenValidationService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{oAuth2TokenValidationService}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); + } + + @AfterMethod + public void tearDown() { + + mockedConstruction.close(); + PrivilegedCarbonContext.endTenantFlow(); } @Test @@ -106,7 +159,7 @@ public Object[][] requestBodyWithNonASCII() { @DataProvider public Object[][] getTokens() { - return new Object[][] { + return new Object[][]{ {"48544572-a796-3d42-a571-505bc609acd8"}, }; } @@ -116,8 +169,10 @@ public void testTokenValidation(String accessTokenIdentifier) throws Exception { prepareOAuth2TokenValidationService(); - try (MockedStatic endpointUtil = mockStatic(EndpointUtil.class)) { - endpointUtil.when(EndpointUtil::getOAuth2TokenValidationService).thenReturn(oAuth2TokenValidationService); + try (MockedStatic utilServiceHolder = + mockStatic(OAuth2TokenValidatorServiceFactory.class)) { + utilServiceHolder.when(OAuth2TokenValidatorServiceFactory::getOAuth2TokenValidatorService) + .thenReturn(oAuth2TokenValidationService); OAuth2TokenValidationResponseDTO responseDTO = userInfoISAccessTokenValidator .validateToken(accessTokenIdentifier); diff --git a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoJSONResponseBuilderTest.java b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoJSONResponseBuilderTest.java index 368d87c8a26..5220872de96 100644 --- a/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoJSONResponseBuilderTest.java +++ b/components/org.wso2.carbon.identity.oauth.endpoint/src/test/java/org/wso2/carbon/identity/oauth/endpoint/user/impl/UserInfoJSONResponseBuilderTest.java @@ -23,7 +23,9 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @@ -78,6 +80,7 @@ public class UserInfoJSONResponseBuilderTest extends UserInfoResponseBaseTest { private UserInfoJSONResponseBuilder userInfoJSONResponseBuilder; + MockedStatic oAuthServerConfiguration; Connection con = null; @@ -94,6 +97,20 @@ public void setUpTest() throws Exception { con = TestUtils.getConnection(); } + @BeforeMethod + public void setUpMethod() { + + oAuthServerConfiguration = mockStatic(OAuthServerConfiguration.class); + oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance).thenReturn(mockOAuthServerConfiguration); + } + + @AfterMethod + public void tearDown() { + + oAuthServerConfiguration.close(); + } + + private void setUpRequestObjectService() throws RequestObjectException { List requestedClaims = Collections.emptyList(); @@ -129,65 +146,58 @@ public void testGetResponseString(Map inputClaims, String[] requestedScopes, Map expectedClaims) throws Exception { - try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { - oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) - .thenReturn(mockOAuthServerConfiguration); - try (MockedStatic jdbcPersistenceManager = - mockStatic(JDBCPersistenceManager.class); - MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic authorizationGrantCache = - mockStatic(AuthorizationGrantCache.class); - MockedStatic claimUtil = mockStatic(ClaimUtil.class); - MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic userInfoEndpointConfig = - mockStatic(UserInfoEndpointConfig.class);) { - setUpRequestObjectService(); - prepareForResponseClaimTest(inputClaims, oidcScopeMap, getClaimsFromCache, - authorizationGrantCache, frameworkUtils, claimUtil, oAuth2Util, identityTenantUtil, - userInfoEndpointConfig); - mockDataSource(jdbcPersistenceManager); - mockObjectsRelatedToTokenValidation(oAuth2Util); - - frameworkUtils.when(() -> FrameworkUtils.resolveUserIdFromUsername(anyInt(), anyString(), anyString())) - .thenReturn(AUTHORIZED_USER_ID); - - AuthenticatedUser authenticatedUser = new AuthenticatedUser(); - authenticatedUser.setUserName(AUTHORIZED_USER_NAME); - authenticatedUser.setTenantDomain(TENANT_DOT_COM); - authenticatedUser.setUserStoreDomain(JDBC_DOMAIN); - authenticatedUser.setUserId(AUTHORIZED_USER_ID); - authenticatedUser.setAuthenticatedSubjectIdentifier(AUTHORIZED_USER_ID); - mockAccessTokenDOInOAuth2Util(authenticatedUser, oAuth2Util); - - String responseString = - userInfoJSONResponseBuilder.getResponseString( - getTokenResponseDTO(AUTHORIZED_USER_FULL_QUALIFIED, requestedScopes)); - - Map claimsInResponse = JSONUtils.parseJSON(responseString); - assertNotNull(claimsInResponse); - assertFalse(claimsInResponse.isEmpty()); - assertNotNull(claimsInResponse.get(sub)); - - for (Map.Entry expectClaimEntry : expectedClaims.entrySet()) { - assertTrue(claimsInResponse.containsKey(expectClaimEntry.getKey())); - assertNotNull(claimsInResponse.get(expectClaimEntry.getKey())); - assertEquals(expectClaimEntry.getValue(), claimsInResponse.get(expectClaimEntry.getKey())); - } - - } finally { - PrivilegedCarbonContext.endTenantFlow(); + try (MockedStatic jdbcPersistenceManager = + mockStatic(JDBCPersistenceManager.class); + MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); + MockedStatic authorizationGrantCache = + mockStatic(AuthorizationGrantCache.class); + MockedStatic claimUtil = mockStatic(ClaimUtil.class); + MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic userInfoEndpointConfig = + mockStatic(UserInfoEndpointConfig.class);) { + setUpRequestObjectService(); + prepareForResponseClaimTest(inputClaims, oidcScopeMap, getClaimsFromCache, + authorizationGrantCache, frameworkUtils, claimUtil, oAuth2Util, identityTenantUtil, + userInfoEndpointConfig); + mockDataSource(jdbcPersistenceManager); + mockObjectsRelatedToTokenValidation(oAuth2Util); + + frameworkUtils.when(() -> FrameworkUtils.resolveUserIdFromUsername(anyInt(), anyString(), anyString())) + .thenReturn(AUTHORIZED_USER_ID); + + AuthenticatedUser authenticatedUser = new AuthenticatedUser(); + authenticatedUser.setUserName(AUTHORIZED_USER_NAME); + authenticatedUser.setTenantDomain(TENANT_DOT_COM); + authenticatedUser.setUserStoreDomain(JDBC_DOMAIN); + authenticatedUser.setUserId(AUTHORIZED_USER_ID); + authenticatedUser.setAuthenticatedSubjectIdentifier(AUTHORIZED_USER_ID); + mockAccessTokenDOInOAuth2Util(authenticatedUser, oAuth2Util); + + String responseString = + userInfoJSONResponseBuilder.getResponseString( + getTokenResponseDTO(AUTHORIZED_USER_FULL_QUALIFIED, requestedScopes)); + + Map claimsInResponse = JSONUtils.parseJSON(responseString); + assertNotNull(claimsInResponse); + assertFalse(claimsInResponse.isEmpty()); + assertNotNull(claimsInResponse.get(sub)); + + for (Map.Entry expectClaimEntry : expectedClaims.entrySet()) { + assertTrue(claimsInResponse.containsKey(expectClaimEntry.getKey())); + assertNotNull(claimsInResponse.get(expectClaimEntry.getKey())); + assertEquals(expectClaimEntry.getValue(), claimsInResponse.get(expectClaimEntry.getKey())); } + + } finally { + PrivilegedCarbonContext.endTenantFlow(); } } @Test public void testEssentialClaims() throws Exception { - try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class); - MockedStatic authorizationGrantCache = + try (MockedStatic authorizationGrantCache = mockStatic(AuthorizationGrantCache.class); MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); MockedStatic claimUtil = mockStatic(ClaimUtil.class);) { @@ -260,76 +270,59 @@ public void testEssentialClaims() throws Exception { @Test public void testUpdateAtClaim() throws Exception { - try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { - oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) - .thenReturn(mockOAuthServerConfiguration); - - try (MockedStatic jdbcPersistenceManager = - mockStatic(JDBCPersistenceManager.class); - MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic authorizationGrantCache = - mockStatic(AuthorizationGrantCache.class); - MockedStatic claimUtil = mockStatic(ClaimUtil.class); - MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic userInfoEndpointConfig = - mockStatic(UserInfoEndpointConfig.class);) { - String updateAtValue = "1509556412"; - testLongClaimInUserInfoResponse(UPDATED_AT, updateAtValue, jdbcPersistenceManager, frameworkUtils, - authorizationGrantCache, claimUtil, oAuth2Util, identityTenantUtil, userInfoEndpointConfig); - } + try (MockedStatic jdbcPersistenceManager = + mockStatic(JDBCPersistenceManager.class); + MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); + MockedStatic authorizationGrantCache = + mockStatic(AuthorizationGrantCache.class); + MockedStatic claimUtil = mockStatic(ClaimUtil.class); + MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic userInfoEndpointConfig = + mockStatic(UserInfoEndpointConfig.class);) { + String updateAtValue = "1509556412"; + testLongClaimInUserInfoResponse(UPDATED_AT, updateAtValue, jdbcPersistenceManager, frameworkUtils, + authorizationGrantCache, claimUtil, oAuth2Util, identityTenantUtil, userInfoEndpointConfig); } } @Test public void testEmailVerified() throws Exception { - try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { - oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) - .thenReturn(mockOAuthServerConfiguration); - - try (MockedStatic jdbcPersistenceManager = - mockStatic(JDBCPersistenceManager.class); - MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic authorizationGrantCache = - mockStatic(AuthorizationGrantCache.class); - MockedStatic claimUtil = mockStatic(ClaimUtil.class); - MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic userInfoEndpointConfig = - mockStatic(UserInfoEndpointConfig.class);) { - String emailVerifiedClaimValue = "true"; - testBooleanClaimInUserInfoResponse(EMAIL_VERIFIED, emailVerifiedClaimValue, jdbcPersistenceManager, - frameworkUtils, authorizationGrantCache, claimUtil, oAuth2Util, identityTenantUtil, - userInfoEndpointConfig); - } + try (MockedStatic jdbcPersistenceManager = + mockStatic(JDBCPersistenceManager.class); + MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); + MockedStatic authorizationGrantCache = + mockStatic(AuthorizationGrantCache.class); + MockedStatic claimUtil = mockStatic(ClaimUtil.class); + MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic userInfoEndpointConfig = + mockStatic(UserInfoEndpointConfig.class);) { + String emailVerifiedClaimValue = "true"; + testBooleanClaimInUserInfoResponse(EMAIL_VERIFIED, emailVerifiedClaimValue, jdbcPersistenceManager, + frameworkUtils, authorizationGrantCache, claimUtil, oAuth2Util, identityTenantUtil, + userInfoEndpointConfig); } } @Test public void testPhoneNumberVerified() throws Exception { - try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { - oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) - .thenReturn(mockOAuthServerConfiguration); - try (MockedStatic jdbcPersistenceManager = - mockStatic(JDBCPersistenceManager.class); - MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic authorizationGrantCache = - mockStatic(AuthorizationGrantCache.class); - MockedStatic claimUtil = mockStatic(ClaimUtil.class); - MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic userInfoEndpointConfig = - mockStatic(UserInfoEndpointConfig.class);) { - String phoneNumberVerifiedClaimValue = "true"; - testBooleanClaimInUserInfoResponse(PHONE_NUMBER_VERIFIED, phoneNumberVerifiedClaimValue, - jdbcPersistenceManager, frameworkUtils, authorizationGrantCache, - claimUtil, oAuth2Util, identityTenantUtil, userInfoEndpointConfig); - } + try (MockedStatic jdbcPersistenceManager = + mockStatic(JDBCPersistenceManager.class); + MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); + MockedStatic authorizationGrantCache = + mockStatic(AuthorizationGrantCache.class); + MockedStatic claimUtil = mockStatic(ClaimUtil.class); + MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic userInfoEndpointConfig = + mockStatic(UserInfoEndpointConfig.class);) { + String phoneNumberVerifiedClaimValue = "true"; + testBooleanClaimInUserInfoResponse(PHONE_NUMBER_VERIFIED, phoneNumberVerifiedClaimValue, + jdbcPersistenceManager, frameworkUtils, authorizationGrantCache, + claimUtil, oAuth2Util, identityTenantUtil, userInfoEndpointConfig); } } @@ -418,41 +411,36 @@ public void testSubjectClaim(Map inputClaims, boolean appendUserStoreDomain, boolean isPairwiseSubject, String expectedSubjectValue, String expectedPPID) throws Exception { - try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { - oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) - .thenReturn(mockOAuthServerConfiguration); - try (MockedStatic jdbcPersistenceManager = - mockStatic(JDBCPersistenceManager.class); - MockedStatic authorizationGrantCache = - mockStatic(AuthorizationGrantCache.class); - MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic claimUtil = mockStatic(ClaimUtil.class); - MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic userInfoEndpointConfig = - mockStatic(UserInfoEndpointConfig.class);) { - setUpRequestObjectService(); - AuthenticatedUser authzUser = (AuthenticatedUser) authorizedUser; - prepareForSubjectClaimTest(authzUser, inputClaims, appendTenantDomain, appendUserStoreDomain, - isPairwiseSubject, authorizationGrantCache, frameworkUtils, claimUtil, oAuth2Util, - identityTenantUtil, userInfoEndpointConfig); - updateAuthenticatedSubjectIdentifier(authzUser, appendTenantDomain, appendUserStoreDomain, inputClaims); - when(userInfoJSONResponseBuilder.retrieveUserClaims(any(OAuth2TokenValidationResponseDTO.class))) - .thenReturn(inputClaims); - Mockito.when(IdentityTenantUtil.getTenantId(isNull())).thenReturn(-1234); - mockDataSource(jdbcPersistenceManager); - mockObjectsRelatedToTokenValidation(oAuth2Util); - String responseString = - userInfoJSONResponseBuilder - .getResponseString(getTokenResponseDTO((authzUser).toFullQualifiedUsername())); - - Map claimsInResponse = JSONUtils.parseJSON(responseString); - assertSubjectClaimPresent(claimsInResponse); - assertEquals(claimsInResponse.get(sub), isPairwiseSubject ? expectedPPID : expectedSubjectValue); - } finally { - PrivilegedCarbonContext.endTenantFlow(); - } + try (MockedStatic jdbcPersistenceManager = + mockStatic(JDBCPersistenceManager.class); + MockedStatic authorizationGrantCache = + mockStatic(AuthorizationGrantCache.class); + MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); + MockedStatic claimUtil = mockStatic(ClaimUtil.class); + MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic userInfoEndpointConfig = + mockStatic(UserInfoEndpointConfig.class);) { + setUpRequestObjectService(); + AuthenticatedUser authzUser = (AuthenticatedUser) authorizedUser; + prepareForSubjectClaimTest(authzUser, inputClaims, appendTenantDomain, appendUserStoreDomain, + isPairwiseSubject, authorizationGrantCache, frameworkUtils, claimUtil, oAuth2Util, + identityTenantUtil, userInfoEndpointConfig); + updateAuthenticatedSubjectIdentifier(authzUser, appendTenantDomain, appendUserStoreDomain, inputClaims); + when(userInfoJSONResponseBuilder.retrieveUserClaims(any(OAuth2TokenValidationResponseDTO.class))) + .thenReturn(inputClaims); + Mockito.when(IdentityTenantUtil.getTenantId(isNull())).thenReturn(-1234); + mockDataSource(jdbcPersistenceManager); + mockObjectsRelatedToTokenValidation(oAuth2Util); + String responseString = + userInfoJSONResponseBuilder + .getResponseString(getTokenResponseDTO((authzUser).toFullQualifiedUsername())); + + Map claimsInResponse = JSONUtils.parseJSON(responseString); + assertSubjectClaimPresent(claimsInResponse); + assertEquals(claimsInResponse.get(sub), isPairwiseSubject ? expectedPPID : expectedSubjectValue); + } finally { + PrivilegedCarbonContext.endTenantFlow(); } } @@ -464,45 +452,39 @@ public void testSubjectClaimWithAlteredApplicationConfigs(Map in String expectedSubjectValue, String expectedPPID) throws Exception { - try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { - oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) - .thenReturn(mockOAuthServerConfiguration); - - try (MockedStatic jdbcPersistenceManager = - mockStatic(JDBCPersistenceManager.class); - MockedStatic authorizationGrantCache = - mockStatic(AuthorizationGrantCache.class); - MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic claimUtil = mockStatic(ClaimUtil.class); - MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic userInfoEndpointConfig = - mockStatic(UserInfoEndpointConfig.class);) { - setUpRequestObjectService(); - AuthenticatedUser authzUser = (AuthenticatedUser) authorizedUser; - prepareForSubjectClaimTest(authzUser, inputClaims, !appendTenantDomain, !appendUserStoreDomain, - isPairwiseSubject, authorizationGrantCache, frameworkUtils, claimUtil, oAuth2Util, - identityTenantUtil, userInfoEndpointConfig); - authzUser.setAuthenticatedSubjectIdentifier(expectedSubjectValue, - applicationManagementService.getServiceProviderByClientId(CLIENT_ID, - IdentityApplicationConstants.OAuth2.NAME, SUPER_TENANT_DOMAIN_NAME)); - - when(userInfoJSONResponseBuilder.retrieveUserClaims(any(OAuth2TokenValidationResponseDTO.class))) - .thenReturn(inputClaims); - Mockito.when(IdentityTenantUtil.getTenantId(isNull())).thenReturn(-1234); - mockDataSource(jdbcPersistenceManager); - mockObjectsRelatedToTokenValidation(oAuth2Util); - String responseString = - userInfoJSONResponseBuilder - .getResponseString(getTokenResponseDTO((authzUser).toFullQualifiedUsername())); - - Map claimsInResponse = JSONUtils.parseJSON(responseString); - assertSubjectClaimPresent(claimsInResponse); - assertEquals(claimsInResponse.get(sub), isPairwiseSubject ? expectedPPID : expectedSubjectValue); - } finally { - PrivilegedCarbonContext.endTenantFlow(); - } + try (MockedStatic jdbcPersistenceManager = + mockStatic(JDBCPersistenceManager.class); + MockedStatic authorizationGrantCache = + mockStatic(AuthorizationGrantCache.class); + MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); + MockedStatic claimUtil = mockStatic(ClaimUtil.class); + MockedStatic oAuth2Util = mockStatic(OAuth2Util.class, Mockito.CALLS_REAL_METHODS); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic userInfoEndpointConfig = + mockStatic(UserInfoEndpointConfig.class);) { + setUpRequestObjectService(); + AuthenticatedUser authzUser = (AuthenticatedUser) authorizedUser; + prepareForSubjectClaimTest(authzUser, inputClaims, !appendTenantDomain, !appendUserStoreDomain, + isPairwiseSubject, authorizationGrantCache, frameworkUtils, claimUtil, oAuth2Util, + identityTenantUtil, userInfoEndpointConfig); + authzUser.setAuthenticatedSubjectIdentifier(expectedSubjectValue, + applicationManagementService.getServiceProviderByClientId(CLIENT_ID, + IdentityApplicationConstants.OAuth2.NAME, SUPER_TENANT_DOMAIN_NAME)); + + when(userInfoJSONResponseBuilder.retrieveUserClaims(any(OAuth2TokenValidationResponseDTO.class))) + .thenReturn(inputClaims); + Mockito.when(IdentityTenantUtil.getTenantId(isNull())).thenReturn(-1234); + mockDataSource(jdbcPersistenceManager); + mockObjectsRelatedToTokenValidation(oAuth2Util); + String responseString = + userInfoJSONResponseBuilder + .getResponseString(getTokenResponseDTO((authzUser).toFullQualifiedUsername())); + + Map claimsInResponse = JSONUtils.parseJSON(responseString); + assertSubjectClaimPresent(claimsInResponse); + assertEquals(claimsInResponse.get(sub), isPairwiseSubject ? expectedPPID : expectedSubjectValue); + } finally { + PrivilegedCarbonContext.endTenantFlow(); } } } 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 188c2943859..2fd006c97a0 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 @@ -28,12 +28,16 @@ import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.message.OAuthResponse; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockedConstruction; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.testng.MockitoTestNGListener; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; import org.testng.Assert; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; @@ -41,9 +45,9 @@ import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.ServerConfiguration; import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationRequestCacheEntry; import org.wso2.carbon.identity.application.authentication.framework.config.builder.FileBasedConfigurationBuilder; -import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.consent.SSOConsentService; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.common.model.LocalAndOutboundAuthenticationConfig; @@ -57,7 +61,6 @@ import org.wso2.carbon.identity.discovery.DefaultOIDCProcessor; import org.wso2.carbon.identity.discovery.OIDCProcessor; import org.wso2.carbon.identity.discovery.builders.DefaultOIDCProviderRequestBuilder; -import org.wso2.carbon.identity.discovery.builders.OIDCProviderRequestBuilder; import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl; import org.wso2.carbon.identity.oauth.cache.SessionDataCache; import org.wso2.carbon.identity.oauth.cache.SessionDataCacheEntry; @@ -67,6 +70,15 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.endpoint.exception.InvalidApplicationClientException; import org.wso2.carbon.identity.oauth.endpoint.expmapper.InvalidRequestExceptionMapper; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2ServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuth2TokenValidatorServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuthAdminServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OAuthServerConfigurationFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OIDCProviderRequestValidatorFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.OIDCProviderServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.Oauth2ScopeServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.RequestObjectServiceFactory; +import org.wso2.carbon.identity.oauth.endpoint.util.factory.WebFingerServiceFactory; import org.wso2.carbon.identity.oauth2.OAuth2ScopeService; import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; @@ -106,9 +118,12 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -138,9 +153,6 @@ public class EndpointUtilTest { @Mock HttpServletResponse mockedHttpServletResponse; - @Mock - PrivilegedCarbonContext mockedPrivilegedCarbonContext; - @Mock ServerConfiguration mockedServerConfiguration; @@ -151,16 +163,15 @@ public class EndpointUtilTest { OAuthAdminServiceImpl mockedOAuthAdminService; @Mock - SSOConsentService mockedSSOConsentService; + OAuth2ScopeService oAuth2ScopeService; @Mock - RequestObjectService mockedRequestObjectService; + FileBasedConfigurationBuilder mockFileBasedConfigurationBuilder; @Mock - OAuth2ScopeService oAuth2ScopeService; + BundleContext bundleContext; - @Mock - FileBasedConfigurationBuilder mockFileBasedConfigurationBuilder; + MockedConstruction mockedConstruction; private static final String COMMONAUTH_URL = "https://localhost:9443/commonauth"; private static final String OIDC_CONSENT_PAGE_URL = @@ -207,6 +218,52 @@ public void setUp() { user.setUserId("4b4414e1-916b-4475-aaee-6b0751c29ff6"); oAuth2ScopeConsentResponse = new OAuth2ScopeConsentResponse("sampleUser", "sampleApp", -1234, new ArrayList<>(), new ArrayList<>()); + + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain("carbon.super"); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + mockedConstruction = mockConstruction(ServiceTracker.class, + (mock, context) -> { + verify(bundleContext, atLeastOnce()).createFilter(argumentCaptor.capture()); + if (argumentCaptor.getValue().contains(DefaultOIDCProviderRequestBuilder.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{new DefaultOIDCProviderRequestBuilder()}); + } + if (argumentCaptor.getValue().contains(OAuthServerConfiguration.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{mockedOAuthServerConfiguration}); + } + if (argumentCaptor.getValue().contains(WebFingerProcessor.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{DefaultWebFingerProcessor.getInstance()}); + } + if (argumentCaptor.getValue().contains(OIDCProcessor.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{DefaultOIDCProcessor.getInstance()}); + } + if (argumentCaptor.getValue().contains(OAuth2Service.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{new OAuth2Service()}); + } + if (argumentCaptor.getValue().contains(OAuth2TokenValidationService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{new OAuth2TokenValidationService()}); + } + if (argumentCaptor.getValue().contains(RequestObjectService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{new RequestObjectService()}); + } + if (argumentCaptor.getValue().contains(OAuth2ScopeService.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{new OAuth2ScopeService()}); + } + if (argumentCaptor.getValue().contains(OAuthAdminServiceImpl.class.getName())) { + when(mock.getServices()).thenReturn(new Object[]{new OAuthAdminServiceImpl()}); + } + }); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); + } + + @AfterMethod + public void tearDown() { + + mockedConstruction.close(); + PrivilegedCarbonContext.endTenantFlow(); + Mockito.reset(bundleContext); + OSGiDataHolder.getInstance().setBundleContext(bundleContext); } @DataProvider(name = "provideAuthzHeader") @@ -283,7 +340,9 @@ public void testGetUserConsentURL(Object oAuth2ParamObject, boolean isOIDC, bool try (MockedStatic oAuthServerConfiguration = mockStatic( OAuthServerConfiguration.class); MockedStatic fileBasedConfigurationBuilder = - mockStatic(FileBasedConfigurationBuilder.class);) { + mockStatic(FileBasedConfigurationBuilder.class); + MockedStatic oAuthServerConfigurationFactory = + mockStatic(OAuthServerConfigurationFactory.class)) { oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) .thenReturn(mockedOAuthServerConfiguration); @@ -291,11 +350,17 @@ 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 oauth2ScopeServiceFactory = + mockStatic(Oauth2ScopeServiceFactory.class); + MockedStatic oAuthAdminServiceFactory = + mockStatic(OAuthAdminServiceFactory.class)) { - EndpointUtil.setOauthServerConfiguration(mockedOAuthServerConfiguration); + oAuthServerConfigurationFactory.when(OAuthServerConfigurationFactory::getOAuthServerConfiguration) + .thenReturn(mockedOAuthServerConfiguration); lenient().when(mockedOAuthServerConfiguration.isDropUnregisteredScopes()).thenReturn(false); - EndpointUtil.setOAuth2ScopeService(oAuth2ScopeService); + oauth2ScopeServiceFactory.when(Oauth2ScopeServiceFactory::getOAuth2ScopeService) + .thenReturn(oAuth2ScopeService); lenient().when(oAuth2ScopeService.getUserConsentForApp(anyString(), anyString(), anyInt())) .thenReturn(oAuth2ScopeConsentResponse); @@ -339,7 +404,8 @@ public void testGetUserConsentURL(Object oAuth2ParamObject, boolean isOIDC, bool thenReturn(null); } - EndpointUtil.setOAuthAdminService(mockedOAuthAdminService); + oAuthAdminServiceFactory.when(OAuthAdminServiceFactory::getOAuthAdminService) + .thenReturn(mockedOAuthAdminService); lenient().when(mockedOAuthAdminService.getScopeNames()).thenReturn(new String[0]); lenient().when(mockedOAuthAdminService.getRegisteredOIDCScope(anyString())) .thenReturn(Arrays.asList("openid", "email", "profile", "groups")); @@ -548,19 +614,20 @@ public void testGetErrorRedirectURL(boolean isImplicitResponse, boolean isImplic try (MockedConstruction mockedConstruction = Mockito.mockConstruction(OAuthResponse.OAuthErrorResponseBuilder.class, - (mock, context) -> { - when(mock.error(any(OAuthProblemException.class))).thenReturn(mock); - when(mock.location(anyString())).thenReturn(mock); - when(mock.setState(anyString())).thenReturn(mock); - when(mock.setParam(anyString(), isNull())). - thenReturn(mock); - if (exeObject != null) { - OAuthSystemException oAuthSystemException = (OAuthSystemException) exeObject; - when(mock.buildQueryMessage()).thenThrow(oAuthSystemException); - } else { - when(mock.buildQueryMessage()).thenReturn(mockedOAuthResponse); - } - })) { + (mock, context) -> { + when(mock.error(any(OAuthProblemException.class))).thenReturn(mock); + when(mock.location(anyString())).thenReturn(mock); + when(mock.setState(anyString())).thenReturn(mock); + when(mock.setParam(anyString(), isNull())). + thenReturn(mock); + if (exeObject != null) { + OAuthSystemException oAuthSystemException = + (OAuthSystemException) exeObject; + when(mock.buildQueryMessage()).thenThrow(oAuthSystemException); + } else { + when(mock.buildQueryMessage()).thenReturn(mockedOAuthResponse); + } + })) { lenient().when(mockedOAuthResponse.getLocationUri()).thenReturn("http://localhost:8080/location"); String url = EndpointUtil.getErrorRedirectURL(exception, parameters); @@ -616,7 +683,7 @@ public void testGetErrorPageURL(boolean isImplicitResponse, boolean isHybridResp OAuth2Parameters parameters = (OAuth2Parameters) oAuth2ParamObject; try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class);) { + mockStatic(OAuthServerConfiguration.class);) { oAuthServerConfiguration.when( OAuthServerConfiguration::getInstance).thenReturn(mockedOAuthServerConfiguration); when(mockedOAuthServerConfiguration.isRedirectToRequestedRedirectUriEnabled()) @@ -624,8 +691,8 @@ public void testGetErrorPageURL(boolean isImplicitResponse, boolean isHybridResp try (MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); MockedStatic oAuthURL = mockStatic(OAuth2Util.OAuthURL.class);) { - oAuth2Util.when(()->OAuth2Util.isImplicitResponseType(anyString())).thenReturn(isImplicitResponse); - oAuth2Util.when(()->OAuth2Util.isHybridResponseType(anyString())).thenReturn(isHybridResponse); + oAuth2Util.when(() -> OAuth2Util.isImplicitResponseType(anyString())).thenReturn(isImplicitResponse); + oAuth2Util.when(() -> OAuth2Util.isHybridResponseType(anyString())).thenReturn(isHybridResponse); oAuthURL.when(OAuth2Util.OAuthURL::getOAuth2ErrorPageUrl).thenReturn(ERROR_PAGE_URL); @@ -689,7 +756,7 @@ public void testValidateParams(Object paramObject, Map request public void testGetLoginPageURLFromCache() throws Exception { try (MockedStatic oAuthServerConfiguration = - mockStatic(OAuthServerConfiguration.class)) { + mockStatic(OAuthServerConfiguration.class)) { oAuthServerConfiguration.when( OAuthServerConfiguration::getInstance).thenReturn(mockedOAuthServerConfiguration); @@ -725,29 +792,23 @@ public void testGetLoginPageURLFromCache() throws Exception { @Test public void testGetServices() { - try (MockedStatic privilegedCarbonContext = - mockStatic(PrivilegedCarbonContext.class);) { - mockPrivilegedCarbonContext(privilegedCarbonContext); - EndpointUtil.setOAuth2Service(mockedOAuth2Service); - EndpointUtil.setSSOConsentService(mockedSSOConsentService); - EndpointUtil.setRequestObjectService(mockedRequestObjectService); - assertTrue(EndpointUtil.getWebFingerService() instanceof DefaultWebFingerProcessor, - "Retrieved incorrect WebFingerService"); - assertTrue(EndpointUtil.getOIDProviderRequestValidator() instanceof DefaultOIDCProviderRequestBuilder, - "Retrieved incorrect OIDProviderRequestValidator"); - assertTrue(EndpointUtil.getOIDCService() instanceof DefaultOIDCProcessor, - "Retrieved incorrect OIDCService"); - assertTrue(EndpointUtil.getOAuth2Service() instanceof OAuth2Service, - "Retrieved incorrect OAuth2Service"); - assertTrue(EndpointUtil.getOAuthServerConfiguration() instanceof OAuthServerConfiguration, - "Retrieved incorrect OAuthServerConfiguration"); - assertTrue(EndpointUtil.getOAuth2TokenValidationService() instanceof OAuth2TokenValidationService, - "Retrieved incorrect OAuth2TokenValidationService"); - assertTrue(EndpointUtil.getSSOConsentService() instanceof SSOConsentService, - "Retrieved incorrect SSOConsentService"); - assertTrue(EndpointUtil.getRequestObjectService() instanceof RequestObjectService, - "Retrieved incorrect RequestObjectService"); - } + assertTrue(WebFingerServiceFactory.getWebFingerService() instanceof DefaultWebFingerProcessor, + "Retrieved incorrect WebFingerService"); + assertTrue(OIDCProviderRequestValidatorFactory.getOIDProviderRequestValidator() + instanceof DefaultOIDCProviderRequestBuilder, + "Retrieved incorrect OIDProviderRequestValidator"); + assertTrue(OIDCProviderServiceFactory.getOIDCService() instanceof DefaultOIDCProcessor, + "Retrieved incorrect OIDCService"); + assertTrue(OAuth2ServiceFactory.getOAuth2Service() instanceof OAuth2Service, + "Retrieved incorrect OAuth2Service"); + assertTrue(OAuthServerConfigurationFactory.getOAuthServerConfiguration() + instanceof OAuthServerConfiguration, + "Retrieved incorrect OAuthServerConfiguration"); + assertTrue(OAuth2TokenValidatorServiceFactory.getOAuth2TokenValidatorService() + instanceof OAuth2TokenValidationService, + "Retrieved incorrect OAuth2TokenValidationService"); + assertTrue(RequestObjectServiceFactory.getRequestObjectService() instanceof RequestObjectService, + "Retrieved incorrect RequestObjectService"); } @Test @@ -764,17 +825,18 @@ public void testGetRealmInfo() { @Test public void testGetOAuthServerConfigProperties() throws Exception { - try (MockedStatic privilegedCarbonContext = - mockStatic(PrivilegedCarbonContext.class);) { - mockPrivilegedCarbonContext(privilegedCarbonContext); + try (MockedStatic oAuthServerConfigurationFactory = + mockStatic(OAuthServerConfigurationFactory.class)) { + oAuthServerConfigurationFactory.when(OAuthServerConfigurationFactory::getOAuthServerConfiguration) + .thenReturn(mockedOAuthServerConfiguration); setMockedOAuthServerConfiguration(); - EndpointUtil.setOauthServerConfiguration(mockedOAuthServerConfiguration); assertEquals(EndpointUtil.getUserInfoRequestValidator(), USER_INFO_REQUEST_VALIDATOR); assertEquals(EndpointUtil.getAccessTokenValidator(), USER_INFO_TOKEN_VALIDATOR); assertEquals(EndpointUtil.getUserInfoResponseBuilder(), USER_INFO_RESPONSE_BUILDER); assertEquals(EndpointUtil.getUserInfoClaimRetriever(), USER_INFO_CLAIM_RETRIEVER); assertEquals(EndpointUtil.getUserInfoClaimDialect(), USER_INFO_CLAIM_DIALECT); } + } @DataProvider(name = "provideState") @@ -790,9 +852,10 @@ public Object[][] provideState() { @Test(dataProvider = "provideState") public void testValidateOauthApplication(String state, boolean diagnosticLogEnabled) { - try (MockedStatic loggerUtils = mockStatic(LoggerUtils.class);) { + try (MockedStatic loggerUtils = mockStatic(LoggerUtils.class); + MockedStatic oAuth2ServiceFactory = mockStatic(OAuth2ServiceFactory.class);) { loggerUtils.when(LoggerUtils::isDiagnosticLogsEnabled).thenReturn(diagnosticLogEnabled); - EndpointUtil.setOAuth2Service(mockedOAuth2Service); + oAuth2ServiceFactory.when(OAuth2ServiceFactory::getOAuth2Service).thenReturn(mockedOAuth2Service); when(mockedOAuth2Service.getOauthApplicationState(anyString())).thenReturn(state); Response response; @@ -832,24 +895,6 @@ private void setMockedLog(boolean isDebugEnabled) throws Exception { lenient().when(mockedLog.isDebugEnabled()).thenReturn(isDebugEnabled); } - private void mockPrivilegedCarbonContext(MockedStatic privilegedCarbonContext) { - - privilegedCarbonContext.when( - PrivilegedCarbonContext::getThreadLocalCarbonContext).thenReturn(mockedPrivilegedCarbonContext); - lenient().when(mockedPrivilegedCarbonContext.getOSGiService(OAuthServerConfiguration.class, null)). - thenReturn(mockedOAuthServerConfiguration); - lenient().when(mockedPrivilegedCarbonContext.getOSGiService(WebFingerProcessor.class, null)). - thenReturn(DefaultWebFingerProcessor.getInstance()); - lenient().when(mockedPrivilegedCarbonContext.getOSGiService(OIDCProviderRequestBuilder.class, null)). - thenReturn(new DefaultOIDCProviderRequestBuilder()); - lenient().when(mockedPrivilegedCarbonContext.getOSGiService(OIDCProcessor.class, null)). - thenReturn(DefaultOIDCProcessor.getInstance()); - lenient().when(mockedPrivilegedCarbonContext.getOSGiService(OAuth2Service.class, null)) - .thenReturn(new OAuth2Service()); - lenient().when(mockedPrivilegedCarbonContext.getOSGiService(OAuth2TokenValidationService.class, null)). - thenReturn(new OAuth2TokenValidationService()); - } - private void setMockedOAuthServerConfiguration() { when(mockedOAuthServerConfiguration.getOpenIDConnectUserInfoEndpointRequestValidator()). diff --git a/components/org.wso2.carbon.identity.oauth.extension/pom.xml b/components/org.wso2.carbon.identity.oauth.extension/pom.xml index 285a2a2d9c6..cef5adab8d1 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.191-SNAPSHOT + 7.0.214-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 70c7ea0a949..162ed83271d 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.191-SNAPSHOT + 7.0.214-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 33469d095b5..16f21087edd 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0 @@ -74,25 +74,6 @@ jackson-databind provided - - org.springframework - spring-web - provided - - - com.fasterxml.jackson.core - jackson-databind - - - com.fasterxml.jackson.core - jackson-core - - - com.fasterxml.jackson.core - jackson-annotations - - - com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider diff --git a/components/org.wso2.carbon.identity.oauth.scope.endpoint/src/main/webapp/WEB-INF/beans.xml b/components/org.wso2.carbon.identity.oauth.scope.endpoint/src/main/webapp/WEB-INF/beans.xml deleted file mode 100644 index 2e3ccb79601..00000000000 --- a/components/org.wso2.carbon.identity.oauth.scope.endpoint/src/main/webapp/WEB-INF/beans.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/components/org.wso2.carbon.identity.oauth.scope.endpoint/src/main/webapp/WEB-INF/web.xml b/components/org.wso2.carbon.identity.oauth.scope.endpoint/src/main/webapp/WEB-INF/web.xml index 55d9840f0a5..9ce927a50cf 100644 --- a/components/org.wso2.carbon.identity.oauth.scope.endpoint/src/main/webapp/WEB-INF/web.xml +++ b/components/org.wso2.carbon.identity.oauth.scope.endpoint/src/main/webapp/WEB-INF/web.xml @@ -9,11 +9,6 @@ WSO2 Identity Server Scope Endpoint WSO2 Identity Server Scope Endpoint - - contextConfigLocation - WEB-INF/beans.xml - - HttpHeaderSecurityFilter org.apache.catalina.filters.HttpHeaderSecurityFilter @@ -54,24 +49,28 @@ * - - - org.springframework.web.context.ContextLoaderListener - - - CXFServlet - org.apache.cxf.transport.servlet.CXFServlet + org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet 1 + + + jaxrs.serviceClasses + + org.wso2.carbon.identity.oauth.scope.endpoint.ScopesApi + + + + jaxrs.providers + + com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider, + org.wso2.carbon.identity.oauth.scope.endpoint.expmapper.JsonProcessingExceptionMapper + + - - CXFServlet - /* - 60 diff --git a/components/org.wso2.carbon.identity.oauth.stub/pom.xml b/components/org.wso2.carbon.identity.oauth.stub/pom.xml index 0198c6042e5..7943761922e 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.191-SNAPSHOT + 7.0.214-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 1f8c092994b..61a2531ecfd 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.191-SNAPSHOT + 7.0.214-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 e161c0c21f5..fe95751cb7b 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0 @@ -176,10 +176,6 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.application.common - - org.wso2.carbon.identity.framework - org.wso2.carbon.identity.entitlement - @@ -421,7 +417,8 @@ 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.entitlement; version="${carbon.identity.framework.imp.pkg.version.range}"; resolution:=optional, + org.wso2.carbon.identity.entitlement; + version="${identity.oauth.xacml.version.range}"; resolution:=optional, org.wso2.carbon.idp.mgt; version="${carbon.identity.framework.imp.pkg.version.range}", org.wso2.carbon.identity.base; version="${carbon.identity.framework.imp.pkg.version.range}", org.wso2.carbon.identity.core.*; version="${carbon.identity.framework.imp.pkg.version.range}", diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminService.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminService.java index a21135cb428..369ab4f6fd8 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminService.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminService.java @@ -88,6 +88,24 @@ public OAuthConsumerAppDTO getOAuthApplicationData(String consumerKey) throws Id } } + /** + * Get OAuth application data by the consumer key and tenant domain. + * + * @param consumerKey Consumer Key. + * @param tenantDomain Tenant Domain. + * @return OAuthConsumerAppDTO with application information. + * @throws IdentityOAuthAdminException Error when reading application information from persistence store. + */ + public OAuthConsumerAppDTO getOAuthApplicationData(String consumerKey, String tenantDomain) + throws IdentityOAuthAdminException { + + try { + return oAuthAdminServiceImpl.getOAuthApplicationData(consumerKey, tenantDomain); + } catch (IdentityOAuthAdminException ex) { + throw handleError(ex); + } + } + /** * Get OAuth application data by the application name. * diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java index 2e3c6414c72..739ee3aa55e 100755 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java @@ -800,7 +800,7 @@ void updateConsumerApplication(OAuthConsumerAppDTO consumerAppDTO, boolean enabl throw handleClientError(INVALID_REQUEST, errorMessage); } - String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getAppTenantDomain(); OAuthAppDAO dao = new OAuthAppDAO(); OAuthAppDO oAuthAppDO; @@ -2391,7 +2391,7 @@ AuthenticatedUser getAppOwner(OAuthConsumerAppDTO application, try { // Since the app owner sent in OAuthConsumerAppDTO is a valid one we set the appOwner to be // the one sent in the OAuthConsumerAppDTO. - String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String tenantDomain = getAppTenantDomain(); Optional maybeAppOwner = OAuthUtil.getUser(tenantDomain, tenantAwareAppOwnerInRequest); if (maybeAppOwner.isPresent()) { appOwner = new AuthenticatedUser(maybeAppOwner.get()); @@ -2925,4 +2925,21 @@ private boolean isAccessTokenClaimsSeparationEnabledForApp(String consumerKey, S return OAuth2Util.isAppVersionAllowed(serviceProvider.getApplicationVersion(), ApplicationConstants.ApplicationVersion.APP_VERSION_V2); } + + private static String getAppTenantDomain() throws IdentityOAuthAdminException { + + String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw handleError("Error while resolving tenant domain from the organization id: " + + applicationResidentOrgId, e); + } + } + return tenantDomain; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthUtil.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthUtil.java index 4cf88072dcf..29986ed26a4 100755 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthUtil.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthUtil.java @@ -31,9 +31,10 @@ import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; import org.wso2.carbon.identity.application.common.model.IdentityProvider; +import org.wso2.carbon.identity.application.common.model.InboundAuthenticationRequestConfig; import org.wso2.carbon.identity.application.common.model.ServiceProvider; import org.wso2.carbon.identity.application.common.model.User; -import org.wso2.carbon.identity.application.mgt.ApplicationConstants; +import org.wso2.carbon.identity.application.mgt.ApplicationConstants.StandardInboundProtocols; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.base.IdentityConstants; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; @@ -66,8 +67,7 @@ import org.wso2.carbon.identity.role.v2.mgt.core.RoleConstants; import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService; import org.wso2.carbon.identity.role.v2.mgt.core.exception.IdentityRoleManagementException; -import org.wso2.carbon.identity.role.v2.mgt.core.model.AssociatedApplication; -import org.wso2.carbon.identity.role.v2.mgt.core.model.Role; +import org.wso2.carbon.identity.role.v2.mgt.core.model.RoleBasicInfo; import org.wso2.carbon.idp.mgt.IdentityProviderManagementException; import org.wso2.carbon.user.api.Tenant; import org.wso2.carbon.user.core.UserStoreException; @@ -86,7 +86,6 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -716,7 +715,7 @@ private static AuthenticatedUser buildAuthenticatedUser(UserStoreManager userSto AuthenticatedUser authenticatedUser = new AuthenticatedUser(); authenticatedUser.setUserStoreDomain(userStoreDomain); authenticatedUser.setTenantDomain(tenantDomain); - authenticatedUser.setUserName(username); + authenticatedUser.setUserName(UserCoreUtil.removeDomainFromName(username)); boolean isOrganization; try { isOrganization = OrganizationManagementUtil.isOrganization(tenantDomain); @@ -775,51 +774,43 @@ private static AuthenticatedUser buildAuthenticatedUser(UserStoreManager userSto /** * Get clientIds of associated application of an application role. - * @param role Role object. + * + * @param role Role basic info object. * @param authenticatedUser Authenticated user. * @return Set of clientIds of associated applications. */ - private static Set getClientIdsOfAssociatedApplications(Role role, AuthenticatedUser authenticatedUser) + private static Optional getClientIdOfAssociatedApplication(RoleBasicInfo role, + AuthenticatedUser authenticatedUser) throws UserStoreException { ApplicationManagementService applicationManagementService = OAuthComponentServiceHolder.getInstance().getApplicationManagementService(); - List associatedApplications = role.getAssociatedApplications().stream() - .map(AssociatedApplication::getId).collect(Collectors.toList()); + String associatedApplication = role.getAudienceId(); try { if (authenticatedUser.getUserResidentOrganization() != null) { - List newAssociatedApplications = new ArrayList<>(); - for (String app : associatedApplications) { - newAssociatedApplications.add( - SharedAppResolveDAO.getMainApplication(app, authenticatedUser.getAccessingOrganization())); - } - associatedApplications = newAssociatedApplications; + associatedApplication = SharedAppResolveDAO.getMainApplication( + associatedApplication, authenticatedUser.getAccessingOrganization()); } } catch (IdentityOAuth2Exception e) { throw new UserStoreException("Error occurred while getting the main applications of the shared apps.", e); } - Set clientIds = new HashSet<>(); - associatedApplications.forEach(associatedApplication -> { - try { - ServiceProvider application = applicationManagementService - .getApplicationByResourceId(associatedApplication, authenticatedUser.getTenantDomain()); - if (application == null || application.getInboundAuthenticationConfig() == null) { - return; - } - Arrays.stream(application.getInboundAuthenticationConfig().getInboundAuthenticationRequestConfigs()) - .forEach(inboundAuthenticationRequestConfig -> { - if (ApplicationConstants.StandardInboundProtocols.OAUTH2.equals( - inboundAuthenticationRequestConfig.getInboundAuthType())) { - clientIds.add(inboundAuthenticationRequestConfig.getInboundAuthKey()); - } - }); - } catch (IdentityApplicationManagementException e) { - String errorMessage = "Error occurred while retrieving application of id : " + - associatedApplication; - LOG.error(errorMessage); + try { + ServiceProvider application = applicationManagementService + .getApplicationByResourceId(associatedApplication, authenticatedUser.getTenantDomain()); + if (application != null && application.getInboundAuthenticationConfig() != null) { + InboundAuthenticationRequestConfig[] inboundAuthenticationRequestConfigs = + application.getInboundAuthenticationConfig().getInboundAuthenticationRequestConfigs(); + return Arrays.stream(inboundAuthenticationRequestConfigs) + .filter(config -> StandardInboundProtocols.OAUTH2.equals(config.getInboundAuthType())) + .map(InboundAuthenticationRequestConfig::getInboundAuthKey) + .findFirst(); } - }); - return clientIds; + } catch (IdentityApplicationManagementException e) { + String errorMessage = "Error occurred while retrieving application of id : " + + associatedApplication; + LOG.error(errorMessage); + } + return Optional.empty(); } private static Set filterClientIdsWithOrganizationAudience(List clientIds, String tenantDomain) { @@ -849,14 +840,14 @@ private static Set filterClientIdsWithOrganizationAudience(List * @param tenantDomain Tenant domain. * @return Role. */ - private static Role getRole(String roleId, String tenantDomain) throws UserStoreException { + private static RoleBasicInfo getRoleBasicInfo(String roleId, String tenantDomain) throws UserStoreException { try { RoleManagementService roleV2ManagementService = OAuthComponentServiceHolder.getInstance().getRoleV2ManagementService(); - return roleV2ManagementService.getRole(roleId, tenantDomain); + return roleV2ManagementService.getRoleBasicInfoById(roleId, tenantDomain); } catch (IdentityRoleManagementException e) { - String errorMessage = "Error occurred while retrieving role of id : " + roleId; + String errorMessage = "Error occurred while retrieving basic role info of id : " + roleId; throw new UserStoreException(errorMessage, e); } } @@ -1011,18 +1002,19 @@ public static boolean revokeTokens(String username, UserStoreManager userStoreMa } // Get details about the role to identify the audience and associated applications. - Set clientIds = null; - Role role = null; + Set clientIds = new HashSet<>();; + RoleBasicInfo role = null; boolean getClientIdsFromUser = false; if (roleId != null) { - role = getRole(roleId, IdentityTenantUtil.getTenantDomain(userStoreManager.getTenantId())); + role = getRoleBasicInfo(roleId, tenantDomain); if (role != null && RoleConstants.APPLICATION.equals(role.getAudience())) { // Get clientIds of associated applications for the specific application role. if (LOG.isDebugEnabled()) { LOG.debug("Get clientIds of associated applications for the application role: " + role.getName()); } - clientIds = getClientIdsOfAssociatedApplications(role, authenticatedUser); + getClientIdOfAssociatedApplication(role, authenticatedUser) + .ifPresent(clientIds::add); } else { // Get all the distinct client Ids authorized by this user since this is an organization role. if (LOG.isDebugEnabled()) { diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCache.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCache.java index 89164caa086..019ac1d81f3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCache.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCache.java @@ -18,6 +18,8 @@ package org.wso2.carbon.identity.oauth.cache; +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTParser; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; @@ -29,10 +31,10 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; -import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.utils.CarbonUtils; +import java.text.ParseException; import java.util.concurrent.TimeUnit; /** @@ -237,11 +239,22 @@ private String replaceFromCodeId(String authzCode) { * @return TOKEN_ID from the database */ private String replaceFromTokenId(String keyValue) { - try { - AccessTokenDO accessTokenDO = OAuth2Util.findAccessToken(keyValue, true); - if (accessTokenDO != null) { - return accessTokenDO.getTokenId(); + if (OAuth2Util.isJWT(keyValue)) { + try { + JWT parsedJwtToken = JWTParser.parse(keyValue); + keyValue = parsedJwtToken.getJWTClaimsSet().getJWTID(); + } catch (ParseException e) { + if (log.isDebugEnabled()) { + if (IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.ACCESS_TOKEN)) { + log.debug("Error while getting JWTID from token: " + keyValue, e); + } else { + log.debug("Error while getting JWTID from token"); + } + } } + } + try { + return OAuthTokenPersistenceFactory.getInstance().getAccessTokenDAO().getTokenIdByAccessToken(keyValue); } catch (IdentityOAuth2Exception e) { log.error("Failed to retrieve token id by token from store for - ." + keyValue, e); } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCacheEntry.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCacheEntry.java index 41e81160253..a0cc0d474c7 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCacheEntry.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCacheEntry.java @@ -66,6 +66,8 @@ public class AuthorizationGrantCacheEntry extends CacheEntry { private boolean hasNonOIDCClaims; + private Map mappedRemoteClaims; + /* OIDC sub claim. This should be formatted based on the Service Provider configurations to append userStoreDomain and tenantDomain. @@ -390,4 +392,15 @@ public void setPreIssueAccessTokenActionsExecuted(boolean preIssueAccessTokenAct isPreIssueAccessTokenActionsExecuted = preIssueAccessTokenActionsExecuted; } + + public Map getMappedRemoteClaims() { + + return mappedRemoteClaims; + } + + public void setMappedRemoteClaims( + Map mappedRemoteClaims) { + + this.mappedRemoteClaims = mappedRemoteClaims; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/SessionDataCacheEntry.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/SessionDataCacheEntry.java index b2febaedfb5..59d07dc961e 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/SessionDataCacheEntry.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/cache/SessionDataCacheEntry.java @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.oauth.cache; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.ClaimMapping; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.model.FederatedTokenDO; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; @@ -53,6 +54,7 @@ public class SessionDataCacheEntry extends CacheEntry { private Map endpointParams = new HashMap<>(); private List federatedTokens; + private Map mappedRemoteClaims; public OAuthAuthzReqMessageContext getAuthzReqMsgCtx() { return authzReqMsgCtx; @@ -172,4 +174,14 @@ public void setFederatedTokens(List federatedTokens) { this.federatedTokens = federatedTokens; } + + public Map getMappedRemoteClaims() { + + return mappedRemoteClaims; + } + + public void setMappedRemoteClaims(Map mappedRemoteClaims) { + + this.mappedRemoteClaims = mappedRemoteClaims; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java index 0cd470c03c2..6ccffbb41ee 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/config/OAuthServerConfiguration.java @@ -232,6 +232,7 @@ public class OAuthServerConfiguration { private String defaultIdTokenEncryptionMethod = "A128GCM"; private List supportedIdTokenEncryptionMethods = new ArrayList<>(); private String userInfoJWTSignatureAlgorithm = "SHA256withRSA"; + private boolean userInfoMultiValueSupportEnabled = true; private String authContextTTL = "15L"; // property added to fix IDENTITY-4551 in backward compatible manner private boolean useMultiValueSeparatorForAuthContextToken = true; @@ -1564,6 +1565,16 @@ public String getUserInfoJWTSignatureAlgorithm() { return userInfoJWTSignatureAlgorithm; } + /** + * Returns whether multi value support is enabled for userinfo response. + * + * @return True if multi value support is enabled for userinfo response. + */ + public boolean getUserInfoMultiValueSupportEnabled() { + + return userInfoMultiValueSupportEnabled; + } + public String getConsumerDialectURI() { return consumerDialectURI; } @@ -3486,6 +3497,12 @@ private void parseOpenIDConnectConfig(OMElement oauthConfigElem) { getQNameWithIdentityNS(ConfigElements.OPENID_CONNECT_USERINFO_JWT_SIGNATURE_ALGORITHM)) .getText().trim(); } + OMElement userInfoMultiValueSupportEnabledElem = openIDConnectConfigElem.getFirstChildWithName( + getQNameWithIdentityNS(ConfigElements.OPENID_CONNECT_USERINFO_MULTI_VALUE_SUPPORT_ENABLED)); + if (userInfoMultiValueSupportEnabledElem != null) { + userInfoMultiValueSupportEnabled = Boolean.parseBoolean( + userInfoMultiValueSupportEnabledElem.getText().trim()); + } if (openIDConnectConfigElem.getFirstChildWithName( getQNameWithIdentityNS(ConfigElements.OPENID_CONNECT_SIGN_JWT_WITH_SP_KEY)) != null) { isJWTSignedWithSPKey = Boolean.parseBoolean(openIDConnectConfigElem.getFirstChildWithName( @@ -4113,6 +4130,8 @@ private class ConfigElements { public static final String OPENID_CONNECT_USERINFO_ENDPOINT_RESPONSE_BUILDER = "UserInfoEndpointResponseBuilder"; public static final String OPENID_CONNECT_USERINFO_JWT_SIGNATURE_ALGORITHM = "UserInfoJWTSignatureAlgorithm"; + public static final String OPENID_CONNECT_USERINFO_MULTI_VALUE_SUPPORT_ENABLED = + "UserInfoMultiValueSupportEnabled"; public static final String OPENID_CONNECT_SIGN_JWT_WITH_SP_KEY = "SignJWTWithSPKey"; public static final String OPENID_CONNECT_IDTOKEN_CUSTOM_CLAIM_CALLBACK_HANDLER = "IDTokenCustomClaimsCallBackHandler"; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAO.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAO.java index 0044ac7cecc..43656059ba3 100755 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAO.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAO.java @@ -157,6 +157,16 @@ public void addOAuthApplication(OAuthAppDO consumerAppDO) throws IdentityOAuthAd AuthenticatedUser appOwner = consumerAppDO.getAppOwner(); String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + } catch (OrganizationManagementException e) { + throw handleError("Error occurred while resolving tenant domain for organization id: " + + appOrgId, e); + } + } int spTenantId = IdentityTenantUtil.getTenantId(tenantDomain); String userStoreDomain = appOwner.getUserStoreDomain(); if (!isDuplicateApplication(appOwner.getUserName(), spTenantId, userStoreDomain, consumerAppDO)) { @@ -212,6 +222,7 @@ public void addOAuthApplication(OAuthAppDO consumerAppDO) throws IdentityOAuthAd } appId = getAppIdByClientId(connection, consumerAppDO.getOauthConsumerKey()); } + consumerAppDO.setId(appId); addScopeValidators(connection, appId, consumerAppDO.getScopeValidators()); addAccessTokenClaims(connection, appId, consumerAppDO.getAccessTokenClaims()); // Handle OIDC Related Properties. These are persisted in IDN_OIDC_PROPERTY table. @@ -686,6 +697,18 @@ public OAuthAppDO getAppInformationByAppName(String appName, int tenantID) OAuthAppDO oauthApp; try (Connection connection = IdentityDatabaseUtil.getDBConnection(false)) { + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + String tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + tenantID = IdentityTenantUtil.getTenantId(tenantDomain); + } catch (OrganizationManagementException e) { + throw new IdentityOAuth2Exception("Error occurred while resolving tenant domain for " + + "organization id: " + appOrgId, e); + } + } String sqlQuery = SQLQueries.OAuthAppDAOSQLQueries.GET_APP_INFO_BY_APP_NAME_WITH_PKCE; try (PreparedStatement prepStmt = connection.prepareStatement(sqlQuery)) { @@ -877,6 +900,18 @@ private void setValuesToStatementWithPKCEAndOwnerUpdate(OAuthAppDO oauthAppDO, P prepStmt.setString(11, oauthAppDO.getAppOwner().getUserStoreDomain()); prepStmt.setString(12, persistenceProcessor.getProcessedClientId(oauthAppDO.getOauthConsumerKey())); prepStmt.setInt(13, IdentityTenantUtil.getLoginTenantId()); + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + String tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + prepStmt.setInt(13, IdentityTenantUtil.getTenantId(tenantDomain)); + } catch (OrganizationManagementException e) { + throw new IdentityOAuth2Exception("Error occurred while resolving tenant domain for " + + "organization id: " + appOrgId, e); + } + } } private void setValuesToStatementWithPKCENoOwnerUpdate(OAuthAppDO oauthAppDO, PreparedStatement prepStmt) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/listener/IdentityOauthEventHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/listener/IdentityOauthEventHandler.java index f563449abd3..a9f31ca9f2a 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/listener/IdentityOauthEventHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/listener/IdentityOauthEventHandler.java @@ -490,23 +490,24 @@ private void terminateSession(List userIDList, String roleId, String ten throws IdentityEventException { try { - int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); - UserStoreManager userStoreManager = getUserStoreManager(tenantId); - - String userName; if (CollectionUtils.isNotEmpty(userIDList)) { + int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); + UserStoreManager userStoreManager = getUserStoreManager(tenantId); + for (String userId : userIDList) { try { - userName = FrameworkUtils.resolveUserNameFromUserId(userStoreManager, userId); + String userName = FrameworkUtils.resolveUserNameFromUserId(userStoreManager, userId); if (userName == null) { log.warn("User name is null for user id: " + userId + ". Hence skipping " + "token revocation and session termination processes."); continue; } + UserStoreManager userStoreManagerOfUser = getUserStoreManagerOfUser( + userStoreManager, userName); OAuth2ServiceComponentHolder.getInstance() .getRevocationProcessor() - .revokeTokens(userName, userStoreManager, roleId); - OAuthUtil.removeUserClaimsFromCache(userName, userStoreManager); + .revokeTokens(userName, userStoreManagerOfUser, roleId); + OAuthUtil.removeUserClaimsFromCache(userName, userStoreManagerOfUser); } catch (UserSessionException e) { String errorMsg = "Error occurred while revoking access token for user Id: " + userId; log.error(errorMsg, e); @@ -520,4 +521,22 @@ private void terminateSession(List userIDList, String roleId, String ten throw new IdentityEventException(errorMsg, e); } } + + /** + * Get the user store manager of the user. + * + * @param userStoreManager User store manager. + * @param userName Username of the user. + * @return User store manager of the user. + */ + private UserStoreManager getUserStoreManagerOfUser(UserStoreManager userStoreManager, String userName) { + + String userStoreDomainOfUser = IdentityUtil.extractDomainFromName(userName); + UserStoreManager secondaryUserStoreManager = userStoreManager.getSecondaryUserStoreManager( + userStoreDomainOfUser); + if (secondaryUserStoreManager == null) { + return userStoreManager; + } + return secondaryUserStoreManager; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Constants.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Constants.java index 1a72ef869f3..b170f205d5f 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Constants.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/OAuth2Constants.java @@ -34,6 +34,16 @@ public static class TokenBinderType { public static final String CLIENT_REQUEST = "client-request"; } + + /** + * Constants for token types. + */ + public static class TokenTypes { + + public static final String OPAQUE = "Opaque"; + public static final String JWT = "jwt"; + } + public static final String GROUPS = "groups"; public static final String ENTITY_ID = "entity_id"; public static final String IS_CONSENTED = "is_consented"; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandler.java index c2563ab165a..55523e995b8 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandler.java @@ -554,6 +554,11 @@ private void addUserAttributesToCache(String accessToken, authorizationGrantCacheEntry.setMaxAge(authorizeReqDTO.getMaxAge()); } + if (authorizeReqDTO.getMappedRemoteClaims() != null) { + authorizationGrantCacheEntry.setMappedRemoteClaims( + authorizeReqDTO.getMappedRemoteClaims()); + } + ClaimMapping key = new ClaimMapping(); Claim claimOfKey = new Claim(); claimOfKey.setClaimUri(OAuth2Util.SUB); 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 d124e392b62..08696c48c9d 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 @@ -487,6 +487,11 @@ private static void addUserAttributesToCache(String accessToken, OAuthAuthzReqMe userAttributes.put(key, sub); } + if (authorizeReqDTO.getMappedRemoteClaims() != null) { + authorizationGrantCacheEntry.setMappedRemoteClaims( + authorizeReqDTO.getMappedRemoteClaims()); + } + authorizationGrantCacheEntry .setValidityPeriod(TimeUnit.MILLISECONDS.toNanos(accessTokenDO.getValidityPeriodInMillis())); AuthorizationGrantCache.getInstance().addToCacheByToken(authorizationGrantCacheKey, diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/OldTokensCleanDAO.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/OldTokensCleanDAO.java index 719d932b758..3560806df09 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/OldTokensCleanDAO.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/OldTokensCleanDAO.java @@ -18,11 +18,13 @@ package org.wso2.carbon.identity.oauth2.dao; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.OldAccessTokenDO; +import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinding; import java.sql.Connection; import java.sql.PreparedStatement; @@ -31,6 +33,8 @@ import java.sql.Timestamp; import java.util.List; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenBindings.NONE; + /** * This is DAO class for cleaning old Tokens. When new tokens is generated ,refreshed or revoked old access token * will be moved to Audit table and deleted from the Access token table. Token cleaning process can be enable or @@ -98,8 +102,22 @@ public void cleanupTokenByTokenValue(String token, Connection connection) throws oldAccessTokenObject.setSubjectIdentifier(resultSet.getString(17)); oldAccessTokenObject.setAccessTokenHash(resultSet.getString(18)); oldAccessTokenObject.setRefreshTokenHash(resultSet.getString(19)); + String tokenBindingRef = resultSet.getString(20); + if (StringUtils.isNotBlank(tokenBindingRef)) { + TokenBinding tokenBinding = new TokenBinding(); + tokenBinding.setBindingReference(tokenBindingRef); + oldAccessTokenObject.setTokenBinding(tokenBinding); + } + + String isConsentedToken = resultSet.getString(21); + if (StringUtils.isNotEmpty(isConsentedToken)) { + oldAccessTokenObject.setIsConsentedToken(Boolean.parseBoolean(isConsentedToken)); + } + + oldAccessTokenObject.setAuthorizedOrganizationId(resultSet.getString(22)); + if (OAuth2ServiceComponentHolder.isIDPIdColumnEnabled()) { - oldAccessTokenObject.setIdpId(resultSet.getInt(20)); + oldAccessTokenObject.setIdpId(resultSet.getInt(23)); } } if (OAuthServerConfiguration.getInstance().useRetainOldAccessTokens()) { @@ -138,8 +156,16 @@ private void saveTokenInAuditTable(OldAccessTokenDO oldAccessTokenDAO, Connectio insertintoaudittable.setString(18, oldAccessTokenDAO.getAccessTokenHash()); insertintoaudittable.setString(19, oldAccessTokenDAO.getRefreshTokenHash()); insertintoaudittable.setTimestamp(20, new Timestamp(System.currentTimeMillis())); + if (oldAccessTokenDAO.getTokenBinding() != null && StringUtils + .isNotBlank(oldAccessTokenDAO.getTokenBinding().getBindingReference())) { + insertintoaudittable.setString(21, oldAccessTokenDAO.getTokenBinding().getBindingReference()); + } else { + insertintoaudittable.setString(21, NONE); + } + insertintoaudittable.setString(22, Boolean.toString(oldAccessTokenDAO.isConsentedToken())); + insertintoaudittable.setString(23, oldAccessTokenDAO.getAuthorizedOrganizationId()); if (OAuth2ServiceComponentHolder.isIDPIdColumnEnabled()) { - insertintoaudittable.setInt(21, oldAccessTokenDAO.getIdpId()); + insertintoaudittable.setInt(24, oldAccessTokenDAO.getIdpId()); } insertintoaudittable.execute(); if (log.isDebugEnabled()) { diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/SQLQueries.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/SQLQueries.java index 8abccfe10fd..c03994c6947 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/SQLQueries.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/dao/SQLQueries.java @@ -878,13 +878,15 @@ public class SQLQueries { public static final String RETRIEVE_OLD_TOKEN_BY_TOKEN_HASH = "SELECT TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, " + "CONSUMER_KEY_ID, AUTHZ_USER, TENANT_ID, USER_DOMAIN, USER_TYPE, GRANT_TYPE, TIME_CREATED, " + "REFRESH_TOKEN_TIME_CREATED, VALIDITY_PERIOD, REFRESH_TOKEN_VALIDITY_PERIOD, TOKEN_SCOPE_HASH, " + - "TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, REFRESH_TOKEN_HASH " + + "TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, REFRESH_TOKEN_HASH, " + + "TOKEN_BINDING_REF, CONSENTED_TOKEN, AUTHORIZED_ORGANIZATION " + "FROM IDN_OAUTH2_ACCESS_TOKEN WHERE ACCESS_TOKEN_HASH = ?"; public static final String RETRIEVE_OLD_TOKEN_BY_TOKEN_HASH_WITH_IDP_NAME = "SELECT TOKEN_ID, ACCESS_TOKEN, " + "REFRESH_TOKEN, CONSUMER_KEY_ID, AUTHZ_USER, TENANT_ID, USER_DOMAIN, USER_TYPE, GRANT_TYPE, TIME_CREATED," + " REFRESH_TOKEN_TIME_CREATED, VALIDITY_PERIOD, REFRESH_TOKEN_VALIDITY_PERIOD, TOKEN_SCOPE_HASH, " + - "TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, REFRESH_TOKEN_HASH, IDP_ID FROM " + + "TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, REFRESH_TOKEN_HASH, " + + "TOKEN_BINDING_REF, CONSENTED_TOKEN, AUTHORIZED_ORGANIZATION, IDP_ID FROM " + "IDN_OAUTH2_ACCESS_TOKEN WHERE ACCESS_TOKEN_HASH = ?"; public static final String INSERT_OAUTH2_ACCESS_TOKEN = "INSERT INTO IDN_OAUTH2_ACCESS_TOKEN (ACCESS_TOKEN, " + @@ -932,33 +934,39 @@ public class SQLQueries { "(TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, CONSUMER_KEY_ID, AUTHZ_USER, TENANT_ID, USER_DOMAIN, USER_TYPE, " + "GRANT_TYPE, TIME_CREATED, REFRESH_TOKEN_TIME_CREATED, VALIDITY_PERIOD, REFRESH_TOKEN_VALIDITY_PERIOD, " + "TOKEN_SCOPE_HASH, TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, " + - "REFRESH_TOKEN_HASH, INVALIDATED_TIME) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + "REFRESH_TOKEN_HASH, INVALIDATED_TIME, TOKEN_BINDING_REF, CONSENTED_TOKEN, AUTHORIZED_ORGANIZATION) " + + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; public static final String STORE_OLD_TOKEN_IN_AUDIT_WITH_IDP_NAME = "INSERT INTO IDN_OAUTH2_ACCESS_TOKEN_AUDIT " + "(TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, CONSUMER_KEY_ID, AUTHZ_USER, TENANT_ID, USER_DOMAIN, USER_TYPE, " + "GRANT_TYPE, TIME_CREATED, REFRESH_TOKEN_TIME_CREATED, VALIDITY_PERIOD, REFRESH_TOKEN_VALIDITY_PERIOD, " + "TOKEN_SCOPE_HASH, TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, " + - "REFRESH_TOKEN_HASH, INVALIDATED_TIME, IDP_ID) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + "REFRESH_TOKEN_HASH, INVALIDATED_TIME, TOKEN_BINDING_REF, CONSENTED_TOKEN, AUTHORIZED_ORGANIZATION, " + + "IDP_ID) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; public static final String RETRIEVE_AND_STORE_IN_AUDIT = "INSERT INTO IDN_OAUTH2_ACCESS_TOKEN_AUDIT (TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, CONSUMER_KEY_ID, " + "AUTHZ_USER, TENANT_ID, USER_DOMAIN, USER_TYPE, GRANT_TYPE, TIME_CREATED, " + "REFRESH_TOKEN_TIME_CREATED, VALIDITY_PERIOD, REFRESH_TOKEN_VALIDITY_PERIOD, " + "TOKEN_SCOPE_HASH, TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, " + - "REFRESH_TOKEN_HASH, INVALIDATED_TIME) SELECT TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, " + + "REFRESH_TOKEN_HASH, INVALIDATED_TIME, TOKEN_BINDING_REF, CONSENTED_TOKEN, " + + "AUTHORIZED_ORGANIZATION) SELECT TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, " + "CONSUMER_KEY_ID, AUTHZ_USER, TENANT_ID, USER_DOMAIN, USER_TYPE, GRANT_TYPE, TIME_CREATED, " + "REFRESH_TOKEN_TIME_CREATED, VALIDITY_PERIOD, REFRESH_TOKEN_VALIDITY_PERIOD, TOKEN_SCOPE_HASH, " + - "TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, REFRESH_TOKEN_HASH, ? " + + "TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, REFRESH_TOKEN_HASH, ?, " + + "TOKEN_BINDING_REF, CONSENTED_TOKEN, AUTHORIZED_ORGANIZATION " + "FROM IDN_OAUTH2_ACCESS_TOKEN WHERE TOKEN_ID = ?"; public static final String RETRIEVE_AND_STORE_IN_AUDIT_WITH_IDP_NAME = "INSERT INTO IDN_OAUTH2_ACCESS_TOKEN_AUDIT" + " (TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, CONSUMER_KEY_ID, AUTHZ_USER, TENANT_ID, USER_DOMAIN, USER_TYPE," + " GRANT_TYPE, TIME_CREATED, REFRESH_TOKEN_TIME_CREATED, VALIDITY_PERIOD, REFRESH_TOKEN_VALIDITY_PERIOD, " + "TOKEN_SCOPE_HASH, TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, " + - "REFRESH_TOKEN_HASH, INVALIDATED_TIME, IDP_ID) SELECT TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, " + + "REFRESH_TOKEN_HASH, INVALIDATED_TIME, IDP_ID, TOKEN_BINDING_REF, CONSENTED_TOKEN, " + + "AUTHORIZED_ORGANIZATION) SELECT TOKEN_ID, ACCESS_TOKEN, REFRESH_TOKEN, " + "CONSUMER_KEY_ID, AUTHZ_USER, TENANT_ID, USER_DOMAIN, USER_TYPE, GRANT_TYPE, TIME_CREATED, " + "REFRESH_TOKEN_TIME_CREATED, VALIDITY_PERIOD, REFRESH_TOKEN_VALIDITY_PERIOD, TOKEN_SCOPE_HASH, " + - "TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, REFRESH_TOKEN_HASH, ?, IDP_ID " + + "TOKEN_STATE, TOKEN_STATE_ID, SUBJECT_IDENTIFIER, ACCESS_TOKEN_HASH, REFRESH_TOKEN_HASH, ?, IDP_ID, " + + "TOKEN_BINDING_REF, CONSENTED_TOKEN, AUTHORIZED_ORGANIZATION " + "FROM IDN_OAUTH2_ACCESS_TOKEN WHERE TOKEN_ID = ?"; public static final String DELETE_OLD_TOKEN_BY_ID = "DELETE FROM IDN_OAUTH2_ACCESS_TOKEN WHERE TOKEN_ID = ?"; diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/device/cache/DeviceAuthorizationGrantCacheEntry.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/device/cache/DeviceAuthorizationGrantCacheEntry.java index 9e6b022940e..3d77c42c7e4 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/device/cache/DeviceAuthorizationGrantCacheEntry.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/device/cache/DeviceAuthorizationGrantCacheEntry.java @@ -31,6 +31,7 @@ public class DeviceAuthorizationGrantCacheEntry extends CacheEntry { private static final long serialVersionUID = -3043225645166013281L; private Map userAttributes; + private Map mappedRemoteClaims; public DeviceAuthorizationGrantCacheEntry(Map userAttributes) { @@ -56,4 +57,15 @@ public void setUserAttributes(Map userAttributes) { this.userAttributes = userAttributes; } + + public Map getMappedRemoteClaims() { + + return mappedRemoteClaims; + } + + public void setMappedRemoteClaims( + Map mappedRemoteClaims) { + + this.mappedRemoteClaims = mappedRemoteClaims; + } } 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 e3db5c13814..94cc22c362c 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 @@ -19,10 +19,12 @@ package org.wso2.carbon.identity.oauth2.dto; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.ClaimMapping; import org.wso2.carbon.identity.oauth2.model.HttpRequestHeader; import org.wso2.carbon.identity.openidconnect.model.RequestObject; import java.util.LinkedHashSet; +import java.util.Map; import java.util.Properties; import javax.servlet.http.Cookie; @@ -61,6 +63,7 @@ public class OAuth2AuthorizeReqDTO { private boolean isRequestObjectFlow; private String state; private String requestedSubjectId; + private Map mappedRemoteClaims; public String getRequestedSubjectId() { @@ -303,4 +306,15 @@ public void setHttpServletRequestWrapper(HttpServletRequestWrapper httpServletRe this.httpServletRequestWrapper = httpServletRequestWrapper; } + + public Map getMappedRemoteClaims() { + + return mappedRemoteClaims; + } + + public void setMappedRemoteClaims( + Map mappedRemoteClaims) { + + this.mappedRemoteClaims = mappedRemoteClaims; + } } 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 16f539f4ec4..0158db681b1 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 @@ -621,7 +621,13 @@ private Optional getAuthzGrantCacheEntryFromDevice DeviceAuthorizationGrantCache.getInstance().getValueFromCache(deviceCodeCacheKey); if (cacheEntry != null) { Map userAttributes = cacheEntry.getUserAttributes(); - return Optional.of(new AuthorizationGrantCacheEntry(userAttributes)); + AuthorizationGrantCacheEntry authorizationGrantCacheEntry = + new AuthorizationGrantCacheEntry(userAttributes); + if (cacheEntry.getMappedRemoteClaims() != null) { + authorizationGrantCacheEntry.setMappedRemoteClaims(cacheEntry + .getMappedRemoteClaims()); + } + return Optional.of(authorizationGrantCacheEntry); } return Optional.empty(); } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/JWTTokenIssuer.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/JWTTokenIssuer.java index 6a80d030efb..72b81f1e694 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/JWTTokenIssuer.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/JWTTokenIssuer.java @@ -120,6 +120,12 @@ public JWTTokenIssuer() throws IdentityOAuth2Exception { signatureAlgorithm = mapSignatureAlgorithm(config.getSignatureAlgorithm()); } + @Override + public String getAccessTokenType() { + + return JWT_TYP_HEADER_VALUE; + } + /** * {@inheritDoc} */ diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/OauthTokenIssuer.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/OauthTokenIssuer.java index c6b4ee45162..04aa6c8ae96 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/OauthTokenIssuer.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/token/OauthTokenIssuer.java @@ -24,6 +24,8 @@ import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; +import static org.wso2.carbon.identity.oauth2.OAuth2Constants.TokenTypes.OPAQUE; + /** * OAuth 2 access token issuer. */ @@ -99,4 +101,14 @@ default boolean usePersistedAccessTokenAlias() { default String issueSubjectToken(OAuthAuthzReqMessageContext oauthAuthzMsgCtx) throws IdentityOAuth2Exception { return StringUtils.EMPTY; } + + /** + * Default method to retrieve the access token type + * + * @return The type of the token (e.g., "JWT" or "Opaque"). + */ + default String getAccessTokenType() { + + return OPAQUE; + } } 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 a667db09353..4a628f0bef3 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 @@ -81,10 +81,13 @@ import java.util.UUID; import java.util.function.Consumer; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OAUTH_APP; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.RENEW_TOKEN_WITHOUT_REVOKING_EXISTING_ENABLE_CONFIG; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenBindings.NONE; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.TokenStates.TOKEN_STATE_ACTIVE; import static org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration.JWT_TOKEN_TYPE; import static org.wso2.carbon.identity.oauth2.util.OAuth2Util.EXTENDED_REFRESH_TOKEN_DEFAULT_TIME; +import static org.wso2.carbon.identity.oauth2.util.OAuth2Util.JWT; /** * Abstract authorization grant handler. @@ -171,6 +174,29 @@ public OAuth2AccessTokenRespDTO issue(OAuthTokenReqMessageContext tokReqMsgCtx) synchronized ((consumerKey + ":" + authorizedUserId + ":" + scope + ":" + tokenBindingReference).intern()) { AccessTokenDO existingTokenBean = null; + + OAuthAppDO oAuthAppDO = (OAuthAppDO) tokReqMsgCtx.getProperty(OAUTH_APP); + String tokenType = oauthTokenIssuer.getAccessTokenType(); + + /* + Check if the token type is JWT and renew without revoking existing tokens is enabled. + Additionally, ensure that the grant type used for the token request is allowed to renew without revoke, + based on the config. + */ + if (JWT.equalsIgnoreCase(tokenType) && getRenewWithoutRevokingExistingStatus() && + OAuth2ServiceComponentHolder.getJwtRenewWithoutRevokeAllowedGrantTypes() + .contains(tokReqMsgCtx.getOauth2AccessTokenReqDTO().getGrantType())) { + /* + If the application does not have a token binding type (i.e., no specific binding type is set), + binding reference will be randomly generated UUID, in that case we can generate a new access token + without looking up the existing tokens in the token table. + */ + if (oAuthAppDO.getTokenBindingType() == null) { + return generateNewAccessToken(tokReqMsgCtx, scope, consumerKey, existingTokenBean, + false, oauthTokenIssuer); + } + } + if (isHashDisabled) { existingTokenBean = getExistingToken(tokReqMsgCtx, getOAuthCacheKey(scope, consumerKey, authorizedUserId, authenticatedIDP, @@ -706,6 +732,12 @@ private void updateCacheIfEnabled(AccessTokenDO newTokenBean, String scope, Oaut } } + private boolean getRenewWithoutRevokingExistingStatus() { + + return Boolean.parseBoolean(IdentityUtil. + getProperty(RENEW_TOKEN_WITHOUT_REVOKING_EXISTING_ENABLE_CONFIG)); + } + private String getNewAccessToken(OAuthTokenReqMessageContext tokReqMsgCtx, OauthTokenIssuer oauthTokenIssuer) throws IdentityOAuth2Exception { try { @@ -1137,7 +1169,8 @@ private boolean isTokenRenewalPerRequestConfigured() { return OAuthServerConfiguration.getInstance().isTokenRenewalPerRequestEnabled(); } - private void clearExistingTokenFromCache(OAuthTokenReqMessageContext tokenMsgCtx, AccessTokenDO existingTokenBean) { + private void clearExistingTokenFromCache(OAuthTokenReqMessageContext tokenMsgCtx, AccessTokenDO existingTokenBean) + throws IdentityOAuth2Exception { if (cacheEnabled) { String tokenBindingReference = getTokenBindingReference(tokenMsgCtx); @@ -1174,18 +1207,68 @@ private boolean hasValidationByApplicationScopeValidatorsFailed(OAuthTokenReqMes * @param tokReqMsgCtx OAuthTokenReqMessageContext. * @return token binding reference. */ - protected String getTokenBindingReference(OAuthTokenReqMessageContext tokReqMsgCtx) { + protected String getTokenBindingReference(OAuthTokenReqMessageContext tokReqMsgCtx) + throws IdentityOAuth2Exception { - if (tokReqMsgCtx.getTokenBinding() == null) { - if (log.isDebugEnabled()) { - log.debug("Token binding data is null."); + /** + * If OAuth.JWT.RenewTokenWithoutRevokingExisting is enabled from configurations, and current token + * binding is null,then we will add a new token binding (request binding) to the token binding with + * a value of a random UUID. + * The purpose of this new token binding type is to add a random value to the token binding so that + * "User, Application, Scope, Binding" combination will be unique for each token. + * Previously, if a token issue request come for the same combination of "User, Application, Scope, Binding", + * the existing JWT token will be revoked and issue a new token. but with this way, we can issue new tokens + * without revoking the old ones. + * + * Add following configuration to deployment.toml file to enable this feature. + * [oauth.jwt.renew_token_without_revoking_existing] + * enable = true + * + * By default, the allowed grant type for this feature is "client_credentials". If you need to enable for + * other grant types, add the following configuration to deployment.toml file. + * [oauth.jwt.renew_token_without_revoking_existing] + * enable = true + * allowed_grant_types = ["client_credentials","password", ...] + */ + String consumerKey = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId(); + OauthTokenIssuer oauthTokenIssuer; + + try { + oauthTokenIssuer = OAuth2Util.getOAuthTokenIssuerForOAuthApp(consumerKey); + } catch (InvalidOAuthClientException | IdentityOAuth2Exception e) { + throw new IdentityOAuth2Exception( + "Error while retrieving oauth issuer for the app with clientId: " + consumerKey, e); + } + + String tokenType = oauthTokenIssuer.getAccessTokenType(); + + if (JWT.equalsIgnoreCase(tokenType)) { + if (getRenewWithoutRevokingExistingStatus() + && tokReqMsgCtx != null && (tokReqMsgCtx.getTokenBinding() == null + || StringUtils.isBlank(tokReqMsgCtx.getTokenBinding().getBindingReference()))) { + if (OAuth2ServiceComponentHolder.getJwtRenewWithoutRevokeAllowedGrantTypes() + .contains(tokReqMsgCtx.getOauth2AccessTokenReqDTO().getGrantType())) { + return UUID.randomUUID().toString(); + } + return NONE; } - return NONE; } - if (StringUtils.isBlank(tokReqMsgCtx.getTokenBinding().getBindingReference())) { + return getExistingTokenBindingReference(tokReqMsgCtx); + } + + /** + * Retrieves the existing token binding reference if available, otherwise returns NONE. + * + * @param tokReqMsgCtx OAuthTokenReqMessageContext. + * @return token binding reference. + */ + private String getExistingTokenBindingReference(OAuthTokenReqMessageContext tokReqMsgCtx) { + + if (tokReqMsgCtx == null || tokReqMsgCtx.getTokenBinding() == null) { return NONE; } - return tokReqMsgCtx.getTokenBinding().getBindingReference(); + String bindingReference = tokReqMsgCtx.getTokenBinding().getBindingReference(); + return StringUtils.isBlank(bindingReference) ? NONE : bindingReference; } /** 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 0bf8bb7c047..bba40461009 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 @@ -29,6 +29,7 @@ import org.wso2.carbon.identity.application.authentication.framework.AuthenticatorFlowStatus; import org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationRequestCacheEntry; import org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationResultCacheEntry; +import org.wso2.carbon.identity.application.authentication.framework.config.builder.FileBasedConfigurationBuilder; import org.wso2.carbon.identity.application.authentication.framework.config.model.ApplicationConfig; import org.wso2.carbon.identity.application.authentication.framework.config.model.AuthenticatorConfig; import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig; @@ -89,7 +90,8 @@ import javax.servlet.http.HttpServletResponse; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ALLOW_SESSION_CREATION; - +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.BASIC_AUTHENTICATOR_CLASS; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.SHOW_AUTHFAILURE_RESON_CONFIG; /** * Handles the Password Grant Type of the OAuth 2.0 specification. Resource owner sends his @@ -334,6 +336,9 @@ private AuthenticatedUser validateUserCredentials(OAuth2AccessTokenReqDTO tokenR boolean isPublishPasswordGrantLoginEnabled = Boolean.parseBoolean( IdentityUtil.getProperty(PUBLISH_PASSWORD_GRANT_LOGIN)); + boolean isShowAuthFailureReason = Boolean.parseBoolean( + getBasicAuthenticatorConfigs().getParameterMap().get(SHOW_AUTHFAILURE_RESON_CONFIG)); + String genericErrorUserName = tokenReq.getResourceOwnerUsername(); try { // Get the user store preference order supplier. UserStorePreferenceOrderSupplier> userStorePreferenceOrderSupplier = @@ -365,6 +370,11 @@ private AuthenticatedUser validateUserCredentials(OAuth2AccessTokenReqDTO tokenR tokenReq.setResourceOwnerUsername(tenantAwareUserName + "@" + userTenantDomain); } + if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equalsIgnoreCase(MultitenantUtils.getTenantDomain + (tokenReq.getResourceOwnerUsername())) || IdentityTenantUtil.isTenantQualifiedUrlsEnabled()) { + genericErrorUserName = tenantAwareUserName; + } + AbstractUserStoreManager userStoreManager = getUserStoreManager(userTenantDomain); Optional authenticatedUser; ServiceProviderProperty[] spProps = serviceProvider.getSpProperties(); @@ -406,6 +416,7 @@ private AuthenticatedUser validateUserCredentials(OAuth2AccessTokenReqDTO tokenR if (StringUtils.isNotBlank(e.getErrorCode())) { message = e.getErrorCode() + " " + e.getMessage(); } + message = isShowAuthFailureReason ? message : "Authentication failed for " + genericErrorUserName; throw new IdentityOAuth2Exception(message, e); } catch (UserStoreException e) { if (isPublishPasswordGrantLoginEnabled) { @@ -429,6 +440,7 @@ private AuthenticatedUser validateUserCredentials(OAuth2AccessTokenReqDTO tokenR message = identityException.getErrorCode() + " " + e.getMessage(); } } + message = isShowAuthFailureReason ? message : "Authentication failed for " + genericErrorUserName; throw new IdentityOAuth2Exception(message, e); } catch (AuthenticationFailedException e) { String message = "Authentication failed for the user: " + tokenReq.getResourceOwnerUsername(); @@ -492,6 +504,16 @@ protected void publishAuthenticationData(OAuth2AccessTokenReqDTO tokenReq, boole } } + /** + * This method will return the basic authenticator configurations. + * + * @return AuthenticatorConfig - Basic authenticator configurations. + */ + private AuthenticatorConfig getBasicAuthenticatorConfigs() { + + return FileBasedConfigurationBuilder.getInstance().getAuthenticatorBean(BASIC_AUTHENTICATOR_CLASS); + } + /** * This method will create an AuthenticationContext object which needs to be passed to the publish methods. * diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java index 08982d55aa5..6503a0cd59c 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java @@ -2441,7 +2441,8 @@ public static OauthTokenIssuer getOAuthTokenIssuerForOAuthApp(String clientId) OAuthAppDO appDO; try { - appDO = getAppInformationByClientId(clientId); + String tenantDomain = getTenantDomain(); + appDO = getAppInformationByClientId(clientId, tenantDomain); } catch (IdentityOAuth2Exception e) { throw new IdentityOAuth2Exception("Error while retrieving app information for clientId: " + clientId, e); } @@ -2619,6 +2620,32 @@ public static String getTenantDomainOfOauthApp(String clientId) return getTenantDomainOfOauthApp(oAuthAppDO); } + /** + * This is used to get the tenant domain of an application by clientId. Internally it uses the tenant present in + * the carbon context. + * + * @param clientId Consumer key of Application. + * @return Tenant Domain. + * @throws IdentityOAuth2Exception Error while retrieving the application. + * @throws InvalidOAuthClientException If an application not found for the given client ID. + */ + public static String getTenantDomainOfOauthApp(String clientId, String tenantDomain) + throws IdentityOAuth2Exception, InvalidOAuthClientException { + + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(appOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + } catch (OrganizationManagementException e) { + throw new IdentityOAuth2Exception("Error while resolving tenant domain for the organization ID: " + + appOrgId, e); + } + } + OAuthAppDO oAuthAppDO = getAppInformationByClientId(clientId, tenantDomain); + return getTenantDomainOfOauthApp(oAuthAppDO); + } + /** * Get all the OAuth applications for the client ID. * @@ -3864,9 +3891,9 @@ public static ServiceProvider getServiceProvider(String clientId, public static ServiceProvider getServiceProvider(String clientId) throws IdentityOAuth2Exception { ApplicationManagementService applicationMgtService = OAuth2ServiceComponentHolder.getApplicationMgtService(); - String tenantDomain = null; + String tenantDomain = IdentityTenantUtil.getTenantDomain(IdentityTenantUtil.getLoginTenantId()); try { - tenantDomain = getTenantDomainOfOauthApp(clientId); + tenantDomain = getTenantDomainOfOauthApp(clientId, tenantDomain); // Get the Service Provider. return applicationMgtService.getServiceProviderByClientId( clientId, IdentityApplicationConstants.OAuth2.NAME, tenantDomain); @@ -4338,7 +4365,8 @@ public static String getIdTokenIssuer(String tenantDomain) throws IdentityOAuth2 public static String getIdTokenIssuer(String tenantDomain, boolean isMtlsRequest) throws IdentityOAuth2Exception { - if (IdentityTenantUtil.isTenantQualifiedUrlsEnabled()) { + if (IdentityTenantUtil.isTenantQualifiedUrlsEnabled() && StringUtils.isEmpty(PrivilegedCarbonContext. + getThreadLocalCarbonContext().getApplicationResidentOrganizationId())) { try { return isMtlsRequest ? OAuthURL.getOAuth2MTLSTokenEPUrl() : ServiceURLBuilder.create().addPath(OAUTH2_TOKEN_EP_URL).build().getAbsolutePublicURL(); @@ -4979,7 +5007,18 @@ public static void validateRequestTenantDomain(String tenantDomainOfApp) throws if (IdentityTenantUtil.isTenantQualifiedUrlsEnabled()) { - String tenantDomainFromContext = IdentityTenantUtil.resolveTenantDomain(); + String tenantDomainFromContext = getTenantDomain(); + String appOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext(). + getApplicationResidentOrganizationId(); + if (StringUtils.isNotBlank(appOrgId)) { + try { + tenantDomainFromContext = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(appOrgId); + } catch (OrganizationManagementException e) { + throw new InvalidOAuthClientException("Error while resolving tenant domain from organization id: " + + appOrgId, e); + } + } if (!StringUtils.equals(tenantDomainFromContext, tenantDomainOfApp)) { // This means the tenant domain sent in the request and app's tenant domain do not match. if (log.isDebugEnabled()) { @@ -5326,7 +5365,7 @@ public static boolean isFapiConformantApp(String clientId) if (!Boolean.parseBoolean(IdentityUtil.getProperty(OAuthConstants.ENABLE_FAPI))) { return false; } - String tenantDomain = IdentityTenantUtil.resolveTenantDomain(); + String tenantDomain = getTenantDomain(); OAuthAppDO oAuthAppDO = OAuth2Util.getAppInformationByClientId(clientId, tenantDomain); return oAuthAppDO.isFapiConformanceEnabled(); } @@ -5662,4 +5701,21 @@ public static boolean isAppVersionAllowed(String appVersion, String allowedAppVe } return true; } + + private static String getTenantDomain() throws InvalidOAuthClientException { + + String tenantDomain = IdentityTenantUtil.resolveTenantDomain(); + String applicationResidentOrgId = PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getApplicationResidentOrganizationId(); + if (StringUtils.isNotEmpty(applicationResidentOrgId)) { + try { + tenantDomain = OAuthComponentServiceHolder.getInstance().getOrganizationManager() + .resolveTenantDomain(applicationResidentOrgId); + } catch (OrganizationManagementException e) { + throw new InvalidOAuthClientException("Error while resolving tenant domain from the organization " + + "id: ", e); + } + } + return tenantDomain; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandler.java index ede19a67f64..dd2ecabfa41 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandler.java @@ -20,27 +20,46 @@ import com.nimbusds.jwt.JWTClaimsSet; import net.minidev.json.JSONArray; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.wso2.carbon.CarbonConstants; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; +import org.wso2.carbon.identity.application.common.model.ClaimMapping; import org.wso2.carbon.identity.application.common.model.ServiceProvider; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.base.IdentityConstants; import org.wso2.carbon.identity.base.IdentityException; import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataHandler; import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCache; +import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCacheEntry; +import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCacheKey; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthClientException; +import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; +import org.wso2.carbon.identity.oauth2.device.cache.DeviceAuthorizationGrantCache; +import org.wso2.carbon.identity.oauth2.device.cache.DeviceAuthorizationGrantCacheEntry; +import org.wso2.carbon.identity.oauth2.device.cache.DeviceAuthorizationGrantCacheKey; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; +import org.wso2.carbon.identity.oauth2.model.RefreshTokenValidationDataDO; +import org.wso2.carbon.identity.oauth2.token.AccessTokenIssuer; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuer; +import org.wso2.carbon.identity.oauth2.token.handlers.grant.RefreshGrantHandler; +import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.openidconnect.internal.OpenIDConnectServiceComponentHolder; import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; @@ -48,6 +67,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -55,8 +75,13 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import static org.apache.commons.collections.MapUtils.isEmpty; +import static org.apache.commons.collections.MapUtils.isNotEmpty; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.ACCESS_TOKEN; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.AUTHZ_CODE; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDCClaims.ADDRESS; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDCClaims.GROUPS; +import static org.wso2.carbon.identity.oauth2.device.constants.Constants.DEVICE_CODE; /** * A class that provides OIDC claims for JWT access tokens. @@ -66,76 +91,574 @@ public class JWTAccessTokenOIDCClaimsHandler implements CustomClaimsCallbackHand private static final Log log = LogFactory.getLog(JWTAccessTokenOIDCClaimsHandler.class); private static final String OAUTH2 = "oauth2"; + private static final String OIDC_DIALECT = "http://wso2.org/oidc/claim"; @Override public JWTClaimsSet handleCustomClaims(JWTClaimsSet.Builder builder, OAuthTokenReqMessageContext request) throws IdentityOAuth2Exception { - String clientId = request.getOauth2AccessTokenReqDTO().getClientId(); - String spTenantDomain = getServiceProviderTenantDomain(request); - AuthenticatedUser authenticatedUser = request.getAuthorizedUser(); - - Map claims = getAccessTokenUserClaims(authenticatedUser, clientId, spTenantDomain); - if (claims == null || claims.isEmpty()) { - return builder.build(); - } - Map filteredClaims = handleClaimsFormat(claims, clientId, spTenantDomain); - return setClaimsToJwtClaimSet(builder, filteredClaims); + Map claims = getUserClaimsInOIDCDialect(request); + return setClaimsToJwtClaimSet(builder, claims); } @Override public JWTClaimsSet handleCustomClaims(JWTClaimsSet.Builder builder, OAuthAuthzReqMessageContext request) throws IdentityOAuth2Exception { - // TODO : Implement this method for implicit flow and hybrid flow. - return builder.build(); + /* + Handling the user attributes for the access token. There is no requirement of the consent + to manage user attributes for the access token. + */ + Map claims = getUserClaimsInOIDCDialect(request); + return setClaimsToJwtClaimSet(builder, claims); } - private Map getAccessTokenUserClaims(AuthenticatedUser authenticatedUser, String clientId, - String spTenantDomain) + /** + * Get user claims in OIDC dialect. + * + * @param requestMsgCtx OAuthTokenReqMessageContext + * @return User claims in OIDC dialect + * @throws IdentityOAuth2Exception IdentityOAuth2Exception + */ + private Map getUserClaimsInOIDCDialect(OAuthTokenReqMessageContext requestMsgCtx) throws IdentityOAuth2Exception { + Map userClaimsInOIDCDialect; + + Map userAttributes = getCachedUserAttributes(requestMsgCtx, false); + if ((userAttributes.isEmpty() || isOrganizationSwitchGrantType(requestMsgCtx)) + && (isLocalUser(requestMsgCtx.getAuthorizedUser()) + || isOrganizationSsoUserSwitchingOrganization(requestMsgCtx.getAuthorizedUser()))) { + if (log.isDebugEnabled()) { + log.debug("User attributes not found in cache against the access token or authorization code. " + + "Retrieving claims for local user: " + requestMsgCtx.getAuthorizedUser() + " from userstore."); + } + if (!StringUtils.equals(requestMsgCtx.getAuthorizedUser().getUserResidentOrganization(), + requestMsgCtx.getAuthorizedUser().getAccessingOrganization()) && + !CarbonConstants.ENABLE_LEGACY_AUTHZ_RUNTIME && + StringUtils.isNotEmpty(AuthzUtil.getUserIdOfAssociatedUser(requestMsgCtx.getAuthorizedUser()))) { + requestMsgCtx.getAuthorizedUser().setSharedUserId(AuthzUtil.getUserIdOfAssociatedUser(requestMsgCtx + .getAuthorizedUser())); + requestMsgCtx.getAuthorizedUser().setUserSharedOrganizationId(requestMsgCtx.getAuthorizedUser() + .getAccessingOrganization()); + } + // Get claim in oidc dialect from user store. + userClaimsInOIDCDialect = retrieveClaimsForLocalUser(requestMsgCtx); + } else { + // Get claim map from the cached attributes + userClaimsInOIDCDialect = getOIDCClaimsFromUserAttributes(userAttributes, requestMsgCtx); + // Since this is a federated flow, we need to get the federated user attributes as well. + Map federatedUserAttributes = getCachedUserAttributes(requestMsgCtx, true); + Map federatedUserClaimsInOIDCDialect = + getOIDCClaimsFromFederatedUserAttributes(federatedUserAttributes, requestMsgCtx); + userClaimsInOIDCDialect.putAll(federatedUserClaimsInOIDCDialect); + } + + Object hasNonOIDCClaimsProperty = requestMsgCtx.getProperty(OIDCConstants.HAS_NON_OIDC_CLAIMS); + if (isPreserverClaimUrisInAssertion(requestMsgCtx) || (hasNonOIDCClaimsProperty != null + && (Boolean) hasNonOIDCClaimsProperty)) { + return userClaimsInOIDCDialect; + } else { + return filterClaims(userClaimsInOIDCDialect, requestMsgCtx); + } + } + + /** + * Filter claims with allowed access token claims + * + * @param userClaimsInOIDCDialect User claims in OIDC dialect + * @param requestMsgCtx OAuthTokenReqMessageContext + * @return Filtered claims + * @throws IdentityOAuth2Exception IdentityOAuth2Exception + */ + private Map filterClaims(Map userClaimsInOIDCDialect, + OAuthTokenReqMessageContext requestMsgCtx) throws IdentityOAuth2Exception { + + String spTenantDomain = getServiceProviderTenantDomain(requestMsgCtx); + String clientId = requestMsgCtx.getOauth2AccessTokenReqDTO().getClientId(); // Get allowed access token claims. List allowedClaims = getAccessTokenClaims(clientId, spTenantDomain); if (allowedClaims.isEmpty()) { return new HashMap<>(); } + Map claims = allowedClaims.stream() + .filter(userClaimsInOIDCDialect::containsKey) + .collect(Collectors.toMap(claim -> claim, userClaimsInOIDCDialect::get)); + return handleClaimsFormat(claims, clientId, spTenantDomain); + } - // Get OIDC to Local claim mappings. - Map oidcToLocalClaimMappings = getOIDCToLocalClaimMappings(spTenantDomain); - if (oidcToLocalClaimMappings.isEmpty()) { + /** + * Filter claims with allowed access token claims + * + * @param userClaimsInOIDCDialect User claims in OIDC dialect + * @param authzReqMessageContext OAuthAuthzReqMessageContext + * @return Filtered claims + * @throws IdentityOAuth2Exception IdentityOAuth2Exception + */ + private Map filterClaims(Map userClaimsInOIDCDialect, + OAuthAuthzReqMessageContext authzReqMessageContext) + throws IdentityOAuth2Exception { + + String spTenantDomain = getServiceProviderTenantDomain(authzReqMessageContext); + String clientId = authzReqMessageContext.getAuthorizationReqDTO().getConsumerKey(); + // Get allowed access token claims. + List allowedClaims = getAccessTokenClaims(clientId, spTenantDomain); + if (allowedClaims.isEmpty()) { return new HashMap<>(); } - List localClaimURIs = allowedClaims.stream().map(oidcToLocalClaimMappings::get).filter(Objects::nonNull) - .collect(Collectors.toList()); + Map claims = allowedClaims.stream().filter(userClaimsInOIDCDialect::containsKey) + .collect(Collectors.toMap(claim -> claim, userClaimsInOIDCDialect::get)); + return handleClaimsFormat(claims, clientId, spTenantDomain); + } + + /** + * Get claims for local user form userstore. + * + * @param requestMsgCtx OAuthTokenReqMessageContext + * @return Local user claims + * @throws IdentityOAuth2Exception IdentityOAuth2Exception + */ + private Map retrieveClaimsForLocalUser(OAuthTokenReqMessageContext requestMsgCtx) + throws IdentityOAuth2Exception { + try { - return getUserClaimsFromUserStore(authenticatedUser, clientId, spTenantDomain, localClaimURIs); + String spTenantDomain = getServiceProviderTenantDomain(requestMsgCtx); + String clientId = requestMsgCtx.getOauth2AccessTokenReqDTO().getClientId(); + AuthenticatedUser authenticatedUser = requestMsgCtx.getAuthorizedUser(); + + return getLocalUserClaimsInOIDCDialect(spTenantDomain, clientId, authenticatedUser); } catch (UserStoreException | IdentityApplicationManagementException | IdentityException | OrganizationManagementException e) { if (FrameworkUtils.isContinueOnClaimHandlingErrorAllowed()) { - log.error("Error occurred while getting claims for user: " + authenticatedUser + + log.error("Error occurred while getting claims for user: " + requestMsgCtx.getAuthorizedUser() + " from userstore.", e); } else { throw new IdentityOAuth2Exception("Error occurred while getting claims for user: " + - authenticatedUser + " from userstore.", e); + requestMsgCtx.getAuthorizedUser() + " from userstore.", e); } } - return null; + return new HashMap<>(); } /** - * This method retrieves user claims from the user store. + * Get oidc claims mapping. * - * @param authenticatedUser Authenticated user. - * @param clientId Client Id. - * @param spTenantDomain SP tenant domain. - * @param claimURIList List of claim URIs. - * @return Map of user claims. + * @param userAttributes User attributes. + * @param requestMsgCtx Request Context. + * @return User attributes Map. + */ + private Map getOIDCClaimsFromUserAttributes(Map userAttributes, + OAuthTokenReqMessageContext requestMsgCtx) + throws IdentityOAuth2Exception { + + String spTenantDomain = getServiceProviderTenantDomain(requestMsgCtx); + Map claims = new HashMap<>(); + if (isNotEmpty(userAttributes)) { + for (Map.Entry entry : userAttributes.entrySet()) { + claims.put(entry.getKey().getRemoteClaim().getClaimUri(), entry.getValue().toString()); + } + } + return OIDCClaimUtil.getMergedUserClaimsInOIDCDialect(spTenantDomain, claims); + } + + /** + * Get oidc claims mapping. + * + * @param federatedUserAttributes User attributes. + * @param requestMsgCtx Request Context. + * @return User attributes Map. + */ + private Map getOIDCClaimsFromFederatedUserAttributes(Map federatedUserAttributes, OAuthTokenReqMessageContext requestMsgCtx) + throws IdentityOAuth2Exception { + + String spTenantDomain = getServiceProviderTenantDomain(requestMsgCtx); + // Retrieve OIDC to Local Claim Mappings. + Map oidcToLocalClaimMappings = null; + try { + oidcToLocalClaimMappings = ClaimMetadataHandler.getInstance() + .getMappingsMapFromOtherDialectToCarbon(OIDC_DIALECT, null, spTenantDomain, false); + } catch (ClaimMetadataException e) { + throw new IdentityOAuth2Exception("Error while retrieving OIDC to Local claim mappings.", e); + } + // Get user claims in OIDC dialect. + Map userClaimsInOidcDialect = new HashMap<>(); + if (MapUtils.isNotEmpty(federatedUserAttributes)) { + for (Map.Entry userAttribute : federatedUserAttributes.entrySet()) { + ClaimMapping claimMapping = userAttribute.getKey(); + String claimValue = userAttribute.getValue().toString(); + String localClaimURI = claimMapping.getLocalClaim().getClaimUri(); + if (oidcToLocalClaimMappings.containsKey(localClaimURI) && StringUtils.isNotBlank(claimValue)) { + userClaimsInOidcDialect.put(localClaimURI, claimValue); + if (log.isDebugEnabled() && + IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.USER_CLAIMS)) { + log.debug("Mapped claim: key - " + localClaimURI + " value - " + claimValue); + } + } + } + } + return OIDCClaimUtil.getMergedUserClaimsInOIDCDialect(spTenantDomain, userClaimsInOidcDialect); + } + + /** + * Get user claims in OIDC dialect. + * + * @param authzReqMessageContext OAuthAuthzReqMessageContext + * @return User claims in OIDC dialect + * @throws IdentityOAuth2Exception IdentityOAuth2Exception + */ + private Map getUserClaimsInOIDCDialect(OAuthAuthzReqMessageContext authzReqMessageContext) + throws IdentityOAuth2Exception { + + Map userClaimsInOIDCDialect; + Map userAttributes = + getUserAttributesCachedAgainstToken(getAccessToken(authzReqMessageContext), false); + + if (isEmpty(userAttributes)) { + if (isLocalUser(authzReqMessageContext)) { + if (log.isDebugEnabled()) { + log.debug("User attributes not found in cache. Trying to retrieve attribute for " + + "local user: " + authzReqMessageContext.getAuthorizationReqDTO().getUser()); + } + + userClaimsInOIDCDialect = retrieveClaimsForLocalUser(authzReqMessageContext); + } else { + if (log.isDebugEnabled()) { + log.debug("User attributes not found in cache. Trying to retrieve attribute for federated " + + "user: " + authzReqMessageContext.getAuthorizationReqDTO().getUser()); + } + userClaimsInOIDCDialect = retrieveClaimsForFederatedUser(authzReqMessageContext); + } + } else { + userClaimsInOIDCDialect = getOIDCClaimMapFromUserAttributes(userAttributes); + // Since this is a federated flow we are retrieving the federated user attributes as well. + Map federatedUserAttributes = + getUserAttributesCachedAgainstToken(getAccessToken(authzReqMessageContext), true); + Map federatedUserClaimsInOIDCDialect = + getUserClaimsInOIDCDialectFromFederatedUserAttributes(authzReqMessageContext + .getAuthorizationReqDTO().getTenantDomain(), federatedUserAttributes); + userClaimsInOIDCDialect.putAll(federatedUserClaimsInOIDCDialect); + } + return filterClaims(userClaimsInOIDCDialect, authzReqMessageContext); + } + + /** + * This method retrieves the user attributes cached against the access token or the authorization code. + * Currently, this is supported for the code grant and the refresh grant. + * + * @param requestMsgCtx The context of the OAuth token request containing necessary properties. + * @param fetchFederatedUserAttributes Flag to indicate whether to fetch federated user attributes. + * @return A map of cached user attributes against the code or the access token. + * @throws IdentityOAuth2Exception If an error occurs while selecting the OAuth2 token issuer. + */ + private Map getCachedUserAttributes(OAuthTokenReqMessageContext requestMsgCtx, + boolean fetchFederatedUserAttributes) + throws IdentityOAuth2Exception { + + Map userAttributes = getUserAttributesCachedAgainstAuthorizationCode( + getAuthorizationCode(requestMsgCtx), fetchFederatedUserAttributes); + if (log.isDebugEnabled()) { + log.debug("Retrieving claims cached against authorization_code for user: " + + requestMsgCtx.getAuthorizedUser()); + } + if (isEmpty(userAttributes)) { + if (log.isDebugEnabled()) { + log.debug("No claims cached against the authorization_code for user: " + requestMsgCtx. + getAuthorizedUser() + ". Retrieving claims cached against the access_token."); + } + userAttributes = getUserAttributesCachedAgainstToken(getAccessToken(requestMsgCtx), + fetchFederatedUserAttributes); + if (log.isDebugEnabled()) { + log.debug("Retrieving claims cached against access_token for user: " + + requestMsgCtx.getAuthorizedUser()); + } + } + // Check for claims cached against the device code. + if (isEmpty(userAttributes)) { + if (log.isDebugEnabled()) { + log.debug("No claims cached against the access_token for user: " + + requestMsgCtx.getAuthorizedUser() + ". Retrieving claims cached against the device code."); + } + userAttributes = getUserAttributesCachedAgainstDeviceCode(getDeviceCode(requestMsgCtx), + fetchFederatedUserAttributes); + } + /* When building the jwt token, we cannot add it to authorization cache, as we save entries against, access + token. Hence if it is added against authenticated user object.*/ + if (isEmpty(userAttributes)) { + if (log.isDebugEnabled()) { + log.debug("No claims found in authorization cache. Retrieving claims from attributes of user : " + + requestMsgCtx.getAuthorizedUser()); + } + AuthenticatedUser user = requestMsgCtx.getAuthorizedUser(); + userAttributes = user != null ? user.getUserAttributes() : null; + } + // In the refresh flow, we need to follow the same way to get the claims. + if (isEmpty(userAttributes)) { + if (log.isDebugEnabled()) { + log.debug("No claims found in user in user attributes for user : " + requestMsgCtx.getAuthorizedUser()); + } + + /* + The purpose of this segment is retrieving the user attributes at the refresh grant while the caches + are disabled. The code/token acts as the key in cache layer while access token hash acts as the key for + entries in the persistence layer(SessionStore). + At this point, the token indicated by RefreshGrantHandler.PREV_ACCESS_TOKEN is no longer + present in the caches or the persistence layer because a new access token has already been generated + and added to the cache with new token references. However, RefreshGrantHandler.PREV_ACCESS_TOKEN cannot + yet be replaced with the new access token since the refresh token has not been generated, and + the new token is not yet considered "previous" by definition. + */ + String latestAccessTokenHash = getLatestAccessTokenHash(requestMsgCtx); + if (StringUtils.isNotBlank(latestAccessTokenHash)) { + userAttributes = getUserAttributesCachedAgainstToken(latestAccessTokenHash, + fetchFederatedUserAttributes); + } + + Object previousAccessTokenObject = requestMsgCtx.getProperty(RefreshGrantHandler.PREV_ACCESS_TOKEN); + + if (previousAccessTokenObject != null) { + if (log.isDebugEnabled()) { + log.debug("Retrieving claims from previous access token of user : " + requestMsgCtx + .getAuthorizedUser()); + } + RefreshTokenValidationDataDO refreshTokenValidationDataDO = + (RefreshTokenValidationDataDO) previousAccessTokenObject; + + // This segment is retrieving the user attributes at the refresh grant while the caches are enabled. + if (isEmpty(userAttributes)) { + userAttributes = getUserAttributesCachedAgainstToken(refreshTokenValidationDataDO.getAccessToken(), + fetchFederatedUserAttributes); + } + requestMsgCtx.addProperty(OIDCConstants.HAS_NON_OIDC_CLAIMS, + isTokenHasCustomUserClaims(refreshTokenValidationDataDO)); + } + } + return userAttributes; + } + + /** + * Get user attributes cached against the authorization code. + * + * @param authorizationCode Authorization Code + * @param fetchFederatedUserAttr Flag to indicate whether to fetch federated user attributes. + * @return User attributes cached against the authorization code + */ + private Map getUserAttributesCachedAgainstAuthorizationCode(String authorizationCode, + boolean fetchFederatedUserAttr) { + + Map userAttributes = Collections.emptyMap(); + if (authorizationCode != null) { + // Get the cached user claims against the authorization code if any. + userAttributes = getUserAttributesFromCacheUsingCode(authorizationCode, fetchFederatedUserAttr); + } + return userAttributes; + } + + /** + * GEt user attributes cached against the device code. + * + * @param deviceCode Device Code + * @param fetchFederatedUserAttributes Flag to indicate whether to fetch federated user attributes. + * @return User attributes cached against the device code + */ + private Map getUserAttributesCachedAgainstDeviceCode(String deviceCode, + boolean fetchFederatedUserAttributes) { + + if (StringUtils.isEmpty(deviceCode)) { + return Collections.emptyMap(); + } + DeviceAuthorizationGrantCacheKey cacheKey = new DeviceAuthorizationGrantCacheKey(deviceCode); + DeviceAuthorizationGrantCacheEntry cacheEntry = + DeviceAuthorizationGrantCache.getInstance().getValueFromCache(cacheKey); + if (fetchFederatedUserAttributes) { + return cacheEntry == null ? Collections.emptyMap() : cacheEntry.getMappedRemoteClaims(); + } + return cacheEntry == null ? Collections.emptyMap() : cacheEntry.getUserAttributes(); + } + + /** + * Get user attributes cached against the authorization code. + * + * @param authorizationCode Authorization Code + * @param fetchFederatedUserAttributes Flag to indicate whether to fetch federated user attributes. + * @return User attributes cached against the authorization code + */ + private Map getUserAttributesFromCacheUsingCode(String authorizationCode, + boolean fetchFederatedUserAttributes) { + if (log.isDebugEnabled()) { + if (IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.AUTHORIZATION_CODE)) { + log.debug("Retrieving user attributes cached against authorization code: " + authorizationCode); + } else { + log.debug("Retrieving user attributes cached against authorization code."); + } + } + + AuthorizationGrantCacheKey cacheKey = new AuthorizationGrantCacheKey(authorizationCode); + AuthorizationGrantCacheEntry cacheEntry = + AuthorizationGrantCache.getInstance().getValueFromCacheByCode(cacheKey); + if (fetchFederatedUserAttributes) { + return cacheEntry == null ? new HashMap<>() : cacheEntry.getMappedRemoteClaims(); + } + return cacheEntry == null ? new HashMap<>() : cacheEntry.getUserAttributes(); + } + + /** + * Get user attributes cached against the access token. + * + * @param accessToken Access Token + * @param fetchFederatedUserAttributes Flag to indicate whether to fetch federated user attributes. + * @return User attributes cached against the access token + */ + private Map getUserAttributesCachedAgainstToken(String accessToken, + boolean fetchFederatedUserAttributes) { + Map userAttributes = Collections.emptyMap(); + if (accessToken != null) { + // get the user claims cached against the access token if any + userAttributes = getUserAttributesFromCacheUsingToken(accessToken, fetchFederatedUserAttributes); + } + return userAttributes; + } + + /** + * Get claims for local user form userstore. + * + * @param authzReqMessageContext OAuthAuthzReqMessageContext + * @return Local user claims + * @throws IdentityOAuth2Exception IdentityOAuth2Exception + */ + private Map retrieveClaimsForLocalUser(OAuthAuthzReqMessageContext authzReqMessageContext) + throws IdentityOAuth2Exception { + + try { + String spTenantDomain = getServiceProviderTenantDomain(authzReqMessageContext); + String clientId = authzReqMessageContext.getAuthorizationReqDTO().getConsumerKey(); + AuthenticatedUser authenticatedUser = authzReqMessageContext.getAuthorizationReqDTO().getUser(); + + return getLocalUserClaimsInOIDCDialect(spTenantDomain, clientId, authenticatedUser); + } catch (UserStoreException | IdentityApplicationManagementException | IdentityException | + OrganizationManagementException e) { + if (FrameworkUtils.isContinueOnClaimHandlingErrorAllowed()) { + log.error("Error occurred while getting claims for user " + + authzReqMessageContext.getAuthorizationReqDTO().getUser(), e); + } else { + throw new IdentityOAuth2Exception("Error occurred while getting claims for user " + + authzReqMessageContext.getAuthorizationReqDTO().getUser(), e); + } + } + return new HashMap<>(); + } + + /** + * Retrieve the claim set of the AuthenticatedUser from the OAuthAuthzReqMessageContext. + * + * @param authzReqMessageContext OAuthAuthzReqMessageContext. + * @return Map of user attributes. */ - private Map getUserClaimsFromUserStore(AuthenticatedUser authenticatedUser, String clientId, - String spTenantDomain, List claimURIList) - throws IdentityApplicationManagementException, UserStoreException, OrganizationManagementException, - IdentityException { + private Map retrieveClaimsForFederatedUser(OAuthAuthzReqMessageContext authzReqMessageContext) + throws IdentityOAuth2Exception { + + OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO = authzReqMessageContext.getAuthorizationReqDTO(); + Map userClaimsMappedToOIDCDialect = new HashMap<>(); + + if (oAuth2AuthorizeReqDTO == null) { + if (log.isDebugEnabled()) { + log.debug("OAuth2AuthorizeReqDTO is NULL for federated user: " + + authzReqMessageContext.getAuthorizationReqDTO().getUser()); + } + return userClaimsMappedToOIDCDialect; + } + AuthenticatedUser authenticatedUser = oAuth2AuthorizeReqDTO.getUser(); + if (authenticatedUser == null) { + if (log.isDebugEnabled()) { + log.debug("Authenticated User is not available in the request"); + } + return userClaimsMappedToOIDCDialect; + } + Map userAttributes = authenticatedUser.getUserAttributes(); + // Since this is a federated flow we are retrieving the federated user attributes as well. + Map federatedUserAttributes = + oAuth2AuthorizeReqDTO.getMappedRemoteClaims(); + userClaimsMappedToOIDCDialect = getOIDCClaimMapFromUserAttributes(userAttributes); + Map federatedUserClaimsMappedToOIDCDialect = + getUserClaimsInOIDCDialectFromFederatedUserAttributes(authzReqMessageContext.getAuthorizationReqDTO() + .getTenantDomain(), federatedUserAttributes); + userClaimsMappedToOIDCDialect.putAll(federatedUserClaimsMappedToOIDCDialect); + return userClaimsMappedToOIDCDialect; + } + + /** + * Get claims map. + * + * @param userAttributes User Attributes + * @return User attribute map + */ + private Map getOIDCClaimMapFromUserAttributes(Map userAttributes) { + + Map claims = new HashMap<>(); + if (isNotEmpty(userAttributes)) { + for (Map.Entry entry : userAttributes.entrySet()) { + claims.put(entry.getKey().getRemoteClaim().getClaimUri(), entry.getValue()); + } + } + return claims; + } + + /** + * Get user claims in OIDC claim dialect from federated user attributes. + * + * @param spTenantDomain Service Provider Tenant Domain + * @param federatedUserAttr Federated User Attributes + * @return User claims in OIDC dialect + * @throws IdentityOAuth2Exception Identity OAuth2 Exception + */ + private static Map getUserClaimsInOIDCDialectFromFederatedUserAttributes(String spTenantDomain, + Map + federatedUserAttr) + throws IdentityOAuth2Exception { + + // Retrieve OIDC to Local Claim Mappings. + Map oidcToLocalClaimMappings = null; + try { + oidcToLocalClaimMappings = ClaimMetadataHandler.getInstance() + .getMappingsMapFromOtherDialectToCarbon(OIDC_DIALECT, null, spTenantDomain, false); + } catch (ClaimMetadataException e) { + throw new IdentityOAuth2Exception("Error while retrieving OIDC to Local claim mappings.", e); + } + // Get user claims in OIDC dialect. + Map userClaimsInOidcDialect = new HashMap<>(); + if (MapUtils.isNotEmpty(federatedUserAttr)) { + for (Map.Entry userAttribute : federatedUserAttr.entrySet()) { + ClaimMapping claimMapping = userAttribute.getKey(); + String claimValue = userAttribute.getValue(); + String localClaimURI = claimMapping.getLocalClaim().getClaimUri(); + if (oidcToLocalClaimMappings.containsKey(localClaimURI) && StringUtils.isNotBlank(claimValue)) { + userClaimsInOidcDialect.put(localClaimURI, claimValue); + if (log.isDebugEnabled() && + IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.USER_CLAIMS)) { + log.debug("Mapped claim: key - " + localClaimURI + " value - " + claimValue); + } + } + } + } + return userClaimsInOidcDialect; + } + + /** + * Get user claims in OIDC claim dialect from userstore. + * + * @param spTenantDomain Service Provider Tenant Domain + * @param clientId Client Id + * @param authenticatedUser Authenticated User + * @return User claims in OIDC dialect + * @throws IdentityApplicationManagementException Identity Application Management Exception + * @throws IdentityException Identity Exception + * @throws UserStoreException User Store Exception + * @throws OrganizationManagementException Organization Management Exception + */ + private Map getLocalUserClaimsInOIDCDialect(String spTenantDomain, String clientId, + AuthenticatedUser authenticatedUser) + throws IdentityApplicationManagementException, IdentityException, UserStoreException, + OrganizationManagementException { Map userClaimsMappedToOIDCDialect = new HashMap<>(); ServiceProvider serviceProvider = getServiceProvider(spTenantDomain, clientId); @@ -144,9 +667,143 @@ private Map getUserClaimsFromUserStore(AuthenticatedUser authent spTenantDomain + ". Returning empty claim map for user."); return userClaimsMappedToOIDCDialect; } - return OIDCClaimUtil.getUserClaimsInOIDCDialect(serviceProvider, authenticatedUser, claimURIList); + + List allowedClaims = getAccessTokenClaims(clientId, spTenantDomain); + if (allowedClaims.isEmpty()) { + return new HashMap<>(); + } + Map oidcToLocalClaimMappings = getOIDCToLocalClaimMappings(spTenantDomain); + if (oidcToLocalClaimMappings.isEmpty()) { + return new HashMap<>(); + } + List localClaimURIs = allowedClaims.stream().map(oidcToLocalClaimMappings::get).filter(Objects::nonNull) + .collect(Collectors.toList()); + return OIDCClaimUtil.getUserClaimsInOIDCDialect(serviceProvider, authenticatedUser, localClaimURIs); + } + + /** + * Get user attribute cached against the access token. + * + * @param accessToken Access token + * @return User attributes cached against the access token + */ + private Map getUserAttributesFromCacheUsingToken(String accessToken, + boolean fetchFederatedUserAttributes) { + + if (log.isDebugEnabled()) { + if (IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.ACCESS_TOKEN)) { + log.debug("Retrieving user attributes cached against access token: " + accessToken); + } else { + log.debug("Retrieving user attributes cached against access token."); + } + } + + AuthorizationGrantCacheKey cacheKey = new AuthorizationGrantCacheKey(accessToken); + AuthorizationGrantCacheEntry cacheEntry = AuthorizationGrantCache.getInstance() + .getValueFromCacheByToken(cacheKey); + if (fetchFederatedUserAttributes) { + return cacheEntry == null ? new HashMap<>() : cacheEntry.getMappedRemoteClaims(); + } + return cacheEntry == null ? new HashMap<>() : cacheEntry.getUserAttributes(); + } + + private String getAuthorizationCode(OAuthTokenReqMessageContext requestMsgCtx) { + + return (String) requestMsgCtx.getProperty(AUTHZ_CODE); + } + + private String getAccessToken(OAuthAuthzReqMessageContext authzReqMessageContext) { + + return (String) authzReqMessageContext.getProperty(ACCESS_TOKEN); + } + + private String getAccessToken(OAuthTokenReqMessageContext requestMsgCtx) { + + return (String) requestMsgCtx.getProperty(ACCESS_TOKEN); + } + + private String getDeviceCode(OAuthTokenReqMessageContext requestMsgCtx) { + + return (String) requestMsgCtx.getProperty(DEVICE_CODE); + } + + private boolean isLocalUser(AuthenticatedUser authenticatedUser) { + + return !authenticatedUser.isFederatedUser(); } + private boolean isLocalUser(OAuthAuthzReqMessageContext authzReqMessageContext) { + + return !authzReqMessageContext.getAuthorizationReqDTO().getUser().isFederatedUser(); + } + + /** + * The access token hash acts as the key for entries in the SessionStore. + * This method retrieves the access token hash for OAuthConstants.ACCESS_TOKEN from the properties + * of OAuthTokenReqMessageContext treating it as the latest access token. It determines the type + * of access token (opaque or JWT) via the OAuth token issuer and obtains the access token hash accordingly. + * This method is useful for retrieving access tokens when the cache is disabled and + * SessionStore persistence is employed. + * + * @param oAuthTokenReqMessageContext The context of the OAuth token request containing necessary properties. + * @return The hash of the latest access token if available and valid, otherwise null. + * @throws IdentityOAuth2Exception If an error occurs while selecting the OAuth2 token issuer. + */ + private String getLatestAccessTokenHash(OAuthTokenReqMessageContext oAuthTokenReqMessageContext) + throws IdentityOAuth2Exception { + + // The OAuthConstants.ACCESS_TOKEN is considered as the latest access token. + Object latestAccessTokenObj = getAccessToken(oAuthTokenReqMessageContext); + if (latestAccessTokenObj != null && StringUtils.isNotBlank(latestAccessTokenObj.toString())) { + + Object oAuthAppDOObj = oAuthTokenReqMessageContext.getProperty(AccessTokenIssuer.OAUTH_APP_DO); + + if (oAuthAppDOObj != null) { + try { + OAuthAppDO oAuthAppDO = (OAuthAppDO) oAuthAppDOObj; + OauthTokenIssuer tokenIssuer = OAuth2Util.getOAuthTokenIssuerForOAuthApp(oAuthAppDO); + if (tokenIssuer != null) { + String latestAccessToken = latestAccessTokenObj.toString(); + try { + return tokenIssuer.getAccessTokenHash(latestAccessToken); + } catch (OAuthSystemException e) { + throw new IdentityOAuth2Exception("Error occurred while generating the access token hash " + + "at user attribute retrieval", e); + } + } + } catch (ClassCastException e) { + log.error("Error occurred while generating the access token hash at user attribute " + + "retrieval", e); + + } + } + } + return null; + } + + /** + * To check whether a token has custom user claims. + * + * @param refreshTokenValidationDataDO RefreshTokenValidationDataDO. + * @return true if the token user attributes has non OIDC claims. + */ + private boolean isTokenHasCustomUserClaims(RefreshTokenValidationDataDO refreshTokenValidationDataDO) { + + if (refreshTokenValidationDataDO.getAccessToken() == null) { + return false; + } + AuthorizationGrantCacheKey cacheKey = new AuthorizationGrantCacheKey( + refreshTokenValidationDataDO.getAccessToken()); + AuthorizationGrantCacheEntry cacheEntry = AuthorizationGrantCache.getInstance() + .getValueFromCacheByToken(cacheKey); + boolean hasNonOIDCClaims = cacheEntry != null && cacheEntry.isHasNonOIDCClaims(); + + if (log.isDebugEnabled()) { + log.debug("hasNonOIDCClaims is set to " + hasNonOIDCClaims + " for the access token of the user : " + + refreshTokenValidationDataDO.getAuthorizedUser()); + } + return cacheEntry != null && cacheEntry.isHasNonOIDCClaims(); + } /** * This method retrieves OIDC to Local claim mappings. @@ -298,4 +955,55 @@ private String getServiceProviderTenantDomain(OAuthTokenReqMessageContext reques } return spTenantDomain; } + + /** + * Retrieves the service provider tenant domain from the OAuthAuthzReqMessageContext. + * + * @param requestMsgCtx OAuthAuthzReqMessageContext containing the tenant domain. + * @return The tenant domain. + */ + private String getServiceProviderTenantDomain(OAuthAuthzReqMessageContext requestMsgCtx) { + + String spTenantDomain = (String) requestMsgCtx.getProperty(MultitenantConstants.TENANT_DOMAIN); + // There are certain flows where tenant domain is not added as a message context property. + if (spTenantDomain == null) { + spTenantDomain = requestMsgCtx.getAuthorizationReqDTO().getTenantDomain(); + } + return spTenantDomain; + } + + /** + * Check whether an organization SSO user is trying to switch the organization. + * + * @param authorizedUser authorized user from the token request. + * @return true if an organization SSO user is trying to switch the organization. + */ + private boolean isOrganizationSsoUserSwitchingOrganization(AuthenticatedUser authorizedUser) { + + String accessingOrganization = authorizedUser.getAccessingOrganization(); + String userResidentOrganization = authorizedUser.getUserResidentOrganization(); + /* A federated user with resident organization is considered as an organization SSO user. When the accessing + organization is different to the resident organization, it means the user is trying to switch the + organization. */ + return authorizedUser.isFederatedUser() && userResidentOrganization != null && !userResidentOrganization.equals + (accessingOrganization); + } + + /** + * Check whether grant type is organization switch grant. + * + * @param requestMsgCtx OAuthTokenReqMessageContext + * @return true if grant type is organization switch grant. + */ + private boolean isOrganizationSwitchGrantType(OAuthTokenReqMessageContext requestMsgCtx) { + + return StringUtils.equals(requestMsgCtx.getOauth2AccessTokenReqDTO().getGrantType(), + OAuthConstants.GrantTypes.ORGANIZATION_SWITCH); + } + + private boolean isPreserverClaimUrisInAssertion(OAuthTokenReqMessageContext requestMsgCtx) { + + return !OAuthServerConfiguration.getInstance().isConvertOriginalClaimsFromAssertionsToOIDCDialect() && + requestMsgCtx.getAuthorizedUser().isFederatedUser(); + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/OpenIDConnectClaimFilterImpl.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/OpenIDConnectClaimFilterImpl.java index 93376387678..124e6baddd6 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/OpenIDConnectClaimFilterImpl.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/OpenIDConnectClaimFilterImpl.java @@ -61,6 +61,7 @@ import static org.wso2.carbon.identity.oauth.common.OAuthConstants.LogConstants.ActionIDs.ISSUE_ACCESS_TOKEN; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.LogConstants.OAUTH_INBOUND_SERVICE; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDCClaims.ADDRESS; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDCClaims.APP_ROLES; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDCClaims.EMAIL_VERIFIED; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDCClaims.PHONE_NUMBER_VERIFIED; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDCClaims.ROLES; @@ -137,6 +138,7 @@ public Map getClaimsFilteredByOIDCScopes(Map use handleAddressClaim(claimsToBeReturned, addressScopeClaims); } handleRolesClaim(claimsToBeReturned); + handleApplicationRolesClaim(claimsToBeReturned); handleUpdateAtClaim(claimsToBeReturned); handlePhoneNumberVerifiedClaim(claimsToBeReturned); handleEmailVerifiedClaim(claimsToBeReturned); @@ -501,6 +503,23 @@ private void handleRolesClaim(Map returnClaims) { } } + private void handleApplicationRolesClaim(Map returnClaims) { + + if (returnClaims.containsKey(APP_ROLES) && IdentityUtil.isGroupsVsRolesSeparationImprovementsEnabled() + && returnClaims.get(APP_ROLES) instanceof String) { + String multiAttributeSeparator = FrameworkUtils.getMultiAttributeSeparator(); + List roles = Arrays.asList(returnClaims.get(APP_ROLES).toString().split(multiAttributeSeparator)); + + for (String role : roles) { + if (UserCoreConstants.INTERNAL_DOMAIN.equalsIgnoreCase(IdentityUtil.extractDomainFromName(role))) { + String domainRemovedRole = UserCoreUtil.removeDomainFromName(role); + roles.set(roles.indexOf(role), domainRemovedRole); + } + } + returnClaims.put(APP_ROLES, StringUtils.join(roles, multiAttributeSeparator)); + } + } + private void startTenantFlow(String tenantDomain, int tenantId) { PrivilegedCarbonContext.startTenantFlow(); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthUtilTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthUtilTest.java index 1d7b5da5ec5..f6e982060af 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthUtilTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthUtilTest.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2017-2025, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -11,7 +11,7 @@ * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the + * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ @@ -19,15 +19,50 @@ package org.wso2.carbon.identity.oauth; import org.apache.commons.lang.StringUtils; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.InboundAuthenticationConfig; +import org.wso2.carbon.identity.application.common.model.InboundAuthenticationRequestConfig; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; import org.wso2.carbon.identity.application.common.model.User; +import org.wso2.carbon.identity.application.mgt.ApplicationConstants; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.common.testng.WithRealmService; import org.wso2.carbon.identity.oauth.cache.CacheEntry; import org.wso2.carbon.identity.oauth.cache.OAuthCache; import org.wso2.carbon.identity.oauth.cache.OAuthCacheKey; - +import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; +import org.wso2.carbon.identity.oauth2.dao.AccessTokenDAO; +import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.organization.management.service.util.OrganizationManagementUtil; +import org.wso2.carbon.identity.role.v2.mgt.core.RoleConstants; +import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService; +import org.wso2.carbon.identity.role.v2.mgt.core.model.RoleBasicInfo; +import org.wso2.carbon.user.api.RealmConfiguration; +import org.wso2.carbon.user.core.UserStoreManager; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +import java.util.HashSet; +import java.util.Set; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; @@ -40,6 +75,37 @@ @WithCarbonHome @WithRealmService public class OAuthUtilTest { + + @Mock + RoleManagementService roleManagementService; + @Mock + ApplicationManagementService applicationManagementService; + + private AutoCloseable closeable; + private MockedStatic organizationManagementUtil; + private MockedStatic oAuthComponentServiceHolder; + private MockedStatic oAuth2Util; + private MockedStatic oAuthTokenPersistenceFactory; + + @BeforeMethod + public void setUp() throws Exception { + + organizationManagementUtil = mockStatic(OrganizationManagementUtil.class); + oAuthComponentServiceHolder = mockStatic(OAuthComponentServiceHolder.class); + oAuth2Util = mockStatic(OAuth2Util.class); + oAuthTokenPersistenceFactory = mockStatic(OAuthTokenPersistenceFactory.class); + closeable = MockitoAnnotations.openMocks(this); + } + + @AfterMethod + public void tearDown() throws Exception { + + organizationManagementUtil.close(); + oAuthComponentServiceHolder.close(); + oAuth2Util.close(); + oAuthTokenPersistenceFactory.close(); + closeable.close(); + } @DataProvider(name = "testGetAuthenticatedUser") public Object[][] fullQualifiedUserName() { @@ -160,6 +226,71 @@ public void testGetAuthenticatedUserException() throws Exception { OAuthUtil.getAuthenticatedUser(""); } + @Test + public void testRevokeTokensForApplicationAudienceRoles() throws Exception { + + String username = "testUser"; + String roleId = "testRoleId"; + String roleName = "testRole"; + String appId = "testAppId"; + String clientId = "testClientId"; + String accessToken = "testAccessToken"; + + UserStoreManager userStoreManager = mock(UserStoreManager.class); + when(userStoreManager.getTenantId()).thenReturn(-1234); + when(userStoreManager.getRealmConfiguration()).thenReturn(mock(RealmConfiguration.class)); + when(userStoreManager.getRealmConfiguration().getUserStoreProperty(anyString())).thenReturn("PRIMARY"); + + when(OrganizationManagementUtil.isOrganization(anyString())).thenReturn(false); + when(OAuth2Util.getTenantId(anyString())).thenReturn(-1234); + + OAuthComponentServiceHolder mockOAuthComponentServiceHolder = mock(OAuthComponentServiceHolder.class); + when(OAuthComponentServiceHolder.getInstance()).thenReturn(mockOAuthComponentServiceHolder); + + when(mockOAuthComponentServiceHolder.getRoleV2ManagementService()).thenReturn(roleManagementService); + RoleBasicInfo roleBasicInfo = new RoleBasicInfo(); + roleBasicInfo.setId(roleId); + roleBasicInfo.setAudience(RoleConstants.APPLICATION); + roleBasicInfo.setAudienceId(appId); + roleBasicInfo.setName(roleName); + when(roleManagementService.getRoleBasicInfoById(roleId, MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) + .thenReturn(roleBasicInfo); + + when(mockOAuthComponentServiceHolder.getApplicationManagementService()) + .thenReturn(applicationManagementService); + ServiceProvider serviceProvider = new ServiceProvider(); + InboundAuthenticationConfig inboundAuthenticationConfig = new InboundAuthenticationConfig(); + InboundAuthenticationRequestConfig[] inboundAuthenticationRequestConfigs = + new InboundAuthenticationRequestConfig[1]; + InboundAuthenticationRequestConfig inboundAuthenticationRequestConfig = + new InboundAuthenticationRequestConfig(); + inboundAuthenticationRequestConfig.setInboundAuthKey(clientId); + inboundAuthenticationRequestConfig.setInboundAuthType(ApplicationConstants.StandardInboundProtocols.OAUTH2); + inboundAuthenticationRequestConfigs[0] = inboundAuthenticationRequestConfig; + inboundAuthenticationConfig.setInboundAuthenticationRequestConfigs(inboundAuthenticationRequestConfigs); + serviceProvider.setInboundAuthenticationConfig(inboundAuthenticationConfig); + when(applicationManagementService.getApplicationByResourceId( + appId, MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)).thenReturn(serviceProvider); + + OAuthTokenPersistenceFactory mockOAuthTokenPersistenceFactory = mock(OAuthTokenPersistenceFactory.class); + when(OAuthTokenPersistenceFactory.getInstance()).thenReturn(mockOAuthTokenPersistenceFactory); + AccessTokenDAO mockAccessTokenDAO = mock(AccessTokenDAO.class); + when(mockOAuthTokenPersistenceFactory.getAccessTokenDAO()).thenReturn(mockAccessTokenDAO); + Set accessTokens = new HashSet<>(); + AccessTokenDO accessTokenDO = new AccessTokenDO(); + accessTokenDO.setAccessToken(accessToken); + accessTokenDO.setConsumerKey(clientId); + accessTokenDO.setScope(new String[]{"default"}); + accessTokenDO.setAuthzUser(new AuthenticatedUser()); + accessTokens.add(accessTokenDO); + when(mockAccessTokenDAO.getAccessTokens(anyString(), + any(AuthenticatedUser.class), nullable(String.class), anyBoolean())).thenReturn(accessTokens); + + boolean result = OAuthUtil.revokeTokens(username, userStoreManager, roleId); + verify(mockAccessTokenDAO, times(1)).revokeAccessTokens(any(), anyBoolean()); + assertTrue(result, "Token revocation failed."); + } + private OAuthCache getOAuthCache(OAuthCacheKey oAuthCacheKey) { diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCacheTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCacheTest.java new file mode 100644 index 00000000000..49e845d0184 --- /dev/null +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/cache/AuthorizationGrantCacheTest.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.oauth.cache; + +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.JWTParser; +import org.apache.commons.logging.Log; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.store.SessionDataStore; +import org.wso2.carbon.identity.base.IdentityConstants; +import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dao.AccessTokenDAO; +import org.wso2.carbon.identity.oauth2.dao.AuthorizationCodeDAO; +import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.text.ParseException; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Unit tests for AuthorizationGrantCacheTest class. + */ +public class AuthorizationGrantCacheTest { + + @Mock + private AccessTokenDAO accessTokenDAO; + + private AuthorizationGrantCache cache; + + @Mock + private OAuthTokenPersistenceFactory mockedOAuthTokenPersistenceFactory; + + @Mock + private AuthorizationCodeDAO authorizationCodeDAO; + + @Mock + private SessionDataStore sessionDataStore; + + private Log mockLog; + + private static final String AUTHORIZATION_GRANT_CACHE_NAME = "AuthorizationGrantCache"; + + @BeforeMethod + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + cache = AuthorizationGrantCache.getInstance(); + + mockLog = mock(Log.class); + + Field logField = + AuthorizationGrantCache.class.getDeclaredField("log"); + logField.setAccessible(true); + + // Remove the 'final' modifier using reflection + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(logField, logField.getModifiers() & ~Modifier.FINAL); + + // Set the static field to the mock object + logField.set(null, mockLog); + } + + @Test(dataProvider = "replaceFromTokenIdDataProvider") + public void testReplaceFromTokenId(String accessToken, String jwtId, String tokenId, boolean isJwtToken, + boolean isInvalidJWTToken, boolean isFailedTokenRetrieval, + boolean isTokenLoggable) throws Exception { + + try (MockedStatic mockedFactory = + mockStatic(OAuthTokenPersistenceFactory.class); + MockedStatic mockedJwtParser = mockStatic(JWTParser.class); + MockedStatic mockedSessionDataStore = mockStatic(SessionDataStore.class); + MockedStatic mockedIdentityUtil = mockStatic(IdentityUtil.class)) { + + when(mockLog.isDebugEnabled()).thenReturn(true); + mockedFactory.when(OAuthTokenPersistenceFactory::getInstance).thenReturn( + mockedOAuthTokenPersistenceFactory); + + when(mockedOAuthTokenPersistenceFactory.getAccessTokenDAO()).thenReturn(accessTokenDAO); + if (isTokenLoggable) { + mockedIdentityUtil.when(() -> IdentityUtil.isTokenLoggable(IdentityConstants + .IdentityTokens.ACCESS_TOKEN)).thenReturn(true); + } else { + mockedIdentityUtil.when(() -> IdentityUtil.isTokenLoggable(IdentityConstants + .IdentityTokens.ACCESS_TOKEN)).thenReturn(false); + } + if (isJwtToken) { + JWT jwtMock = mock(JWT.class); + JWTClaimsSet claimsSetMock = mock(JWTClaimsSet.class); + + if (isInvalidJWTToken) { + when(JWTParser.parse(accessToken)).thenThrow(new ParseException("Invalid JWT", 0)); + } else { + mockedJwtParser.when(() -> JWTParser.parse(accessToken)).thenReturn(jwtMock); + when(jwtMock.getJWTClaimsSet()).thenReturn(claimsSetMock); + when(claimsSetMock.getJWTID()).thenReturn(jwtId); + } + } + + if (isFailedTokenRetrieval) { + when(accessTokenDAO.getTokenIdByAccessToken(jwtId)).thenThrow( + new IdentityOAuth2Exception("Failed to retrieve token id by token from store")); + } else { + when(accessTokenDAO.getTokenIdByAccessToken(jwtId != null ? jwtId : accessToken)).thenReturn(tokenId); + } + + // Mock SessionDataStore static instance and return a mock session data store. + mockedSessionDataStore.when(SessionDataStore::getInstance).thenReturn(sessionDataStore); + + AuthorizationGrantCacheEntry mockCacheEntry = new AuthorizationGrantCacheEntry(); + mockCacheEntry.setTokenId(tokenId); + + when(sessionDataStore.getSessionData(tokenId, AUTHORIZATION_GRANT_CACHE_NAME)).thenReturn(mockCacheEntry); + + AuthorizationGrantCacheKey key = new AuthorizationGrantCacheKey(accessToken); + AuthorizationGrantCacheEntry result = cache.getValueFromCacheByToken(key); + + // Verify the token ID returned from the DAO is as expected. + assertEquals(tokenId, result.getTokenId()); + + // Verify that the JWT token was parsed and the correct claim was retrieved if it was a JWT. + if (isJwtToken && !isInvalidJWTToken) { + verify(accessTokenDAO).getTokenIdByAccessToken(jwtId); + } else { + verify(accessTokenDAO).getTokenIdByAccessToken(accessToken); + } + + if (isInvalidJWTToken) { + if (isTokenLoggable) { + verify(mockLog).debug(eq("Error while getting JWTID from token: " + accessToken), + any(ParseException.class)); + } else { + verify(mockLog).debug(eq("Error while getting JWTID from token")); + } + } + } + } + + @DataProvider(name = "replaceFromTokenIdDataProvider") + public Object[][] getReplaceFromTokenIdData() { + + return new Object[][]{ + {"jwt.Access.Token", "jwtId", "jwtTokenId", true, false, false, false}, + {"nonJWTAccessToken", null, "nonJWTTokenId", false, false, false, false}, + {"invalid.JWT.Token", null, "invalid.JWT.Token", true, true, false, true}, + {"invalid.JWT.Token", null, "invalid.JWT.Token", true, true, false, false}, + {"fail.Store.TokenId", "jwtId", "jwtId", true, false, true, false} + }; + } + + @Test + public void testGetValueFromCacheByCode() throws IdentityOAuth2Exception { + + String authCode = "authCode"; + String codeId = "codeId"; + AuthorizationGrantCacheKey key = new AuthorizationGrantCacheKey(authCode); + AuthorizationGrantCacheEntry expectedEntry = new AuthorizationGrantCacheEntry(); + expectedEntry.setCodeId(codeId); + + try (MockedStatic mockedFactory = + mockStatic(OAuthTokenPersistenceFactory.class); + MockedStatic mockedSessionDataStore = mockStatic(SessionDataStore.class); + MockedStatic mockedIdentityUtil = mockStatic(IdentityUtil.class)) { + + mockedSessionDataStore.when(SessionDataStore::getInstance).thenReturn(sessionDataStore); + when(sessionDataStore.getSessionData(codeId, "AuthorizationGrantCache")).thenReturn(expectedEntry); + + mockedFactory.when(OAuthTokenPersistenceFactory::getInstance). + thenReturn(mockedOAuthTokenPersistenceFactory); + when(mockedOAuthTokenPersistenceFactory.getAuthorizationCodeDAO()).thenReturn(authorizationCodeDAO); + when(authorizationCodeDAO.getCodeIdByAuthorizationCode(authCode)).thenReturn(codeId); + + AuthorizationGrantCacheEntry result = cache.getValueFromCacheByCode(key); + + assertEquals(expectedEntry, result); + } + } +} diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAOTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAOTest.java index c85de96151a..43313c7c55e 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAOTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/dao/OAuthAppDAOTest.java @@ -20,6 +20,7 @@ import org.apache.commons.lang.StringUtils; import org.mockito.Mock; import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; @@ -41,6 +42,8 @@ import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; import org.wso2.carbon.identity.oauth2.test.utils.CommonTestUtils; +import org.wso2.carbon.identity.organization.management.service.OrganizationManager; +import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException; import org.wso2.carbon.user.api.Tenant; import org.wso2.carbon.user.api.UserRealm; import org.wso2.carbon.user.core.common.AbstractUserStoreManager; @@ -85,6 +88,7 @@ public class OAuthAppDAOTest extends TestOAuthDAOBase { private static final String USER_STORE_DOMAIN = "USER_STORE_DOMAIN_NAME"; private static final String TENANT_DOMAIN = "TENANT_DOMAIN"; private static final String TENANT_DOMAIN_2 = "TENANT_DOMAIN_2"; + private static final String TENANT_DOMAIN_2_ORG_ID = "1234-1234"; private static final String CONSUMER_KEY = "ca19a540f544777860e44e75f605d927"; private static final String CONSUMER_SECRET = "87n9a540f544777860e44e75f605d435"; private static final String APP_NAME = "myApp"; @@ -137,6 +141,9 @@ public class OAuthAppDAOTest extends TestOAuthDAOBase { @Mock OAuthComponentServiceHolder mockOAuthComponentServiceHolder; + @Mock + OrganizationManager mockOrganizationManager; + @BeforeClass public void setUp() throws Exception { initMocks(this); @@ -173,6 +180,34 @@ public void testAddOAuthApplication() throws Exception { } } + @Test + public void testAddOAuthApplicationWithAppResidentOrgId() throws Exception { + + try (MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); + MockedStatic oAuthComponentServiceHolder = + mockStatic(OAuthComponentServiceHolder.class)) { + setupMocksForTest(oAuthServerConfiguration, identityTenantUtil, identityUtil); + // Set the application resident organization id + PrivilegedCarbonContext.getThreadLocalCarbonContext(). + setApplicationResidentOrganizationId(TENANT_DOMAIN_2_ORG_ID); + oAuthComponentServiceHolder.when(OAuthComponentServiceHolder::getInstance) + .thenReturn(mockOAuthComponentServiceHolder); + when(mockOAuthComponentServiceHolder.getOrganizationManager()).thenReturn(mockOrganizationManager); + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)).thenReturn(TENANT_DOMAIN_2); + OAuthAppDO appDO = getDefaultOAuthAppDO(); + try (Connection connection = getConnection(DB_NAME)) { + mockIdentityUtilDataBaseConnection(connection, identityDatabaseUtil); + addOAuthApplication(appDO, TENANT_ID_2); + } + } finally { + resetPrivilegedCarbonContext(); + } + } + /** * Add an OAuth app. This method will be reused in other tests where an OAuth app is required to be present * before the actual test can take place. @@ -290,6 +325,35 @@ public void testAddOAuthApplicationWithExceptions() throws Exception { } } + @Test(expectedExceptions = IdentityOAuthAdminException.class) + public void testAddOAuthApplicationWithAppResidentOrgIdAndWithExceptions() throws Exception { + + try (MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); + MockedStatic oAuthComponentServiceHolder = + mockStatic(OAuthComponentServiceHolder.class)) { + setupMocksForTest(oAuthServerConfiguration, identityTenantUtil, identityUtil); + PrivilegedCarbonContext.getThreadLocalCarbonContext(). + setApplicationResidentOrganizationId(TENANT_DOMAIN_2_ORG_ID); + oAuthComponentServiceHolder.when(OAuthComponentServiceHolder::getInstance) + .thenReturn(mockOAuthComponentServiceHolder); + when(mockOAuthComponentServiceHolder.getOrganizationManager()).thenReturn(mockOrganizationManager); + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)). + thenThrow(new OrganizationManagementException("Error while resolving tenant domain.")); + OAuthAppDO appDO = getDefaultOAuthAppDO(); + try (Connection connection = getConnection(DB_NAME)) { + mockIdentityUtilDataBaseConnection(connection, identityDatabaseUtil); + new OAuthAppDAO().addOAuthApplication(appDO); + } + } finally { + resetPrivilegedCarbonContext(); + Mockito.reset(mockOrganizationManager); + } + } + @Test public void testAddOAuthConsumer() throws Exception { @@ -1004,6 +1068,41 @@ public void testGetAppInformationByAppName() throws Exception { } } + @Test + public void testGetAppInformationByAppNameWithAppResidentOrgId() throws Exception { + + try (MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); + MockedStatic oAuthComponentServiceHolder = + mockStatic(OAuthComponentServiceHolder.class)) { + setupMocksForTest(oAuthServerConfiguration, identityTenantUtil, identityUtil); + try (Connection connection = getConnection(DB_NAME)) { + mockIdentityUtilDataBaseConnection(connection, identityDatabaseUtil); + // Set the application resident organization id + PrivilegedCarbonContext.getThreadLocalCarbonContext(). + setApplicationResidentOrganizationId(TENANT_DOMAIN_2_ORG_ID); + oAuthComponentServiceHolder.when(OAuthComponentServiceHolder::getInstance) + .thenReturn(mockOAuthComponentServiceHolder); + when(mockOAuthComponentServiceHolder.getOrganizationManager()).thenReturn(mockOrganizationManager); + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)).thenReturn(TENANT_DOMAIN_2); + + OAuthAppDO oAuthAppDO = getDefaultOAuthAppDO(); + new OAuthAppDAO().addOAuthApplication(oAuthAppDO); + + OAuthAppDO actualAppDO = new OAuthAppDAO().getAppInformationByAppName(APP_NAME, TENANT_ID); + assertNotNull(actualAppDO); + assertEquals(actualAppDO.getApplicationName(), APP_NAME); + assertEquals(actualAppDO.getOauthConsumerKey(), CONSUMER_KEY); + assertEquals(actualAppDO.getOauthConsumerSecret(), CONSUMER_SECRET); + } + } finally { + resetPrivilegedCarbonContext(); + } + } + @Test(expectedExceptions = IdentityOAuth2Exception.class) public void testGetAppInformationByAppNameWithExceptions() throws Exception { @@ -1030,6 +1129,41 @@ public void testGetAppInformationByAppNameWithExceptions() throws Exception { } } + @Test(expectedExceptions = IdentityOAuth2Exception.class) + public void testGetAppInformationByAppNameWithAppResidentOrgIdAndWithException() throws Exception { + + try (MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class); + MockedStatic oAuthComponentServiceHolder = + mockStatic(OAuthComponentServiceHolder.class)) { + setupMocksForTest(oAuthServerConfiguration, identityTenantUtil, identityUtil); + // Set the application resident organization id + PrivilegedCarbonContext.getThreadLocalCarbonContext(). + setApplicationResidentOrganizationId(TENANT_DOMAIN_2_ORG_ID); + oAuthComponentServiceHolder.when(OAuthComponentServiceHolder::getInstance) + .thenReturn(mockOAuthComponentServiceHolder); + when(mockOAuthComponentServiceHolder.getOrganizationManager()).thenReturn(mockOrganizationManager); + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)).thenReturn(TENANT_DOMAIN_2); + try (Connection connection = getConnection(DB_NAME)) { + + mockIdentityUtilDataBaseConnection(connection, identityDatabaseUtil); + OAuthAppDO oAuthAppDO = getDefaultOAuthAppDO(); + OAuthAppDAO appDAO = new OAuthAppDAO(); + appDAO.addOAuthApplication(oAuthAppDO); + + when(mockOrganizationManager.resolveTenantDomain(TENANT_DOMAIN_2_ORG_ID)).thenThrow( + new OrganizationManagementException("Error while resolving tenant domain.")); + appDAO.getAppInformationByAppName(APP_NAME, TENANT_ID); + } + } finally { + resetPrivilegedCarbonContext(); + Mockito.reset(mockOrganizationManager); + } + } + private OAuthAppDO getDefaultOAuthAppDO() { AuthenticatedUser authenticatedUser = new AuthenticatedUser(); authenticatedUser.setUserName(USER_NAME); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManagerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManagerTest.java index d2612c2abb5..79895798fb3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManagerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/AuthorizationHandlerManagerTest.java @@ -16,6 +16,7 @@ package org.wso2.carbon.identity.oauth2.authz; import org.apache.oltu.oauth2.common.error.OAuthError; +import org.mockito.MockedStatic; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -37,11 +38,13 @@ 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.util.AuthzUtil; import org.wso2.carbon.identity.testutil.IdentityBaseTest; import org.wso2.carbon.user.api.UserStoreException; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; @WithCarbonHome @@ -56,6 +59,7 @@ public class AuthorizationHandlerManagerTest extends IdentityBaseTest { private AuthorizationHandlerManager authorizationHandlerManager; private OAuth2AuthorizeReqDTO authzReqDTO = new OAuth2AuthorizeReqDTO(); private ServiceProvider serviceProvider; + private MockedStatic mockedAuthzUtil; @BeforeClass public void setUp() throws Exception { @@ -70,12 +74,16 @@ public void setUp() throws Exception { when(applicationManagementService.getServiceProviderByClientId(anyString(), anyString(), anyString())) .thenReturn(serviceProvider); authorizationHandlerManager = AuthorizationHandlerManager.getInstance(); + mockedAuthzUtil = mockStatic(AuthzUtil.class); + mockedAuthzUtil.when(AuthzUtil::isLegacyAuthzRuntime).thenReturn(false); } @AfterClass public void tearDown() { CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(null); + mockedAuthzUtil.close(); + } @BeforeMethod diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandlerTest.java index 2765c5ad189..5f09858950d 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/CodeResponseTypeHandlerTest.java @@ -18,6 +18,8 @@ package org.wso2.carbon.identity.oauth2.authz.handlers; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -41,8 +43,10 @@ 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.util.AuthzUtil; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; /** * Test class covering CodeResponseTypeHandler @@ -62,6 +66,7 @@ public class CodeResponseTypeHandlerTest { OAuthAuthzReqMessageContext authAuthzReqMessageContext; OAuth2AuthorizeReqDTO authorizationReqDTO; + private MockedStatic mockedAuthzUtil; @BeforeClass public void init() throws IdentityOAuthAdminException { @@ -69,6 +74,9 @@ public void init() throws IdentityOAuthAdminException { IdentityEventService identityEventService = mock(IdentityEventService.class); CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(identityEventService); new OAuthAppDAO().addOAuthApplication(getDefaultOAuthAppDO()); + Mockito.clearAllCaches(); + mockedAuthzUtil = mockStatic(AuthzUtil.class); + mockedAuthzUtil.when(AuthzUtil::isLegacyAuthzRuntime).thenReturn(false); } @AfterClass @@ -76,6 +84,7 @@ public void clear() throws IdentityOAuthAdminException { CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(null); new OAuthAppDAO().removeConsumerApplication(TEST_CONSUMER_KEY); + mockedAuthzUtil.close(); } @BeforeMethod diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandlerTest.java index 40cabbd9e50..6f4e3ee3bea 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/authz/handlers/TokenResponseTypeHandlerTest.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.oauth2.authz.handlers; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.BeforeTest; @@ -27,6 +28,7 @@ import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.common.testng.WithH2Database; import org.wso2.carbon.identity.common.testng.WithRealmService; +import org.wso2.carbon.identity.oauth.cache.AppInfoCache; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.dao.OAuthAppDAO; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; @@ -38,14 +40,21 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.test.common.testng.utils.MockAuthenticatedUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; + /** * Unit test covering TokenResponseTypeHandler class */ @WithCarbonHome @WithRealmService(injectToSingletons = OAuthComponentServiceHolder.class) -@WithH2Database(files = { "dbScripts/identity.sql" }) +@WithH2Database(files = { "dbScripts/identity.sql", "dbScripts/insert_local_idp.sql" }) public class TokenResponseTypeHandlerTest { private static final String TEST_CLIENT_ID_1 = "SDSDSDS23131231"; @@ -57,6 +66,7 @@ public class TokenResponseTypeHandlerTest { public void setUp() throws Exception { OAuthEventInterceptor interceptor = Mockito.mock(OAuthEventInterceptor.class); OAuthComponentServiceHolder.getInstance().addOauthEventInterceptorProxy(interceptor); + Mockito.clearAllCaches(); } /** @@ -105,10 +115,19 @@ public void testIssue(boolean isIDPIdColumnEnabled, String clientId) throws Exce new OAuthAppDAO().addOAuthApplication(oAuthAppDO); - OAuth2AuthorizeRespDTO auth2AuthorizeReqDTO = tokenResponseTypeHandler. - issue(authAuthzReqMessageContext); - Assert.assertNotNull(auth2AuthorizeReqDTO.getAccessToken()); - Assert.assertTrue(auth2AuthorizeReqDTO.getValidityPeriod() > 1, - "Access Token should be valid, i.e. not expired."); + try (MockedStatic appInfoCache = mockStatic(AppInfoCache.class); + MockedStatic mockedAuthzUtil = mockStatic(AuthzUtil.class)) { + + mockedAuthzUtil.when(AuthzUtil::isLegacyAuthzRuntime).thenReturn(false); + AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); + appInfoCache.when(AppInfoCache::getInstance).thenReturn(mockAppInfoCache); + doNothing().when(mockAppInfoCache).addToCache(anyString(), any(OAuthAppDO.class)); + + OAuth2AuthorizeRespDTO auth2AuthorizeReqDTO = tokenResponseTypeHandler. + issue(authAuthzReqMessageContext); + Assert.assertNotNull(auth2AuthorizeReqDTO.getAccessToken()); + Assert.assertTrue(auth2AuthorizeReqDTO.getValidityPeriod() > 1, + "Access Token should be valid, i.e. not expired."); + } } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandlerTest.java index a11198a8a7d..b23e74675a9 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/AbstractAuthorizationGrantHandlerTest.java @@ -19,6 +19,8 @@ package org.wso2.carbon.identity.oauth2.token.handlers.grant; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -36,6 +38,7 @@ import org.wso2.carbon.identity.common.testng.WithH2Database; import org.wso2.carbon.identity.common.testng.WithRealmService; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.identity.event.services.IdentityEventService; import org.wso2.carbon.identity.oauth.IdentityOAuthAdminException; import org.wso2.carbon.identity.oauth.common.GrantType; @@ -47,11 +50,18 @@ import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.TestConstants; +import org.wso2.carbon.identity.oauth2.dao.AccessTokenDAOImpl; +import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.token.JWTTokenIssuer; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuer; +import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinding; +import org.wso2.carbon.identity.oauth2.util.AuthzUtil; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeHandler; import java.util.Collections; @@ -63,7 +73,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -94,6 +106,7 @@ public class AbstractAuthorizationGrantHandlerTest { "org.wso2.carbon.identity.oauth.callback.DefaultCallbackHandler"; private static final String PASSWORD_GRANT = "password"; private OAuthAppDO oAuthAppDO; + private MockedStatic mockedAuthzUtil; @BeforeMethod public void setUp() throws IdentityOAuth2Exception, IdentityOAuthAdminException, ActionExecutionException { @@ -134,12 +147,68 @@ public void setUpMocks() { IdentityEventService identityEventService = mock(IdentityEventService.class); CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(identityEventService); + Mockito.clearAllCaches(); + mockedAuthzUtil = mockStatic(AuthzUtil.class); + mockedAuthzUtil.when(AuthzUtil::isLegacyAuthzRuntime).thenReturn(false); } @AfterClass public void tearDown() { CentralLogMgtServiceComponentHolder.getInstance().setIdentityEventService(null); + mockedAuthzUtil.close(); + } + + @Test(dataProvider = "IssueWithRenewDataProvider", expectedExceptions = IdentityOAuth2Exception.class) + public void testIssueWithRenewWithoutRevokingExistingEnabled + (boolean cacheEnabled, boolean cacheEntryAvailable, long cachedTokenValidity, + long cachedRefreshTokenValidity, long dbTokenValidity, long dbRefreshTokenValidity, + boolean dbEntryAvailable, String dbTokenState, boolean tokenLoggable, boolean isIDPIdColumnEnabled, + boolean setBindingReference) throws Exception { + + OAuth2ServiceComponentHolder.setIDPIdColumnEnabled(isIDPIdColumnEnabled); + + Map supportedGrantTypes = new HashMap<>(); + supportedGrantTypes.put("refresh_token", refreshGrantHandler); + + OAuth2AccessTokenReqDTO oAuth2AccessTokenReqDTO = new OAuth2AccessTokenReqDTO(); + oAuth2AccessTokenReqDTO.setClientId(clientId); + oAuth2AccessTokenReqDTO.setGrantType(PASSWORD_GRANT); // Ensure the grant type is valid for renewal + + OAuthTokenReqMessageContext tokReqMsgCtx = new OAuthTokenReqMessageContext(oAuth2AccessTokenReqDTO); + tokReqMsgCtx.setAuthorizedUser(authenticatedUser); + tokReqMsgCtx.setScope(new String[]{"scope1", "scope2"}); + + tokReqMsgCtx.addProperty("OAuthAppDO", oAuthAppDO); + + TokenBinding tokenBinding = new TokenBinding(); + if (setBindingReference) { + tokenBinding.setBindingReference("bindingReference"); + } + tokReqMsgCtx.setTokenBinding(tokenBinding); + + // Mocking static methods using try-with-resources + try (MockedStatic identityUtil = mockStatic(IdentityUtil.class); + MockedStatic oauth2Util = mockStatic(OAuth2Util.class)) { + + identityUtil.when(() -> IdentityUtil.getProperty(anyString())) + .thenReturn(Boolean.TRUE.toString()); + + OAuthComponentServiceHolder.getInstance().setActionExecutorService(mockActionExecutionService); + OAuthTokenPersistenceFactory persistenceFactory = mock(OAuthTokenPersistenceFactory.class); + when(persistenceFactory.getAccessTokenDAO()).thenReturn(new AccessTokenDAOImpl()); + + OauthTokenIssuer oauthTokenIssuer = mock(JWTTokenIssuer.class); + when(oauthTokenIssuer.getAccessTokenType()).thenReturn("jwt"); + oauth2Util.when(() -> OAuth2Util.getOAuthTokenIssuerForOAuthApp(clientId)).thenReturn(oauthTokenIssuer); + oauth2Util.when(() -> OAuth2Util.getAppInformationByClientId(clientId)).thenReturn(oAuthAppDO); + + // Set allowed grant types (ensure PASSWORD_GRANT is allowed for renewal) + OAuth2ServiceComponentHolder.setJwtRenewWithoutRevokeAllowedGrantTypes( + Collections.singletonList("password")); // This allows PASSWORD_GRANT + + OAuth2AccessTokenRespDTO tokenRespDTO = handler.issue(tokReqMsgCtx); + } } @DataProvider(name = "IssueDataProvider") @@ -174,6 +243,14 @@ public Object[][] issueDataProvider() { {false, true, 0L, 0L, -1L, 3600L, true, TOKEN_STATE_ACTIVE, true, false}}; } + @DataProvider(name = "IssueWithRenewDataProvider") + public Object[][] issueWithRenewDataProvider() { + return new Object[][]{ + {true, true, 3600L, 3600L, 0L, 0L, false, TOKEN_STATE_ACTIVE, false, true, true}, + {true, true, 3600L, 3600L, 0L, 0L, false, TOKEN_STATE_ACTIVE, false, true, false} + }; + } + @Test(dataProvider = "IssueDataProvider") public void testIssue(boolean cacheEnabled, boolean cacheEntryAvailable, long cachedTokenValidity, long cachedRefreshTokenValidity, long dbTokenValidity, long dbRefreshTokenValidity, diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/PasswordGrantHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/PasswordGrantHandlerTest.java index 8ce32831868..b33606f2d2d 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/PasswordGrantHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/token/handlers/grant/PasswordGrantHandlerTest.java @@ -22,6 +22,8 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.config.builder.FileBasedConfigurationBuilder; +import org.wso2.carbon.identity.application.authentication.framework.config.model.AuthenticatorConfig; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; import org.wso2.carbon.identity.application.common.model.LocalAndOutboundAuthenticationConfig; @@ -48,6 +50,9 @@ import org.wso2.carbon.user.core.util.UserCoreUtil; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; +import java.util.HashMap; +import java.util.Map; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -57,6 +62,7 @@ import static org.mockito.Mockito.when; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.SHOW_AUTHFAILURE_RESON_CONFIG; import static org.wso2.carbon.user.core.UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME; public class PasswordGrantHandlerTest { @@ -64,6 +70,7 @@ public class PasswordGrantHandlerTest { private OAuthTokenReqMessageContext tokReqMsgCtx; private OAuth2AccessTokenReqDTO oAuth2AccessTokenReqDTO; private ApplicationManagementService applicationManagementService; + private FileBasedConfigurationBuilder fileBasedConfigurationBuilder; private ServiceProvider serviceProvider; private OAuthComponentServiceHolder oAuthComponentServiceHolder; private RealmService realmService; @@ -81,6 +88,7 @@ public void init() { tokReqMsgCtx = mock(OAuthTokenReqMessageContext.class); oAuth2AccessTokenReqDTO = mock(OAuth2AccessTokenReqDTO.class); applicationManagementService = mock(ApplicationManagementService.class); + fileBasedConfigurationBuilder = mock(FileBasedConfigurationBuilder.class); serviceProvider = mock(ServiceProvider.class); oAuthComponentServiceHolder = mock(OAuthComponentServiceHolder.class); realmService = mock(RealmService.class); @@ -108,7 +116,18 @@ public void testValidateGrant(String username, boolean isSaas) throws Exception MockedStatic multitenantUtils = mockStatic(MultitenantUtils.class); MockedStatic userCoreUtil = mockStatic(UserCoreUtil.class); MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) { + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic fileBasedConfigBuilder = mockStatic( + FileBasedConfigurationBuilder.class)) { + + fileBasedConfigBuilder.when(FileBasedConfigurationBuilder::getInstance) + .thenReturn(fileBasedConfigurationBuilder); + AuthenticatorConfig basicAuthenticatorConfig = new AuthenticatorConfig(); + Map parameterMap = new HashMap<>(); + parameterMap.put(SHOW_AUTHFAILURE_RESON_CONFIG, "false"); + basicAuthenticatorConfig.setParameterMap(parameterMap); + when(fileBasedConfigurationBuilder.getAuthenticatorBean(anyString())).thenReturn( + basicAuthenticatorConfig); when(tokReqMsgCtx.getOauth2AccessTokenReqDTO()).thenReturn(oAuth2AccessTokenReqDTO); when(oAuth2AccessTokenReqDTO.getResourceOwnerUsername()).thenReturn(username + "wso2.com"); @@ -191,7 +210,18 @@ public void testValidateGrantForException(String tenantDomain, boolean authentic MockedStatic multitenantUtils = mockStatic(MultitenantUtils.class); MockedStatic identityUtil = mockStatic(IdentityUtil.class); MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); - MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) { + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic fileBasedConfigBuilder = mockStatic( + FileBasedConfigurationBuilder.class)) { + + fileBasedConfigBuilder.when(FileBasedConfigurationBuilder::getInstance) + .thenReturn(fileBasedConfigurationBuilder); + AuthenticatorConfig basicAuthenticatorConfig = new AuthenticatorConfig(); + Map parameterMap = new HashMap<>(); + parameterMap.put(SHOW_AUTHFAILURE_RESON_CONFIG, "false"); + basicAuthenticatorConfig.setParameterMap(parameterMap); + when(fileBasedConfigurationBuilder.getAuthenticatorBean(anyString())).thenReturn( + basicAuthenticatorConfig); oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance).thenReturn(serverConfiguration); when(serverConfiguration.getIdentityOauthTokenIssuer()).thenReturn(oauthIssuer); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java index 16b1a61d69c..7f05221ccf6 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java @@ -2232,12 +2232,13 @@ public void testGetOAuthTokenIssuerForOAuthApp(String tokenType) throws Exceptio appDO.setTokenType(tokenType); AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); - when(mockAppInfoCache.getValueFromCache(clientId)).thenReturn(appDO); + when(mockAppInfoCache.getValueFromCache(clientId, clientTenantDomain)).thenReturn(appDO); appInfoCache.when(AppInfoCache::getInstance).thenReturn(mockAppInfoCache); OauthTokenIssuer oauthTokenIssuer = mock(OauthTokenIssuer.class); when(oauthServerConfigurationMock.getIdentityOauthTokenIssuer()).thenReturn(oauthTokenIssuer); + identityTenantUtil.when(IdentityTenantUtil::resolveTenantDomain).thenReturn(clientTenantDomain); assertEquals(OAuth2Util.getOAuthTokenIssuerForOAuthApp(clientId), oauthTokenIssuer); } } @@ -2247,11 +2248,12 @@ public void testGetOAuthTokenIssuerForOAuthAppWithException() { try (MockedStatic appInfoCache = mockStatic(AppInfoCache.class)) { AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); - when(mockAppInfoCache.getValueFromCache(clientId)). + when(mockAppInfoCache.getValueFromCache(clientId, clientTenantDomain)). thenAnswer(i -> { throw new IdentityOAuth2Exception("IdentityOAuth2Exception"); }); appInfoCache.when(AppInfoCache::getInstance).thenReturn(mockAppInfoCache); + identityTenantUtil.when(IdentityTenantUtil::resolveTenantDomain).thenReturn(clientTenantDomain); try { OAuth2Util.getOAuthTokenIssuerForOAuthApp(clientId); @@ -2603,7 +2605,7 @@ private void setCache(MockedStatic appInfoCache) { appDO.setUser(user); AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); - lenient().when(mockAppInfoCache.getValueFromCache(clientId)).thenReturn(appDO); + lenient().when(mockAppInfoCache.getValueFromCache(clientId, SUPER_TENANT_DOMAIN_NAME)).thenReturn(appDO); appInfoCache.when(AppInfoCache::getInstance).thenReturn(mockAppInfoCache); } @@ -2612,7 +2614,7 @@ public void testGetServiceProviderWithIdentityInvalidOAuthClientException() { try (MockedStatic appInfoCache = mockStatic(AppInfoCache.class)) { AppInfoCache mockAppInfoCache = mock(AppInfoCache.class); - when(mockAppInfoCache.getValueFromCache(clientId)). + when(mockAppInfoCache.getValueFromCache(clientId, SUPER_TENANT_DOMAIN_NAME)). thenAnswer(i -> { throw new InvalidOAuthClientException("InvalidOAuthClientException"); }); diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java index e1ad12bad81..e69e9458283 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java @@ -32,6 +32,7 @@ import org.mockito.Mockito; import org.mockito.stubbing.Answer; import org.mockito.testng.MockitoTestNGListener; +import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeTest; @@ -43,6 +44,7 @@ import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; +import org.wso2.carbon.identity.application.common.model.ClaimMapping; import org.wso2.carbon.identity.application.common.model.PermissionsAndRoleConfig; import org.wso2.carbon.identity.application.common.model.ServiceProvider; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; @@ -51,13 +53,20 @@ import org.wso2.carbon.identity.core.persistence.JDBCPersistenceManager; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCache; +import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCacheEntry; +import org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCacheKey; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.TestConstants; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; +import org.wso2.carbon.identity.oauth2.token.handlers.grant.saml.SAML2BearerGrantHandlerTest; import org.wso2.carbon.identity.oauth2.util.AuthzUtil; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.openidconnect.dao.CacheBackedScopeClaimMappingDAOImpl; @@ -244,11 +253,19 @@ public void testHandleCustomClaimsWithoutRegisteredOIDCClaimsForOAuthTokenReqMsg oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) .thenReturn(oauthServerConfigurationMock); try (MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); - MockedStatic claimMetadataHandler = mockStatic(ClaimMetadataHandler.class)) { - claimMetadataHandler.when(ClaimMetadataHandler::getInstance).thenReturn(this.mockClaimMetadataHandler); + MockedStatic claimMetadataHandler = mockStatic(ClaimMetadataHandler.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic authzUtil = mockStatic(AuthzUtil.class)) { + claimMetadataHandler.when(ClaimMetadataHandler::getInstance).thenReturn(mockClaimMetadataHandler); + lenient().when(mockClaimMetadataHandler.getMappingsMapFromOtherDialectToCarbon( + anyString(), isNull(), anyString(), anyBoolean())).thenReturn(new HashMap<>()); oAuth2Util.when(() -> OAuth2Util.getAppInformationByClientId(any(), any())).thenReturn( getoAuthAppDO(jwtAccessTokenClaims)); + mockApplicationManagementService(); OAuthTokenReqMessageContext requestMsgCtx = getTokenReqMessageContextForLocalUser(); + authzUtil.when(() -> AuthzUtil.getUserRoles(any(), anyString())).thenReturn(new ArrayList<>()); + UserRealm userRealm = getUserRealmWithUserClaims(USER_CLAIMS_MAP); + mockUserRealm(requestMsgCtx.getAuthorizedUser().toString(), userRealm, identityTenantUtil); JWTClaimsSet.Builder jwtClaimsSetBuilder = new JWTClaimsSet.Builder(); JWTClaimsSet jwtClaimsSet = getJwtClaimSet(jwtClaimsSetBuilder, requestMsgCtx, jdbcPersistenceManager, oAuthServerConfiguration); @@ -364,6 +381,107 @@ public void testHandleCustomClaimsWithAddressClaimForOAuthTokenReqMsgContext() t } } + @Test + public void testHandleCustomClaimsForOAuthAuthzReqMsgContext() throws Exception { + + try (MockedStatic jdbcPersistenceManager = mockStatic(JDBCPersistenceManager.class); + MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic claimMetadataHandler = mockStatic(ClaimMetadataHandler.class)) { + OAuthServerConfiguration oauthServerConfigurationMock = mock(OAuthServerConfiguration.class); + oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) + .thenReturn(oauthServerConfigurationMock); + try (MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); + MockedStatic authzUtil = mockStatic(AuthzUtil.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class, Mockito.CALLS_REAL_METHODS)) { + identityUtil.when(IdentityUtil::isGroupsVsRolesSeparationImprovementsEnabled).thenReturn(true); + oAuth2Util.when(() -> OAuth2Util.getAppInformationByClientId(any(), any())).thenReturn( + getoAuthAppDO(jwtAccessTokenClaims)); + Map mappings = getOIDCtoLocalClaimsMapping(); + claimMetadataHandler.when(ClaimMetadataHandler::getInstance).thenReturn(mockClaimMetadataHandler); + lenient().when(mockClaimMetadataHandler.getMappingsMapFromOtherDialectToCarbon( + anyString(), isNull(), anyString(), anyBoolean())).thenReturn(mappings); + OAuthAuthzReqMessageContext requestMsgCtx = getOAuthAuthzReqMessageContextForLocalUser(); + mockApplicationManagementService(); + authzUtil.when(() -> AuthzUtil.getUserRoles(any(), anyString())).thenReturn(new ArrayList<>()); + UserRealm userRealm = getUserRealmWithUserClaims(USER_CLAIMS_MAP); + mockUserRealm(requestMsgCtx.getAuthorizationReqDTO().getUser().toString(), userRealm, + identityTenantUtil); + JWTClaimsSet.Builder jwtClaimsSetBuilder = new JWTClaimsSet.Builder(); + JWTClaimsSet jwtClaimsSet = getJwtClaimSet(jwtClaimsSetBuilder, requestMsgCtx, jdbcPersistenceManager, + oAuthServerConfiguration); + assertNotNull(jwtClaimsSet); + assertFalse(jwtClaimsSet.getClaims().isEmpty()); + } + } + } + + @Test + public void testHandleClaimsForOAuthTokenReqMessageContextWithAuthorizationCode() throws Exception { + + try (MockedStatic jdbcPersistenceManager = mockStatic(JDBCPersistenceManager.class); + MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic claimMetadataHandler = mockStatic(ClaimMetadataHandler.class)) { + OAuthServerConfiguration oauthServerConfigurationMock = mock(OAuthServerConfiguration.class); + oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) + .thenReturn(oauthServerConfigurationMock); + try (MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); + MockedStatic authzUtil = mockStatic(AuthzUtil.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class, Mockito.CALLS_REAL_METHODS)) { + MockedStatic authorizationGrantCache = + mockStatic(AuthorizationGrantCache.class); + identityUtil.when(IdentityUtil::isGroupsVsRolesSeparationImprovementsEnabled).thenReturn(true); + authzUtil.when(() -> AuthzUtil.getUserRoles(any(), anyString())).thenReturn(new ArrayList<>()); + oAuth2Util.when(() -> OAuth2Util.getAppInformationByClientId(any(), any())).thenReturn( + getoAuthAppDO(jwtAccessTokenClaims)); + Map mappings = getOIDCtoLocalClaimsMapping(); + claimMetadataHandler.when(ClaimMetadataHandler::getInstance).thenReturn(mockClaimMetadataHandler); + lenient().when(mockClaimMetadataHandler.getMappingsMapFromOtherDialectToCarbon( + anyString(), isNull(), anyString(), anyBoolean())).thenReturn(mappings); + Map userAttributes = new HashMap<>(); + OAuthTokenReqMessageContext requestMsgCtx = getTokenReqMessageContextForFederatedUser(userAttributes); + requestMsgCtx.addProperty("AuthorizationCode", "dummyAuthorizationCode"); + Map federatedUserAttributes = new HashMap<>(); + federatedUserAttributes.put(SAML2BearerGrantHandlerTest.buildClaimMapping("country"), + TestConstants.CLAIM_VALUE1); + federatedUserAttributes.put(SAML2BearerGrantHandlerTest.buildClaimMapping("email"), + TestConstants.CLAIM_VALUE2); + AuthorizationGrantCacheEntry authorizationGrantCacheEntry = new + AuthorizationGrantCacheEntry(); + authorizationGrantCacheEntry.setMappedRemoteClaims(federatedUserAttributes); + mockAuthorizationGrantCache(authorizationGrantCacheEntry, authorizationGrantCache); + + UserRealm userRealm = getUserRealmWithUserClaims(USER_CLAIMS_MAP); + mockUserRealm(requestMsgCtx.getAuthorizedUser().toString(), userRealm, identityTenantUtil); + JWTClaimsSet.Builder jwtClaimsSetBuilder = new JWTClaimsSet.Builder(); + JWTClaimsSet jwtClaimsSet = getJwtClaimSet(jwtClaimsSetBuilder, requestMsgCtx, jdbcPersistenceManager, + oAuthServerConfiguration); + assertNotNull(jwtClaimsSet, "JWT Custom claim handling failed."); + assertFalse(jwtClaimsSet.getClaims().isEmpty(), "JWT custom claim handling failed"); + Assert.assertEquals(jwtClaimsSet.getClaims().size(), 2, + "Expected custom claims are not set."); + Assert.assertEquals(jwtClaimsSet.getClaim("email"), TestConstants.CLAIM_VALUE2, + "OIDC claim email is not added with the JWT token"); + } + } + } + + private void mockAuthorizationGrantCache(AuthorizationGrantCacheEntry authorizationGrantCacheEntry, + MockedStatic authorizationGrantCache) { + + AuthorizationGrantCache mockAuthorizationGrantCache = mock(AuthorizationGrantCache.class); + + if (authorizationGrantCacheEntry == null) { + authorizationGrantCacheEntry = mock(AuthorizationGrantCacheEntry.class); + } + authorizationGrantCache.when(AuthorizationGrantCache::getInstance).thenReturn(mockAuthorizationGrantCache); + lenient().when(mockAuthorizationGrantCache.getValueFromCacheByCode(any(AuthorizationGrantCacheKey.class))). + thenReturn(authorizationGrantCacheEntry); + } + private static Map getOIDCtoLocalClaimsMapping() { Map mappings = new HashMap<>(); @@ -405,6 +523,26 @@ private JWTClaimsSet getJwtClaimSet(JWTClaimsSet.Builder jwtClaimsSetBuilder, MockedStatic oAuthServerConfiguration) throws IdentityOAuth2Exception { + JWTAccessTokenOIDCClaimsHandler jWTAccessTokenOIDCClaimsHandler = + getJwtAccessTokenOIDCClaimsHandler(jdbcPersistenceManager, oAuthServerConfiguration); + return jWTAccessTokenOIDCClaimsHandler.handleCustomClaims(jwtClaimsSetBuilder, requestMsgCtx); + } + + private JWTClaimsSet getJwtClaimSet(JWTClaimsSet.Builder jwtClaimsSetBuilder, + OAuthAuthzReqMessageContext requestMsgCtx, + MockedStatic jdbcPersistenceManager, + MockedStatic oAuthServerConfiguration) + throws IdentityOAuth2Exception { + + JWTAccessTokenOIDCClaimsHandler jWTAccessTokenOIDCClaimsHandler = + getJwtAccessTokenOIDCClaimsHandler(jdbcPersistenceManager, oAuthServerConfiguration); + return jWTAccessTokenOIDCClaimsHandler.handleCustomClaims(jwtClaimsSetBuilder, requestMsgCtx); + } + + private JWTAccessTokenOIDCClaimsHandler getJwtAccessTokenOIDCClaimsHandler( + MockedStatic jdbcPersistenceManager, + MockedStatic oAuthServerConfiguration) { + OAuthServerConfiguration mockOAuthServerConfiguration = mock(OAuthServerConfiguration.class); oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance).thenReturn(mockOAuthServerConfiguration); DataSource dataSource = mock(DataSource.class); @@ -432,9 +570,7 @@ private JWTClaimsSet getJwtClaimSet(JWTClaimsSet.Builder jwtClaimsSetBuilder, jdbcPersistenceManager.when(JDBCPersistenceManager::getInstance).thenReturn(mockJdbcPersistenceManager); lenient().when(mockJdbcPersistenceManager.getDataSource()).thenReturn(dataSource); - JWTAccessTokenOIDCClaimsHandler jWTAccessTokenOIDCClaimsHandler = - new JWTAccessTokenOIDCClaimsHandler(); - return jWTAccessTokenOIDCClaimsHandler.handleCustomClaims(jwtClaimsSetBuilder, requestMsgCtx); + return new JWTAccessTokenOIDCClaimsHandler(); } private OAuthTokenReqMessageContext getTokenReqMessageContextForLocalUser() { @@ -448,6 +584,38 @@ private OAuthTokenReqMessageContext getTokenReqMessageContextForLocalUser() { return requestMsgCtx; } + /** + * To get token request message context for federates user. + * + * @param userAttributes Relevant user attributes need to be added to authenticates user. + * @return relevant token request context for federated authenticated user. + */ + private OAuthTokenReqMessageContext getTokenReqMessageContextForFederatedUser(Map userAttributes) { + + OAuth2AccessTokenReqDTO accessTokenReqDTO = new OAuth2AccessTokenReqDTO(); + accessTokenReqDTO.setTenantDomain(TENANT_DOMAIN); + accessTokenReqDTO.setClientId(DUMMY_CLIENT_ID); + OAuthTokenReqMessageContext requestMsgCtx = new OAuthTokenReqMessageContext(accessTokenReqDTO); + requestMsgCtx.addProperty(MultitenantConstants.TENANT_DOMAIN, TENANT_DOMAIN); + AuthenticatedUser authenticatedUser = getDefaultAuthenticatedUserFederatedUser(); + + if (userAttributes != null) { + authenticatedUser.setUserAttributes(userAttributes); + } + requestMsgCtx.setAuthorizedUser(authenticatedUser); + return requestMsgCtx; + } + + private AuthenticatedUser getDefaultAuthenticatedUserFederatedUser() { + + AuthenticatedUser authenticatedUser = new AuthenticatedUser(); + authenticatedUser.setUserName(USER_NAME); + authenticatedUser.setUserId(StringUtils.EMPTY); + authenticatedUser.setFederatedUser(true); + return authenticatedUser; + } + private AuthenticatedUser getDefaultAuthenticatedLocalUser() { AuthenticatedUser authenticatedUser = new AuthenticatedUser(); @@ -515,4 +683,13 @@ private void setPrivateField(Object object, String fieldName, Object value) thro field.set(object, value); } + private OAuthAuthzReqMessageContext getOAuthAuthzReqMessageContextForLocalUser() { + + OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO = new OAuth2AuthorizeReqDTO(); + oAuth2AuthorizeReqDTO.setTenantDomain(TENANT_DOMAIN); + oAuth2AuthorizeReqDTO.setConsumerKey(DUMMY_CLIENT_ID); + oAuth2AuthorizeReqDTO.setUser(getDefaultAuthenticatedLocalUser()); + + return new OAuthAuthzReqMessageContext(oAuth2AuthorizeReqDTO); + } } 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 0f4c1fe1ed3..a31ffda9146 100755 --- a/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml @@ -124,6 +124,7 @@ + @@ -199,6 +200,8 @@ + + diff --git a/components/org.wso2.carbon.identity.oidc.dcr/pom.xml b/components/org.wso2.carbon.identity.oidc.dcr/pom.xml index cbb88cdd6ee..e6ad3385ae9 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.191-SNAPSHOT + 7.0.214-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 b66c5e99100..45a50012d92 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.191-SNAPSHOT + 7.0.214-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 2af3e18fe22..f880315572e 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.191-SNAPSHOT + 7.0.214-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 30d86deec91..e4a278211b6 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.191-SNAPSHOT + 7.0.214-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 2b4701289e0..60650366df9 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.191-SNAPSHOT + 7.0.214-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 9bd8f21171f..866005fd40e 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.191-SNAPSHOT + 7.0.214-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 0f18fd95027..8cbace2e18a 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.191-SNAPSHOT + 7.0.214-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 58f6608032b..2a03fd48578 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 49bb4558418..d7a3df77500 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.191-SNAPSHOT + 7.0.214-SNAPSHOT pom WSO2 Carbon OAuth module http://wso2.org @@ -209,11 +209,6 @@ org.wso2.carbon.identity.application.common ${carbon.identity.framework.version} - - org.wso2.carbon.identity.framework - org.wso2.carbon.identity.entitlement - ${carbon.identity.framework.version} - org.wso2.carbon.identity.framework org.wso2.carbon.identity.application.authentication.framework @@ -571,11 +566,6 @@ jackson-databind ${jackson-databind.version} - - org.springframework - spring-web - ${spring-web.version} - io.swagger swagger-jaxrs @@ -670,6 +660,16 @@ tomcat-coyote ${tomcat.version} + + org.apache.httpcomponents.wso2 + httpcore + ${httpcore.version} + + + org.wso2.orbit.org.apache.httpcomponents + httpclient + ${httpcomponents-httpclient.wso2.version} + javax.ws.rs javax.ws.rs-api @@ -933,15 +933,16 @@ 1.2.4 - 4.10.22 + 4.10.26 4.10.22 [4.10.22, 5.0.0) [1.0.1, 2.0.0) - 7.6.0 + 7.7.49 [5.25.234, 8.0.0) + [2.0.0, 3.0.0) 1.4.7 @@ -1010,7 +1011,7 @@ [3.0.0.wso2v1, 4.0.0) 3.3.1 - 3.3.1.wso2v11 + 3.3.1.wso2v12 [3.3.1,3.4.0) 2.9.4 @@ -1020,6 +1021,9 @@ 9.0.96 [9.0.0, 9.5.0) + 4.3.3.wso2v1 + [4.3.0, 5.0.0) + 4.3.6.wso2v2 3.5.9 1.2.0.wso2v1 1.1.wso2v1 @@ -1044,7 +1048,6 @@ 2.16.1 2.16.1 - 4.3.29.RELEASE 1.6.2 [2.13.0, 3.0.0) @@ -1062,7 +1065,6 @@ 0.9.5 5.7.0 - 5.1.1.RELEASE 1.10.1 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 e9bc4baa8d2..51a66c8a521 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.191-SNAPSHOT + 7.0.214-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 58d4621e800..278a0dd428f 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.191-SNAPSHOT + 7.0.214-SNAPSHOT 4.0.0