diff --git a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManager.java b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManager.java index e73660df1d80..42f698a3007d 100644 --- a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManager.java +++ b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2026, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -386,4 +386,14 @@ default void deleteResourcesByType(String resourceType) throws ConfigurationMana throw new NotImplementedException("This functionality is not implemented."); } + + /** + * Retrieves the default configuration for the given resource type and resource name, if it exists. + * @param resourceTypeName + * @param resourceName + * @return the resource object corresponding to the resource with default configurations. + * @throws ConfigurationManagementException + */ + Resource getDefaultResource(String resourceTypeName, String resourceName) + throws ConfigurationManagementException; } diff --git a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManagerImpl.java b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManagerImpl.java index f356e8a7cd4d..28e0592b340e 100644 --- a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManagerImpl.java +++ b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManagerImpl.java @@ -69,6 +69,7 @@ .ERROR_CODE_ATTRIBUTE_IDENTIFIERS_REQUIRED; import static org.wso2.carbon.identity.configuration.mgt.core.constant.ConfigurationConstants.ErrorMessages .ERROR_CODE_ATTRIBUTE_REQUIRED; +import static org.wso2.carbon.identity.configuration.mgt.core.constant.ConfigurationConstants.ErrorMessages.ERROR_CODE_DEFAULT_RESOLVER_DOES_NOT_EXISTS; import static org.wso2.carbon.identity.configuration.mgt.core.constant.ConfigurationConstants.ErrorMessages .ERROR_CODE_FILES_DOES_NOT_EXISTS; import static org.wso2.carbon.identity.configuration.mgt.core.constant.ConfigurationConstants.ErrorMessages @@ -598,6 +599,28 @@ public Attribute replaceAttribute(String resourceTypeName, String resourceName, return attribute; } + /** + * Resolve the default configurations for the given resource from the registered default config resolvers. + * + * @param resourceType Resource type name. + * @param resourceName Resource name. + * @return Default configurations for the given resource. + * @throws ConfigurationManagementException if no default resolver is found. + */ + @Override + public Resource getDefaultResource(String resourceType, String resourceName) + throws ConfigurationManagementException { + + DefaultConfigResolver resolver = ConfigurationManagerComponentDataHolder.getInstance() + .getDefaultConfigResolver(resourceType, resourceName); + + if (resolver == null) { + throw handleServerException(ERROR_CODE_DEFAULT_RESOLVER_DOES_NOT_EXISTS, resourceType); + } + + return resolver.getDefaultConfigs(resourceType, resourceName); + } + private void validateSearchRequest(Condition condition) throws ConfigurationManagementClientException { if (condition == null) { diff --git a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/DefaultConfigResolver.java b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/DefaultConfigResolver.java new file mode 100644 index 000000000000..f82045265036 --- /dev/null +++ b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/DefaultConfigResolver.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, 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.configuration.mgt.core; + +import org.wso2.carbon.identity.configuration.mgt.core.model.Resource; +import org.wso2.carbon.identity.configuration.mgt.core.model.ResourceIdentifier; + +/** + * Interface for resolving default configurations for a given resource type and name. + */ +public interface DefaultConfigResolver { + + /** + * Get the resource identifier that this resolver can handle. + * @return ResourceIdentifier of the default configuration. + */ + ResourceIdentifier getResourceIdentifier(); + + /** + * Get the default configurations for the given resource type and name. + * + * @param resourceTypeName Name of the resource type. + * @param resourceName Name of the resource. + * @return Resource containing the default configurations. + */ + Resource getDefaultConfigs(String resourceTypeName, String resourceName); +} diff --git a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/constant/ConfigurationConstants.java b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/constant/ConfigurationConstants.java index 0eeec8f5a36d..2044e5c13b8e 100644 --- a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/constant/ConfigurationConstants.java +++ b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/constant/ConfigurationConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2025, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018-2026, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -190,7 +190,9 @@ public enum ErrorMessages { ERROR_CODE_RESOLVING_TENANT_DOMAIN("CONFIGM_00050", "Error occurred while resolving the tenant domain " + "for the organization id: %s."), ERROR_CODE_RESOLVING_TENANT_ID("CONFIGM_00051", "Error occurred while resolving the tenant id " + - "for the organization id: %s."); + "for the organization id: %s."), + ERROR_CODE_DEFAULT_RESOLVER_DOES_NOT_EXISTS("CONFIGM_00052", "Default Config Resolver " + + "does not exists for the resource type : %s."); private final String code; diff --git a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/internal/ConfigurationManagerComponent.java b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/internal/ConfigurationManagerComponent.java index 3c1cc6242e56..4149c0302866 100644 --- a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/internal/ConfigurationManagerComponent.java +++ b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/internal/ConfigurationManagerComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2025, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018-2026, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import org.wso2.carbon.database.utils.jdbc.exceptions.DataAccessException; import org.wso2.carbon.identity.configuration.mgt.core.ConfigurationManager; import org.wso2.carbon.identity.configuration.mgt.core.ConfigurationManagerImpl; +import org.wso2.carbon.identity.configuration.mgt.core.DefaultConfigResolver; import org.wso2.carbon.identity.configuration.mgt.core.dao.ConfigurationDAO; import org.wso2.carbon.identity.configuration.mgt.core.dao.impl.CachedBackedConfigurationDAO; import org.wso2.carbon.identity.configuration.mgt.core.dao.impl.ConfigurationDAOImpl; @@ -189,4 +190,27 @@ protected void unsetOrgResourceResolverService(OrgResourceResolverService orgRes ConfigurationManagerComponentDataHolder.getInstance().setOrgResourceResolverService(null); } + + @Reference( + name = "default.config.resolver", + service = DefaultConfigResolver.class, + cardinality = ReferenceCardinality.MULTIPLE, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetDefaultConfigResolver" + ) + protected void setDefaultConfigResolver(DefaultConfigResolver defaultConfigResolver) { + + ConfigurationManagerComponentDataHolder.getInstance().addDefaultConfigResolver(defaultConfigResolver); + if (log.isDebugEnabled()) { + log.debug("DefaultConfigResolver registered: " + defaultConfigResolver.getClass().getName()); + } + } + + protected void unsetDefaultConfigResolver(DefaultConfigResolver defaultConfigResolver) { + + ConfigurationManagerComponentDataHolder.getInstance().removeDefaultConfigResolver(defaultConfigResolver); + if (log.isDebugEnabled()) { + log.debug("DefaultConfigResolver unregistered: " + defaultConfigResolver.getClass().getName()); + } + } } diff --git a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/internal/ConfigurationManagerComponentDataHolder.java b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/internal/ConfigurationManagerComponentDataHolder.java index bc0d61efb97f..e3e4d0ed4daa 100644 --- a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/internal/ConfigurationManagerComponentDataHolder.java +++ b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/internal/ConfigurationManagerComponentDataHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2025, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2019-2026, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,13 @@ package org.wso2.carbon.identity.configuration.mgt.core.internal; +import java.util.HashMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Map; +import org.wso2.carbon.identity.configuration.mgt.core.DefaultConfigResolver; +import org.wso2.carbon.identity.configuration.mgt.core.model.ResourceIdentifier; import org.wso2.carbon.identity.organization.management.service.OrganizationManager; import org.wso2.carbon.identity.organization.resource.hierarchy.traverse.service.OrgResourceResolverService; import org.wso2.carbon.user.core.service.RealmService; @@ -25,6 +32,7 @@ */ public class ConfigurationManagerComponentDataHolder { + private static final Log LOG = LogFactory.getLog(ConfigurationManagerComponentDataHolder.class); private static ConfigurationManagerComponentDataHolder instance = new ConfigurationManagerComponentDataHolder(); private static boolean useCreatedTime = false; @@ -32,6 +40,7 @@ public class ConfigurationManagerComponentDataHolder { private RealmService realmService; private OrganizationManager organizationManager; private OrgResourceResolverService orgResourceResolverService; + private final Map defaultConfigResolvers = new HashMap<>(); public static ConfigurationManagerComponentDataHolder getInstance() { @@ -107,4 +116,51 @@ public void setOrgResourceResolverService(OrgResourceResolverService orgResource this.orgResourceResolverService = orgResourceResolverService; } + + /** + * Add a DefaultConfigResolver. + * + * @param resolver DefaultConfigResolver to add. + */ + public void addDefaultConfigResolver(DefaultConfigResolver resolver) { + + ResourceIdentifier resourceIdentifier = resolver.getResourceIdentifier(); + if (resourceIdentifier == null) { + if(LOG.isDebugEnabled()){ + LOG.debug("Skipping registration of DefaultConfigResolver with a null resource identifier: " + + resolver.getClass().getName()); + } + return; + } + defaultConfigResolvers.put(resourceIdentifier, resolver); + } + + /** + * Remove a DefaultConfigResolver. + * + * @param resolver DefaultConfigResolver to remove. + */ + public void removeDefaultConfigResolver(DefaultConfigResolver resolver) { + + ResourceIdentifier resourceIdentifier = resolver.getResourceIdentifier(); + if (resourceIdentifier == null) { + if(LOG.isDebugEnabled()) { + LOG.debug("Skipping removal of DefaultConfigResolver with a null resource identifier: " + + resolver.getClass().getName()); + } + return; + } + defaultConfigResolvers.remove(resourceIdentifier); + } + + /** + * Get the DefaultConfigResolver for the given resource type and name. + * @param resourceType + * @param resourceName + * @return + */ + public DefaultConfigResolver getDefaultConfigResolver(String resourceType, String resourceName){ + + return defaultConfigResolvers.get(new ResourceIdentifier(resourceType, resourceName)); + } } diff --git a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/model/ResourceIdentifier.java b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/model/ResourceIdentifier.java new file mode 100644 index 000000000000..c84e096ffc37 --- /dev/null +++ b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/main/java/org/wso2/carbon/identity/configuration/mgt/core/model/ResourceIdentifier.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2026, 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.configuration.mgt.core.model; + +import java.util.Objects; + +public class ResourceIdentifier { + + private final String resourceType; + private final String resourceName; + + public ResourceIdentifier(String resourceType, String resourceName) { + + this.resourceType = resourceType; + this.resourceName = resourceName; + } + + public String getResourceType() { + + return resourceType; + } + + public String getResourceName() { + + return resourceName; + } + + @Override + public boolean equals(Object o) { + + if (!(o instanceof ResourceIdentifier that)) { + return false; + } + return Objects.equals(resourceType, that.resourceType) && + Objects.equals(resourceName, that.resourceName); + } + + @Override + public int hashCode() { + + return Objects.hash(resourceType, resourceName); + } +} diff --git a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/test/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManagerTest.java b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/test/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManagerTest.java index b5f62f15e369..467b9ec68180 100644 --- a/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/test/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManagerTest.java +++ b/components/configuration-mgt/org.wso2.carbon.identity.configuration.mgt.core/src/test/java/org/wso2/carbon/identity/configuration/mgt/core/ConfigurationManagerTest.java @@ -30,6 +30,7 @@ import org.wso2.carbon.identity.configuration.mgt.core.dao.ConfigurationDAO; import org.wso2.carbon.identity.configuration.mgt.core.dao.impl.ConfigurationDAOImpl; import org.wso2.carbon.identity.configuration.mgt.core.exception.ConfigurationManagementClientException; +import org.wso2.carbon.identity.configuration.mgt.core.exception.ConfigurationManagementException; import org.wso2.carbon.identity.configuration.mgt.core.internal.ConfigurationManagerComponentDataHolder; import org.wso2.carbon.identity.configuration.mgt.core.model.Attribute; import org.wso2.carbon.identity.configuration.mgt.core.model.ConfigurationManagerConfigurationHolder; @@ -37,6 +38,7 @@ import org.wso2.carbon.identity.configuration.mgt.core.model.ResourceAdd; import org.wso2.carbon.identity.configuration.mgt.core.model.ResourceType; import org.wso2.carbon.identity.configuration.mgt.core.model.ResourceFile; +import org.wso2.carbon.identity.configuration.mgt.core.model.ResourceIdentifier; import org.wso2.carbon.identity.configuration.mgt.core.model.ResourceTypeAdd; import org.wso2.carbon.identity.configuration.mgt.core.model.Resources; import org.wso2.carbon.identity.configuration.mgt.core.search.ComplexCondition; @@ -64,6 +66,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -889,6 +892,77 @@ private void prepareConfigs(MockedStatic privilegedCarb configurationManager = new ConfigurationManagerImpl(configurationHolder); } + @Test(priority = 44) + public void testAddAndGetDefaultConfigResolver() { + + ConfigurationManagerComponentDataHolder dataHolder = + ConfigurationManagerComponentDataHolder.getInstance(); + DefaultConfigResolver resolver = mock(DefaultConfigResolver.class); + when(resolver.getResourceIdentifier()).thenReturn(new ResourceIdentifier("testType", "testName")); + try { + dataHolder.addDefaultConfigResolver(resolver); + assertEquals("Resolver should be present after bind", resolver, + dataHolder.getDefaultConfigResolver("testType", "testName")); + } finally { + dataHolder.removeDefaultConfigResolver(resolver); + } + assertNull("Resolver should be absent after unbind", + dataHolder.getDefaultConfigResolver("testType", "testName")); + } + + @Test(priority = 45) + public void testGetDefaultResourceUsesMatchingResolver() throws Exception { + + ConfigurationManagerComponentDataHolder dataHolder = + ConfigurationManagerComponentDataHolder.getInstance(); + Resource expected = new Resource(); + expected.setResourceName("default"); + + DefaultConfigResolver matching = mock(DefaultConfigResolver.class); + when(matching.getResourceIdentifier()).thenReturn(new ResourceIdentifier("anyType", "anyName")); + when(matching.getDefaultConfigs(anyString(), anyString())).thenReturn(expected); + + DefaultConfigResolver shouldNotBeCalled = mock(DefaultConfigResolver.class); + when(shouldNotBeCalled.getResourceIdentifier()) + .thenReturn(new ResourceIdentifier("otherType", "otherName")); + + try { + dataHolder.addDefaultConfigResolver(matching); + dataHolder.addDefaultConfigResolver(shouldNotBeCalled); + + Resource actual = configurationManager.getDefaultResource("anyType", "anyName"); + + assertEquals(expected, actual); + verify(matching, times(1)).getDefaultConfigs("anyType", "anyName"); + verify(shouldNotBeCalled, times(0)).getDefaultConfigs(anyString(), anyString()); + } finally { + dataHolder.removeDefaultConfigResolver(matching); + dataHolder.removeDefaultConfigResolver(shouldNotBeCalled); + } + } + + @Test(priority = 46, expectedExceptions = ConfigurationManagementException.class) + public void testGetDefaultResourceThrowsWhenNoResolverMatches() throws Exception { + + ConfigurationManagerComponentDataHolder dataHolder = + ConfigurationManagerComponentDataHolder.getInstance(); + DefaultConfigResolver nonMatching = mock(DefaultConfigResolver.class); + when(nonMatching.getResourceIdentifier()).thenReturn(new ResourceIdentifier("someType", "someName")); + + try { + dataHolder.addDefaultConfigResolver(nonMatching); + configurationManager.getDefaultResource("unknownType", "unknownName"); + } finally { + dataHolder.removeDefaultConfigResolver(nonMatching); + } + } + + @Test(priority = 47, expectedExceptions = ConfigurationManagementException.class) + public void testGetDefaultResourceThrowsWhenNoResolversRegistered() throws Exception { + + configurationManager.getDefaultResource("anyType", "anyName"); + } + private void mockCarbonContextForTenant(int tenantId, String tenantDomain, MockedStatic privilegedCarbonContext) { diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/db2.sql b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/db2.sql index e2d877c479fe..2e9e781b8029 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/db2.sql +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/db2.sql @@ -1651,7 +1651,8 @@ INSERT INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('32360745-9c3e-4391-b563-66f17f0eb93a', 'ADMIN_ADVISORY_BANNER', 'A resource type to store admin advisory banner configurations.'), ('82ab7001-fb0e-44da-9169-1f63e4964d9b', 'REMOTE_LOGGING_CONFIG', 'A resource type to store remote server logger configurations.'), ('08fbc096-56c5-4ae6-9edc-54198a07e0dc', 'ISSUER_USAGE_SCOPE', 'A resource type to store issuer usage scope for organizations.'), -('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.') +('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'), +('4fed2813-cfa8-40b1-83e6-4ab85d7fcb16', 'DEVICE_MANAGEMENT', 'A resource type to keep tenant level configurations for user device management.') / CREATE TABLE IDN_CONFIG_RESOURCE ( @@ -2608,7 +2609,7 @@ CREATE TABLE IDN_PUSH_DEVICE_STORE ( PROVIDER VARCHAR(45) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), - UNIQUE (USER_ID) + UNIQUE (USER_ID, DEVICE_TOKEN, TENANT_ID) ) / diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/h2.sql b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/h2.sql index 7bafed8fa168..67d410cb7653 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/h2.sql +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/h2.sql @@ -1012,7 +1012,8 @@ INSERT INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('32360745-9c3e-4391-b563-66f17f0eb93a', 'ADMIN_ADVISORY_BANNER', 'A resource type to store admin advisory banner configurations.'), ('82ab7001-fb0e-44da-9169-1f63e4964d9b', 'REMOTE_LOGGING_CONFIG', 'A resource type to store remote server logger configurations.'), ('08fbc096-56c5-4ae6-9edc-54198a07e0dc', 'ISSUER_USAGE_SCOPE', 'A resource type to store issuer usage scope for organizations.'), -('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'); +('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'), +('4fed2813-cfa8-40b1-83e6-4ab85d7fcb16', 'DEVICE_MANAGEMENT', 'A resource type to keep tenant level configurations for user device management.'); CREATE TABLE IF NOT EXISTS IDN_CONFIG_RESOURCE ( ID VARCHAR(255) NOT NULL, @@ -1625,7 +1626,7 @@ CREATE TABLE IF NOT EXISTS IDN_PUSH_DEVICE_STORE ( PROVIDER VARCHAR(45) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), - UNIQUE (USER_ID) + UNIQUE (USER_ID, DEVICE_TOKEN, TENANT_ID) ); CREATE TABLE IF NOT EXISTS IDN_FLOW ( diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mssql.sql b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mssql.sql index 7484a815c6aa..196abf606a92 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mssql.sql +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mssql.sql @@ -1122,7 +1122,8 @@ INSERT INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('32360745-9c3e-4391-b563-66f17f0eb93a', 'ADMIN_ADVISORY_BANNER', 'A resource type to store admin advisory banner configurations.'), ('82ab7001-fb0e-44da-9169-1f63e4964d9b', 'REMOTE_LOGGING_CONFIG', 'A resource type to store remote server logger configurations.'), ('08fbc096-56c5-4ae6-9edc-54198a07e0dc', 'ISSUER_USAGE_SCOPE', 'A resource type to store issuer usage scope for organizations.'), -('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'); +('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'), +('4fed2813-cfa8-40b1-83e6-4ab85d7fcb16', 'DEVICE_MANAGEMENT', 'A resource type to keep tenant level configurations for user device management.'); IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[IDN_CONFIG_RESOURCE]') AND TYPE IN (N'U')) @@ -1792,7 +1793,7 @@ CREATE TABLE IDN_PUSH_DEVICE_STORE ( PROVIDER VARCHAR(45) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), - UNIQUE (USER_ID) + UNIQUE (USER_ID, DEVICE_TOKEN, TENANT_ID) ); IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[IDN_FLOW]') AND TYPE IN (N'U')) diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mysql-cluster.sql b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mysql-cluster.sql index 9e62af17c8e3..04fe80d3a01e 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mysql-cluster.sql +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mysql-cluster.sql @@ -1281,7 +1281,8 @@ INSERT INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('32360745-9c3e-4391-b563-66f17f0eb93a', 'ADMIN_ADVISORY_BANNER', 'A resource type to store admin advisory banner configurations.'), ('82ab7001-fb0e-44da-9169-1f63e4964d9b', 'REMOTE_LOGGING_CONFIG', 'A resource type to store remote server logger configurations.'), ('08fbc096-56c5-4ae6-9edc-54198a07e0dc', 'ISSUER_USAGE_SCOPE', 'A resource type to store issuer usage scope for organizations.'), -('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'); +('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'), +('4fed2813-cfa8-40b1-83e6-4ab85d7fcb16', 'DEVICE_MANAGEMENT', 'A resource type to keep tenant level configurations for user device management.'); CREATE TABLE IF NOT EXISTS IDN_CONFIG_RESOURCE ( ID VARCHAR(255) NOT NULL, @@ -1896,7 +1897,7 @@ CREATE TABLE IF NOT EXISTS IDN_PUSH_DEVICE_STORE ( PROVIDER VARCHAR(45) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), - UNIQUE (USER_ID) + UNIQUE (USER_ID, DEVICE_TOKEN, TENANT_ID) ) ENGINE NDB; CREATE TABLE IF NOT EXISTS IDN_FLOW ( diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mysql.sql b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mysql.sql index b5aa3b4e5684..fe5422b7abda 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mysql.sql +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/mysql.sql @@ -1128,7 +1128,8 @@ INSERT INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('32360745-9c3e-4391-b563-66f17f0eb93a', 'ADMIN_ADVISORY_BANNER', 'A resource type to store admin advisory banner configurations.'), ('82ab7001-fb0e-44da-9169-1f63e4964d9b', 'REMOTE_LOGGING_CONFIG', 'A resource type to store remote server logger configurations.'), ('08fbc096-56c5-4ae6-9edc-54198a07e0dc', 'ISSUER_USAGE_SCOPE', 'A resource type to store issuer usage scope for organizations.'), -('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'); +('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'), +('4fed2813-cfa8-40b1-83e6-4ab85d7fcb16', 'DEVICE_MANAGEMENT', 'A resource type to keep tenant level configurations for user device management.'); CREATE TABLE IF NOT EXISTS IDN_CONFIG_RESOURCE ( ID VARCHAR(255) NOT NULL, @@ -1745,7 +1746,7 @@ CREATE TABLE IF NOT EXISTS IDN_PUSH_DEVICE_STORE ( PROVIDER VARCHAR(45) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), - UNIQUE (USER_ID) + UNIQUE (USER_ID, DEVICE_TOKEN, TENANT_ID) ) DEFAULT CHARACTER SET latin1 ENGINE INNODB; CREATE TABLE IF NOT EXISTS IDN_FLOW ( diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/oracle.sql b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/oracle.sql index 49771a8a6d69..f54491df9159 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/oracle.sql +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/oracle.sql @@ -1851,6 +1851,8 @@ INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('08fbc096-56c5-4ae6-9edc-54198a07e0dc', 'ISSUER_USAGE_SCOPE', 'A resource type to store issuer usage scope for organizations.') INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.') +INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES +('4fed2813-cfa8-40b1-83e6-4ab85d7fcb16', 'DEVICE_MANAGEMENT', 'A resource type to keep tenant level configurations for user device management.') SELECT 1 FROM dual / @@ -2694,7 +2696,7 @@ CREATE TABLE IDN_PUSH_DEVICE_STORE ( PROVIDER VARCHAR(45) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), - UNIQUE (USER_ID) + UNIQUE (USER_ID, DEVICE_TOKEN, TENANT_ID) ) / diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/oracle_rac.sql b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/oracle_rac.sql index 89c6ecaff150..81f57edbf10b 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/oracle_rac.sql +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/oracle_rac.sql @@ -1694,6 +1694,8 @@ INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('08fbc096-56c5-4ae6-9edc-54198a07e0dc', 'ISSUER_USAGE_SCOPE', 'A resource type to store issuer usage scope for organizations.') INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.') +INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES +('4fed2813-cfa8-40b1-83e6-4ab85d7fcb16', 'DEVICE_MANAGEMENT', 'A resource type to keep tenant level configurations for user device management.') SELECT 1 FROM dual / CREATE TABLE IDN_CONFIG_RESOURCE ( @@ -2620,7 +2622,7 @@ CREATE TABLE IDN_PUSH_DEVICE_STORE ( PROVIDER VARCHAR(45) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), - UNIQUE (USER_ID) + UNIQUE (USER_ID, DEVICE_TOKEN, TENANT_ID) ) / diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/postgresql.sql b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/postgresql.sql index a68482e37fe2..872c24cd039d 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/postgresql.sql +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/dbscripts/postgresql.sql @@ -1177,7 +1177,8 @@ INSERT INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES ('32360745-9c3e-4391-b563-66f17f0eb93a', 'ADMIN_ADVISORY_BANNER', 'A resource type to store admin advisory banner configurations.'), ('82ab7001-fb0e-44da-9169-1f63e4964d9b', 'REMOTE_LOGGING_CONFIG', 'A resource type to store remote server logger configurations.'), ('08fbc096-56c5-4ae6-9edc-54198a07e0dc', 'ISSUER_USAGE_SCOPE', 'A resource type to store issuer usage scope for organizations.'), -('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'); +('12c78d11-65cd-4b6e-b482-98538ecd7a5c', 'FAPI_CONFIGURATION', 'A resource type to keep the FAPI configurations.'), +('4fed2813-cfa8-40b1-83e6-4ab85d7fcb16', 'DEVICE_MANAGEMENT', 'A resource type to keep tenant level configurations for user device management.'); CREATE TABLE IF NOT EXISTS IDN_CONFIG_RESOURCE ( ID VARCHAR(255) NOT NULL, @@ -1821,7 +1822,7 @@ CREATE TABLE IF NOT EXISTS IDN_PUSH_DEVICE_STORE ( PROVIDER VARCHAR(45) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), - UNIQUE (USER_ID) + UNIQUE (USER_ID, DEVICE_TOKEN, TENANT_ID) ); CREATE TABLE IF NOT EXISTS IDN_FLOW ( diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 index 868ac2c1b6fb..dbd608b2b8c4 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/identity.xml.j2 @@ -1536,6 +1536,10 @@ + + {{push_device_management.max_device_limit_per_user}} + + {{rest_api_authentication.add_realm_user_to_error}} diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.default.json b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.default.json index c43ef06bd382..175440ee28cd 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.default.json +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/org.wso2.carbon.identity.core.server.feature.default.json @@ -861,6 +861,7 @@ "cache.push_device_registration_request_cache.timeout": "300", "cache.push_device_registration_request_cache.capacity": "$ref{cache.default_capacity}", "push_authenticator.device_registration_context.validity_period": "180", + "push_device_management.max_device_limit_per_user": "10", "cache.saml_cert_cache.enable": true, "cache.saml_cert_cache.timeout": "900", "cache.saml_cert_cache.capacity": "100", @@ -1319,6 +1320,11 @@ "description": "This email is sent to the user to complete the CIBA authentication request.", "displayName": "CIBA Authentication Request", "id": "Q0lCQUF1dGhlbnRpY2F0aW9uTm90aWZpY2F0aW9u" + }, + { + "description": "This email is sent to the user to inform when a new device has been registered for push authentication.", + "displayName": "Push Device Registration", + "id": "UHVzaERldmljZVJlZ2lzdHJhdGlvbg" } ], "console.extensions.smsTemplates": [ diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/resource-access-control-v2.xml.j2 b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/resource-access-control-v2.xml.j2 index 40b48a588a01..ee7190fab5ad 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/resource-access-control-v2.xml.j2 +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/resource-access-control-v2.xml.j2 @@ -1048,6 +1048,9 @@ internal_login + + internal_login + {% if configs.endpoint.elevate_permission is sameas false %} internal_login