From d346886e8f13b13f08580fd0039cdc09a1cf929e Mon Sep 17 00:00:00 2001 From: Ashan Thamara Palihakkara <75057725+ashanthamara@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:51:22 +0530 Subject: [PATCH 1/6] Integrate secret-management to action-mgt component --- .../pom.xml | 7 + .../management/ActionManagementService.java | 14 ++ .../ActionManagementServiceImpl.java | 35 ++- .../management/ActionSecretProcessor.java | 192 ++++++++++++++++ .../constant/ActionMgtConstants.java | 1 + .../constant/ActionMgtSQLConstants.java | 3 + .../management/dao/ActionManagementDAO.java | 31 ++- .../dao/impl/ActionManagementDAOImpl.java | 213 ++++++++++++++---- .../dao/impl/CacheBackedActionMgtDAO.java | 24 +- .../internal/ActionMgtServiceComponent.java | 39 ++++ .../ActionMgtServiceComponentHolder.java | 57 +++++ .../action/management/model/AuthProperty.java | 93 ++++++++ .../action/management/model/AuthType.java | 100 ++++++-- .../resources/dbscripts/h2.sql | 3 +- .../resources/identity.xml | 4 + .../resources/identity.xml.j2 | 4 + .../resources/resource-access-control-v2.xml | 4 + .../resource-access-control-v2.xml.j2 | 4 + 18 files changed, 760 insertions(+), 68 deletions(-) create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml b/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml index fabf6682fade..8a78bc7673de 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml @@ -37,6 +37,10 @@ org.wso2.carbon.identity.framework org.wso2.carbon.identity.core + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.secret.mgt.core + org.testng @@ -72,6 +76,9 @@ org.wso2.carbon.database.utils.jdbc;version="${org.wso2.carbon.database.utils.version.range}", org.wso2.carbon.identity.core.cache; version="${carbon.identity.package.import.version.range}", org.wso2.carbon.identity.core.util; version="${carbon.identity.package.import.version.range}", + org.wso2.carbon.identity.secret.mgt.core; version="${carbon.identity.package.import.version.range}", + org.wso2.carbon.identity.secret.mgt.core.exception; version="${carbon.identity.package.import.version.range}", + org.wso2.carbon.identity.secret.mgt.core.model; version="${carbon.identity.package.import.version.range}", org.wso2.carbon.utils; version="${carbon.kernel.package.import.version.range}", diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementService.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementService.java index fe8518bb2f68..9f6416320bde 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementService.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementService.java @@ -20,6 +20,7 @@ import org.wso2.carbon.identity.action.management.exception.ActionMgtException; import org.wso2.carbon.identity.action.management.model.Action; +import org.wso2.carbon.identity.action.management.model.AuthType; import java.util.List; import java.util.Map; @@ -113,4 +114,17 @@ Action updateAction(String actionType, String actionId, Action action, String te * @throws ActionMgtException If an error occurs while retrieving the Action of a given Action ID. */ Action getActionByActionId(String actionId, String tenantDomain) throws ActionMgtException; + + /** + * Update the authentication of the action endpoint. + * + * @param actionType Action Type. + * @param actionId Action ID. + * @param authentication Authentication Information to be updated. + * @param tenantDomain Tenant domain. + * @return Action response after update. + * @throws ActionMgtException If an error occurs while updating action endpoint authentication information. + */ + Action updateActionEndpointAuthentication(String actionType, String actionId, AuthType authentication, + String tenantDomain) throws ActionMgtException; } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java index 55a29b429e06..a36f49a84a62 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java @@ -26,6 +26,8 @@ import org.wso2.carbon.identity.action.management.exception.ActionMgtClientException; import org.wso2.carbon.identity.action.management.exception.ActionMgtException; import org.wso2.carbon.identity.action.management.model.Action; +import org.wso2.carbon.identity.action.management.model.AuthType; +import org.wso2.carbon.identity.action.management.model.EndpointConfig; import org.wso2.carbon.identity.action.management.util.ActionManagementUtil; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; @@ -44,6 +46,7 @@ public class ActionManagementServiceImpl implements ActionManagementService { private static final ActionManagementService INSTANCE = new ActionManagementServiceImpl(); private static final CacheBackedActionMgtDAO CACHE_BACKED_DAO = new CacheBackedActionMgtDAO(new ActionManagementDAOImpl()); + private static final ActionSecretProcessor ACTION_SECRET_PROCESSOR = new ActionSecretProcessor(); private ActionManagementServiceImpl() { } @@ -95,8 +98,8 @@ public void deleteAction(String actionType, String actionId, String tenantDomain if (LOG.isDebugEnabled()) { LOG.debug("Deleting Action for Action Type: " + actionType + " and Action Id: " + actionId); } - checkIfActionExists(actionId, tenantDomain); - CACHE_BACKED_DAO.deleteAction(getActionTypeFromPath(actionType), actionId, + Action action = checkIfActionExists(actionId, tenantDomain); + CACHE_BACKED_DAO.deleteAction(getActionTypeFromPath(actionType), actionId, action, IdentityTenantUtil.getTenantId(tenantDomain)); } @@ -140,6 +143,28 @@ public Action getActionByActionId(String actionId, String tenantDomain) throws A return CACHE_BACKED_DAO.getActionByActionId(actionId, IdentityTenantUtil.getTenantId(tenantDomain)); } + @Override + public Action updateActionEndpointAuthentication(String actionType, String actionId, AuthType authentication, + String tenantDomain) throws ActionMgtException { + + if (LOG.isDebugEnabled()) { + LOG.debug("Updating Action endpoint authentication for Auth Type: " + authentication.getType().name() + + " and Action Type: " + actionType + " and Action Id: " + actionId); + } + Action action = checkIfActionExists(actionId, tenantDomain); + if (action.getEndpoint().getAuthentication().getType().equals(authentication.getType())) { + + return CACHE_BACKED_DAO.updateActionEndpointAuthProperties(actionId, authentication, + IdentityTenantUtil.getTenantId(tenantDomain)); + } else { + EndpointConfig endpoint = new EndpointConfig.EndpointConfigBuilder() + .uri(action.getEndpoint().getUri()) + .authentication(authentication).build(); + return CACHE_BACKED_DAO.updateActionEndpoint(getActionTypeFromPath(actionType), actionId, endpoint, + action.getEndpoint().getAuthentication(), IdentityTenantUtil.getTenantId(tenantDomain)); + } + } + /** * Get Action Type from path. * @@ -181,11 +206,13 @@ private void validateMaxActionsPerType(String actionType, String tenantDomain) t * @param tenantDomain Tenant Domain. * @throws ActionMgtException If the action does not exist. */ - private void checkIfActionExists(String actionId, String tenantDomain) throws ActionMgtException { + private Action checkIfActionExists(String actionId, String tenantDomain) throws ActionMgtException { - if (CACHE_BACKED_DAO.getActionByActionId(actionId, IdentityTenantUtil.getTenantId(tenantDomain)) == null) { + Action action = CACHE_BACKED_DAO.getActionByActionId(actionId, IdentityTenantUtil.getTenantId(tenantDomain)); + if (action == null) { throw ActionManagementUtil.handleClientException( ActionMgtConstants.ErrorMessages.ERROR_NO_ACTION_CONFIGURED_ON_GIVEN_ID); } + return action; } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java new file mode 100644 index 000000000000..fbb774dd67fa --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.management; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder; +import org.wso2.carbon.identity.action.management.model.AuthProperty; +import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException; +import org.wso2.carbon.identity.secret.mgt.core.model.ResolvedSecret; +import org.wso2.carbon.identity.secret.mgt.core.model.Secret; +import org.wso2.carbon.identity.secret.mgt.core.model.SecretType; + +import java.util.ArrayList; +import java.util.List; + +import static org.wso2.carbon.identity.action.management.constant.ActionMgtConstants.IDN_SECRET_TYPE_ACTION_SECRETS; + +/** + * Action secrets processor service implementation. + */ +public class ActionSecretProcessor { + + private SecretType secretType; + + public ActionSecretProcessor() { + } + + public List encryptAssociatedSecrets(List authProperties, String actionId, + String authType) throws SecretManagementException { + + List encryptedAuthProperties = new ArrayList<>(); + for (AuthProperty prop : authProperties) { + if (!prop.getIsConfidential()) { + encryptedAuthProperties.add(prop); + continue; + } + String secretName = buildSecretName(actionId, authType, prop.getName()); + if (ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .isSecretExist(IDN_SECRET_TYPE_ACTION_SECRETS, secretName)) { + // Update existing secret property. + updateExistingSecretProperty(secretName, prop); + } else { + // Add secret to the DB. + if (StringUtils.isEmpty(prop.getValue())) { + continue; + } + addNewActionSecretProperty(secretName, prop); + } + encryptedAuthProperties.add(new AuthProperty.AuthPropertyBuilder() + .name(prop.getName()) + .isConfidential(prop.getIsConfidential()) + .value(buildSecretReference(secretName)).build()); + } + return encryptedAuthProperties; + } + + public List decryptAssociatedSecrets(List authProperties, String actionId, + String authType) throws SecretManagementException { + + List decryptedAuthProperties = new ArrayList<>(); + for (AuthProperty prop : authProperties) { + if (!prop.getIsConfidential()) { + decryptedAuthProperties.add(prop); + continue; + } + String secretName = buildSecretName(actionId, authType, prop.getName()); + if (ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .isSecretExist(IDN_SECRET_TYPE_ACTION_SECRETS, secretName)) { + ResolvedSecret resolvedSecret = ActionMgtServiceComponentHolder.getInstance().getSecretResolveManager() + .getResolvedSecret(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); + decryptedAuthProperties.add(new AuthProperty.AuthPropertyBuilder() + .name(prop.getName()) + .isConfidential(prop.getIsConfidential()) + .value(resolvedSecret.getResolvedSecretValue()).build()); + } + } + return decryptedAuthProperties; + } + + public void deleteAssociatedSecrets(List authProperties, String actionId, String authType) + throws SecretManagementException { + + for (AuthProperty prop : authProperties) { + if (!prop.getIsConfidential()) { + continue; + } + String secretName = buildSecretName(actionId, authType, prop.getName()); + if (ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .isSecretExist(IDN_SECRET_TYPE_ACTION_SECRETS, secretName)) { + ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .deleteSecret(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); + } + } + } + + public List getPropertiesWithSecretReferences(List authProperties, String actionId, + String authType) throws SecretManagementException { + + List referenceUpdatedProperties = new ArrayList<>(); + for (AuthProperty prop : authProperties) { + if (!prop.getIsConfidential()) { + referenceUpdatedProperties.add(prop); + continue; + } + referenceUpdatedProperties.add(new AuthProperty.AuthPropertyBuilder() + .name(prop.getName()) + .isConfidential(prop.getIsConfidential()) + .value(buildSecretReference(buildSecretName(actionId, authType, prop.getName()))).build()); + } + return referenceUpdatedProperties; + } + + /** + * Create secret name. + * + * @param actionId Action Id. + * @param authType Authentication Type. + * @param authProperty Authentication Property. + * @return Secret Name. + */ + private String buildSecretName(String actionId, String authType, String authProperty) { + + return actionId + ":" + authType + ":" + authProperty; + } + + /** + * Create secret reference name. + * + * @param secretName Name of the secret. + * @return Secret reference name. + * @throws SecretManagementException If an error occurs while retrieving the secret type. + */ + private String buildSecretReference(String secretName) throws SecretManagementException { + + if (secretType == null) { + secretType = ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .getSecretType(IDN_SECRET_TYPE_ACTION_SECRETS); + } + return secretType.getId() + ":" + secretName; + } + + /** + * Add new Secret for Action secret type. + * + * @param secretName Name of the secret. + * @param property Secret property. + * @throws SecretManagementException If an error occurs while adding the secret. + */ + private void addNewActionSecretProperty(String secretName, AuthProperty property) throws SecretManagementException { + + Secret secret = new Secret(); + secret.setSecretName(secretName); + secret.setSecretValue(property.getValue()); + ActionMgtServiceComponentHolder.getInstance().getSecretManager().addSecret(IDN_SECRET_TYPE_ACTION_SECRETS, + secret); + } + + /** + * Update an existing secret of Action secret type. + * + * @param secretName Name of the secret. + * @param property Secret property. + * @throws SecretManagementException If an error occurs while adding the secret. + */ + private void updateExistingSecretProperty(String secretName, AuthProperty property) + throws SecretManagementException { + + ResolvedSecret resolvedSecret = ActionMgtServiceComponentHolder.getInstance().getSecretResolveManager() + .getResolvedSecret(IDN_SECRET_TYPE_ACTION_SECRETS, + secretName); + if (!resolvedSecret.getResolvedSecretValue().equals(property.getValue())) { + ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .updateSecretValue(IDN_SECRET_TYPE_ACTION_SECRETS, secretName, property.getValue()); + } + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java index 100cc205d2c5..e03cd138c321 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java @@ -25,6 +25,7 @@ public class ActionMgtConstants { public static final String URI_ATTRIBUTE = "uri"; public static final String AUTHN_TYPE_ATTRIBUTE = "authnType"; + public static final String IDN_SECRET_TYPE_ACTION_SECRETS = "ACTION_SECRET_PROPERTIES"; /** * Error messages. diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtSQLConstants.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtSQLConstants.java index 4d1685cb1791..bb267a2dc683 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtSQLConstants.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtSQLConstants.java @@ -74,6 +74,9 @@ public static class Query { ":UUID; AND TYPE = :TYPE; AND TENANT_ID = :TENANT_ID;"; public static final String GET_ACTIONS_COUNT_PER_ACTION_TYPE = "SELECT TYPE, COUNT(UUID) AS COUNT" + " FROM IDN_ACTION WHERE TENANT_ID = :TENANT_ID; GROUP BY TYPE"; + public static final String UPDATE_ACTION_ENDPOINT_PROPERTIES = "UPDATE IDN_ACTION_ENDPOINT SET " + + "PROPERTY_VALUE = :PROPERTY_VALUE; WHERE ACTION_UUID = :ACTION_UUID; AND " + + "TENANT_ID = :TENANT_ID; AND PROPERTY_NAME = :PROPERTY_NAME;"; private Query() { diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAO.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAO.java index e45cf9b2f1b9..5929e5cdfd50 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAO.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAO.java @@ -20,6 +20,8 @@ import org.wso2.carbon.identity.action.management.exception.ActionMgtException; import org.wso2.carbon.identity.action.management.model.Action; +import org.wso2.carbon.identity.action.management.model.AuthType; +import org.wso2.carbon.identity.action.management.model.EndpointConfig; import java.util.List; import java.util.Map; @@ -68,10 +70,11 @@ public interface ActionManagementDAO { * * @param actionType Action Type. * @param actionId Action Id. + * @param action Action to be deleted. * @param tenantId Tenant Id. * @throws ActionMgtException If an error occurs while deleting Action. */ - void deleteAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException; + void deleteAction(String actionType, String actionId, Action action, Integer tenantId) throws ActionMgtException; /** * Activate {@link Action} by given Action Type and Action ID. @@ -113,4 +116,30 @@ public interface ActionManagementDAO { * @throws ActionMgtException If an error occurs while retrieving the Action of a given Action ID. */ Action getActionByActionId(String actionId, Integer tenantId) throws ActionMgtException; + + /** + * Update the endpoint authentication properties of an {@link Action} by given Action ID. + * + * @param actionId Action ID. + * @param authentication Authentication information to be updated. + * @param tenantId Tenant Id. + * @return Updated Action. + * @throws ActionMgtException If an error occurs while updating the Action endpoint authentication properties. + */ + Action updateActionEndpointAuthProperties(String actionId, AuthType authentication, int tenantId) + throws ActionMgtException; + + /** + * Update the endpoint authentication properties of an {@link Action} by given Action ID. + * + * @param actionType Action Type. + * @param actionId Action ID. + * @param endpoint Endpoint information to be updated. + * @param currentAuthentication Current Action endpoint authentication information. + * @param tenantId Tenant Id. + * @return Updated Action. + * @throws ActionMgtException If an error occurs while updating the Action endpoint. + */ + Action updateActionEndpoint(String actionType, String actionId, EndpointConfig endpoint, + AuthType currentAuthentication, int tenantId) throws ActionMgtException; } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java index e6a9987bcace..c92e221e5395 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java @@ -21,17 +21,20 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.database.utils.jdbc.NamedPreparedStatement; +import org.wso2.carbon.identity.action.management.ActionSecretProcessor; import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants; import org.wso2.carbon.identity.action.management.constant.ActionMgtSQLConstants; import org.wso2.carbon.identity.action.management.dao.ActionManagementDAO; import org.wso2.carbon.identity.action.management.exception.ActionMgtException; import org.wso2.carbon.identity.action.management.exception.ActionMgtServerException; import org.wso2.carbon.identity.action.management.model.Action; +import org.wso2.carbon.identity.action.management.model.AuthProperty; import org.wso2.carbon.identity.action.management.model.AuthType; import org.wso2.carbon.identity.action.management.model.EndpointConfig; import org.wso2.carbon.identity.action.management.util.ActionManagementUtil; import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException; import java.sql.Connection; import java.sql.ResultSet; @@ -40,6 +43,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * This class implements the {@link ActionManagementDAO} interface. @@ -47,34 +51,55 @@ public class ActionManagementDAOImpl implements ActionManagementDAO { private static final Log LOG = LogFactory.getLog(ActionManagementDAOImpl.class); + private final ActionSecretProcessor actionSecretProcessor; + + public ActionManagementDAOImpl() { + + this.actionSecretProcessor = new ActionSecretProcessor(); + } @Override public Action addAction(String actionType, String actionId, Action action, Integer tenantId) throws ActionMgtException { Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true); - try (NamedPreparedStatement statement = new NamedPreparedStatement(dbConnection, - ActionMgtSQLConstants.Query.ADD_ACTION_TO_ACTION_TYPE)) { - - statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId); - statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType); - statement.setString(ActionMgtSQLConstants.Column.ACTION_NAME, action.getName()); - statement.setString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION, action.getDescription()); - statement.setString(ActionMgtSQLConstants.Column.ACTION_STATUS, String.valueOf(Action.Status.ACTIVE)); - statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId); - statement.executeUpdate(); - - // Add Endpoint configuration properties. - addEndpointProperties(dbConnection, actionId, getEndpointProperties(action), tenantId); - IdentityDatabaseUtil.commitTransaction(dbConnection); - - return getActionByActionId(actionId, tenantId); - } catch (SQLException | ActionMgtException e) { - if (LOG.isDebugEnabled()) { - LOG.debug("Error while creating the action in action type: " + actionType + " in tenantDomain: " + - IdentityTenantUtil.getTenantDomain(tenantId) + ". Rolling back created action information."); + try { + // Encrypt secrets and update action authentication properties with secret alias. + action.getEndpoint().getAuthentication().setProperties( + actionSecretProcessor.encryptAssociatedSecrets( + action.getEndpoint().getAuthentication().getProperties(), actionId, + action.getEndpoint().getAuthentication().getType().name())); + try (NamedPreparedStatement statement = new NamedPreparedStatement(dbConnection, + ActionMgtSQLConstants.Query.ADD_ACTION_TO_ACTION_TYPE)) { + + statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId); + statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType); + statement.setString(ActionMgtSQLConstants.Column.ACTION_NAME, action.getName()); + statement.setString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION, action.getDescription()); + statement.setString(ActionMgtSQLConstants.Column.ACTION_STATUS, String.valueOf(Action.Status.ACTIVE)); + statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId); + statement.executeUpdate(); + + // Add Endpoint configuration properties. + addEndpointProperties(dbConnection, actionId, getEndpointProperties(action.getEndpoint().getUri(), + action.getEndpoint().getAuthentication().getType().name(), + action.getEndpoint().getAuthentication().getProperties()), tenantId); + IdentityDatabaseUtil.commitTransaction(dbConnection); + + return getActionByActionId(actionId, tenantId); + } catch (SQLException | ActionMgtException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Error while creating the action in action type: " + actionType + + " in tenantDomain: " + IdentityTenantUtil.getTenantDomain(tenantId) + + ". Rolling back created action information and deleting added secrets."); + } + actionSecretProcessor.deleteAssociatedSecrets(action.getEndpoint().getAuthentication().getProperties(), + actionId, action.getEndpoint().getAuthentication().getType().name()); + IdentityDatabaseUtil.rollbackTransaction(dbConnection); + throw ActionManagementUtil.handleServerException( + ActionMgtConstants.ErrorMessages.ERROR_WHILE_ADDING_ACTION, e); } - IdentityDatabaseUtil.rollbackTransaction(dbConnection); + } catch (SecretManagementException e) { throw ActionManagementUtil.handleServerException( ActionMgtConstants.ErrorMessages.ERROR_WHILE_ADDING_ACTION, e); } finally { @@ -131,7 +156,8 @@ public Action updateAction(String actionType, String actionId, Action action, In statement.executeUpdate(); // Update Endpoint Properties. - updateActionEndpointProperties(dbConnection, actionId, getEndpointProperties(action), tenantId); + updateActionEndpointProperties(dbConnection, actionId, getEndpointProperties(action.getEndpoint().getUri(), + null, null), tenantId); IdentityDatabaseUtil.commitTransaction(dbConnection); return getActionByActionId(actionId, tenantId); @@ -149,7 +175,8 @@ public Action updateAction(String actionType, String actionId, Action action, In } @Override - public void deleteAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException { + public void deleteAction(String actionType, String actionId, Action action, Integer tenantId) + throws ActionMgtException { Connection dbConnection = IdentityDatabaseUtil.getDBConnection(false); try (NamedPreparedStatement statement = new NamedPreparedStatement(dbConnection, @@ -159,8 +186,13 @@ public void deleteAction(String actionType, String actionId, Integer tenantId) t statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType); statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId); statement.executeUpdate(); + + // Delete action endpoint authentication related secrets. + actionSecretProcessor.deleteAssociatedSecrets( + action.getEndpoint().getAuthentication().getProperties(), actionId, + action.getEndpoint().getAuthentication().getType().name()); IdentityDatabaseUtil.commitTransaction(dbConnection); - } catch (SQLException e) { + } catch (SQLException | SecretManagementException e) { if (LOG.isDebugEnabled()) { LOG.debug("Error while deleting the action in action type: " + actionType + " in tenantDomain: " + IdentityTenantUtil.getTenantDomain(tenantId) + ". Rolling back deleted action information."); @@ -224,6 +256,81 @@ public Action getActionByActionId(String actionId, Integer tenantId) throws Acti } } + @Override + public Action updateActionEndpointAuthProperties(String actionId, AuthType authentication, int tenantId) + throws ActionMgtException { + + Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true); + try { + Map nonSecretEndpointProperties = authentication.getProperties().stream() + .filter(property -> !property.getIsConfidential()) + .collect(Collectors.toMap(AuthProperty::getName, AuthProperty::getValue)); + // Update non-secret endpoint properties. + updateActionEndpointProperties(dbConnection, actionId, nonSecretEndpointProperties, tenantId); + // Encrypt and update non-secret endpoint properties. + actionSecretProcessor.encryptAssociatedSecrets(authentication.getProperties(), actionId, + authentication.getType().name()); + IdentityDatabaseUtil.commitTransaction(dbConnection); + + return getActionByActionId(actionId, tenantId); + } catch (ActionMgtException | SecretManagementException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Error while updating the action secrets of Auth type: " + authentication.getType() + + " of Action id: " + actionId + " in tenantDomain: " + + IdentityTenantUtil.getTenantDomain(tenantId) + + ". Rolling back updated action endpoint authentication properties."); + } + IdentityDatabaseUtil.rollbackTransaction(dbConnection); + throw ActionManagementUtil.handleServerException( + ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ENDPOINT_PROPERTIES, e); + } finally { + IdentityDatabaseUtil.closeConnection(dbConnection); + } + } + + @Override + public Action updateActionEndpoint(String actionType, String actionId, EndpointConfig endpoint, + AuthType currentAuthentication, int tenantId) + throws ActionMgtException { + + Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true); + try (NamedPreparedStatement statement = new NamedPreparedStatement(dbConnection, + ActionMgtSQLConstants.Query.DELETE_ACTION_ENDPOINT_PROPERTIES)) { + + statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_UUID, actionId); + statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId); + statement.executeUpdate(); + + // Add new Endpoint configuration properties. + addEndpointProperties(dbConnection, actionId, getEndpointProperties(endpoint.getUri(), + endpoint.getAuthentication().getType().name(), + endpoint.getAuthentication().getPropertiesWithSecretReferences(actionId)), tenantId); + // Encrypt and add new endpoint properties secrets. + actionSecretProcessor.encryptAssociatedSecrets(endpoint.getAuthentication().getProperties(), actionId, + endpoint.getAuthentication().getType().name()); + + // Delete old secrets. + actionSecretProcessor.deleteAssociatedSecrets(currentAuthentication.getProperties(), actionId, + currentAuthentication.getType().name()); + IdentityDatabaseUtil.commitTransaction(dbConnection); + + return getActionByActionId(actionId, tenantId); + } catch (SQLException | ActionMgtException | SecretManagementException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Error while updating the action endpoint authentication from Auth type: " + + currentAuthentication.getType() + " to Auth type: " + endpoint.getAuthentication().getType() + + " of Action id: " + actionId + " in tenantDomain: " + + IdentityTenantUtil.getTenantDomain(tenantId) + + ". Rolling back updated action endpoint authentication properties."); + } + IdentityDatabaseUtil.rollbackTransaction(dbConnection); + throw ActionManagementUtil.handleServerException( + ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ENDPOINT_PROPERTIES, e); + } finally { + IdentityDatabaseUtil.closeConnection(dbConnection); + } + } + /** * Add Action Endpoint properties to the Database. * @@ -313,7 +420,8 @@ private EndpointConfig getActionEndpointConfigById(Connection dbConnection, Stri String endpointUri = null; AuthType.AuthenticationType authnType = null; - Map authnProperties = new HashMap<>(); + Map authnPropertiesMap = new HashMap<>(); + List authnProperties = new ArrayList<>(); while (rs.next()) { String propName = rs.getString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_NAME); @@ -325,7 +433,16 @@ private EndpointConfig getActionEndpointConfigById(Connection dbConnection, Stri authnType = AuthType.AuthenticationType.valueOf(propValue); } else { // Authentication properties. - authnProperties.put(propName, propValue); + authnPropertiesMap.put(propName, propValue); + } + } + + if (authnType != null) { + for (AuthProperty property : authnType.getProperties()) { + if (authnPropertiesMap.containsKey(property.getName())) { + property.setValue(authnPropertiesMap.get(property.getName())); + authnProperties.add(property); + } } } @@ -344,17 +461,25 @@ private EndpointConfig getActionEndpointConfigById(Connection dbConnection, Stri /** * Get Action Endpoint properties Map. * - * @param action Action Object. + * @param endpointUri Endpoint URI of the Action. + * @param authType Authentication Type of the Action. + * @param authProperties Authentication Properties of the Endpoint. * @return Endpoint Properties Map. */ - private Map getEndpointProperties(Action action) { + private Map getEndpointProperties(String endpointUri, String authType, + List authProperties) { Map endpointProperties = new HashMap<>(); - endpointProperties.put(ActionMgtConstants.URI_ATTRIBUTE, action.getEndpoint().getUri()); - endpointProperties.put(ActionMgtConstants.AUTHN_TYPE_ATTRIBUTE, - String.valueOf(action.getEndpoint().getAuthentication().getType())); - for (Map.Entry property : action.getEndpoint().getAuthentication().getProperties().entrySet()) { - endpointProperties.put(property.getKey(), String.valueOf(property.getValue())); + if (endpointUri != null) { + endpointProperties.put(ActionMgtConstants.URI_ATTRIBUTE, endpointUri); + } + if (authType != null) { + endpointProperties.put(ActionMgtConstants.AUTHN_TYPE_ATTRIBUTE, authType); + } + if (authProperties != null) { + for (AuthProperty property : authProperties) { + endpointProperties.put(property.getName(), property.getValue()); + } } return endpointProperties; @@ -365,7 +490,7 @@ private Map getEndpointProperties(Action action) { * * @param dbConnection DB Connection. * @param actionId UUID of the created Action. - * @param endpointProperties Endpoint Properties. + * @param endpointProperties Endpoint Properties to be updated. * @param tenantId Tenant ID. */ private void updateActionEndpointProperties(Connection dbConnection, String actionId, @@ -373,22 +498,24 @@ private void updateActionEndpointProperties(Connection dbConnection, String acti throws ActionMgtException { try (NamedPreparedStatement statement = new NamedPreparedStatement(dbConnection, - ActionMgtSQLConstants.Query.DELETE_ACTION_ENDPOINT_PROPERTIES)) { + ActionMgtSQLConstants.Query.UPDATE_ACTION_ENDPOINT_PROPERTIES)) { - statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_UUID, actionId); - statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId); - statement.executeUpdate(); - - // Add Endpoint configuration properties. - addEndpointProperties(dbConnection, actionId, endpointProperties, tenantId); - } catch (SQLException | ActionMgtException e) { + for (Map.Entry property : endpointProperties.entrySet()) { + statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_VALUE, property.getValue()); + statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_UUID, actionId); + statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId); + statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_NAME, property.getKey()); + statement.addBatch(); + } + statement.executeBatch(); + } catch (SQLException e) { throw ActionManagementUtil.handleServerException( ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ENDPOINT_PROPERTIES, e); } } /** - * Update Action Endpoint properties. + * Update Action Status. * * @param actionType Action Type. * @param actionId UUID of the Action. diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/CacheBackedActionMgtDAO.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/CacheBackedActionMgtDAO.java index 39bd62214930..f43184921506 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/CacheBackedActionMgtDAO.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/CacheBackedActionMgtDAO.java @@ -26,6 +26,8 @@ import org.wso2.carbon.identity.action.management.dao.ActionManagementDAO; import org.wso2.carbon.identity.action.management.exception.ActionMgtException; import org.wso2.carbon.identity.action.management.model.Action; +import org.wso2.carbon.identity.action.management.model.AuthType; +import org.wso2.carbon.identity.action.management.model.EndpointConfig; import java.util.List; import java.util.Map; @@ -94,10 +96,11 @@ public Action updateAction(String actionType, String actionId, Action action, In } @Override - public void deleteAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException { + public void deleteAction(String actionType, String actionId, Action action, Integer tenantId) + throws ActionMgtException { actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantId); - actionManagementDAO.deleteAction(actionType, actionId, tenantId); + actionManagementDAO.deleteAction(actionType, actionId, action, tenantId); } @Override @@ -125,4 +128,21 @@ public Action getActionByActionId(String actionId, Integer tenantId) throws Acti return actionManagementDAO.getActionByActionId(actionId, tenantId); } + + @Override + public Action updateActionEndpointAuthProperties(String actionId, AuthType authentication, int tenantId) + throws ActionMgtException { + + return actionManagementDAO.updateActionEndpointAuthProperties(actionId, authentication, tenantId); + } + + @Override + public Action updateActionEndpoint(String actionType, String actionId, EndpointConfig endpoint, + AuthType currentAuthentication, int tenantId) + throws ActionMgtException { + + actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantId); + return actionManagementDAO.updateActionEndpoint(actionType, actionId, endpoint, currentAuthentication, + tenantId); + } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponent.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponent.java index 53b549a5d2e7..44fe7f894eac 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponent.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponent.java @@ -25,8 +25,13 @@ import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; import org.wso2.carbon.identity.action.management.ActionManagementService; import org.wso2.carbon.identity.action.management.ActionManagementServiceImpl; +import org.wso2.carbon.identity.secret.mgt.core.SecretManager; +import org.wso2.carbon.identity.secret.mgt.core.SecretResolveManager; /** * Service component for the Action management. @@ -62,4 +67,38 @@ protected void deactivate(ComponentContext context) { LOG.error("Error while deactivating Action management component.", e); } } + + @Reference( + name = "org.wso2.carbon.identity.secret.mgt.core.SecretManager", + service = SecretManager.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetSecretManager" + ) + private void setSecretManager(SecretManager secretManager) { + + ActionMgtServiceComponentHolder.getInstance().setSecretManager(secretManager); + } + + private void unsetSecretManager(SecretManager secretManager) { + + ActionMgtServiceComponentHolder.getInstance().setSecretManager(null); + } + + @Reference( + name = "org.wso2.carbon.identity.secret.mgt.core.SecretResolveManager", + service = SecretResolveManager.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetSecretResolveManager" + ) + private void setSecretResolveManager(SecretResolveManager secretResolveManager) { + + ActionMgtServiceComponentHolder.getInstance().setSecretResolveManager(secretResolveManager); + } + + private void unsetSecretResolveManager(SecretResolveManager secretResolveManager) { + + ActionMgtServiceComponentHolder.getInstance().setSecretResolveManager(null); + } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java new file mode 100644 index 000000000000..6643336b9e90 --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.management.internal; + +import org.wso2.carbon.identity.secret.mgt.core.SecretManager; +import org.wso2.carbon.identity.secret.mgt.core.SecretResolveManager; + +/** + * Service component Holder for the Action management. + */ +public class ActionMgtServiceComponentHolder { + + public static ActionMgtServiceComponentHolder instance = new ActionMgtServiceComponentHolder(); + + public static ActionMgtServiceComponentHolder getInstance() { + return instance; + } + + private SecretManager secretManager; + private SecretResolveManager secretResolveManager; + + public SecretManager getSecretManager() { + + return secretManager; + } + + public void setSecretManager(SecretManager secretManager) { + + this.secretManager = secretManager; + } + + public SecretResolveManager getSecretResolveManager() { + + return secretResolveManager; + } + + public void setSecretResolveManager(SecretResolveManager secretResolveManager) { + + this.secretResolveManager = secretResolveManager; + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java new file mode 100644 index 000000000000..ef9d7bd6821c --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.management.model; + +/** + * Authentication Property. + */ +public class AuthProperty { + + private String name; + private String value; + private boolean isConfidential; + + public AuthProperty() { + + } + + public AuthProperty(String name, String value, boolean isConfidential) { + + this.name = name; + this.value = value; + this.isConfidential = isConfidential; + } + + public String getName() { + + return name; + } + + public String getValue() { + + return value; + } + + public void setValue(String value) { + + this.value = value; + } + + public boolean getIsConfidential() { + + return isConfidential; + } + + /** + * Authentication Property Builder. + */ + public static class AuthPropertyBuilder { + + private String name; + private String value; + private boolean isConfidential; + + public AuthPropertyBuilder name(String name) { + + this.name = name; + return this; + } + + public AuthPropertyBuilder value(String value) { + + this.value = value; + return this; + } + + public AuthPropertyBuilder isConfidential(boolean isConfidential) { + + this.isConfidential = isConfidential; + return this; + } + + public AuthProperty build() { + + return new AuthProperty(name, value, isConfidential); + } + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthType.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthType.java index 3710ebb1639a..538d0b1a70b2 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthType.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthType.java @@ -18,8 +18,12 @@ package org.wso2.carbon.identity.action.management.model; -import java.util.HashMap; -import java.util.Map; +import org.wso2.carbon.identity.action.management.ActionSecretProcessor; +import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * AuthType. @@ -31,33 +35,72 @@ public class AuthType { */ public enum AuthenticationType { - NONE("NONE", new String[]{}), - BEARER("BEARER", new String[]{"accessToken"}), - BASIC("BASIC", new String[]{"username", "password"}), - API_KEY("API_KEY", new String[]{"header", "value"}); - + NONE( + "none", + "NONE", + new ArrayList<>() + ), + BEARER( + "bearer", + "BEARER", + Arrays.asList( + new AuthProperty.AuthPropertyBuilder() + .name("accessToken") + .isConfidential(true).build()) + ), + BASIC( + "basic", + "BASIC", + Arrays.asList( + new AuthProperty.AuthPropertyBuilder() + .name("username") + .isConfidential(true).build(), + new AuthProperty.AuthPropertyBuilder() + .name("password") + .isConfidential(true).build()) + ), + API_KEY( + "apiKey", + "API_KEY", + Arrays.asList( + new AuthProperty.AuthPropertyBuilder() + .name("header") + .isConfidential(false).build(), + new AuthProperty.AuthPropertyBuilder() + .name("value") + .isConfidential(true).build()) + ); + + private final String pathParam; private final String type; - private final String[] properties; + private final List properties; - AuthenticationType(String type, String[] properties) { + AuthenticationType(String pathParam, String type, List properties) { + this.pathParam = pathParam; this.type = type; this.properties = properties; } + public String getPathParam() { + + return pathParam; + } + public String getType() { return type; } - public String[] getProperties() { + public List getProperties() { return properties; } } private AuthenticationType type; - private Map properties = null; + private List properties = null; + private final ActionSecretProcessor secretProcessor = new ActionSecretProcessor(); public AuthType() { } @@ -73,18 +116,41 @@ public AuthenticationType getType() { return type; } - public Map getProperties() { + public void setProperties(List properties) { + + this.properties = properties; + } + + public List getProperties() { return properties; } + public List getPropertiesWithDecryptedValues(String actionId) throws SecretManagementException { + + if (properties != null) { + + return secretProcessor.decryptAssociatedSecrets(properties, actionId, type.name()); + } + return null; + } + + public List getPropertiesWithSecretReferences(String actionId) throws SecretManagementException { + + if (properties != null) { + + return secretProcessor.getPropertiesWithSecretReferences(properties, actionId, type.name()); + } + return null; + } + /** * AuthType builder. */ public static class AuthTypeBuilder { private AuthenticationType type; - private Map properties = null; + private List properties = null; public AuthTypeBuilder() { } @@ -95,18 +161,18 @@ public AuthTypeBuilder type(AuthenticationType type) { return this; } - public AuthTypeBuilder properties(Map properties) { + public AuthTypeBuilder properties(List properties) { this.properties = properties; return this; } - public AuthTypeBuilder addProperty(String key, String value) { + public AuthTypeBuilder addProperty(AuthProperty authProperty) { if (this.properties == null) { - this.properties = new HashMap<>(); + this.properties = new ArrayList<>(); } - this.properties.put(key, value); + this.properties.add(authProperty); return this; } 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 512c0190290f..ff5d31c88623 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 @@ -1125,7 +1125,8 @@ INSERT INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('1358bdbf-e0cc-4268-a42c-c3e0960e13f0', 'ADAPTIVE_AUTH_CALL_CHOREO', 'Secret type to uniquely identify secrets relevant to callChoreo adaptive auth function'), ('c508ca28-60c0-4493-a758-77e4173ffdb9', 'IDP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity providers'), ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers'), -('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'); +('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'), +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties'); CREATE TABLE IF NOT EXISTS IDN_SECRET ( ID VARCHAR(255) NOT NULL, 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 3f9e6d9c5b3f..810f1806099a 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 @@ -2244,6 +2244,10 @@ /permission/admin/manage/identity/actionmgt/update internal_action_mgt_update + + /permission/admin/manage/identity/actionmgt/update + internal_action_mgt_update + /permission/admin/manage/identity/actionmgt/delete internal_action_mgt_delete 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 4f1c58c37f93..afe3cddf54f8 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 @@ -3313,6 +3313,10 @@ /permission/admin/manage/identity/actionmgt/update internal_action_mgt_update + + /permission/admin/manage/identity/actionmgt/update + internal_action_mgt_update + /permission/admin/manage/identity/actionmgt/delete internal_action_mgt_delete diff --git a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/resource-access-control-v2.xml b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/resource-access-control-v2.xml index cfcc40213f3e..9a713eb6cdef 100644 --- a/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/resource-access-control-v2.xml +++ b/features/identity-core/org.wso2.carbon.identity.core.server.feature/resources/resource-access-control-v2.xml @@ -1095,6 +1095,10 @@ internal_action_mgt_update + + /permission/admin/manage/identity/actionmgt/update + internal_action_mgt_update + internal_action_mgt_delete 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 7ea8cff1ce10..4215c50319ff 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 @@ -1151,6 +1151,10 @@ internal_action_mgt_update + + /permission/admin/manage/identity/actionmgt/update + internal_action_mgt_update + internal_action_mgt_delete From 4c40292ff2e65531731f8e68897c74215dae5279 Mon Sep 17 00:00:00 2001 From: Ashan Thamara Palihakkara <75057725+ashanthamara@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:37:24 +0530 Subject: [PATCH 2/6] Add few improvements --- .../pom.xml | 1 + .../ActionManagementServiceImpl.java | 108 +++++++++--- .../management/ActionSecretProcessor.java | 159 +++++++++++------- .../constant/ActionMgtConstants.java | 7 +- .../dao/impl/ActionManagementDAOImpl.java | 76 ++++----- .../action/management/model/AuthProperty.java | 5 - .../action/management/model/AuthType.java | 103 ++++++------ .../management/model/EndpointConfig.java | 1 + .../resources/dbscripts/h2.sql | 2 +- 9 files changed, 278 insertions(+), 184 deletions(-) diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml b/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml index 650217323b65..cfc63ad0a7da 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml @@ -71,6 +71,7 @@ org.apache.commons.lang; version="${commons-lang.wso2.osgi.version.range}", org.apache.commons.logging; version="${import.package.version.commons.logging}", + org.apache.commons.collections; version="${commons-collections.wso2.osgi.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.database.utils.jdbc;version="${org.wso2.carbon.database.utils.version.range}", diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java index a36f49a84a62..012b6ebab4a0 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.action.management; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants; @@ -60,7 +61,7 @@ public static ActionManagementService getInstance() { public Action addAction(String actionType, Action action, String tenantDomain) throws ActionMgtException { if (LOG.isDebugEnabled()) { - LOG.debug("Adding Action for Action Type: " + actionType); + LOG.debug(String.format("Adding Action for Action Type: %s.", actionType)); } String resolvedActionType = getActionTypeFromPath(actionType); // Check whether the maximum allowed actions per type is reached. @@ -74,7 +75,7 @@ public Action addAction(String actionType, Action action, String tenantDomain) t public List getActionsByActionType(String actionType, String tenantDomain) throws ActionMgtException { if (LOG.isDebugEnabled()) { - LOG.debug("Retrieving Actions for Action Type: " + actionType); + LOG.debug(String.format("Retrieving Actions for Action Type: %s.", actionType)); } return CACHE_BACKED_DAO.getActionsByActionType(getActionTypeFromPath(actionType), IdentityTenantUtil.getTenantId(tenantDomain)); @@ -85,9 +86,10 @@ public Action updateAction(String actionType, String actionId, Action action, St throws ActionMgtException { if (LOG.isDebugEnabled()) { - LOG.debug("Updating Action for Action Type: " + actionType + " and Action Id: " + actionId); + LOG.debug(String.format("Updating Action for Action Type: %s and Action ID: %s.", actionType, actionId)); } - checkIfActionExists(actionId, tenantDomain); + Action existingAction = checkIfActionExists(actionId, tenantDomain); + action = mergeActionWithExisting(action, existingAction); return CACHE_BACKED_DAO.updateAction(getActionTypeFromPath(actionType), actionId, action, IdentityTenantUtil.getTenantId(tenantDomain)); } @@ -96,7 +98,7 @@ public Action updateAction(String actionType, String actionId, Action action, St public void deleteAction(String actionType, String actionId, String tenantDomain) throws ActionMgtException { if (LOG.isDebugEnabled()) { - LOG.debug("Deleting Action for Action Type: " + actionType + " and Action Id: " + actionId); + LOG.debug(String.format("Deleting Action for Action Type: %s and Action ID: %s", actionType, actionId)); } Action action = checkIfActionExists(actionId, tenantDomain); CACHE_BACKED_DAO.deleteAction(getActionTypeFromPath(actionType), actionId, action, @@ -107,7 +109,7 @@ public void deleteAction(String actionType, String actionId, String tenantDomain public Action activateAction(String actionType, String actionId, String tenantDomain) throws ActionMgtException { if (LOG.isDebugEnabled()) { - LOG.debug("Activating Action for Action Type: " + actionType + " and Action Id: " + actionId); + LOG.debug(String.format("Activating Action for Action Type: %s and Action ID: %s.", actionType, actionId)); } checkIfActionExists(actionId, tenantDomain); return CACHE_BACKED_DAO.activateAction(getActionTypeFromPath(actionType), actionId, @@ -118,7 +120,8 @@ public Action activateAction(String actionType, String actionId, String tenantDo public Action deactivateAction(String actionType, String actionId, String tenantDomain) throws ActionMgtException { if (LOG.isDebugEnabled()) { - LOG.debug("Deactivating Action for Action Type: " + actionType + " and Action Id: " + actionId); + LOG.debug(String.format("Deactivating Action for Action Type: %s and Action ID: %s.", actionType, + actionId)); } checkIfActionExists(actionId, tenantDomain); return CACHE_BACKED_DAO.deactivateAction(getActionTypeFromPath(actionType), actionId, @@ -138,7 +141,7 @@ public Map getActionsCountPerType(String tenantDomain) throws A public Action getActionByActionId(String actionId, String tenantDomain) throws ActionMgtException { if (LOG.isDebugEnabled()) { - LOG.debug("Retrieving Action of Action Id: " + actionId); + LOG.debug(String.format("Retrieving Action of Action ID: %s", actionId)); } return CACHE_BACKED_DAO.getActionByActionId(actionId, IdentityTenantUtil.getTenantId(tenantDomain)); } @@ -147,21 +150,13 @@ public Action getActionByActionId(String actionId, String tenantDomain) throws A public Action updateActionEndpointAuthentication(String actionType, String actionId, AuthType authentication, String tenantDomain) throws ActionMgtException { - if (LOG.isDebugEnabled()) { - LOG.debug("Updating Action endpoint authentication for Auth Type: " + authentication.getType().name() + - " and Action Type: " + actionType + " and Action Id: " + actionId); - } - Action action = checkIfActionExists(actionId, tenantDomain); - if (action.getEndpoint().getAuthentication().getType().equals(authentication.getType())) { - - return CACHE_BACKED_DAO.updateActionEndpointAuthProperties(actionId, authentication, - IdentityTenantUtil.getTenantId(tenantDomain)); + Action existingAction = checkIfActionExists(actionId, tenantDomain); + if (existingAction.getEndpoint().getAuthentication().getType().equals(authentication.getType())) { + // Only need to update the properties since the authType is same. + return updateEndpointAuthenticationProperties(actionType, actionId, authentication, tenantDomain); } else { - EndpointConfig endpoint = new EndpointConfig.EndpointConfigBuilder() - .uri(action.getEndpoint().getUri()) - .authentication(authentication).build(); - return CACHE_BACKED_DAO.updateActionEndpoint(getActionTypeFromPath(actionType), actionId, endpoint, - action.getEndpoint().getAuthentication(), IdentityTenantUtil.getTenantId(tenantDomain)); + // Need to update the authentication type and properties. + return updateEndpoint(actionType, actionId, existingAction, authentication, tenantDomain); } } @@ -215,4 +210,73 @@ private Action checkIfActionExists(String actionId, String tenantDomain) throws } return action; } + + /** + * Merge the updating action with the existing action. + * + * @param updatingAction Action object with updating information. + * @param existingAction Action object with existing information. + * @return Action object with merged information. + */ + private Action mergeActionWithExisting(Action updatingAction, Action existingAction) { + + return new Action.ActionRequestBuilder() + .name(StringUtils.isEmpty(updatingAction.getName()) ? existingAction.getName() : + updatingAction.getName()) + .description(StringUtils.isEmpty(updatingAction.getDescription()) ? existingAction.getDescription() : + updatingAction.getDescription()) + .endpoint(new EndpointConfig.EndpointConfigBuilder() + .uri(StringUtils.isEmpty(updatingAction.getEndpoint().getUri()) ? + existingAction.getEndpoint().getUri() : updatingAction.getEndpoint().getUri()) + .build()) + .build(); + } + + /** + * Update the authentication type and properties of the action endpoint. + * + * @param actionType Action Type. + * @param actionId Action Id. + * @param existingAction Existing Action Information. + * @param authentication Authentication Information to be updated. + * @param tenantDomain Tenant Domain. + * @return Action response after update. + * @throws ActionMgtException If an error occurs while updating action endpoint authentication. + */ + private Action updateEndpoint(String actionType, String actionId, Action existingAction, + AuthType authentication, String tenantDomain) + throws ActionMgtException { + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Updating endpoint authentication of Action Type: %s " + + "and Action ID: %s to AuthType: %s", actionType, actionId, authentication.getType().name())); + } + EndpointConfig endpoint = new EndpointConfig.EndpointConfigBuilder() + .uri(existingAction.getEndpoint().getUri()) + .authentication(authentication).build(); + return CACHE_BACKED_DAO.updateActionEndpoint(getActionTypeFromPath(actionType), actionId, endpoint, + existingAction.getEndpoint().getAuthentication(), IdentityTenantUtil.getTenantId(tenantDomain)); + } + + /** + * Update the authentication properties of the action endpoint. + * + * @param actionType Action Type. + * @param actionId Action Id. + * @param authentication Authentication Information to be updated. + * @param tenantDomain Tenant domain. + * @return Action response after update. + * @throws ActionMgtException If an error occurs while updating action endpoint authentication properties. + */ + private Action updateEndpointAuthenticationProperties(String actionType, String actionId, AuthType authentication, + String tenantDomain) throws ActionMgtException { + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Updating endpoint authentication properties of Action Type: %s " + + "Action ID: %s and AuthType: %s", actionType, actionId, authentication.getType().name())); + } + return CACHE_BACKED_DAO.updateActionEndpointAuthProperties(actionId, authentication, + IdentityTenantUtil.getTenantId(tenantDomain)); + + } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java index fbb774dd67fa..3fb2d245b5aa 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java @@ -18,9 +18,9 @@ package org.wso2.carbon.identity.action.management; -import org.apache.commons.lang.StringUtils; import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder; import org.wso2.carbon.identity.action.management.model.AuthProperty; +import org.wso2.carbon.identity.action.management.model.AuthType; import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException; import org.wso2.carbon.identity.secret.mgt.core.model.ResolvedSecret; import org.wso2.carbon.identity.secret.mgt.core.model.Secret; @@ -36,75 +36,49 @@ */ public class ActionSecretProcessor { - private SecretType secretType; - public ActionSecretProcessor() { } - public List encryptAssociatedSecrets(List authProperties, String actionId, - String authType) throws SecretManagementException { + public List encryptAssociatedSecrets(AuthType authentication, String actionId) + throws SecretManagementException { List encryptedAuthProperties = new ArrayList<>(); - for (AuthProperty prop : authProperties) { - if (!prop.getIsConfidential()) { - encryptedAuthProperties.add(prop); - continue; - } - String secretName = buildSecretName(actionId, authType, prop.getName()); - if (ActionMgtServiceComponentHolder.getInstance().getSecretManager() - .isSecretExist(IDN_SECRET_TYPE_ACTION_SECRETS, secretName)) { - // Update existing secret property. - updateExistingSecretProperty(secretName, prop); + for (AuthProperty authProperty : authentication.getProperties()) { + if (!authProperty.getIsConfidential()) { + encryptedAuthProperties.add(authProperty); } else { - // Add secret to the DB. - if (StringUtils.isEmpty(prop.getValue())) { - continue; - } - addNewActionSecretProperty(secretName, prop); + encryptedAuthProperties.add(encryptProperty(authProperty, authentication.getType().name(), actionId)); } - encryptedAuthProperties.add(new AuthProperty.AuthPropertyBuilder() - .name(prop.getName()) - .isConfidential(prop.getIsConfidential()) - .value(buildSecretReference(secretName)).build()); } + return encryptedAuthProperties; } - public List decryptAssociatedSecrets(List authProperties, String actionId, - String authType) throws SecretManagementException { + public List decryptAssociatedSecrets(List authProperties, String authType, + String actionId) throws SecretManagementException { List decryptedAuthProperties = new ArrayList<>(); - for (AuthProperty prop : authProperties) { - if (!prop.getIsConfidential()) { - decryptedAuthProperties.add(prop); - continue; - } - String secretName = buildSecretName(actionId, authType, prop.getName()); - if (ActionMgtServiceComponentHolder.getInstance().getSecretManager() - .isSecretExist(IDN_SECRET_TYPE_ACTION_SECRETS, secretName)) { - ResolvedSecret resolvedSecret = ActionMgtServiceComponentHolder.getInstance().getSecretResolveManager() - .getResolvedSecret(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); - decryptedAuthProperties.add(new AuthProperty.AuthPropertyBuilder() - .name(prop.getName()) - .isConfidential(prop.getIsConfidential()) - .value(resolvedSecret.getResolvedSecretValue()).build()); + for (AuthProperty authProperty : authProperties) { + if (!authProperty.getIsConfidential()) { + decryptedAuthProperties.add(authProperty); + } else { + decryptedAuthProperties.add(decryptProperty(authProperty, authType, actionId)); } } + return decryptedAuthProperties; } - public void deleteAssociatedSecrets(List authProperties, String actionId, String authType) + public void deleteAssociatedSecrets(AuthType authentication, String actionId) throws SecretManagementException { - for (AuthProperty prop : authProperties) { - if (!prop.getIsConfidential()) { - continue; - } - String secretName = buildSecretName(actionId, authType, prop.getName()); - if (ActionMgtServiceComponentHolder.getInstance().getSecretManager() - .isSecretExist(IDN_SECRET_TYPE_ACTION_SECRETS, secretName)) { - ActionMgtServiceComponentHolder.getInstance().getSecretManager() - .deleteSecret(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); + for (AuthProperty authProperty : authentication.getProperties()) { + if (authProperty.getIsConfidential()) { + String secretName = buildSecretName(actionId, authentication.getType().name(), authProperty.getName()); + if (isSecretPropertyExists(secretName)) { + ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .deleteSecret(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); + } } } } @@ -116,16 +90,82 @@ public List getPropertiesWithSecretReferences(List a for (AuthProperty prop : authProperties) { if (!prop.getIsConfidential()) { referenceUpdatedProperties.add(prop); - continue; + } else { + referenceUpdatedProperties.add(new AuthProperty.AuthPropertyBuilder() + .name(prop.getName()) + .isConfidential(prop.getIsConfidential()) + .value(buildSecretReference(buildSecretName(actionId, authType, prop.getName()))).build()); } - referenceUpdatedProperties.add(new AuthProperty.AuthPropertyBuilder() - .name(prop.getName()) - .isConfidential(prop.getIsConfidential()) - .value(buildSecretReference(buildSecretName(actionId, authType, prop.getName()))).build()); } + return referenceUpdatedProperties; } + /** + * Encrypt secret property. + * + * @param authProperty Authentication property object. + * @param authType Authentication Type + * @param actionId Action Id. + * @return Encrypted Auth Property if it is a confidential property. + * @throws SecretManagementException If an error occurs while encrypting the secret. + */ + private AuthProperty encryptProperty(AuthProperty authProperty, String authType, String actionId) + throws SecretManagementException { + + String secretName = buildSecretName(actionId, authType, authProperty.getName()); + if (isSecretPropertyExists(secretName)) { + updateExistingSecretProperty(secretName, authProperty); + } else { + addNewActionSecretProperty(secretName, authProperty); + } + + return new AuthProperty.AuthPropertyBuilder() + .name(authProperty.getName()) + .isConfidential(authProperty.getIsConfidential()) + .value(buildSecretReference(secretName)) + .build(); + } + + /** + * Decrypt secret property. + * + * @param authProperty Authentication property object. + * @param authType Authentication Type. + * @param actionId Action Id. + * @return Decrypted Auth Property if it is a confidential property. + * @throws SecretManagementException If an error occurs while decrypting the secret. + */ + private AuthProperty decryptProperty(AuthProperty authProperty, String authType, String actionId) + throws SecretManagementException { + + String secretName = buildSecretName(actionId, authType, authProperty.getName()); + if (!isSecretPropertyExists(secretName)) { + throw new SecretManagementException(); + } + ResolvedSecret resolvedSecret = ActionMgtServiceComponentHolder.getInstance().getSecretResolveManager() + .getResolvedSecret(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); + + return new AuthProperty.AuthPropertyBuilder() + .name(authProperty.getName()) + .isConfidential(authProperty.getIsConfidential()) + .value(resolvedSecret.getResolvedSecretValue()) + .build(); + } + + /** + * Check whether the secret property exists. + * + * @param secretName Secret Name. + * @return True if the secret property exists. + * @throws SecretManagementException If an error occurs while checking the existence of the secret. + */ + private boolean isSecretPropertyExists(String secretName) throws SecretManagementException { + + return ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .isSecretExist(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); + } + /** * Create secret name. * @@ -148,10 +188,8 @@ private String buildSecretName(String actionId, String authType, String authProp */ private String buildSecretReference(String secretName) throws SecretManagementException { - if (secretType == null) { - secretType = ActionMgtServiceComponentHolder.getInstance().getSecretManager() - .getSecretType(IDN_SECRET_TYPE_ACTION_SECRETS); - } + SecretType secretType = ActionMgtServiceComponentHolder.getInstance().getSecretManager() + .getSecretType(IDN_SECRET_TYPE_ACTION_SECRETS); return secretType.getId() + ":" + secretName; } @@ -182,8 +220,7 @@ private void updateExistingSecretProperty(String secretName, AuthProperty proper throws SecretManagementException { ResolvedSecret resolvedSecret = ActionMgtServiceComponentHolder.getInstance().getSecretResolveManager() - .getResolvedSecret(IDN_SECRET_TYPE_ACTION_SECRETS, - secretName); + .getResolvedSecret(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); if (!resolvedSecret.getResolvedSecretValue().equals(property.getValue())) { ActionMgtServiceComponentHolder.getInstance().getSecretManager() .updateSecretValue(IDN_SECRET_TYPE_ACTION_SECRETS, secretName, property.getValue()); diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java index e03cd138c321..f49b423ae738 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java @@ -25,7 +25,7 @@ public class ActionMgtConstants { public static final String URI_ATTRIBUTE = "uri"; public static final String AUTHN_TYPE_ATTRIBUTE = "authnType"; - public static final String IDN_SECRET_TYPE_ACTION_SECRETS = "ACTION_SECRET_PROPERTIES"; + public static final String IDN_SECRET_TYPE_ACTION_SECRETS = "ACTION_API_ENDPOINT_AUTH_SECRETS"; /** * Error messages. @@ -66,7 +66,10 @@ public enum ErrorMessages { "Error while retrieving count of Actions per Action Type.", "Error while retrieving count of Actions per Action Type from the system."), ERROR_WHILE_RETRIEVING_ACTION_BASIC_INFO("65011", "Error while retrieving Action basic info.", - "Error while retrieving Action basic info from the system."),; + "Error while retrieving Action basic info from the system."), + ERROR_WHILE_DECRYPTING_ACTION_ENDPOINT_AUTH_PROPERTIES("65012", + "Error while decrypting Action Endpoint Authentication properties", + "Error while decrypting Action Endpoint Authentication properties in the system."); private final String code; private final String message; diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java index c92e221e5395..5e1eaed2e64c 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java @@ -64,11 +64,6 @@ public Action addAction(String actionType, String actionId, Action action, Integ Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true); try { - // Encrypt secrets and update action authentication properties with secret alias. - action.getEndpoint().getAuthentication().setProperties( - actionSecretProcessor.encryptAssociatedSecrets( - action.getEndpoint().getAuthentication().getProperties(), actionId, - action.getEndpoint().getAuthentication().getType().name())); try (NamedPreparedStatement statement = new NamedPreparedStatement(dbConnection, ActionMgtSQLConstants.Query.ADD_ACTION_TO_ACTION_TYPE)) { @@ -80,21 +75,22 @@ public Action addAction(String actionType, String actionId, Action action, Integ statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId); statement.executeUpdate(); + // Encrypt secrets. + List encryptedAuthProperties = actionSecretProcessor + .encryptAssociatedSecrets(action.getEndpoint().getAuthentication(), actionId); // Add Endpoint configuration properties. addEndpointProperties(dbConnection, actionId, getEndpointProperties(action.getEndpoint().getUri(), - action.getEndpoint().getAuthentication().getType().name(), - action.getEndpoint().getAuthentication().getProperties()), tenantId); + action.getEndpoint().getAuthentication().getType().name(), encryptedAuthProperties), tenantId); IdentityDatabaseUtil.commitTransaction(dbConnection); return getActionByActionId(actionId, tenantId); } catch (SQLException | ActionMgtException e) { if (LOG.isDebugEnabled()) { - LOG.debug("Error while creating the action in action type: " + actionType + - " in tenantDomain: " + IdentityTenantUtil.getTenantDomain(tenantId) + - ". Rolling back created action information and deleting added secrets."); + LOG.debug(String.format("Error while creating the Action of Action Type: %s in Tenant Domain: %s." + + " Rolling back created action information and deleting added secrets.", actionType, + IdentityTenantUtil.getTenantDomain(tenantId))); } - actionSecretProcessor.deleteAssociatedSecrets(action.getEndpoint().getAuthentication().getProperties(), - actionId, action.getEndpoint().getAuthentication().getType().name()); + actionSecretProcessor.deleteAssociatedSecrets(action.getEndpoint().getAuthentication(), actionId); IdentityDatabaseUtil.rollbackTransaction(dbConnection); throw ActionManagementUtil.handleServerException( ActionMgtConstants.ErrorMessages.ERROR_WHILE_ADDING_ACTION, e); @@ -163,8 +159,9 @@ public Action updateAction(String actionType, String actionId, Action action, In return getActionByActionId(actionId, tenantId); } catch (SQLException | ActionMgtException e) { if (LOG.isDebugEnabled()) { - LOG.debug("Error while updating the action in action type: " + actionType + " in tenantDomain: " + - IdentityTenantUtil.getTenantDomain(tenantId) + ". Rolling back updated action information."); + LOG.debug(String.format("Error while updating the Action of Action Type: %s and Action ID: %s in" + + " Tenant Domain: %s. Rolling back updated action information.", actionType, actionId, + IdentityTenantUtil.getTenantDomain(tenantId))); } IdentityDatabaseUtil.rollbackTransaction(dbConnection); throw ActionManagementUtil.handleServerException( @@ -188,14 +185,13 @@ public void deleteAction(String actionType, String actionId, Action action, Inte statement.executeUpdate(); // Delete action endpoint authentication related secrets. - actionSecretProcessor.deleteAssociatedSecrets( - action.getEndpoint().getAuthentication().getProperties(), actionId, - action.getEndpoint().getAuthentication().getType().name()); + actionSecretProcessor.deleteAssociatedSecrets(action.getEndpoint().getAuthentication(), actionId); IdentityDatabaseUtil.commitTransaction(dbConnection); } catch (SQLException | SecretManagementException e) { if (LOG.isDebugEnabled()) { - LOG.debug("Error while deleting the action in action type: " + actionType + " in tenantDomain: " + - IdentityTenantUtil.getTenantDomain(tenantId) + ". Rolling back deleted action information."); + LOG.debug(String.format("Error while deleting the Action of Action Type: %s and Action ID: %s in" + + " Tenant Domain: %s. Rolling back deleted action information.", actionType, actionId, + IdentityTenantUtil.getTenantDomain(tenantId))); } IdentityDatabaseUtil.rollbackTransaction(dbConnection); throw ActionManagementUtil.handleServerException( @@ -268,17 +264,16 @@ public Action updateActionEndpointAuthProperties(String actionId, AuthType authe // Update non-secret endpoint properties. updateActionEndpointProperties(dbConnection, actionId, nonSecretEndpointProperties, tenantId); // Encrypt and update non-secret endpoint properties. - actionSecretProcessor.encryptAssociatedSecrets(authentication.getProperties(), actionId, - authentication.getType().name()); + actionSecretProcessor.encryptAssociatedSecrets(authentication, actionId); IdentityDatabaseUtil.commitTransaction(dbConnection); return getActionByActionId(actionId, tenantId); } catch (ActionMgtException | SecretManagementException e) { if (LOG.isDebugEnabled()) { - LOG.debug("Error while updating the action secrets of Auth type: " + authentication.getType() + - " of Action id: " + actionId + " in tenantDomain: " + - IdentityTenantUtil.getTenantDomain(tenantId) + - ". Rolling back updated action endpoint authentication properties."); + LOG.debug(String.format("Error while updating the Action Endpoint Authentication Properties of " + + "Auth type: %s and Action ID: %s in Tenant Domain: %s. Rolling back updated action" + + " endpoint authentication properties.", authentication.getType(), actionId, + IdentityTenantUtil.getTenantDomain(tenantId))); } IdentityDatabaseUtil.rollbackTransaction(dbConnection); throw ActionManagementUtil.handleServerException( @@ -306,22 +301,20 @@ public Action updateActionEndpoint(String actionType, String actionId, EndpointC endpoint.getAuthentication().getType().name(), endpoint.getAuthentication().getPropertiesWithSecretReferences(actionId)), tenantId); // Encrypt and add new endpoint properties secrets. - actionSecretProcessor.encryptAssociatedSecrets(endpoint.getAuthentication().getProperties(), actionId, - endpoint.getAuthentication().getType().name()); + actionSecretProcessor.encryptAssociatedSecrets(endpoint.getAuthentication(), actionId); // Delete old secrets. - actionSecretProcessor.deleteAssociatedSecrets(currentAuthentication.getProperties(), actionId, - currentAuthentication.getType().name()); + actionSecretProcessor.deleteAssociatedSecrets(currentAuthentication, actionId); IdentityDatabaseUtil.commitTransaction(dbConnection); return getActionByActionId(actionId, tenantId); } catch (SQLException | ActionMgtException | SecretManagementException e) { if (LOG.isDebugEnabled()) { - LOG.debug("Error while updating the action endpoint authentication from Auth type: " + - currentAuthentication.getType() + " to Auth type: " + endpoint.getAuthentication().getType() + - " of Action id: " + actionId + " in tenantDomain: " + - IdentityTenantUtil.getTenantDomain(tenantId) + - ". Rolling back updated action endpoint authentication properties."); + LOG.debug(String.format("Error while updating the Action Endpoint Authentication from Auth type: %s" + + " to Auth type: %s of Action ID: %s in Tenant Domain: %s. Rolling back updated" + + " action endpoint authentication.", currentAuthentication.getType(), + endpoint.getAuthentication().getType(), actionId, + IdentityTenantUtil.getTenantDomain(tenantId))); } IdentityDatabaseUtil.rollbackTransaction(dbConnection); throw ActionManagementUtil.handleServerException( @@ -438,10 +431,13 @@ private EndpointConfig getActionEndpointConfigById(Connection dbConnection, Stri } if (authnType != null) { - for (AuthProperty property : authnType.getProperties()) { + for (AuthType.AuthenticationType.AuthenticationProperty property : authnType.getProperties()) { if (authnPropertiesMap.containsKey(property.getName())) { - property.setValue(authnPropertiesMap.get(property.getName())); - authnProperties.add(property); + authnProperties.add(new AuthProperty.AuthPropertyBuilder() + .name(property.getName()) + .value(authnPropertiesMap.get(property.getName())) + .isConfidential(property.getIsConfidential()) + .build()); } } } @@ -540,9 +536,9 @@ private Action changeActionStatus(String actionType, String actionId, String sta return getActionBasicInfoById(dbConnection, actionId, tenantId); } catch (SQLException e) { if (LOG.isDebugEnabled()) { - LOG.debug("Error while updating the action status in action type: " + actionType + - " in tenantDomain: " + IdentityTenantUtil.getTenantDomain(tenantId) + - ". Rolling back updated action status."); + LOG.debug(String.format("Error while updating the Action Status to %s of Action type: %s in " + + "Tenant Domain: %s. Rolling back updated action status.", status, actionType, + IdentityTenantUtil.getTenantDomain(tenantId))); } IdentityDatabaseUtil.rollbackTransaction(dbConnection); throw ActionManagementUtil.handleServerException( diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java index ef9d7bd6821c..3969a679c643 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java @@ -48,11 +48,6 @@ public String getValue() { return value; } - public void setValue(String value) { - - this.value = value; - } - public boolean getIsConfidential() { return isConfidential; diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthType.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthType.java index 538d0b1a70b2..9ea099ad2b12 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthType.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthType.java @@ -18,11 +18,16 @@ package org.wso2.carbon.identity.action.management.model; +import org.apache.commons.collections.CollectionUtils; import org.wso2.carbon.identity.action.management.ActionSecretProcessor; +import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants; +import org.wso2.carbon.identity.action.management.exception.ActionMgtException; +import org.wso2.carbon.identity.action.management.util.ActionManagementUtil; import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -35,47 +40,18 @@ public class AuthType { */ public enum AuthenticationType { - NONE( - "none", - "NONE", - new ArrayList<>() - ), - BEARER( - "bearer", - "BEARER", - Arrays.asList( - new AuthProperty.AuthPropertyBuilder() - .name("accessToken") - .isConfidential(true).build()) - ), - BASIC( - "basic", - "BASIC", - Arrays.asList( - new AuthProperty.AuthPropertyBuilder() - .name("username") - .isConfidential(true).build(), - new AuthProperty.AuthPropertyBuilder() - .name("password") - .isConfidential(true).build()) - ), - API_KEY( - "apiKey", - "API_KEY", - Arrays.asList( - new AuthProperty.AuthPropertyBuilder() - .name("header") - .isConfidential(false).build(), - new AuthProperty.AuthPropertyBuilder() - .name("value") - .isConfidential(true).build()) - ); + NONE("none", "NONE", Collections.emptyList()), + BEARER("bearer", "BEARER", Arrays.asList(AuthenticationProperty.ACCESS_TOKEN)), + BASIC("basic", "BASIC", + Arrays.asList(AuthenticationProperty.USERNAME, AuthenticationProperty.PASSWORD)), + API_KEY("apiKey", "API_KEY", + Arrays.asList(AuthenticationProperty.HEADER, AuthenticationProperty.VALUE)); private final String pathParam; private final String type; - private final List properties; + private final List properties; - AuthenticationType(String pathParam, String type, List properties) { + AuthenticationType(String pathParam, String type, List properties) { this.pathParam = pathParam; this.type = type; @@ -92,10 +68,37 @@ public String getType() { return type; } - public List getProperties() { + public List getProperties() { return properties; } + + /** + * Authentication Property. + */ + public enum AuthenticationProperty { + ACCESS_TOKEN("accessToken", true), + USERNAME("username", true), + PASSWORD("password", true), + HEADER("header", false), + VALUE("value", true); + + private final String name; + private final boolean isConfidential; + + AuthenticationProperty(String name, boolean isConfidential) { + this.name = name; + this.isConfidential = isConfidential; + } + + public String getName() { + return name; + } + + public boolean getIsConfidential() { + return isConfidential; + } + } } private AuthenticationType type; @@ -116,32 +119,26 @@ public AuthenticationType getType() { return type; } - public void setProperties(List properties) { - - this.properties = properties; - } - public List getProperties() { return properties; } - public List getPropertiesWithDecryptedValues(String actionId) throws SecretManagementException { + public List getPropertiesWithDecryptedValues(String actionId) throws ActionMgtException { - if (properties != null) { - - return secretProcessor.decryptAssociatedSecrets(properties, actionId, type.name()); + try { + return CollectionUtils.isEmpty(properties) ? properties : + secretProcessor.decryptAssociatedSecrets(properties, type.getType(), actionId); + } catch (SecretManagementException e) { + throw ActionManagementUtil.handleServerException( + ActionMgtConstants.ErrorMessages.ERROR_WHILE_DECRYPTING_ACTION_ENDPOINT_AUTH_PROPERTIES, e); } - return null; } public List getPropertiesWithSecretReferences(String actionId) throws SecretManagementException { - if (properties != null) { - - return secretProcessor.getPropertiesWithSecretReferences(properties, actionId, type.name()); - } - return null; + return CollectionUtils.isEmpty(properties) ? properties : + secretProcessor.getPropertiesWithSecretReferences(properties, actionId, type.name()); } /** diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/EndpointConfig.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/EndpointConfig.java index 96f99260abb7..7b97f6587f29 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/EndpointConfig.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/EndpointConfig.java @@ -34,6 +34,7 @@ public EndpointConfig(EndpointConfigBuilder endpointConfigBuilder) { this.uri = endpointConfigBuilder.uri; this.authentication = endpointConfigBuilder.authentication; } + public String getUri() { return uri; 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 ff5d31c88623..7d210a3d7778 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 @@ -1126,7 +1126,7 @@ INSERT INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('c508ca28-60c0-4493-a758-77e4173ffdb9', 'IDP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity providers'), ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers'), ('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'), -('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties'); +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_API_ENDPOINT_AUTH_SECRETS', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties'); CREATE TABLE IF NOT EXISTS IDN_SECRET ( ID VARCHAR(255) NOT NULL, From f7d0dcad568a240ef41ac7e21c4f4dc0c8f37d40 Mon Sep 17 00:00:00 2001 From: Ashan Thamara Palihakkara <75057725+ashanthamara@users.noreply.github.com> Date: Tue, 16 Jul 2024 18:35:34 +0530 Subject: [PATCH 3/6] Update other db scripts --- .../resources/dbscripts/db2.sql | 3 ++- .../resources/dbscripts/mssql.sql | 3 ++- .../resources/dbscripts/mysql-cluster.sql | 3 ++- .../resources/dbscripts/mysql.sql | 3 ++- .../resources/dbscripts/oracle.sql | 2 ++ .../resources/dbscripts/oracle_rac.sql | 2 ++ .../resources/dbscripts/postgresql.sql | 3 ++- 7 files changed, 14 insertions(+), 5 deletions(-) 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 3cb595a6d2d0..1a95b359c778 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 @@ -1683,7 +1683,8 @@ INSERT INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('1358bdbf-e0cc-4268-a42c-c3e0960e13f0', 'ADAPTIVE_AUTH_CALL_CHOREO', 'Secret type to uniquely identify secrets relevant to callChoreo adaptive auth function'), ('c508ca28-60c0-4493-a758-77e4173ffdb9', 'IDP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity providers'), ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers'), -('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials') +('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'), +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_API_ENDPOINT_AUTH_SECRETS', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties') / CREATE TABLE IDN_SECRET ( 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 4133fcb73ce6..22a2df06b6fb 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 @@ -1250,7 +1250,8 @@ INSERT INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('1358bdbf-e0cc-4268-a42c-c3e0960e13f0', 'ADAPTIVE_AUTH_CALL_CHOREO', 'Secret type to uniquely identify secrets relevant to callChoreo adaptive auth function'), ('c508ca28-60c0-4493-a758-77e4173ffdb9', 'IDP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity providers'), ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers'), -('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'); +('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'), +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_API_ENDPOINT_AUTH_SECRETS', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties'); IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[IDN_SECRET]') 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 983096eeb180..57222a6474a3 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 @@ -1287,7 +1287,8 @@ INSERT INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('1358bdbf-e0cc-4268-a42c-c3e0960e13f0', 'ADAPTIVE_AUTH_CALL_CHOREO', 'Secret type to uniquely identify secrets relevant to callChoreo adaptive auth function'), ('c508ca28-60c0-4493-a758-77e4173ffdb9', 'IDP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity providers'), ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers'), -('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'); +('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'), +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_API_ENDPOINT_AUTH_SECRETS', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties'); CREATE TABLE IF NOT EXISTS IDN_SECRET ( ID VARCHAR(255) NOT NULL, 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 28ff8e8d17b3..c5e279844d6b 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 @@ -1152,7 +1152,8 @@ INSERT INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('1358bdbf-e0cc-4268-a42c-c3e0960e13f0', 'ADAPTIVE_AUTH_CALL_CHOREO', 'Secret type to uniquely identify secrets relevant to callChoreo adaptive auth function'), ('c508ca28-60c0-4493-a758-77e4173ffdb9', 'IDP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity providers'), ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers'), -('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'); +('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'), +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_API_ENDPOINT_AUTH_SECRETS', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties'); CREATE TABLE IF NOT EXISTS IDN_SECRET ( ID VARCHAR(255) NOT NULL, 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 f0c70ec7166f..9a115ffdfcca 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 @@ -1861,6 +1861,8 @@ INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers') INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials') +INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_API_ENDPOINT_AUTH_SECRETS', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties') SELECT 1 FROM dual / 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 441ebd6e4aaa..28ce61bb71af 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 @@ -1743,6 +1743,8 @@ INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers') INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials') +INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_API_ENDPOINT_AUTH_SECRETS', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties') SELECT 1 FROM dual / 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 992bcd68565f..0a59499a4aae 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 @@ -1343,7 +1343,8 @@ INSERT INTO IDN_SECRET_TYPE (ID, NAME, DESCRIPTION) VALUES ('1358bdbf-e0cc-4268-a42c-c3e0960e13f0', 'ADAPTIVE_AUTH_CALL_CHOREO', 'Secret type to uniquely identify secrets relevant to callChoreo adaptive auth function'), ('c508ca28-60c0-4493-a758-77e4173ffdb9', 'IDP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity providers'), ('433df096-62b7-4a36-b3eb-1bed9150ed35', 'IDVP_SECRET_PROPERTIES', 'Secret type to uniquely identify secrets relevant to identity verification providers'), -('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'); +('29d0c37d-139a-4b1e-a343-7b8d26f0a2a9', 'ANDROID_ATTESTATION_CREDENTIALS', 'Secret type to uniquely identify secrets relevant to android client attestation credentials'), +('33f0a41b-569d-4ea5-a891-6c0e78a1c3b0', 'ACTION_API_ENDPOINT_AUTH_SECRETS', 'Secret type to uniquely identify secrets relevant to action endpoint authentication properties'); DROP TABLE IF EXISTS IDN_SECRET; CREATE TABLE IDN_SECRET ( From d2420ad5643697c5521872bf43d17fe17dd12580 Mon Sep 17 00:00:00 2001 From: Ashan Thamara Palihakkara <75057725+ashanthamara@users.noreply.github.com> Date: Tue, 16 Jul 2024 20:03:31 +0530 Subject: [PATCH 4/6] Address comments --- .../action/management/ActionSecretProcessor.java | 3 ++- .../management/dao/impl/ActionManagementDAOImpl.java | 2 +- .../action/management/model/AuthProperty.java | 11 +++++------ .../mgt/core/exception/SecretManagementException.java | 5 +++++ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java index 3fb2d245b5aa..861f085b8671 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java @@ -141,7 +141,8 @@ private AuthProperty decryptProperty(AuthProperty authProperty, String authType, String secretName = buildSecretName(actionId, authType, authProperty.getName()); if (!isSecretPropertyExists(secretName)) { - throw new SecretManagementException(); + throw new SecretManagementException(String.format("Unable to find the Secret Property: %s of " + + "Auth Type: %s and Action ID: %s from the system.", authProperty.getName(), authType, actionId)); } ResolvedSecret resolvedSecret = ActionMgtServiceComponentHolder.getInstance().getSecretResolveManager() .getResolvedSecret(IDN_SECRET_TYPE_ACTION_SECRETS, secretName); diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java index 5e1eaed2e64c..e272e39ed9a4 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java @@ -263,7 +263,7 @@ public Action updateActionEndpointAuthProperties(String actionId, AuthType authe .collect(Collectors.toMap(AuthProperty::getName, AuthProperty::getValue)); // Update non-secret endpoint properties. updateActionEndpointProperties(dbConnection, actionId, nonSecretEndpointProperties, tenantId); - // Encrypt and update non-secret endpoint properties. + // Encrypt and update secret endpoint properties. actionSecretProcessor.encryptAssociatedSecrets(authentication, actionId); IdentityDatabaseUtil.commitTransaction(dbConnection); diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java index 3969a679c643..afd37f3b7aff 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/AuthProperty.java @@ -28,14 +28,13 @@ public class AuthProperty { private boolean isConfidential; public AuthProperty() { - } - public AuthProperty(String name, String value, boolean isConfidential) { + public AuthProperty(AuthPropertyBuilder authPropertyBuilder) { - this.name = name; - this.value = value; - this.isConfidential = isConfidential; + this.name = authPropertyBuilder.name; + this.value = authPropertyBuilder.value; + this.isConfidential = authPropertyBuilder.isConfidential; } public String getName() { @@ -82,7 +81,7 @@ public AuthPropertyBuilder isConfidential(boolean isConfidential) { public AuthProperty build() { - return new AuthProperty(name, value, isConfidential); + return new AuthProperty(this); } } } diff --git a/components/secret-mgt/org.wso2.carbon.identity.secret.mgt.core/src/main/java/org/wso2/carbon/identity/secret/mgt/core/exception/SecretManagementException.java b/components/secret-mgt/org.wso2.carbon.identity.secret.mgt.core/src/main/java/org/wso2/carbon/identity/secret/mgt/core/exception/SecretManagementException.java index a5180b8d83a5..6b4170333367 100644 --- a/components/secret-mgt/org.wso2.carbon.identity.secret.mgt.core/src/main/java/org/wso2/carbon/identity/secret/mgt/core/exception/SecretManagementException.java +++ b/components/secret-mgt/org.wso2.carbon.identity.secret.mgt.core/src/main/java/org/wso2/carbon/identity/secret/mgt/core/exception/SecretManagementException.java @@ -30,6 +30,11 @@ public SecretManagementException() { super(); } + public SecretManagementException(String message) { + + super(message); + } + public SecretManagementException(String message, String errorCode) { super(message); From 3b2f225bd8cb3d22aa23530b9f3405522216c18e Mon Sep 17 00:00:00 2001 From: Ashan Thamara Palihakkara <75057725+ashanthamara@users.noreply.github.com> Date: Tue, 16 Jul 2024 20:17:01 +0530 Subject: [PATCH 5/6] Fix spotbug issue --- .../ActionMgtServiceComponentHolder.java | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java index 6643336b9e90..cf6f93d51c73 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java @@ -26,30 +26,60 @@ */ public class ActionMgtServiceComponentHolder { - public static ActionMgtServiceComponentHolder instance = new ActionMgtServiceComponentHolder(); + private SecretManager secretManager; + private SecretResolveManager secretResolveManager; + + public static final ActionMgtServiceComponentHolder instance = new ActionMgtServiceComponentHolder(); + + private ActionMgtServiceComponentHolder() { + + } + /** + * Get the instance of ActionMgtServiceComponentHolder. + * + * @return ActionMgtServiceComponentHolder instance. + */ public static ActionMgtServiceComponentHolder getInstance() { + return instance; } - private SecretManager secretManager; - private SecretResolveManager secretResolveManager; - + /** + * Get the SecretManager. + * + * @return SecretManager instance. + */ public SecretManager getSecretManager() { return secretManager; } + /** + * Set the SecretManager. + * + * @param secretManager SecretManager instance. + */ public void setSecretManager(SecretManager secretManager) { this.secretManager = secretManager; } + /** + * Get the SecretResolveManager. + * + * @return SecretResolveManager instance. + */ public SecretResolveManager getSecretResolveManager() { return secretResolveManager; } + /** + * Set the SecretResolveManager. + * + * @param secretResolveManager SecretResolveManager instance. + */ public void setSecretResolveManager(SecretResolveManager secretResolveManager) { this.secretResolveManager = secretResolveManager; From 32791bd71ccea12404a52aa3e2782de794c3335c Mon Sep 17 00:00:00 2001 From: Ashan Thamara Palihakkara <75057725+ashanthamara@users.noreply.github.com> Date: Tue, 16 Jul 2024 20:49:08 +0530 Subject: [PATCH 6/6] Fix spotbug issue --- .../management/internal/ActionMgtServiceComponentHolder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java index cf6f93d51c73..5866841fdbaa 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponentHolder.java @@ -29,7 +29,7 @@ public class ActionMgtServiceComponentHolder { private SecretManager secretManager; private SecretResolveManager secretResolveManager; - public static final ActionMgtServiceComponentHolder instance = new ActionMgtServiceComponentHolder(); + public static final ActionMgtServiceComponentHolder INSTANCE = new ActionMgtServiceComponentHolder(); private ActionMgtServiceComponentHolder() { @@ -42,7 +42,7 @@ private ActionMgtServiceComponentHolder() { */ public static ActionMgtServiceComponentHolder getInstance() { - return instance; + return INSTANCE; } /**