From f39771ba915ec95d3feee00f14c7e5304bf1e9d0 Mon Sep 17 00:00:00 2001 From: ThumulaPerera <42399179+ThumulaPerera@users.noreply.github.com> Date: Mon, 26 Jun 2023 11:44:40 +0530 Subject: [PATCH 1/2] Modify KeyStoreManager to use DAO --- .../carbon/core/util/KeyStoreManager.java | 124 ++++++++++-------- 1 file changed, 68 insertions(+), 56 deletions(-) diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java index 1cb55cecb84..4f7aeb47070 100644 --- a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java +++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java @@ -27,6 +27,10 @@ import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.service.RegistryService; +import org.wso2.carbon.security.SecurityConfigException; +import org.wso2.carbon.security.keystore.dao.KeyStoreDAO; +import org.wso2.carbon.security.keystore.dao.impl.KeyStoreDAOImpl; +import org.wso2.carbon.security.keystore.model.KeyStoreModel; import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; @@ -37,6 +41,7 @@ import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.Date; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; /** @@ -54,6 +59,8 @@ public class KeyStoreManager { private static Log log = LogFactory.getLog(KeyStoreManager.class); private Registry registry = null; + private KeyStoreDAO keyStoreDAO = null; + private ConcurrentHashMap loadedKeyStores = null; private int tenantId = MultitenantConstants.SUPER_TENANT_ID; @@ -76,10 +83,15 @@ private KeyStoreManager(int tenantId, ServerConfigurationService serverConfigSer this.tenantId = tenantId; try { registry = registryService.getGovernanceSystemRegistry(tenantId); + keyStoreDAO = new KeyStoreDAOImpl(tenantId); } catch (RegistryException e) { String message = "Error when retrieving the system governance registry"; log.error(message, e); throw new SecurityException(message, e); + } catch (SecurityConfigException e) { + String message = "Error when retrieving the key store DAO"; + log.error(message, e); + throw new SecurityException(message, e); } } @@ -134,19 +146,20 @@ public KeyStore getKeyStore(String keyStoreName) throws Exception { } String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName; - if (registry.resourceExists(path)) { - org.wso2.carbon.registry.api.Resource resource = registry.get(path); - byte[] bytes = (byte[]) resource.getContent(); - KeyStore keyStore = KeyStore.getInstance(resource - .getProperty(RegistryResources.SecurityManagement.PROP_TYPE)); + + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(keyStoreName); + if (optionalKeyStoreModel.isPresent()) { + KeyStoreModel keyStoreModel = optionalKeyStoreModel.get(); + + byte[] bytes = keyStoreModel.getContent(); + KeyStore keyStore = KeyStore.getInstance(keyStoreModel.getType()); CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - String encryptedPassword = resource - .getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD); + String encryptedPassword = keyStoreModel.getPassword(); String password = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); ByteArrayInputStream stream = new ByteArrayInputStream(bytes); keyStore.load(stream, password.toCharArray()); - KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, resource.getLastModified()); - resource.discard(); + + KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, keyStoreModel.getLastUpdated()); if (loadedKeyStores.containsKey(keyStoreName)) { loadedKeyStores.replace(keyStoreName, keyStoreBean); @@ -172,37 +185,33 @@ public Key getPrivateKey(String keyStoreName, String alias) { return getDefaultPrivateKey(); } - String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName; - org.wso2.carbon.registry.api.Resource resource; + KeyStoreModel keyStoreModel; KeyStore keyStore; - if (registry.resourceExists(path)) { - resource = registry.get(path); + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(keyStoreName); + if (optionalKeyStoreModel.isPresent()) { + keyStoreModel = optionalKeyStoreModel.get(); } else { - throw new SecurityException("Given Key store is not available in registry : " + keyStoreName); + throw new SecurityException("Given Key store is not available in Database : " + keyStoreName); } CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - String encryptedPassword = resource - .getProperty(RegistryResources.SecurityManagement.PROP_PRIVATE_KEY_PASS); + String encryptedPassword = keyStoreModel.getPrivateKeyPass(); String privateKeyPasswd = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); if (isCachedKeyStoreValid(keyStoreName)) { keyStore = loadedKeyStores.get(keyStoreName).getKeyStore(); return keyStore.getKey(alias, privateKeyPasswd.toCharArray()); - } else { - byte[] bytes = (byte[]) resource.getContent(); - String keyStorePassword = new String(cryptoUtil.base64DecodeAndDecrypt(resource.getProperty( - RegistryResources.SecurityManagement.PROP_PASSWORD))); - keyStore = KeyStore.getInstance(resource - .getProperty(RegistryResources.SecurityManagement.PROP_TYPE)); - ByteArrayInputStream stream = new ByteArrayInputStream(bytes); - keyStore.load(stream, keyStorePassword.toCharArray()); - - KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, resource.getLastModified()); - updateKeyStoreCache(keyStoreName, keyStoreBean); - return keyStore.getKey(alias, privateKeyPasswd.toCharArray()); } + byte[] bytes = keyStoreModel.getContent(); + String keyStorePassword = new String(cryptoUtil.base64DecodeAndDecrypt(keyStoreModel.getPassword())); + keyStore = KeyStore.getInstance(keyStoreModel.getType()); + ByteArrayInputStream stream = new ByteArrayInputStream(bytes); + keyStore.load(stream, keyStorePassword.toCharArray()); + + KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, keyStoreModel.getLastUpdated()); + updateKeyStoreCache(keyStoreName, keyStoreBean); + return keyStore.getKey(alias, privateKeyPasswd.toCharArray()); } catch (Exception e) { log.error("Error loading the private key from the key store : " + keyStoreName); throw new SecurityException("Error loading the private key from the key store : " + @@ -217,6 +226,7 @@ public Key getPrivateKey(String keyStoreName, String alias) { * @return password of the key store * @throws Exception Error when reading the registry resource of decrypting the password */ + // TODO: deprecate this method in the future since we are no longer using registry for key store management. public String getPassword(Resource resource) throws Exception { CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); String encryptedPassword = resource @@ -236,12 +246,11 @@ public String getPassword(Resource resource) throws Exception { */ public String getKeyStorePassword(String keyStoreName) throws Exception { - String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName; - if (registry.resourceExists(path)) { - org.wso2.carbon.registry.api.Resource resource = registry.get(path); + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(keyStoreName); + if (optionalKeyStoreModel.isPresent()) { + KeyStoreModel keyStoreModel = optionalKeyStoreModel.get(); CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - String encryptedPassword = resource - .getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD); + String encryptedPassword = keyStoreModel.getPassword(); if(encryptedPassword != null){ return new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); } else { @@ -281,24 +290,25 @@ public void updateKeyStore(String name, KeyStore keyStore) throws Exception { return; } - String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + name; - - org.wso2.carbon.registry.api.Resource resource = registry.get(path); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - String encryptedPassword = resource - .getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD); - String password = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); - keyStore.store(outputStream, password.toCharArray()); - outputStream.flush(); - outputStream.close(); + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(name); + if (optionalKeyStoreModel.isPresent()) { + KeyStoreModel keyStoreModel = optionalKeyStoreModel.get(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); + String encryptedPassword = keyStoreModel.getPassword(); + String password = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); + keyStore.store(outputStream, password.toCharArray()); + outputStream.flush(); + outputStream.close(); - resource.setContent(outputStream.toByteArray()); + keyStoreModel.setContent(outputStream.toByteArray()); + keyStoreDAO.updateKeyStore(keyStoreModel); - registry.put(path, resource); - resource.discard(); - updateKeyStoreCache(name, new KeyStoreBean(keyStore, new Date())); + // TODO: is it correct to use new Date() here? The value stored in DB might be different. + updateKeyStoreCache(name, new KeyStoreBean(keyStore, new Date())); + } else { + throw new SecurityException("Key Store with a name : " + name + " does not exist."); + } } /** @@ -487,18 +497,20 @@ public X509Certificate getDefaultPrimaryCertificate() throws Exception { } private boolean isCachedKeyStoreValid(String keyStoreName) { - String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName; boolean cachedKeyStoreValid = false; try { if (loadedKeyStores.containsKey(keyStoreName)) { - org.wso2.carbon.registry.api.Resource metaDataResource = registry.get(path); - KeyStoreBean keyStoreBean = loadedKeyStores.get(keyStoreName); - if (keyStoreBean.getLastModifiedDate().equals(metaDataResource.getLastModified())) { - cachedKeyStoreValid = true; + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(keyStoreName); + if (optionalKeyStoreModel.isPresent()) { + KeyStoreModel keyStoreModel = optionalKeyStoreModel.get(); + KeyStoreBean keyStoreBean = loadedKeyStores.get(keyStoreName); + if (keyStoreBean.getLastModifiedDate().equals(keyStoreModel.getLastUpdated())) { + cachedKeyStoreValid = true; + } } } - } catch (org.wso2.carbon.registry.api.RegistryException e) { - String errorMsg = "Error reading key store meta data from registry."; + } catch (SecurityConfigException e) { + String errorMsg = "Error reading key store meta data from Database."; log.error(errorMsg, e); throw new SecurityException(errorMsg, e); } From 4005ad9117367e12298c6f998e101ba4c33b45dc Mon Sep 17 00:00:00 2001 From: mpmadhavig Date: Tue, 22 Aug 2023 15:14:22 +0530 Subject: [PATCH 2/2] Add keystore DAO method signature changes. --- core/org.wso2.carbon.core/pom.xml | 5 ++ .../carbon/core/util/KeyStoreManager.java | 77 +++++++++++-------- parent/pom.xml | 10 +++ 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/core/org.wso2.carbon.core/pom.xml b/core/org.wso2.carbon.core/pom.xml index 90cb6e262e1..b582584a4ca 100644 --- a/core/org.wso2.carbon.core/pom.xml +++ b/core/org.wso2.carbon.core/pom.xml @@ -94,6 +94,10 @@ org.wso2.carbon org.wso2.carbon.utils + + org.wso2.carbon.security.mgt + org.wso2.carbon.security.mgt + org.wso2.carbon.crypto org.wso2.carbon.crypto.api @@ -247,6 +251,7 @@ javax.xml.stream.*; version=1.0.1, org.wso2.carbon.registry.core.service, org.wso2.carbon.user.core.*; version=0.0.0, + org.wso2.carbon.security.mgt.*; version=${carbon.security.mgt.imp.version.range}, org.bouncycastle.*; version="${imp.pkg.version.bcp}", *;resolution:=optional diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java index 4f7aeb47070..fbe8cef7dab 100644 --- a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java +++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java @@ -1,7 +1,7 @@ /* -* Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* Copyright (c) 2005-2010, WSO2 LLC. (https://www.wso2.com). * -* WSO2 Inc. licenses this file to you under the Apache License, +* 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 @@ -27,10 +27,11 @@ import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.service.RegistryService; -import org.wso2.carbon.security.SecurityConfigException; +import org.wso2.carbon.security.keystore.KeyStoreManagementException; import org.wso2.carbon.security.keystore.dao.KeyStoreDAO; import org.wso2.carbon.security.keystore.dao.impl.KeyStoreDAOImpl; import org.wso2.carbon.security.keystore.model.KeyStoreModel; +import org.wso2.carbon.security.util.KeyStoreMgtUtil; import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; @@ -83,15 +84,11 @@ private KeyStoreManager(int tenantId, ServerConfigurationService serverConfigSer this.tenantId = tenantId; try { registry = registryService.getGovernanceSystemRegistry(tenantId); - keyStoreDAO = new KeyStoreDAOImpl(tenantId); + keyStoreDAO = new KeyStoreDAOImpl(); } catch (RegistryException e) { String message = "Error when retrieving the system governance registry"; log.error(message, e); throw new SecurityException(message, e); - } catch (SecurityConfigException e) { - String message = "Error when retrieving the key store DAO"; - log.error(message, e); - throw new SecurityException(message, e); } } @@ -147,17 +144,18 @@ public KeyStore getKeyStore(String keyStoreName) throws Exception { String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName; - Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(keyStoreName); + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore( + KeyStoreMgtUtil.getTenantUUID(tenantId), keyStoreName); if (optionalKeyStoreModel.isPresent()) { KeyStoreModel keyStoreModel = optionalKeyStoreModel.get(); byte[] bytes = keyStoreModel.getContent(); KeyStore keyStore = KeyStore.getInstance(keyStoreModel.getType()); CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - String encryptedPassword = keyStoreModel.getPassword(); - String password = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); + char[] encryptedPassword = keyStoreModel.getPassword(); + char[] password = new String(cryptoUtil.base64DecodeAndDecrypt(String.valueOf(encryptedPassword))).toCharArray(); ByteArrayInputStream stream = new ByteArrayInputStream(bytes); - keyStore.load(stream, password.toCharArray()); + keyStore.load(stream, password); KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, keyStoreModel.getLastUpdated()); @@ -188,7 +186,8 @@ public Key getPrivateKey(String keyStoreName, String alias) { KeyStoreModel keyStoreModel; KeyStore keyStore; - Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(keyStoreName); + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore( + KeyStoreMgtUtil.getTenantUUID(tenantId), keyStoreName); if (optionalKeyStoreModel.isPresent()) { keyStoreModel = optionalKeyStoreModel.get(); } else { @@ -196,22 +195,24 @@ public Key getPrivateKey(String keyStoreName, String alias) { } CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - String encryptedPassword = keyStoreModel.getPrivateKeyPass(); - String privateKeyPasswd = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); + char[] encryptedPassword = keyStoreModel.getPrivateKeyPass(); + char[] privateKeyPasswd = new String(cryptoUtil.base64DecodeAndDecrypt(String.valueOf(encryptedPassword))) + .toCharArray(); if (isCachedKeyStoreValid(keyStoreName)) { keyStore = loadedKeyStores.get(keyStoreName).getKeyStore(); - return keyStore.getKey(alias, privateKeyPasswd.toCharArray()); + return keyStore.getKey(alias, privateKeyPasswd); } byte[] bytes = keyStoreModel.getContent(); - String keyStorePassword = new String(cryptoUtil.base64DecodeAndDecrypt(keyStoreModel.getPassword())); + char[] keyStorePassword = new String(cryptoUtil.base64DecodeAndDecrypt( + String.valueOf(keyStoreModel.getPassword()))).toCharArray(); keyStore = KeyStore.getInstance(keyStoreModel.getType()); ByteArrayInputStream stream = new ByteArrayInputStream(bytes); - keyStore.load(stream, keyStorePassword.toCharArray()); + keyStore.load(stream, keyStorePassword); KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, keyStoreModel.getLastUpdated()); updateKeyStoreCache(keyStoreName, keyStoreBean); - return keyStore.getKey(alias, privateKeyPasswd.toCharArray()); + return keyStore.getKey(alias, privateKeyPasswd); } catch (Exception e) { log.error("Error loading the private key from the key store : " + keyStoreName); throw new SecurityException("Error loading the private key from the key store : " + @@ -240,19 +241,22 @@ public String getPassword(Resource resource) throws Exception { * Get the key store password for the given key store name. * Note: Caching has been not implemented for this method * + * Todo: Change the return type to char[]. + * * @param keyStoreName key store name * @return KeyStore object * @throws Exception If there is not a key store with the given name */ public String getKeyStorePassword(String keyStoreName) throws Exception { - Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(keyStoreName); + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore( + KeyStoreMgtUtil.getTenantUUID(tenantId), keyStoreName); if (optionalKeyStoreModel.isPresent()) { KeyStoreModel keyStoreModel = optionalKeyStoreModel.get(); CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - String encryptedPassword = keyStoreModel.getPassword(); + char[] encryptedPassword = keyStoreModel.getPassword(); if(encryptedPassword != null){ - return new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); + return new String(cryptoUtil.base64DecodeAndDecrypt(String.valueOf(encryptedPassword))); } else { throw new SecurityException("Key Store Password of " + keyStoreName + " does not exist."); } @@ -290,19 +294,31 @@ public void updateKeyStore(String name, KeyStore keyStore) throws Exception { return; } - Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(name); + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore( + KeyStoreMgtUtil.getTenantUUID(tenantId), name); if (optionalKeyStoreModel.isPresent()) { KeyStoreModel keyStoreModel = optionalKeyStoreModel.get(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - String encryptedPassword = keyStoreModel.getPassword(); - String password = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)); - keyStore.store(outputStream, password.toCharArray()); + char[] encryptedPassword = keyStoreModel.getPassword(); + char[] password = new String(cryptoUtil.base64DecodeAndDecrypt( + String.valueOf(encryptedPassword))).toCharArray(); + keyStore.store(outputStream, password); outputStream.flush(); outputStream.close(); - keyStoreModel.setContent(outputStream.toByteArray()); - keyStoreDAO.updateKeyStore(keyStoreModel); + KeyStoreModel updatedKeyStoreModel = new KeyStoreModel.KeyStoreModelBuilder() + .id(keyStoreModel.getId()) + .fileName(keyStoreModel.getFileName()) + .type(keyStoreModel.getType()) + .provider(keyStoreModel.getProvider()) + .password(keyStoreModel.getPassword()) + .privateKeyAlias(keyStoreModel.getPrivateKeyAlias()) + .privateKeyPass(keyStoreModel.getPrivateKeyPass()) + .content(outputStream.toByteArray()) + .build(); + + keyStoreDAO.updateKeyStore(KeyStoreMgtUtil.getTenantUUID(tenantId), updatedKeyStoreModel); // TODO: is it correct to use new Date() here? The value stored in DB might be different. updateKeyStoreCache(name, new KeyStoreBean(keyStore, new Date())); @@ -500,7 +516,8 @@ private boolean isCachedKeyStoreValid(String keyStoreName) { boolean cachedKeyStoreValid = false; try { if (loadedKeyStores.containsKey(keyStoreName)) { - Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(keyStoreName); + Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore( + KeyStoreMgtUtil.getTenantUUID(tenantId), keyStoreName); if (optionalKeyStoreModel.isPresent()) { KeyStoreModel keyStoreModel = optionalKeyStoreModel.get(); KeyStoreBean keyStoreBean = loadedKeyStores.get(keyStoreName); @@ -509,7 +526,7 @@ private boolean isCachedKeyStoreValid(String keyStoreName) { } } } - } catch (SecurityConfigException e) { + } catch (KeyStoreManagementException e) { String errorMsg = "Error reading key store meta data from Database."; log.error(errorMsg, e); throw new SecurityException(errorMsg, e); diff --git a/parent/pom.xml b/parent/pom.xml index 8d006fc0ae5..b481a41b4f2 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -606,6 +606,10 @@ 9.0.65.wso2v1 + + 1.0.0 + [1.0.0,2.0.0) + 1.5.10 1.0M9 @@ -1705,6 +1709,12 @@ zip + + + org.wso2.carbon.security.mgt + org.wso2.carbon.security.mgt + ${carbon.security.mgt.version} +