Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dao implementation for keystores #3654

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/org.wso2.carbon.core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
<groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.utils</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.security.mgt</groupId>
<artifactId>org.wso2.carbon.security.mgt</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.crypto</groupId>
<artifactId>org.wso2.carbon.crypto.api</artifactId>
Expand Down Expand Up @@ -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
</Import-Package>
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -27,6 +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.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;

Expand All @@ -37,6 +42,7 @@
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
Expand All @@ -54,6 +60,8 @@ public class KeyStoreManager {
private static Log log = LogFactory.getLog(KeyStoreManager.class);

private Registry registry = null;
private KeyStoreDAO keyStoreDAO = null;

private ConcurrentHashMap<String, KeyStoreBean> loadedKeyStores = null;
private int tenantId = MultitenantConstants.SUPER_TENANT_ID;

Expand All @@ -76,6 +84,7 @@ private KeyStoreManager(int tenantId, ServerConfigurationService serverConfigSer
this.tenantId = tenantId;
try {
registry = registryService.getGovernanceSystemRegistry(tenantId);
keyStoreDAO = new KeyStoreDAOImpl();
} catch (RegistryException e) {
String message = "Error when retrieving the system governance registry";
log.error(message, e);
Expand Down Expand Up @@ -134,19 +143,21 @@ 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<KeyStoreModel> 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 = resource
.getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD);
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());
KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, resource.getLastModified());
resource.discard();
keyStore.load(stream, password);

KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, keyStoreModel.getLastUpdated());

if (loadedKeyStores.containsKey(keyStoreName)) {
loadedKeyStores.replace(keyStoreName, keyStoreBean);
Expand All @@ -172,37 +183,36 @@ 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<KeyStoreModel> optionalKeyStoreModel = keyStoreDAO.getKeyStore(
KeyStoreMgtUtil.getTenantUUID(tenantId), 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 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());
} 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());
return keyStore.getKey(alias, privateKeyPasswd);
}
byte[] bytes = keyStoreModel.getContent();
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);

KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, keyStoreModel.getLastUpdated());
updateKeyStoreCache(keyStoreName, keyStoreBean);
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 : " +
Expand All @@ -217,6 +227,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
Expand All @@ -230,20 +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 {

String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName;
if (registry.resourceExists(path)) {
org.wso2.carbon.registry.api.Resource resource = registry.get(path);
Optional<KeyStoreModel> optionalKeyStoreModel = keyStoreDAO.getKeyStore(
KeyStoreMgtUtil.getTenantUUID(tenantId), keyStoreName);
if (optionalKeyStoreModel.isPresent()) {
KeyStoreModel keyStoreModel = optionalKeyStoreModel.get();
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
String encryptedPassword = resource
.getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD);
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.");
}
Expand Down Expand Up @@ -281,24 +294,37 @@ 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();

resource.setContent(outputStream.toByteArray());

registry.put(path, resource);
resource.discard();
updateKeyStoreCache(name, new KeyStoreBean(keyStore, new Date()));
Optional<KeyStoreModel> optionalKeyStoreModel = keyStoreDAO.getKeyStore(
KeyStoreMgtUtil.getTenantUUID(tenantId), name);
if (optionalKeyStoreModel.isPresent()) {
KeyStoreModel keyStoreModel = optionalKeyStoreModel.get();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
char[] encryptedPassword = keyStoreModel.getPassword();
char[] password = new String(cryptoUtil.base64DecodeAndDecrypt(
String.valueOf(encryptedPassword))).toCharArray();
keyStore.store(outputStream, password);
outputStream.flush();
outputStream.close();

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()));
} else {
throw new SecurityException("Key Store with a name : " + name + " does not exist.");
}
}

/**
Expand Down Expand Up @@ -487,18 +513,21 @@ 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<KeyStoreModel> optionalKeyStoreModel = keyStoreDAO.getKeyStore(
KeyStoreMgtUtil.getTenantUUID(tenantId), 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 (KeyStoreManagementException e) {
String errorMsg = "Error reading key store meta data from Database.";
log.error(errorMsg, e);
throw new SecurityException(errorMsg, e);
}
Expand Down
10 changes: 10 additions & 0 deletions parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,10 @@

<jdbc-pool.version>9.0.65.wso2v1</jdbc-pool.version>

<!-- Carbon Security Management -->
<carbon.security.mgt.version>1.0.0</carbon.security.mgt.version>
<carbon.security.mgt.imp.version.range>[1.0.0,2.0.0)</carbon.security.mgt.imp.version.range>

<!-- Test integration -->
<slf4j.version>1.5.10</slf4j.version>
<woden.api.version>1.0M9</woden.api.version>
Expand Down Expand Up @@ -1705,6 +1709,12 @@
<type>zip</type>
</dependency>

<!--Other Dependencies-->
<dependency>
<groupId>org.wso2.carbon.security.mgt</groupId>
<artifactId>org.wso2.carbon.security.mgt</artifactId>
<version>${carbon.security.mgt.version}</version>
</dependency>

<!-- Test integration dependencies -->
<dependency>
Expand Down