From 6fcbf445acb3d2fbd4d4f6f00e0bb42487f194f5 Mon Sep 17 00:00:00 2001 From: Vivekvinushanth Christopher <32198547+VivekVinushanth@users.noreply.github.com> Date: Wed, 29 May 2024 11:59:35 +0530 Subject: [PATCH] Block access for apps ifAccessDisabled (#5707) * Block access for apps at fw ifAapplicationDisabled * Update returning logic * address comments * Update unit tests --- .../common/model/ServiceProvider.java | 23 ++-- .../util/IdentityApplicationConstants.java | 4 +- .../mgt/dao/impl/ApplicationDAOImpl.java | 26 ++--- .../framework/AuthenticationService.java | 11 +- .../impl/DefaultRequestCoordinator.java | 34 ++++++ .../framework/util/FrameworkConstants.java | 2 + .../auth/service/AuthServiceConstants.java | 4 + .../framework/AuthenticationServiceTest.java | 41 +++++++ .../impl/DefaultRequestCoordinatorTest.java | 110 ++++++++++++++++++ .../IdentityApplicationManagementService.wsdl | 2 +- 10 files changed, 229 insertions(+), 28 deletions(-) diff --git a/components/application-mgt/org.wso2.carbon.identity.application.common/src/main/java/org/wso2/carbon/identity/application/common/model/ServiceProvider.java b/components/application-mgt/org.wso2.carbon.identity.application.common/src/main/java/org/wso2/carbon/identity/application/common/model/ServiceProvider.java index a2040c894274..e34c66e8b831 100644 --- a/components/application-mgt/org.wso2.carbon.identity.application.common/src/main/java/org/wso2/carbon/identity/application/common/model/ServiceProvider.java +++ b/components/application-mgt/org.wso2.carbon.identity.application.common/src/main/java/org/wso2/carbon/identity/application/common/model/ServiceProvider.java @@ -53,7 +53,7 @@ public class ServiceProvider implements Serializable { private static final String IS_MANAGEMENT_APP = "IsManagementApp"; private static final String IS_B2B_SELF_SERVICE_APP = "IsB2BSelfServiceApp"; - private static final String IS_APPLICATION_ACCESS_ENABLED = "applicationEnabled"; + private static final String IS_APPLICATION_ENABLED = "IsApplicationEnabled"; private static final String ASSOCIATED_ROLES_CONFIG = "AssociatedRolesConfig"; private static final String IS_API_BASED_AUTHENTICATION_ENABLED = "IsAPIBasedAuthenticationEnabled"; @@ -142,8 +142,8 @@ public class ServiceProvider implements Serializable { private AssociatedRolesConfig associatedRolesConfig; @IgnoreNullElement - @XmlElement(name = IS_APPLICATION_ACCESS_ENABLED) - private boolean isApplicationAccessEnabled = true; + @XmlElement(name = IS_APPLICATION_ENABLED) + private boolean isApplicationEnabled = true; @IgnoreNullElement @XmlElement(name = IS_API_BASED_AUTHENTICATION_ENABLED) @@ -170,7 +170,7 @@ public static ServiceProvider build(OMElement serviceProviderOM) { // by default set to true. serviceProvider.setSaasApp(true); - serviceProvider.setApplicationAccessEnabled(true); + serviceProvider.setApplicationEnabled(true); Iterator iter = serviceProviderOM.getChildElements(); @@ -278,11 +278,11 @@ public static ServiceProvider build(OMElement serviceProviderOM) { } else if (ASSOCIATED_ROLES_CONFIG.equals(elementName)) { // build role association. serviceProvider.setAssociatedRolesConfig(AssociatedRolesConfig.build(element)); - } else if (IS_APPLICATION_ACCESS_ENABLED.equals(elementName)) { + } else if (IS_APPLICATION_ENABLED.equals(elementName)) { if (element.getText() != null && "true".equals(element.getText())) { - serviceProvider.setApplicationAccessEnabled(true); + serviceProvider.setApplicationEnabled(true); } else { - serviceProvider.setApplicationAccessEnabled(!"false".equals(element.getText())); + serviceProvider.setApplicationEnabled(!"false".equals(element.getText())); } } } @@ -614,13 +614,14 @@ public void setClientAttestationMetaData(ClientAttestationMetaData clientAttesta this.clientAttestationMetaData = clientAttestationMetaData; } - public boolean isApplicationAccessEnabled() { - return isApplicationAccessEnabled; + public boolean isApplicationEnabled() { + + return isApplicationEnabled; } - public void setApplicationAccessEnabled(boolean applicationAccessEnabled) { + public void setApplicationEnabled(boolean applicationEnabled) { - this.isApplicationAccessEnabled = applicationAccessEnabled; + this.isApplicationEnabled = applicationEnabled; } } diff --git a/components/application-mgt/org.wso2.carbon.identity.application.common/src/main/java/org/wso2/carbon/identity/application/common/util/IdentityApplicationConstants.java b/components/application-mgt/org.wso2.carbon.identity.application.common/src/main/java/org/wso2/carbon/identity/application/common/util/IdentityApplicationConstants.java index dead06983942..933c37912070 100644 --- a/components/application-mgt/org.wso2.carbon.identity.application.common/src/main/java/org/wso2/carbon/identity/application/common/util/IdentityApplicationConstants.java +++ b/components/application-mgt/org.wso2.carbon.identity.application.common/src/main/java/org/wso2/carbon/identity/application/common/util/IdentityApplicationConstants.java @@ -122,8 +122,8 @@ private IdentityApplicationConstants() { public static final String IS_API_BASED_AUTHENTICATION_ENABLED_DISPLAY_NAME = "Is API Based Authentication Enabled"; public static final String IS_ATTESTATION_ENABLED_PROPERTY_NAME = "IsAttestationEnabled"; public static final String IS_ATTESTATION_ENABLED_DISPLAY_NAME = "Is Client Attestation Enabled"; - public static final String IS_APPLICATION_ACCESS_ENABLED_PROPERTY_NAME = "applicationEnabled"; - public static final String IS_APPLICATION_ACCESS_ENABLED_DISPLAY_NAME = "Application Enabled"; + public static final String IS_APPLICATION_ENABLED_PROPERTY_NAME = "IsApplicationEnabled"; + public static final String IS_APPLICATION_ENABLED_DISPLAY_NAME = "Is Application Enabled"; public static final String ANDROID_PACKAGE_NAME_PROPERTY_NAME = "androidPackageName"; public static final String ANDROID_PACKAGE_NAME_DISPLAY_NAME = "Android mobile application package name"; public static final String APPLE_APP_ID_PROPERTY_NAME = "appleAppId"; diff --git a/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/dao/impl/ApplicationDAOImpl.java b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/dao/impl/ApplicationDAOImpl.java index 2514756401e6..b25d17bfe430 100644 --- a/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/dao/impl/ApplicationDAOImpl.java +++ b/components/application-mgt/org.wso2.carbon.identity.application.mgt/src/main/java/org/wso2/carbon/identity/application/mgt/dao/impl/ApplicationDAOImpl.java @@ -149,8 +149,8 @@ import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.ISSUER_SP_PROPERTY_NAME; import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_API_BASED_AUTHENTICATION_ENABLED_DISPLAY_NAME; import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_API_BASED_AUTHENTICATION_ENABLED_PROPERTY_NAME; -import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_APPLICATION_ACCESS_ENABLED_DISPLAY_NAME; -import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_APPLICATION_ACCESS_ENABLED_PROPERTY_NAME; +import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_APPLICATION_ENABLED_DISPLAY_NAME; +import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_APPLICATION_ENABLED_PROPERTY_NAME; import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_ATTESTATION_ENABLED_DISPLAY_NAME; import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_ATTESTATION_ENABLED_PROPERTY_NAME; import static org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants.IS_B2B_SS_APP_SP_PROPERTY_DISPLAY_NAME; @@ -2182,7 +2182,7 @@ public ServiceProvider getApplication(int applicationId) throws IdentityApplicat serviceProvider.setJwksUri(getJwksUri(propertyList)); serviceProvider.setTemplateId(getTemplateId(propertyList)); - serviceProvider.setApplicationAccessEnabled(getAppAccessEnabled(propertyList)); + serviceProvider.setApplicationEnabled(getIsApplicationEnabled(propertyList)); serviceProvider.setManagementApp(getIsManagementApp(propertyList)); serviceProvider.setB2BSelfServiceApp(getIsB2BSSApp(propertyList)); serviceProvider.setAPIBasedAuthenticationEnabled(getIsAPIBasedAuthenticationEnabled(propertyList)); @@ -2435,10 +2435,10 @@ private boolean getIsB2BSSApp(List propertyList) { return Boolean.parseBoolean(value); } - private boolean getAppAccessEnabled(List propertyList) { + private boolean getIsApplicationEnabled(List propertyList) { String value = propertyList.stream() - .filter(property -> IS_APPLICATION_ACCESS_ENABLED_PROPERTY_NAME.equals(property.getName())) + .filter(property -> IS_APPLICATION_ENABLED_PROPERTY_NAME.equals(property.getName())) .findFirst() .map(ServiceProviderProperty::getValue) .orElse("true"); @@ -5151,8 +5151,8 @@ private void updateConfigurationsAsServiceProperties(ServiceProvider sp) ServiceProviderProperty isB2BSSAppProperty = buildIsB2BSSAppProperty(sp); spPropertyMap.put(isB2BSSAppProperty.getName(), isB2BSSAppProperty); - ServiceProviderProperty isApplicationAccessEnabledProperty = buildIsApplicationAccessEnabledProperty(sp); - spPropertyMap.put(isApplicationAccessEnabledProperty.getName(), isApplicationAccessEnabledProperty); + ServiceProviderProperty isApplicationEnabledProperty = buildIsApplicationEnabledProperty(sp); + spPropertyMap.put(isApplicationEnabledProperty.getName(), isApplicationEnabledProperty); ServiceProviderProperty allowedRoleAudienceProperty = buildAllowedRoleAudienceProperty(sp); spPropertyMap.put(allowedRoleAudienceProperty.getName(), allowedRoleAudienceProperty); @@ -5273,13 +5273,13 @@ private ServiceProviderProperty buildIsB2BSSAppProperty(ServiceProvider sp) { return isB2BSSAppProperty; } - private ServiceProviderProperty buildIsApplicationAccessEnabledProperty(ServiceProvider sp) { + private ServiceProviderProperty buildIsApplicationEnabledProperty(ServiceProvider sp) { - ServiceProviderProperty isAppAccessEnabledProperty = new ServiceProviderProperty(); - isAppAccessEnabledProperty.setName(IS_APPLICATION_ACCESS_ENABLED_PROPERTY_NAME); - isAppAccessEnabledProperty.setDisplayName(IS_APPLICATION_ACCESS_ENABLED_DISPLAY_NAME); - isAppAccessEnabledProperty.setValue(String.valueOf(sp.isApplicationAccessEnabled())); - return isAppAccessEnabledProperty; + ServiceProviderProperty isAppEnabledProperty = new ServiceProviderProperty(); + isAppEnabledProperty.setName(IS_APPLICATION_ENABLED_PROPERTY_NAME); + isAppEnabledProperty.setDisplayName(IS_APPLICATION_ENABLED_DISPLAY_NAME); + isAppEnabledProperty.setValue(String.valueOf(sp.isApplicationEnabled())); + return isAppEnabledProperty; } private ServiceProviderProperty buildAllowedRoleAudienceProperty(ServiceProvider serviceProvider) { diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/AuthenticationService.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/AuthenticationService.java index fbc8d611a264..45a48c32e1a0 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/AuthenticationService.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/AuthenticationService.java @@ -348,7 +348,7 @@ private AuthenticationResult getAuthenticationResult(AuthServiceRequestWrapper r AuthenticationResult authenticationResult = (AuthenticationResult) request.getAttribute(FrameworkConstants.RequestAttribute.AUTH_RESULT); - if (authenticationResult == null) { + if (authenticationResult == null && request.getSessionDataKey() != null) { AuthenticationResultCacheEntry authenticationResultCacheEntry = FrameworkUtils.getAuthenticationResultFromCache(request.getSessionDataKey()); if (authenticationResultCacheEntry != null) { @@ -392,6 +392,13 @@ private void validateRequest(AuthServiceRequest authServiceRequest) throws AuthS clientId, tenantDomain)); } + // Check if the application is enabled to proceed with authentication. + if (!serviceProvider.isApplicationEnabled()) { + throw new AuthServiceClientException( + AuthServiceConstants.ErrorMessage.ERROR_DISABLED_APPLICATION.code(), + AuthServiceConstants.ErrorMessage.ERROR_DISABLED_APPLICATION.description()); + } + // Check whether api based authentication is enabled for the SP. if (!serviceProvider.isAPIBasedAuthenticationEnabled()) { throw new AuthServiceClientException( @@ -526,6 +533,8 @@ private AuthServiceConstants.ErrorMessage getMappedError(String errorCode) { return AuthServiceConstants.ErrorMessage.ERROR_AUTHENTICATION_FLOW_TIMEOUT; case FrameworkConstants.ERROR_STATUS_AUTH_CONTEXT_NULL: return AuthServiceConstants.ErrorMessage.ERROR_AUTHENTICATION_CONTEXT_NULL; + case FrameworkConstants.ERROR_STATUS_APP_DISABLED: + return AuthServiceConstants.ErrorMessage.ERROR_DISABLED_APPLICATION; default: return null; } diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/DefaultRequestCoordinator.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/DefaultRequestCoordinator.java index fe9c7b6f17e1..35a0ef567aa3 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/DefaultRequestCoordinator.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/DefaultRequestCoordinator.java @@ -98,6 +98,8 @@ import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ACCOUNT_UNLOCK_TIME_CLAIM; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.AnalyticsAttributes.SESSION_ID; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.BACK_TO_FIRST_STEP; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ERROR_DESCRIPTION_APP_DISABLED; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ERROR_STATUS_APP_DISABLED; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.IS_API_BASED; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ORGANIZATION_AUTHENTICATOR; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ORGANIZATION_LOGIN_HOME_REALM_IDENTIFIER; @@ -108,6 +110,7 @@ import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.IDF; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.RESTART_FLOW; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.TENANT_DOMAIN; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.TYPE; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ResidentIdpPropertyName.ACCOUNT_DISABLE_HANDLER_ENABLE_PROPERTY; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.USER_TENANT_DOMAIN; import static org.wso2.carbon.identity.application.authentication.framework.util.SessionNonceCookieUtil.NONCE_ERROR_CODE; @@ -250,6 +253,13 @@ public void handle(HttpServletRequest request, HttpServletResponse response) thr associateTransientRequestData(request, responseWrapper, context); } + // Check if the application is enabled. + if (!isApplicationEnabled(request, context)) { + FrameworkUtils.sendToRetryPage(request, responseWrapper, null, ERROR_STATUS_APP_DISABLED, + ERROR_DESCRIPTION_APP_DISABLED); + return; + } + if (context != null) { // Adding the context identifier(sessionDataKey) to the request to be used when the context // is not available. @@ -478,6 +488,30 @@ && isStepHasMultiOption(context) } } + private boolean isApplicationEnabled(HttpServletRequest request, AuthenticationContext context) + throws FrameworkException { + + String type = request.getParameter(TYPE); + String relyingParty = request.getParameter(FrameworkConstants.RequestParams.ISSUER); + if (StringUtils.isBlank(type)) { + type = context.getRequestType(); + } + if (StringUtils.isBlank(relyingParty)) { + relyingParty = context.getRelyingParty(); + } + ServiceProvider serviceProvider = getServiceProvider(type, relyingParty, getTenantDomain(request)); + if (serviceProvider == null) { + throw new FrameworkException("Unable to retrieve service provider for relying party : " + relyingParty); + } + if (!serviceProvider.isApplicationEnabled()) { + if (log.isDebugEnabled()) { + log.debug("Application is disabled for the service provider with relying party: " + relyingParty); + } + return false; + } + return true; + } + protected void unwrapResponse(CommonAuthResponseWrapper responseWrapper, String sessionDataKey, HttpServletResponse response, AuthenticationContext context) throws IOException { diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java index c0ea43155f5f..fd5b3c209358 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkConstants.java @@ -251,6 +251,8 @@ public abstract class FrameworkConstants { public static final String ERROR_DESCRIPTION_AUTH_CONTEXT_NULL = "authentication.context.null.description"; public static final String ERROR_STATUS_AUTH_FLOW_TIMEOUT = "authentication.flow.timeout"; public static final String ERROR_DESCRIPTION_AUTH_FLOW_TIMEOUT = "authentication.flow.timeout.description"; + public static final String ERROR_STATUS_APP_DISABLED = "authentication.flow.app.disabled"; + public static final String ERROR_DESCRIPTION_APP_DISABLED = "authentication.flow.app.disabled.description"; public static final String IS_SENT_TO_RETRY = "isSentToRetry"; public static final String CONTEXT_IDENTIFIER = "contextIdentifier"; public static final String REQ_ATTR_RETRY_STATUS = "retryStatus"; diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/auth/service/AuthServiceConstants.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/auth/service/AuthServiceConstants.java index aac23a33b185..64727d23568f 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/auth/service/AuthServiceConstants.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/auth/service/AuthServiceConstants.java @@ -87,6 +87,10 @@ public enum ErrorMessage { ERROR_INVALID_LOGOUT_REQUEST("60010", "Invalid logout request.", "Received logout request is invalid."), + ERROR_DISABLED_APPLICATION("60011", + "Application is disabled.", + "Application is disabled. Unable to proceed with authentication as application access " + + "is restricted."), // Server Error starting from 650xx. /* The 65001 ERROR_UNABLE_TO_PROCEED is used as the default server error therefor be cautious if that is being changed.*/ diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/AuthenticationServiceTest.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/AuthenticationServiceTest.java index 8e16370f3c20..ff77a2c7a0be 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/AuthenticationServiceTest.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/AuthenticationServiceTest.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.wso2.carbon.identity.application.authentication.framework.config.ConfigurationFacade; +import org.wso2.carbon.identity.application.authentication.framework.exception.auth.service.AuthServiceClientException; import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.DefaultRequestCoordinator; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatorData; import org.wso2.carbon.identity.application.authentication.framework.model.auth.service.AuthServiceErrorInfo; @@ -39,6 +40,9 @@ import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.authentication.framework.util.auth.service.AuthServiceConstants; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl; import java.io.IOException; import java.util.ArrayList; @@ -50,6 +54,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -78,6 +83,8 @@ public class AuthenticationServiceTest extends AbstractFrameworkTest { private MockedStatic configurationFacade; private MockedStatic frameworkUtils; + private MockedStatic applicationManagementService; + @BeforeMethod public void init() throws IOException { @@ -92,6 +99,8 @@ public void init() throws IOException { frameworkUtils.when(FrameworkUtils::getRequestCoordinator).thenReturn(defaultRequestCoordinator); frameworkUtils.when(FrameworkUtils::getMaxInactiveInterval).thenReturn(-1); + applicationManagementService = mockStatic(ApplicationManagementService.class); + doNothing().when(defaultRequestCoordinator).handle(request, response); } @@ -99,6 +108,7 @@ public void init() throws IOException { public void tearDown() { configurationFacade.close(); frameworkUtils.close(); + applicationManagementService.close(); } @DataProvider(name = "authProvider") @@ -160,6 +170,37 @@ public void testHandleAuthentication(boolean isMultiOpsResponse, String redirect } } + @Test + public void testHandleAppDisabledInitialAuthentication() throws Exception { + + AuthenticationService authenticationService = new AuthenticationService(); + AuthServiceRequest authServiceRequest = new AuthServiceRequest(request, response); + String clientId = "dummyClientId"; + String tenantDomain = "dummyTenantDomain"; + ServiceProvider serviceProvider = mock(ServiceProvider.class); + when(serviceProvider.isApplicationEnabled()).thenReturn(false); // ServiceProvider is disabled + ApplicationManagementServiceImpl mockApplicationManagementService = + mock(ApplicationManagementServiceImpl.class); + applicationManagementService.when(ApplicationManagementService::getInstance) + .thenReturn(mockApplicationManagementService);; + + when(request.getAttribute(AuthServiceConstants.REQ_ATTR_IS_INITIAL_API_BASED_AUTH_REQUEST)).thenReturn(true); + when(request.getAttribute(AuthServiceConstants.REQ_ATTR_RELYING_PARTY)).thenReturn(clientId); + when(request.getParameter(FrameworkConstants.RequestParams.TENANT_DOMAIN)).thenReturn(tenantDomain); + when(mockApplicationManagementService.getServiceProviderByClientId(anyString(), anyString(), anyString())) + .thenReturn(serviceProvider); + when(request.getAttribute(AuthServiceConstants.REQ_ATTR_IS_INITIAL_API_BASED_AUTH_REQUEST)).thenReturn(true); + when(request.getAttribute(AuthServiceConstants.REQ_ATTR_RELYING_PARTY)).thenReturn(clientId); + when(request.getParameter(FrameworkConstants.RequestParams.TENANT_DOMAIN)).thenReturn(tenantDomain); + try { + authenticationService.handleAuthentication(authServiceRequest); + } catch (AuthServiceClientException e) { + Assert.assertEquals(AuthServiceConstants.ErrorMessage.ERROR_DISABLED_APPLICATION.code(), e.getErrorCode()); + Assert.assertEquals(AuthServiceConstants.ErrorMessage.ERROR_DISABLED_APPLICATION.description(), + e.getMessage()); + } + } + @DataProvider(name = "authProviderForFailures") public Object[][] authProviderForFailures() { diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/DefaultRequestCoordinatorTest.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/DefaultRequestCoordinatorTest.java index 318c91af7d24..3e9fe846267f 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/DefaultRequestCoordinatorTest.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/DefaultRequestCoordinatorTest.java @@ -18,33 +18,51 @@ package org.wso2.carbon.identity.application.authentication.framework.handler.request.impl; +import org.junit.Assert; import org.mockito.MockedStatic; import org.testng.annotations.AfterClass; 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.config.ConfigurationFacade; import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig; import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; +import org.wso2.carbon.identity.application.authentication.framework.model.CommonAuthRequestWrapper; +import org.wso2.carbon.identity.application.authentication.framework.model.CommonAuthResponseWrapper; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.authentication.framework.util.SessionNonceCookieUtil; +import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl; import org.wso2.carbon.identity.central.log.mgt.internal.CentralLogMgtServiceComponentHolder; import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.event.services.IdentityEventService; import org.wso2.carbon.identity.testutil.IdentityBaseTest; +import java.io.IOException; +import java.io.Serializable; +import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ERROR_DESCRIPTION_APP_DISABLED; +import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.ERROR_STATUS_APP_DISABLED; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.LOGOUT; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.TENANT_DOMAIN; import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.RequestParams.TYPE; @@ -185,4 +203,96 @@ public void testCookieValidationFailedException() { } } } + + @Test + public void testApplicationDisabled() { + + try (MockedStatic frameworkUtils = mockStatic(FrameworkUtils.class); + MockedStatic applicationManagementService = + mockStatic(ApplicationManagementService.class); + MockedStatic configurationFacade = mockStatic(ConfigurationFacade.class)) { + + String requestType = "oauth2"; + String relyingParty = "console"; + String tenantDomain = "carbon.super"; + + HttpServletRequest requestMock = spy(HttpServletRequest.class); + HttpServletResponse responseMock = spy(HttpServletResponse.class); + CommonAuthRequestWrapper request = new CommonAuthRequestWrapper(requestMock); + CommonAuthResponseWrapper response = new CommonAuthResponseWrapper(responseMock); + AuthenticationContext context = mock(AuthenticationContext.class); + DefaultRequestCoordinator defaultRequestCoordinator = new DefaultRequestCoordinator(); + + // Mocking request and context parameters + when(request.getParameter(FrameworkConstants.RequestParams.ISSUER)).thenReturn(relyingParty); + when(request.getParameter(TENANT_DOMAIN)).thenReturn(tenantDomain); + when(context.getRequestType()).thenReturn(requestType); + when(context.getTenantDomain()).thenReturn(tenantDomain); + when(context.getServiceProviderName()).thenReturn("consoleApplication"); + when(context.getEndpointParams()).thenReturn(new HashMap<>()); + when(context.getSessionIdentifier()).thenReturn("randomKey"); + + // Mocking FrameworkUtils + frameworkUtils.when(() -> FrameworkUtils.getContextData(request)).thenReturn(context); + + // Mocking ApplicationManagementService behavior + ApplicationManagementServiceImpl mockApplicationManagementService = + mock(ApplicationManagementServiceImpl.class); + applicationManagementService.when(ApplicationManagementService::getInstance) + .thenReturn(mockApplicationManagementService); + + // Mocking ServiceProvider and its properties + ServiceProvider serviceProvider = mock(ServiceProvider.class); + when(serviceProvider.isApplicationEnabled()).thenReturn(false); // ServiceProvider is disabled + when(mockApplicationManagementService.getServiceProviderByClientId(anyString(), anyString(), anyString())) + .thenReturn(serviceProvider); + + ConfigurationFacade configurationFacadeInstance = mock(ConfigurationFacade.class); + configurationFacade.when(ConfigurationFacade::getInstance).thenReturn(configurationFacadeInstance); + when(configurationFacadeInstance.getAuthenticationEndpointRetryURL()) + .thenReturn("https://localhost:9443/retry"); + + frameworkUtils.when(() -> FrameworkUtils.sendToRetryPage(any(), any(), any(), any(), any())). + thenCallRealMethod(); + + frameworkUtils.when(() -> FrameworkUtils.getRedirectURL(any(), any())).thenCallRealMethod(); + + frameworkUtils.when(() -> FrameworkUtils.addAuthenticationErrorToCache(any(), any(), any())). + thenAnswer(invocation -> null); + + frameworkUtils.when(() -> FrameworkUtils.getRedirectURLWithFilteredParams(any(), + (AuthenticationContext) any())).thenCallRealMethod(); + + frameworkUtils.when(() -> FrameworkUtils.getRedirectURLWithFilteredParams(any(), + (Map) any())).thenCallRealMethod(); + + // Invoke handle method + defaultRequestCoordinator.handle(request, response); + + Map queryParams = getQueryParams(response.getRedirectURL()); + String status = queryParams.get(FrameworkConstants.STATUS_PARAM); + String statusMsg = queryParams.get(FrameworkConstants.STATUS_MSG_PARAM); + + // Assert the response + Assert.assertEquals(status, ERROR_STATUS_APP_DISABLED); + Assert.assertEquals(statusMsg, ERROR_DESCRIPTION_APP_DISABLED); + + } catch (IdentityApplicationManagementException | IOException | URISyntaxException e) { + Assert.fail("Exception occurred: " + e.getMessage()); + } + } + + private Map getQueryParams(String url) throws URISyntaxException { + + Map queryPairs = new HashMap<>(); + String query = url.substring(url.indexOf('?') + 1); + String[] pairs = query.split("&"); + for (String pair : pairs) { + int idx = pair.indexOf("="); + String key = pair.substring(0, idx); + String value = pair.substring(idx + 1); + queryPairs.put(key, value); + } + return queryPairs; + } } diff --git a/service-stubs/identity/org.wso2.carbon.identity.application.mgt.stub/src/main/resources/IdentityApplicationManagementService.wsdl b/service-stubs/identity/org.wso2.carbon.identity.application.mgt.stub/src/main/resources/IdentityApplicationManagementService.wsdl index 29ad1edad4c0..42146db2b007 100644 --- a/service-stubs/identity/org.wso2.carbon.identity.application.mgt.stub/src/main/resources/IdentityApplicationManagementService.wsdl +++ b/service-stubs/identity/org.wso2.carbon.identity.application.mgt.stub/src/main/resources/IdentityApplicationManagementService.wsdl @@ -565,7 +565,7 @@ - +