Skip to content

Commit

Permalink
Introduce pre add user validations for email domain discovery feature
Browse files Browse the repository at this point in the history
  • Loading branch information
dewniMW committed Oct 19, 2023
1 parent aef9ec4 commit 2b13ce0
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
org.apache.commons.logging;version="${org.apache.commons.logging.imp.pkg.version.range}",
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.context;version="${carbon.kernel.package.import.version.range}",
org.wso2.carbon.database.utils.jdbc;version="${org.wso2.carbon.database.utils.version.range}",
org.wso2.carbon.database.utils.jdbc.exceptions;version="${org.wso2.carbon.database.utils.version.range}",
org.wso2.carbon.identity.organization.config.service;version="${org.wso2.identity.organization.mgt.imp.pkg.version.range}",
Expand All @@ -83,7 +84,11 @@
org.wso2.carbon.identity.organization.management.service;version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}",
org.wso2.carbon.identity.organization.management.service.constant;version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}",
org.wso2.carbon.identity.organization.management.service.exception;version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}",
org.wso2.carbon.identity.organization.management.service.util;version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}"
org.wso2.carbon.identity.organization.management.service.util;version="${org.wso2.identity.organization.mgt.core.imp.pkg.version.range}",
org.wso2.carbon.identity.core;version="${carbon.identity.package.import.version.range}",
org.wso2.carbon.identity.core.util;version="${carbon.identity.package.import.version.range}",
org.wso2.carbon.user.core;version="${carbon.kernel.package.import.version.range}",
org.wso2.carbon.user.core.listener;version="${carbon.kernel.package.import.version.range}"
</Import-Package>
</instructions>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;

import java.util.List;

/**
* Interface for handling organization discovery types.
*/
Expand Down Expand Up @@ -50,4 +52,12 @@ boolean isDiscoveryConfigurationEnabled(String organizationId)
* @return The extracted attribute value.
*/
String extractAttributeValue(String discoveryInput);

/**
* Get the list of validations that are required for events triggered during organization discovery related
* operations.
*
* @return the list of events.
*/
List<String> requiredEventValidations();
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.List;
import java.util.Optional;

import static org.wso2.carbon.identity.organization.discovery.service.constant.DiscoveryConstants.PRE_ADD_USER_EMAIL_DOMAIN_VALIDATE;
import static org.wso2.carbon.identity.organization.management.service.constant.OrganizationManagementConstants.ErrorMessages.ERROR_CODE_DISCOVERY_CONFIG_DISABLED;
import static org.wso2.carbon.identity.organization.management.service.constant.OrganizationManagementConstants.ErrorMessages.ERROR_CODE_ERROR_RETRIEVING_DISCOVERY_CONFIGURATION;
import static org.wso2.carbon.identity.organization.management.service.util.Utils.getOrganizationId;
Expand Down Expand Up @@ -81,4 +82,10 @@ public String extractAttributeValue(String discoveryInput) {
}
return null;
}

@Override
public List<String> requiredEventValidations() {

return Collections.singletonList(PRE_ADD_USER_EMAIL_DOMAIN_VALIDATE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ List<OrgDiscoveryAttribute> updateOrganizationDiscoveryAttributes(String organiz
*/
boolean isDiscoveryAttributeValueAvailable(String type, String value) throws OrganizationManagementException;

/**
* Check if the given discovery attribute is already mapped to an organization within the hierarchy under the given
* organization.
*
* @param organizationId The organization ID.
* @param type The organization discovery attribute type.
* @param value The organization discovery attribute value.
* @return If the discovery attribute already exists within the hierarchy.
* @throws OrganizationManagementException The exception thrown when checking if the discovery attribute already
* exists within the hierarchy.
*/
boolean isDiscoveryAttributeValueAvailable(String organizationId, String type, String value) throws
OrganizationManagementException;

/**
* List the discovery attributes of all the organizations under the root organization.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ public boolean isDiscoveryAttributeValueAvailable(String type, String value) thr
null, type, Collections.singletonList(value));
}

@Override
public boolean isDiscoveryAttributeValueAvailable(String organizationId, String type, String value)
throws OrganizationManagementException {

return !organizationDiscoveryDAO.isDiscoveryAttributeExistInHierarchy(false, organizationId,
null, type, Collections.singletonList(value));
}

@Override
public Map<String, List<OrgDiscoveryAttribute>> getOrganizationsDiscoveryAttributes()
throws OrganizationManagementException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.organization.discovery.service.constant;

/**
* This class holds the constants related to organization discovery service.
*/
public class DiscoveryConstants {

public static final String ENABLE_CONFIG = ".enable";
public static final String PRE_ADD_USER_EMAIL_DOMAIN_VALIDATE = "PRE_ADD_USER_EMAIL_DOMAIN_VALIDATE";
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
import org.wso2.carbon.identity.organization.discovery.service.EmailDomainBasedDiscoveryHandler;
import org.wso2.carbon.identity.organization.discovery.service.OrganizationDiscoveryManager;
import org.wso2.carbon.identity.organization.discovery.service.OrganizationDiscoveryManagerImpl;
import org.wso2.carbon.identity.organization.discovery.service.listener.OrganizationDiscoveryUserOperationListener;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.user.core.listener.UserOperationEventListener;

/**
* Service component class for the organization discovery service.
Expand All @@ -53,6 +55,8 @@ protected void activate(ComponentContext componentContext) {
AttributeBasedOrganizationDiscoveryHandler emailDomainDiscovery = new EmailDomainBasedDiscoveryHandler();
bundleContext.registerService(AttributeBasedOrganizationDiscoveryHandler.class.getName(), emailDomainDiscovery,
null);
bundleContext.registerService(UserOperationEventListener.class.getName(),
new OrganizationDiscoveryUserOperationListener(), null);
LOG.info("Organization discovery service component activated successfully.");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* 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.organization.discovery.service.listener;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.core.AbstractIdentityUserOperationEventListener;
import org.wso2.carbon.identity.core.util.IdentityCoreConstants;
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.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.AttributeBasedOrganizationDiscoveryHandler;
import org.wso2.carbon.identity.organization.discovery.service.OrganizationDiscoveryManager;
import org.wso2.carbon.identity.organization.discovery.service.OrganizationDiscoveryManagerImpl;
import org.wso2.carbon.identity.organization.discovery.service.internal.OrganizationDiscoveryServiceHolder;
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 org.wso2.carbon.identity.organization.management.service.util.OrganizationManagementUtil;
import org.wso2.carbon.user.core.UserStoreException;
import org.wso2.carbon.user.core.UserStoreManager;

import java.util.List;
import java.util.Map;

import static org.wso2.carbon.identity.organization.config.service.constant.OrganizationConfigConstants.ErrorMessages.ERROR_CODE_DISCOVERY_CONFIG_NOT_EXIST;
import static org.wso2.carbon.identity.organization.discovery.service.constant.DiscoveryConstants.ENABLE_CONFIG;
import static org.wso2.carbon.identity.organization.discovery.service.constant.DiscoveryConstants.PRE_ADD_USER_EMAIL_DOMAIN_VALIDATE;
import static org.wso2.carbon.identity.organization.management.service.constant.OrganizationManagementConstants.ErrorMessages.ERROR_CODE_EMAIL_DOMAIN_ASSOCIATED_WITH_DIFFERENT_ORGANIZATION;
import static org.wso2.carbon.identity.organization.management.service.constant.OrganizationManagementConstants.ErrorMessages.ERROR_CODE_EMAIL_DOMAIN_NOT_MAPPED_TO_ORGANIZATION;

/**
* This is to perform organization discovery related user operations.
*/
public class OrganizationDiscoveryUserOperationListener extends AbstractIdentityUserOperationEventListener {

private static final Log LOG = LogFactory.getLog(OrganizationDiscoveryUserOperationListener.class);
private final OrganizationDiscoveryManager organizationDiscoveryManager = new OrganizationDiscoveryManagerImpl();

@Override
public int getExecutionOrderId() {

int orderId = getOrderId();
if (orderId != IdentityCoreConstants.EVENT_LISTENER_ORDER_ID) {
return orderId;
}
return 114;
}

@Override
public boolean doPreAddUserWithID(String userName, Object credential, String[] roleList, Map<String, String> claims,
String profile, UserStoreManager userStoreManager) throws UserStoreException {

if (!isEnable()) {
return true;
}

try {
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
if (!OrganizationManagementUtil.isOrganization(tenantDomain)) {
return true;
}
String organizationId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getOrganizationId();
if (StringUtils.isBlank(organizationId)) {
organizationId = getOrganizationManager().resolveOrganizationId(tenantDomain);
}
String primaryOrganizationId = getOrganizationManager().getPrimaryOrganizationId(organizationId);
int tenantId = IdentityTenantUtil.getTenantId(getOrganizationManager()
.resolveTenantDomain(primaryOrganizationId));
DiscoveryConfig discoveryConfig = getOrganizationConfigManager()
.getDiscoveryConfigurationByTenantId(tenantId);
List<ConfigProperty> configProperties = discoveryConfig.getConfigProperties();
Map<String, AttributeBasedOrganizationDiscoveryHandler> discoveryHandlers =
organizationDiscoveryManager.getAttributeBasedOrganizationDiscoveryHandlers();
for (ConfigProperty configProperty : configProperties) {
String type = configProperty.getKey().split(ENABLE_CONFIG)[0];
if (discoveryHandlers.get(type) != null && Boolean.parseBoolean(configProperty.getValue())) {
AttributeBasedOrganizationDiscoveryHandler handler = discoveryHandlers.get(type);
// Currently only email domain based organization discovery is supported.
if (handler.requiredEventValidations().contains(PRE_ADD_USER_EMAIL_DOMAIN_VALIDATE)) {
String domain = handler.extractAttributeValue(userName);
List<OrgDiscoveryAttribute> organizationDiscoveryAttributes = organizationDiscoveryManager
.getOrganizationDiscoveryAttributes(organizationId, false);
// If the organization doesn't have any email domains mapped, then we need to check if the
// email domain in the username is not mapped to any other organization .
if (organizationDiscoveryAttributes.isEmpty()) {
boolean domainAvailable = organizationDiscoveryManager.isDiscoveryAttributeValueAvailable
(primaryOrganizationId, handler.getType(), domain);
if (!domainAvailable) {
throw new UserStoreException(
ERROR_CODE_EMAIL_DOMAIN_ASSOCIATED_WITH_DIFFERENT_ORGANIZATION.getDescription(),
ERROR_CODE_EMAIL_DOMAIN_ASSOCIATED_WITH_DIFFERENT_ORGANIZATION.getCode());
}
return true;
} else {
for (OrgDiscoveryAttribute attribute : organizationDiscoveryAttributes) {
List<String> organizationMappedEmailDomains = attribute.getValues();
if (organizationMappedEmailDomains != null &&
organizationMappedEmailDomains.contains(domain)) {
return true;
}
throw new UserStoreException(
ERROR_CODE_EMAIL_DOMAIN_NOT_MAPPED_TO_ORGANIZATION.getDescription(),
ERROR_CODE_EMAIL_DOMAIN_NOT_MAPPED_TO_ORGANIZATION.getCode());
}
}
}
}
}
} catch (OrganizationManagementException e) {
LOG.error("Error while creating user", e);
return false;
} catch (OrganizationConfigException e) {
if (ERROR_CODE_DISCOVERY_CONFIG_NOT_EXIST.getCode().equals(e.getErrorCode())) {
return true;
}
LOG.error("Error while creating user", e);
return false;
}
return true;
}

private OrganizationConfigManager getOrganizationConfigManager() {

return OrganizationDiscoveryServiceHolder.getInstance().getOrganizationConfigManager();
}

private OrganizationManager getOrganizationManager() {

return OrganizationDiscoveryServiceHolder.getInstance().getOrganizationManager();
}
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@
<org.wso2.identity.organization.mgt.imp.pkg.version.range>[1.0.0,2.0.0)
</org.wso2.identity.organization.mgt.imp.pkg.version.range>

<identity.organization.management.core.version>1.0.69</identity.organization.management.core.version>
<identity.organization.management.core.version>1.0.71</identity.organization.management.core.version>
<org.wso2.identity.organization.mgt.core.imp.pkg.version.range>[1.0.0,2.0.0)
</org.wso2.identity.organization.mgt.core.imp.pkg.version.range>

Expand Down

0 comments on commit 2b13ce0

Please sign in to comment.