diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/pom.xml b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/pom.xml
index d4d8093120eb..0376fb4b8170 100644
--- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/pom.xml
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/pom.xml
@@ -229,6 +229,14 @@
org.wso2.carbon.identity.organization.management.core
org.wso2.carbon.identity.organization.management.service
+
+ org.wso2.carbon.identity.organization.management
+ org.wso2.carbon.identity.organization.discovery.service
+
+
+ org.wso2.carbon.identity.organization.management
+ org.wso2.carbon.identity.organization.config.service
+
org.wso2.carbon.identity.framework
org.wso2.carbon.identity.role.v2.mgt.core
@@ -303,6 +311,8 @@
version="${carbon.identity.package.import.version.range}",
org.wso2.carbon.identity.central.log.mgt.*; version="${carbon.identity.package.import.version.range}",
org.wso2.carbon.identity.organization.management.service; version="${org.wso2.carbon.identity.organization.management.core.version.range}",
+ org.wso2.carbon.identity.organization.discovery.service; version="${org.wso2.carbon.identity.organization.management.version.range}",
+ org.wso2.carbon.identity.organization.config.service; version="${org.wso2.carbon.identity.organization.management.version.range}",
org.wso2.carbon.identity.configuration.mgt.core; version="${carbon.identity.package.import.version.range}",
org.wso2.carbon.identity.configuration.mgt.core.exception; version="${carbon.identity.package.import.version.range}",
org.wso2.carbon.identity.configuration.mgt.core.model; version="${carbon.identity.package.import.version.range}",
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/EmailDomainValidationHandler.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/EmailDomainValidationHandler.java
new file mode 100644
index 000000000000..d8a5eae85a4c
--- /dev/null
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/EmailDomainValidationHandler.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2025, 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.application.authentication.framework.handler.request.impl;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.context.CarbonContext;
+import org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticator;
+import org.wso2.carbon.identity.application.authentication.framework.FederatedApplicationAuthenticator;
+import org.wso2.carbon.identity.application.authentication.framework.config.model.AuthenticatorConfig;
+import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig;
+import org.wso2.carbon.identity.application.authentication.framework.config.model.StepConfig;
+import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext;
+import org.wso2.carbon.identity.application.authentication.framework.exception.PostAuthenticationFailedException;
+import org.wso2.carbon.identity.application.authentication.framework.handler.request.AbstractPostAuthnHandler;
+import org.wso2.carbon.identity.application.authentication.framework.handler.request.PostAuthnHandlerFlowStatus;
+import org.wso2.carbon.identity.application.authentication.framework.internal.FrameworkServiceDataHolder;
+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.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.organization.config.service.exception.OrganizationConfigClientException;
+import org.wso2.carbon.identity.organization.config.service.exception.OrganizationConfigException;
+import org.wso2.carbon.identity.organization.config.service.model.ConfigProperty;
+import org.wso2.carbon.identity.organization.config.service.model.DiscoveryConfig;
+import org.wso2.carbon.identity.organization.discovery.service.model.OrgDiscoveryAttribute;
+import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
+import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_RETRIEVING_ORG_DISCOVERY_ATTRIBUTES;
+import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.INVALID_EMAIL_DOMAIN;
+import static org.wso2.carbon.identity.application.authentication.framework.util.FrameworkErrorConstants.ErrorMessages.NO_EMAIL_ATTRIBUTE_FOUND;
+
+/**
+ * Responsible for validating the email domain of the user during the authentication flow.
+ */
+public class EmailDomainValidationHandler extends AbstractPostAuthnHandler {
+
+ private static final Log LOG = LogFactory.getLog(EmailDomainValidationHandler.class);
+ private static final String EMAIL_DOMAIN_ENABLE = "emailDomain.enable";
+ public static final String EMAIL_DOMAIN = "emailDomain";
+
+ private EmailDomainValidationHandler() {
+
+ }
+
+ private static class Holder {
+
+ private static final EmailDomainValidationHandler INSTANCE = new EmailDomainValidationHandler();
+ }
+
+ public static EmailDomainValidationHandler getInstance() {
+
+ return Holder.INSTANCE;
+ }
+
+ @Override
+ public boolean isEnabled() {
+
+ if (!super.isEnabled()) {
+ return false;
+ }
+
+ try {
+ OrganizationManager organizationManager = FrameworkServiceDataHolder.getInstance().getOrganizationManager();
+ String organizationId = organizationManager.resolveOrganizationId(CarbonContext
+ .getThreadLocalCarbonContext().getTenantDomain());
+
+ if (organizationManager.isPrimaryOrganization(organizationId)) {
+ // Skip email domain validation since email domains cannot be mapped to primary organizations.
+ return false;
+ }
+ organizationId = organizationManager.getPrimaryOrganizationId(organizationId);
+
+ return isEmailDomainDiscoveryEnabled(organizationId);
+ } catch (OrganizationConfigClientException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("No organization discovery configurations found for tenant domain: " + CarbonContext
+ .getThreadLocalCarbonContext().getTenantDomain());
+ }
+ return false;
+ } catch (OrganizationManagementException | OrganizationConfigException e) {
+ LOG.error("Error while retrieving organization discovery configuration.", e);
+ return false;
+ }
+ }
+
+ @Override
+ public int getPriority() {
+
+ int priority = super.getPriority();
+ if (priority == -1) {
+ priority = 15;
+ }
+ return priority;
+ }
+
+ @Override
+ public PostAuthnHandlerFlowStatus handle(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationContext context) throws PostAuthenticationFailedException {
+
+ SequenceConfig sequenceConfig = context.getSequenceConfig();
+ for (Map.Entry entry : sequenceConfig.getStepMap().entrySet()) {
+ StepConfig stepConfig = entry.getValue();
+ AuthenticatorConfig authenticatorConfig = stepConfig.getAuthenticatedAutenticator();
+ if (authenticatorConfig == null) {
+ continue;
+ }
+
+ ApplicationAuthenticator authenticator = authenticatorConfig.getApplicationAuthenticator();
+ if (authenticator instanceof FederatedApplicationAuthenticator) {
+ Map localClaimValues;
+ if (stepConfig.isSubjectAttributeStep()) {
+ localClaimValues =
+ (Map) context.getProperty(FrameworkConstants.UNFILTERED_LOCAL_CLAIM_VALUES);
+ } else {
+ /*
+ * Need to validate even if this is not the subject attribute step since
+ * jit provisioning will happen in both scenarios.
+ */
+ localClaimValues =
+ FrameworkUtils.getLocalClaimValuesOfIDPInNonAttributeSelectionStep(context, stepConfig,
+ context.getExternalIdP());
+ }
+
+ Optional emailDomain =
+ extractEmailDomain(localClaimValues.get(FrameworkConstants.EMAIL_ADDRESS_CLAIM));
+
+ if (!emailDomain.isPresent()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Email address not found or is not in the correct format." +
+ " Email domain validation failed for tenant: " + context.getTenantDomain());
+ }
+ throw new PostAuthenticationFailedException(NO_EMAIL_ATTRIBUTE_FOUND.getCode(),
+ NO_EMAIL_ATTRIBUTE_FOUND.getMessage());
+ }
+
+ if (!isValidEmailDomain(context, emailDomain.get())) {
+ throw new PostAuthenticationFailedException(INVALID_EMAIL_DOMAIN.getCode(),
+ String.format(INVALID_EMAIL_DOMAIN.getMessage(), context.getTenantDomain()));
+ }
+ }
+ }
+ return PostAuthnHandlerFlowStatus.SUCCESS_COMPLETED;
+ }
+
+ private boolean isEmailDomainDiscoveryEnabled(String primaryOrganizationId)
+ throws OrganizationConfigException, OrganizationManagementException {
+
+ String tenantDomain = FrameworkServiceDataHolder.getInstance().getOrganizationManager()
+ .resolveTenantDomain(primaryOrganizationId);
+
+ DiscoveryConfig discoveryConfiguration =
+ FrameworkServiceDataHolder.getInstance().getOrganizationConfigManager()
+ .getDiscoveryConfigurationByTenantId(IdentityTenantUtil.getTenantId(tenantDomain));
+ List configProperties = discoveryConfiguration.getConfigProperties();
+ for (ConfigProperty configProperty : configProperties) {
+ if (EMAIL_DOMAIN_ENABLE.equals(configProperty.getKey())) {
+ return Boolean.parseBoolean(configProperty.getValue());
+ }
+ }
+ return false;
+ }
+
+ private boolean isValidEmailDomain(AuthenticationContext context, String emaildomain)
+ throws PostAuthenticationFailedException {
+
+ try {
+ List organizationDiscoveryAttributes =
+ FrameworkServiceDataHolder.getInstance().getOrganizationDiscoveryManager()
+ .getOrganizationDiscoveryAttributes(context.getTenantDomain(), false);
+
+ if (organizationDiscoveryAttributes.isEmpty()) {
+ LOG.debug("No email domains are mapped to the organization. Skipping email domain validation.");
+ return true;
+ }
+
+ for (OrgDiscoveryAttribute orgDiscoveryAttribute : organizationDiscoveryAttributes) {
+ if (!EMAIL_DOMAIN.equals(orgDiscoveryAttribute.getType())) {
+ continue;
+ }
+
+ List mappedEmailDomains = orgDiscoveryAttribute.getValues();
+ if (mappedEmailDomains != null && !mappedEmailDomains.contains(emaildomain)) {
+ return false;
+ }
+ }
+ } catch (OrganizationManagementException e) {
+ LOG.error(
+ "Error while retrieving organization discovery attributes for tenant: " + context.getTenantDomain(),
+ e);
+ throw new PostAuthenticationFailedException(ERROR_WHILE_RETRIEVING_ORG_DISCOVERY_ATTRIBUTES.getCode(),
+ String.format(ERROR_WHILE_RETRIEVING_ORG_DISCOVERY_ATTRIBUTES.getMessage(),
+ context.getTenantDomain()), e);
+ }
+ return true;
+ }
+
+ private Optional extractEmailDomain(String email) {
+
+ if (StringUtils.isBlank(email)) {
+ return Optional.empty();
+ }
+
+ String[] emailSplit = email.split("@");
+ return emailSplit.length == 2 ? Optional.of(emailSplit[1]) : Optional.empty();
+ }
+}
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/JITProvisioningPostAuthenticationHandler.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/JITProvisioningPostAuthenticationHandler.java
index ca60572e759f..289e26da8e0e 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/JITProvisioningPostAuthenticationHandler.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/JITProvisioningPostAuthenticationHandler.java
@@ -304,8 +304,9 @@ private PostAuthnHandlerFlowStatus handleRequestFlow(HttpServletRequest request,
localClaimValues = (Map) context
.getProperty(FrameworkConstants.UNFILTERED_LOCAL_CLAIM_VALUES);
} else {
- localClaimValues = getLocalClaimValuesOfIDPInNonAttributeSelectionStep(context, stepConfig,
- externalIdPConfig);
+ localClaimValues =
+ FrameworkUtils.getLocalClaimValuesOfIDPInNonAttributeSelectionStep(context, stepConfig,
+ externalIdPConfig);
}
if (localClaimValues == null || localClaimValues.size() == 0) {
Map userAttributes = stepConfig.getAuthenticatedUser().getUserAttributes();
@@ -1083,59 +1084,6 @@ private String getUserIdClaimUriInLocalDialect(ExternalIdPConfig idPConfig) {
return null;
}
- /**
- * Uses to get local claim values of an authenticated user from an IDP in non attribute selection steps.
- *
- * @param context Authentication Context.
- * @param stepConfig Current step configuration.
- * @param externalIdPConfig Identity providers config.
- * @return Mapped federated user values to local claims.
- * @throws PostAuthenticationFailedException Post Authentication failed exception.
- */
- private Map getLocalClaimValuesOfIDPInNonAttributeSelectionStep(AuthenticationContext context,
- StepConfig stepConfig,
- ExternalIdPConfig externalIdPConfig)
- throws PostAuthenticationFailedException {
-
- boolean useDefaultIdpDialect = externalIdPConfig.useDefaultLocalIdpDialect();
- ApplicationAuthenticator authenticator =
- stepConfig.getAuthenticatedAutenticator().getApplicationAuthenticator();
- String idPStandardDialect = authenticator.getClaimDialectURI();
- Map extAttrs = stepConfig.getAuthenticatedUser().getUserAttributes();
- Map originalExternalAttributeValueMap = FrameworkUtils.getClaimMappings(extAttrs, false);
- Map claimMapping = new HashMap<>();
- Map localClaimValues = new HashMap<>();
- if (useDefaultIdpDialect && StringUtils.isNotBlank(idPStandardDialect)) {
- try {
- claimMapping = ClaimMetadataHandler.getInstance()
- .getMappingsMapFromOtherDialectToCarbon(idPStandardDialect,
- originalExternalAttributeValueMap.keySet(), context.getTenantDomain(),
- true);
- } catch (ClaimMetadataException e) {
- throw new PostAuthenticationFailedException(ErrorMessages.ERROR_WHILE_HANDLING_CLAIM_MAPPINGS.getCode(),
- ErrorMessages.ERROR_WHILE_HANDLING_CLAIM_MAPPINGS.getMessage(), e);
- }
- } else {
- ClaimMapping[] customClaimMapping = context.getExternalIdP().getClaimMappings();
- for (ClaimMapping externalClaim : customClaimMapping) {
- if (originalExternalAttributeValueMap.containsKey(externalClaim.getRemoteClaim().getClaimUri())) {
- claimMapping.put(externalClaim.getLocalClaim().getClaimUri(),
- externalClaim.getRemoteClaim().getClaimUri());
- }
- }
- }
-
- if (claimMapping != null && claimMapping.size() > 0) {
- for (Map.Entry entry : claimMapping.entrySet()) {
- if (originalExternalAttributeValueMap.containsKey(entry.getValue()) &&
- originalExternalAttributeValueMap.get(entry.getValue()) != null) {
- localClaimValues.put(entry.getKey(), originalExternalAttributeValueMap.get(entry.getValue()));
- }
- }
- }
- return localClaimValues;
- }
-
private UserRealm getUserRealm(String tenantDomain) throws UserStoreException {
RealmService realmService = FrameworkServiceComponent.getRealmService();
diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/FrameworkServiceComponent.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/FrameworkServiceComponent.java
index 42ecadb98176..e1eb42401c0c 100644
--- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/FrameworkServiceComponent.java
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/FrameworkServiceComponent.java
@@ -60,6 +60,7 @@
import org.wso2.carbon.identity.application.authentication.framework.handler.claims.impl.DefaultClaimFilter;
import org.wso2.carbon.identity.application.authentication.framework.handler.provisioning.listener.JITProvisioningIdentityProviderMgtListener;
import org.wso2.carbon.identity.application.authentication.framework.handler.request.PostAuthenticationHandler;
+import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.EmailDomainValidationHandler;
import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.JITProvisioningPostAuthenticationHandler;
import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.PostAuthAssociationHandler;
import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.PostAuthenticatedSubjectIdentifierHandler;
@@ -108,6 +109,8 @@
import org.wso2.carbon.identity.event.services.IdentityEventService;
import org.wso2.carbon.identity.functions.library.mgt.FunctionLibraryManagementService;
import org.wso2.carbon.identity.multi.attribute.login.mgt.MultiAttributeLoginService;
+import org.wso2.carbon.identity.organization.config.service.OrganizationConfigManager;
+import org.wso2.carbon.identity.organization.discovery.service.OrganizationDiscoveryManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationManagementInitialize;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService;
@@ -343,6 +346,8 @@ protected void activate(ComponentContext ctxt) {
bundleContext
.registerService(PostAuthenticationHandler.class.getName(), postAuthenticatedUserDomainHandler, null);
+ PostAuthenticationHandler emailDomainValidationHandler = EmailDomainValidationHandler.getInstance();
+ bundleContext.registerService(PostAuthenticationHandler.class.getName(), emailDomainValidationHandler, null);
if (log.isDebugEnabled()) {
log.debug("Application Authentication Framework bundle is activated");
}
@@ -938,7 +943,7 @@ private void loadCodeForSecrets() {
unbind = "unsetFederatedAssociationManagerService"
)
protected void setFederatedAssociationManagerService(FederatedAssociationManager
- federatedAssociationManagerService) {
+ federatedAssociationManagerService) {
if (log.isDebugEnabled()) {
log.debug("Federated Association Manager Service is set in the Application Authentication Framework " +
@@ -1069,6 +1074,37 @@ protected void unsetOrganizationManager(OrganizationManager organizationManager)
FrameworkServiceDataHolder.getInstance().setOrganizationManager(null);
}
+ @Reference(
+ name = "identity.organization.discovery.management.component",
+ service = OrganizationDiscoveryManager.class,
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetOrganizationDiscoveryManager")
+ protected void setOrganizationDiscoveryManager(OrganizationDiscoveryManager organizationDiscoveryManager) {
+
+ FrameworkServiceDataHolder.getInstance().setOrganizationDiscoveryManager(organizationDiscoveryManager);
+ }
+
+ protected void unsetOrganizationDiscoveryManager(OrganizationDiscoveryManager organizationDiscoveryManager) {
+
+ FrameworkServiceDataHolder.getInstance().setOrganizationDiscoveryManager(null);
+ }
+
+ @Reference(name = "identity.organization.config.management.component",
+ service = OrganizationConfigManager.class,
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetOrganizationConfigManager")
+ protected void setOrganizationConfigManager(OrganizationConfigManager organizationConfigManager) {
+
+ FrameworkServiceDataHolder.getInstance().setOrganizationConfigManager(organizationConfigManager);
+ }
+
+ protected void unsetOrganizationConfigManager(OrganizationConfigManager organizationConfigManager) {
+
+ FrameworkServiceDataHolder.getInstance().setOrganizationConfigManager(null);
+ }
+
@Reference(
name = "resource.configuration.manager",
service = ConfigurationManager.class,
diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/FrameworkServiceDataHolder.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/FrameworkServiceDataHolder.java
index b821d417f881..060f90026cb6 100644
--- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/FrameworkServiceDataHolder.java
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/internal/FrameworkServiceDataHolder.java
@@ -53,6 +53,8 @@
import org.wso2.carbon.identity.event.services.IdentityEventService;
import org.wso2.carbon.identity.functions.library.mgt.FunctionLibraryManagementService;
import org.wso2.carbon.identity.multi.attribute.login.mgt.MultiAttributeLoginService;
+import org.wso2.carbon.identity.organization.config.service.OrganizationConfigManager;
+import org.wso2.carbon.identity.organization.discovery.service.OrganizationDiscoveryManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationManagementInitialize;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService;
@@ -123,6 +125,8 @@ public class FrameworkServiceDataHolder {
private boolean isAdaptiveAuthenticationAvailable = false;
private boolean isOrganizationManagementEnable = false;
private OrganizationManager organizationManager;
+ private OrganizationDiscoveryManager organizationDiscoveryManager;
+ private OrganizationConfigManager organizationConfigManager;
private RoleManagementService roleManagementServiceV2;
private SecretResolveManager secretConfigManager;
@@ -778,6 +782,46 @@ public void setOrganizationManager(OrganizationManager organizationManager) {
this.organizationManager = organizationManager;
}
+ /**
+ * Get {@link OrganizationDiscoveryManager}.
+ *
+ * @return organization discovery manager instance {@link OrganizationDiscoveryManager}.
+ */
+ public OrganizationDiscoveryManager getOrganizationDiscoveryManager() {
+
+ return organizationDiscoveryManager;
+ }
+
+ /**
+ * Set {@link OrganizationDiscoveryManager}.
+ *
+ * @param organizationDiscoveryManager Instance of {@link OrganizationDiscoveryManager}.
+ */
+ public void setOrganizationDiscoveryManager(OrganizationDiscoveryManager organizationDiscoveryManager) {
+
+ this.organizationDiscoveryManager = organizationDiscoveryManager;
+ }
+
+ /**
+ * Get {@link OrganizationConfigManager}.
+ *
+ * @return organization config manager instance {@link OrganizationConfigManager}.
+ */
+ public OrganizationConfigManager getOrganizationConfigManager() {
+
+ return organizationConfigManager;
+ }
+
+ /**
+ * Set {@link OrganizationConfigManager}.
+ *
+ * @param organizationConfigManager Instance of {@link OrganizationConfigManager}.
+ */
+ public void setOrganizationConfigManager(OrganizationConfigManager organizationConfigManager) {
+
+ this.organizationConfigManager = organizationConfigManager;
+ }
+
public IdpManager getIdentityProviderManager() {
return identityProviderManager;
diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkErrorConstants.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkErrorConstants.java
index 9d941122f0ee..c914419e5f81 100644
--- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkErrorConstants.java
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkErrorConstants.java
@@ -76,6 +76,11 @@ public enum ErrorMessages {
ERROR_WHILE_TRYING_TO_HANDLE_ROLE_CLAIM_FOR_PROVISIONED_USER("80030", "Error while trying to handle role "
+ "claim for provisioned user."),
ERROR_WHILE_ENCRYPTING_TOTP_SECRET_KEY("80031", "Error while encrypting TOTP secret key for user. %s"),
+ ERROR_WHILE_RETRIEVING_ORG_DISCOVERY_ATTRIBUTES("80032", "Error while retrieving organization discovery "
+ + "attributes for tenantDomain: %s"),
+ INVALID_EMAIL_DOMAIN("80033",
+ "Email domain resolved from the authenticated federated IDP is not mapped to the organization: %s"),
+ NO_EMAIL_ATTRIBUTE_FOUND("80034", "No email attribute returned by the authenticated federated IDP"),
MISMATCHING_TENANT_DOMAIN("AFW-60001",
"Service Provider tenant domain must be equal to user tenant domain for non-SaaS applications"),
SYSTEM_ERROR_WHILE_AUTHENTICATING("AFW-65001", "System error while authenticating");
@@ -90,6 +95,7 @@ public enum ErrorMessages {
* @param message Relevant error message.
*/
ErrorMessages(String code, String message) {
+
this.code = code;
this.message = message;
}
@@ -100,6 +106,7 @@ public enum ErrorMessages {
* @return Error code.
*/
public String getCode() {
+
return code;
}
@@ -109,11 +116,13 @@ public String getCode() {
* @return Error message.
*/
public String getMessage() {
+
return message;
}
@Override
public String toString() {
+
return code + " - " + message;
}
}
diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkUtils.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkUtils.java
index e346a3c25f52..1fe95608f060 100644
--- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkUtils.java
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/util/FrameworkUtils.java
@@ -4297,4 +4297,59 @@ public static boolean isURLRelative(String uriString) throws URISyntaxException
return !new URI(uriString).isAbsolute();
}
+
+ /**
+ * Get local claim values of an authenticated user from an IDP in non attribute selection steps.
+ *
+ * @param context Authentication Context.
+ * @param stepConfig Current step configuration.
+ * @param externalIdPConfig Identity providers config.
+ * @return Mapped federated user values to local claims.
+ * @throws PostAuthenticationFailedException Post Authentication failed exception.
+ */
+ public static Map getLocalClaimValuesOfIDPInNonAttributeSelectionStep(AuthenticationContext context,
+ StepConfig stepConfig,
+ ExternalIdPConfig externalIdPConfig)
+ throws PostAuthenticationFailedException {
+
+ boolean useDefaultIdpDialect = externalIdPConfig.useDefaultLocalIdpDialect();
+ ApplicationAuthenticator authenticator =
+ stepConfig.getAuthenticatedAutenticator().getApplicationAuthenticator();
+ String idPStandardDialect = authenticator.getClaimDialectURI();
+ Map extAttrs = stepConfig.getAuthenticatedUser().getUserAttributes();
+ Map originalExternalAttributeValueMap = getClaimMappings(extAttrs, false);
+ Map claimMapping = new HashMap<>();
+ Map localClaimValues = new HashMap<>();
+
+ if (useDefaultIdpDialect && StringUtils.isNotBlank(idPStandardDialect)) {
+ try {
+ claimMapping = ClaimMetadataHandler.getInstance()
+ .getMappingsMapFromOtherDialectToCarbon(idPStandardDialect,
+ originalExternalAttributeValueMap.keySet(), context.getTenantDomain(),
+ true);
+ } catch (ClaimMetadataException e) {
+ throw new PostAuthenticationFailedException(
+ FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_HANDLING_CLAIM_MAPPINGS.getCode(),
+ FrameworkErrorConstants.ErrorMessages.ERROR_WHILE_HANDLING_CLAIM_MAPPINGS.getMessage(), e);
+ }
+ } else {
+ ClaimMapping[] customClaimMapping = context.getExternalIdP().getClaimMappings();
+ for (ClaimMapping externalClaim : customClaimMapping) {
+ if (originalExternalAttributeValueMap.containsKey(externalClaim.getRemoteClaim().getClaimUri())) {
+ claimMapping.put(externalClaim.getLocalClaim().getClaimUri(),
+ externalClaim.getRemoteClaim().getClaimUri());
+ }
+ }
+ }
+
+ if (claimMapping != null && !claimMapping.isEmpty()) {
+ for (Map.Entry entry : claimMapping.entrySet()) {
+ if (originalExternalAttributeValueMap.containsKey(entry.getValue()) &&
+ originalExternalAttributeValueMap.get(entry.getValue()) != null) {
+ localClaimValues.put(entry.getKey(), originalExternalAttributeValueMap.get(entry.getValue()));
+ }
+ }
+ }
+ return localClaimValues;
+ }
}
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/EmailDomainValidationHandlerTest.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/EmailDomainValidationHandlerTest.java
new file mode 100644
index 000000000000..fdf616fdd71f
--- /dev/null
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/java/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/EmailDomainValidationHandlerTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2025, 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.application.authentication.framework.handler.request.impl;
+
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.wso2.carbon.context.CarbonContext;
+import org.wso2.carbon.identity.application.authentication.framework.AbstractFrameworkTest;
+import org.wso2.carbon.identity.application.authentication.framework.FederatedApplicationAuthenticator;
+import org.wso2.carbon.identity.application.authentication.framework.config.loader.UIBasedConfigurationLoader;
+import org.wso2.carbon.identity.application.authentication.framework.config.model.AuthenticatorConfig;
+import org.wso2.carbon.identity.application.authentication.framework.config.model.ExternalIdPConfig;
+import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig;
+import org.wso2.carbon.identity.application.authentication.framework.config.model.StepConfig;
+import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext;
+import org.wso2.carbon.identity.application.authentication.framework.exception.PostAuthenticationFailedException;
+import org.wso2.carbon.identity.application.authentication.framework.handler.request.PostAuthnHandlerFlowStatus;
+import org.wso2.carbon.identity.application.authentication.framework.internal.FrameworkServiceDataHolder;
+import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser;
+import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants;
+import org.wso2.carbon.identity.application.common.model.ClaimMapping;
+import org.wso2.carbon.identity.application.common.model.ServiceProvider;
+import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataHandler;
+import org.wso2.carbon.identity.common.testng.WithCarbonHome;
+import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.organization.config.service.OrganizationConfigManager;
+import org.wso2.carbon.identity.organization.config.service.exception.OrganizationConfigClientException;
+import org.wso2.carbon.identity.organization.config.service.model.ConfigProperty;
+import org.wso2.carbon.identity.organization.config.service.model.DiscoveryConfig;
+import org.wso2.carbon.identity.organization.discovery.service.OrganizationDiscoveryManager;
+import org.wso2.carbon.identity.organization.discovery.service.model.OrgDiscoveryAttribute;
+import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anySet;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit tests for {@link EmailDomainValidationHandler}
+ */
+@WithCarbonHome
+public class EmailDomainValidationHandlerTest extends AbstractFrameworkTest {
+
+ private static final String VALID_EMAIL = "user@test.com";
+ private static final String INVALID_EMAIL = "user@testInvalid.com";
+ private static final String SUPER_ORG_ID = "10084a8d-113f-4211-a0d5-efe36b082211";
+ private static final String SUB_ORG_ID = "93d996f9-a5ba-4275-a52b-adaad9eba869";
+ public static final String SUPER_ORG_TENANT_DOMAIN = "carbon.super";
+ public static final String SUB_ORG_TENANT_DOMAIN = "test";
+ public static final String EMAIL_ADDRESS_CLAIM_URI = "http://wso2.org/claims/emailaddress";
+ public static final String EMAIL = "email";
+
+ private MockedStatic carbonContextMockedStatic;
+ private MockedStatic identityTenantUtil;
+ private MockedStatic claimMetadataHandler;
+ @Mock
+ private OrganizationDiscoveryManager organizationDiscoveryManager;
+ @Mock
+ private OrganizationConfigManager organizationConfigManager;
+ @Mock
+ private OrganizationManager organizationManager;
+ private CarbonContext carbonContext;
+ private EmailDomainValidationHandler emailDomainValidationHandler;
+ private HttpServletRequest request;
+ private HttpServletResponse response;
+ private UIBasedConfigurationLoader configurationLoader;
+ private ServiceProvider sp;
+ private AutoCloseable mocks;
+
+ @BeforeClass
+ public void setUp() throws Exception {
+
+ mocks = MockitoAnnotations.openMocks(this);
+ request = mock(HttpServletRequest.class);
+ response = mock(HttpServletResponse.class);
+ configurationLoader = new UIBasedConfigurationLoader();
+
+ identityTenantUtil = mockStatic(IdentityTenantUtil.class);
+ claimMetadataHandler = mockStatic(ClaimMetadataHandler.class);
+
+ emailDomainValidationHandler = EmailDomainValidationHandler.getInstance();
+ sp = getTestServiceProvider("email-domain-validation-sp.xml");
+
+ FrameworkServiceDataHolder.getInstance().setOrganizationDiscoveryManager(organizationDiscoveryManager);
+ FrameworkServiceDataHolder.getInstance().setOrganizationConfigManager(organizationConfigManager);
+ FrameworkServiceDataHolder.getInstance().setOrganizationManager(organizationManager);
+
+ List orgDiscoveryAttributes = new ArrayList<>();
+ OrgDiscoveryAttribute orgDiscoveryAttribute = new OrgDiscoveryAttribute();
+ orgDiscoveryAttribute.setType("emailDomain");
+ orgDiscoveryAttribute.setValues(Collections.singletonList("test.com"));
+ orgDiscoveryAttributes.add(orgDiscoveryAttribute);
+ when(organizationDiscoveryManager.getOrganizationDiscoveryAttributes(anyString(), anyBoolean())).thenReturn(
+ orgDiscoveryAttributes);
+
+ carbonContextMockedStatic = mockStatic(CarbonContext.class);
+ carbonContext = mock(CarbonContext.class);
+ carbonContextMockedStatic.when(CarbonContext::getThreadLocalCarbonContext).thenReturn(carbonContext);
+ when(carbonContext.getTenantDomain()).thenReturn(SUPER_ORG_TENANT_DOMAIN);
+ }
+
+ @AfterClass
+ public void tearDown() throws Exception {
+
+ carbonContextMockedStatic.close();
+ identityTenantUtil.close();
+ claimMetadataHandler.close();
+ mocks.close();
+ }
+
+ @Test(description = "Test whether the email domain validation handler is disabled for primary organizations.")
+ public void testIsDisabledForPrimaryOrganizations() throws Exception {
+
+ when(carbonContext.getTenantDomain()).thenReturn(SUPER_ORG_TENANT_DOMAIN);
+ when(organizationManager.resolveOrganizationId(SUPER_ORG_TENANT_DOMAIN)).thenReturn(SUPER_ORG_ID);
+ when(organizationManager.isPrimaryOrganization(SUPER_ORG_ID)).thenReturn(true);
+ Assert.assertFalse(emailDomainValidationHandler.isEnabled(),
+ "Email domain validation handler should be disabled for primary organizations.");
+ }
+
+ @Test(description = "Test whether the email domain validation handler is enabled for sub organizations when " +
+ "email domain discovery is enabled.")
+ public void testIsEnabledForSubOrganizationsWhenEmailDomainDiscoveryEnabled() throws Exception {
+
+ reset(organizationConfigManager);
+ when(carbonContext.getTenantDomain()).thenReturn(SUB_ORG_TENANT_DOMAIN);
+ when(organizationManager.resolveOrganizationId(SUB_ORG_TENANT_DOMAIN)).thenReturn(SUB_ORG_ID);
+ when(organizationManager.isPrimaryOrganization(SUB_ORG_ID)).thenReturn(false);
+ when(organizationManager.getPrimaryOrganizationId(SUB_ORG_ID)).thenReturn(SUPER_ORG_ID);
+ when(organizationManager.resolveTenantDomain(SUPER_ORG_ID)).thenReturn(SUPER_ORG_TENANT_DOMAIN);
+
+ identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(SUPER_ORG_TENANT_DOMAIN)).thenReturn(-1234);
+
+ List configProperties = new ArrayList<>();
+ ConfigProperty configProperty = new ConfigProperty("emailDomain.enable", "true");
+ configProperties.add(configProperty);
+ DiscoveryConfig discoveryConfig = new DiscoveryConfig(configProperties);
+ when(organizationConfigManager.getDiscoveryConfigurationByTenantId(-1234)).thenReturn(discoveryConfig);
+
+ Assert.assertTrue(emailDomainValidationHandler.isEnabled(),
+ "Email domain validation handler should be enabled for" +
+ "sub organizations when email domain discovery is enabled.");
+ }
+
+ @Test(description = "Test whether the email domain validation handler is disabled for sub organizations when " +
+ "email domain discovery is disabled.")
+ public void testIsDisabledWhenNoDiscoveryConfigsForOrganization() throws Exception {
+
+ when(carbonContext.getTenantDomain()).thenReturn(SUB_ORG_TENANT_DOMAIN);
+ when(organizationManager.resolveOrganizationId(SUB_ORG_TENANT_DOMAIN)).thenReturn(SUB_ORG_ID);
+ when(organizationManager.isPrimaryOrganization(SUB_ORG_ID)).thenReturn(false);
+ when(organizationManager.getPrimaryOrganizationId(SUB_ORG_ID)).thenReturn(SUPER_ORG_ID);
+ when(organizationManager.resolveTenantDomain(SUPER_ORG_ID)).thenReturn(SUPER_ORG_TENANT_DOMAIN);
+
+ identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(SUPER_ORG_TENANT_DOMAIN)).thenReturn(-1234);
+
+ when(organizationConfigManager.getDiscoveryConfigurationByTenantId(-1234)).thenThrow(
+ new OrganizationConfigClientException("No organization configs found."));
+
+ Assert.assertFalse(emailDomainValidationHandler.isEnabled(),
+ "Email domain validation handler should be disabled when there are no discovery" +
+ " configurations for the organization.");
+ }
+
+ @Test(description = "Test if the validation pass with a valid email domain for the authenticated user.")
+ public void testAuthenticatedUserWithValidEmailDomain() throws Exception {
+
+ AuthenticationContext context = buildAuthenticationContext(sp, VALID_EMAIL, false);
+ PostAuthnHandlerFlowStatus status = emailDomainValidationHandler.handle(request, response, context);
+ Assert.assertEquals(status, PostAuthnHandlerFlowStatus.SUCCESS_COMPLETED,
+ "Expected the email domain validation handler to succeed with a valid email domain.");
+ }
+
+ @Test(description = "Test if the validation fails with an invalid email domain for the authenticated user.",
+ expectedExceptions = PostAuthenticationFailedException.class)
+ public void testAuthenticatedUserWithInvalidEmailDomain() throws Exception {
+
+ AuthenticationContext context = buildAuthenticationContext(sp, INVALID_EMAIL, false);
+ emailDomainValidationHandler.handle(request, response, context);
+ }
+
+ @Test(description = "Test if the validation pass with a valid email domain when the user authenticates in a" +
+ " non-subject attribute step.")
+ public void testAuthenticatedUserWithValidEmailDomainAndNotSubjectAttributeStep() throws Exception {
+
+ AuthenticationContext context = buildAuthenticationContext(sp, VALID_EMAIL, true);
+
+ Map mockedMappings = new HashMap<>();
+ mockedMappings.put(EMAIL_ADDRESS_CLAIM_URI, EMAIL);
+
+ ClaimMetadataHandler mockClaimMetadataHandler = mock(ClaimMetadataHandler.class);
+ when(mockClaimMetadataHandler.getMappingsMapFromOtherDialectToCarbon(
+ anyString(), anySet(), anyString(), anyBoolean())).thenReturn(mockedMappings);
+ claimMetadataHandler.when(ClaimMetadataHandler::getInstance).thenReturn(mockClaimMetadataHandler);
+
+ PostAuthnHandlerFlowStatus status = emailDomainValidationHandler.handle(request, response, context);
+ Assert.assertEquals(status, PostAuthnHandlerFlowStatus.SUCCESS_COMPLETED,
+ "Expected the email domain validation handler to succeed with a valid email domain when the user " +
+ "authenticates in a non-subject attribute step.");
+ }
+
+ private AuthenticationContext buildAuthenticationContext(ServiceProvider sp, String userEmail,
+ boolean notSubjectAttributeStep) throws Exception {
+
+ AuthenticationContext authenticationContext = getAuthenticationContext(sp);
+ authenticationContext.setProperty(FrameworkConstants.STEP_BASED_SEQUENCE_HANDLER_TRIGGERED, true);
+ SequenceConfig sequenceConfig =
+ configurationLoader.getSequenceConfig(authenticationContext, Collections.emptyMap(), sp);
+ authenticationContext.setSequenceConfig(sequenceConfig);
+
+ FederatedApplicationAuthenticator authenticator = mock(FederatedApplicationAuthenticator.class);
+ AuthenticatorConfig authenticatorConfig = new AuthenticatorConfig();
+ when(authenticator.getClaimDialectURI()).thenReturn("http://wso2.org/oidc/claim");
+ authenticatorConfig.setApplicationAuthenticator(authenticator);
+
+ AuthenticatedUser user = new AuthenticatedUser();
+ user.setUserName(userEmail);
+ user.setAuthenticatedSubjectIdentifier(userEmail);
+
+ Map userAttributes = new HashMap<>();
+ userAttributes.put(ClaimMapping.build(
+ EMAIL_ADDRESS_CLAIM_URI,
+ EMAIL,
+ null, false), userEmail);
+
+ user.setUserAttributes(userAttributes);
+
+ for (Map.Entry entry : sequenceConfig.getStepMap().entrySet()) {
+ StepConfig stepConfig = entry.getValue();
+ stepConfig.setAuthenticatedUser(user);
+ stepConfig.setAuthenticatedAutenticator(authenticatorConfig);
+ if (notSubjectAttributeStep) {
+ stepConfig.setSubjectAttributeStep(false);
+ }
+ }
+
+ if (notSubjectAttributeStep) {
+ ExternalIdPConfig externalIdPConfig = mock(ExternalIdPConfig.class);
+ when(externalIdPConfig.useDefaultLocalIdpDialect()).thenReturn(true);
+ authenticationContext.setExternalIdP(externalIdPConfig);
+ }
+
+ authenticationContext.setSequenceConfig(sequenceConfig);
+
+ Map unfilteredLocalClaimValues = new HashMap<>();
+ unfilteredLocalClaimValues.put(EMAIL_ADDRESS_CLAIM_URI, userEmail);
+ authenticationContext.setProperty(FrameworkConstants.UNFILTERED_LOCAL_CLAIM_VALUES, unfilteredLocalClaimValues);
+
+ return authenticationContext;
+ }
+}
diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/resources/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/email-domain-validation-sp.xml b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/resources/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/email-domain-validation-sp.xml
new file mode 100644
index 000000000000..00f25e06a228
--- /dev/null
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/resources/org/wso2/carbon/identity/application/authentication/framework/handler/request/impl/email-domain-validation-sp.xml
@@ -0,0 +1,55 @@
+
+
+
+ 1
+ default
+ Default Service Provider
+
+
+
+ default
+
+
+
+
+
+
+
+
+ 1
+
+
+ BasicMockAuthenticator
+ basicauth
+ true
+
+
+ true
+ true
+
+
+
+
+
+
+
+ true
+
+
+
diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/resources/testng.xml b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/resources/testng.xml
index 6a92baeb22da..4209f59bb02e 100644
--- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/resources/testng.xml
+++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/test/resources/testng.xml
@@ -29,6 +29,7 @@
+
diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml
index 62e241854070..6a280df3d67d 100644
--- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml
+++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml
@@ -1322,6 +1322,12 @@
name="org.wso2.carbon.identity.mgt.listener.UserSessionTerminationListener"
orderId="85" enable="true"/>
+
+
+
+
+
org.wso2.carbon.identity.organization.management.service
${org.wso2.carbon.identity.organization.management.core.version}
+
+ org.wso2.carbon.identity.organization.management
+ org.wso2.carbon.identity.organization.discovery.service
+ ${org.wso2.carbon.identity.organization.management.version}
+
+
+ org.wso2.carbon.identity.organization.management
+ org.wso2.carbon.identity.organization.config.service
+ ${org.wso2.carbon.identity.organization.management.version}
+
@@ -1857,10 +1867,14 @@
[5.14.0, 8.0.0)
[0.0.0,2.0.0)
- 1.0.90
+ 1.1.19
+ 1.4.57
+
[1.0.0, 2.0.0)
+ [1.0.0, 2.0.0)
+
4.8.37