/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.workflow.impl.dao;
import org.wso2.carbon.core.util.CryptoException;
import org.wso2.carbon.core.util.CryptoUtil;
import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
import org.wso2.carbon.identity.workflow.impl.WFImplConstant;
import org.wso2.carbon.identity.workflow.impl.WorkflowImplException;
import org.wso2.carbon.identity.workflow.impl.bean.BPSProfile;
import org.wso2.carbon.identity.workflow.mgt.util.SQLConstants;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BPSProfileDAO {
/**
* Add a new BPS profile
*
* @param bpsProfileDTO Details of profile to add
* @param tenantId ID of tenant domain
* @throws WorkflowImplException
*/
public void addProfile(BPSProfile bpsProfileDTO, int tenantId)
throws WorkflowImplException {
Connection connection = IdentityDatabaseUtil.getDBConnection();
PreparedStatement prepStmt = null;
String query = SQLConstants.ADD_BPS_PROFILE_QUERY;
String profileName = bpsProfileDTO.getProfileName();
String encryptedPassword;
try {
encryptedPassword = encryptPassword(bpsProfileDTO.getPassword());
} catch (CryptoException e) {
throw new WorkflowImplException("Error while encrypting the passwords of BPS Profile: " + profileName, e);
}
try {
prepStmt = connection.prepareStatement(query);
prepStmt.setString(1, bpsProfileDTO.getProfileName());
prepStmt.setString(2, bpsProfileDTO.getManagerHostURL());
prepStmt.setString(3, bpsProfileDTO.getWorkerHostURL());
prepStmt.setString(4, bpsProfileDTO.getUsername());
prepStmt.setString(5, encryptedPassword);
prepStmt.setInt(6, tenantId);
prepStmt.executeUpdate();
connection.commit();
} catch (SQLException e) {
throw new WorkflowImplException("Error when executing the sql query", e);
} finally {
IdentityDatabaseUtil.closeAllConnections(connection, null, prepStmt);
}
}
/**
* Update existing BPS Profile
*
* @param bpsProfile BPS profile object with new details
* @param tenantId ID of tenant domain
* @throws WorkflowImplException
*/
public void updateProfile(BPSProfile bpsProfile, int tenantId)
throws WorkflowImplException {
Connection connection = IdentityDatabaseUtil.getDBConnection();
PreparedStatement prepStmt = null;
String query = SQLConstants.UPDATE_BPS_PROFILE_QUERY;
String profileName = bpsProfile.getProfileName();
String encryptedPassword;
try {
encryptedPassword = encryptPassword(bpsProfile.getPassword());
} catch (CryptoException e) {
throw new WorkflowImplException("Error while encrypting the passwords of BPS Profile: " + profileName, e);
}
try {
prepStmt = connection.prepareStatement(query);
prepStmt.setString(1, bpsProfile.getManagerHostURL());
prepStmt.setString(2, bpsProfile.getWorkerHostURL());
prepStmt.setString(3, bpsProfile.getUsername());
prepStmt.setString(4, encryptedPassword);
prepStmt.setInt(5, tenantId);
prepStmt.setString(6, bpsProfile.getProfileName());
prepStmt.executeUpdate();
connection.commit();
} catch (SQLException e) {
throw new WorkflowImplException("Error when executing the sql query", e);
} finally {
IdentityDatabaseUtil.closeAllConnections(connection, null, prepStmt);
}
}
/**
* Retrieve details of a BPS profile
*
* @param profileName Name of profile to retrieve
* @param tenantId Id of tenant domain
* @param isWithPasswords Whether password to be retrieved or not
* @return
* @throws WorkflowImplException
*/
public BPSProfile getBPSProfile(String profileName, int tenantId, boolean isWithPasswords) throws
WorkflowImplException {
BPSProfile bpsProfileDTO = null;
Connection connection = IdentityDatabaseUtil.getDBConnection();
PreparedStatement prepStmt = null;
ResultSet rs;
String query = SQLConstants.GET_BPS_PROFILE_FOR_TENANT_QUERY;
try {
prepStmt = connection.prepareStatement(query);
prepStmt.setString(1, profileName);
prepStmt.setInt(2, tenantId);
rs = prepStmt.executeQuery();
if (rs.next()) {
String managerHostName = rs.getString(SQLConstants.HOST_URL_MANAGER_COLUMN);
String workerHostName = rs.getString(SQLConstants.HOST_URL_WORKER_COLUMN);
String user = rs.getString(SQLConstants.USERNAME_COLUMN);
bpsProfileDTO = new BPSProfile();
bpsProfileDTO.setProfileName(profileName);
bpsProfileDTO.setManagerHostURL(managerHostName);
bpsProfileDTO.setWorkerHostURL(workerHostName);
bpsProfileDTO.setUsername(user);
if (isWithPasswords) {
String password = rs.getString(SQLConstants.PASSWORD_COLUMN);
try {
bpsProfileDTO.setPassword(decryptPassword(password));
} catch (CryptoException | UnsupportedEncodingException e) {
throw new WorkflowImplException("Error while decrypting the password for BPEL Profile "
+ profileName, e);
}
}
}
} catch (SQLException e) {
throw new WorkflowImplException("Error when executing the sql.", e);
} finally {
IdentityDatabaseUtil.closeAllConnections(connection, null, prepStmt);
}
return bpsProfileDTO;
}
/**
* Retrieve list of existing BPS profiles
*
* @param tenantId Id of tenant domain to retrieve BPS profiles
* @return
* @throws WorkflowImplException
*/
public List<BPSProfile> listBPSProfiles(int tenantId) throws WorkflowImplException {
Connection connection = IdentityDatabaseUtil.getDBConnection();
PreparedStatement prepStmt = null;
ResultSet rs;
List<BPSProfile> profiles = new ArrayList<>();
String query = SQLConstants.LIST_BPS_PROFILES_QUERY;
String decryptPassword;
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
try {
Object classCheckResult = null;
//Checks if IS has BPS features installed with it
try {
classCheckResult = Class.forName("org.wso2.carbon.humantask.deployer.HumanTaskDeployer");
} catch (ClassNotFoundException e) {
//The purpose of this code segment is to check if BPS features have been installed by trying to load
// 'HumanTaskDeployer'.If BPS features are not installed, it will throw a ClassNotFoundException. The
// object retrieved here will be checked for null it will kept null when following this path. So no
// need to do anything here.
}
prepStmt = connection.prepareStatement(query);
prepStmt.setInt(1, tenantId);
rs = prepStmt.executeQuery();
while (rs.next()) {
String name = rs.getString(SQLConstants.PROFILE_NAME_COLUMN);
if (classCheckResult == null && name.equals("embeded_bps")) {
continue;
}
String managerHostName = rs.getString(SQLConstants.HOST_URL_MANAGER_COLUMN);
String workerHostName = rs.getString(SQLConstants.HOST_URL_WORKER_COLUMN);
String user = rs.getString(SQLConstants.USERNAME_COLUMN);
String password = rs.getString(SQLConstants.PASSWORD_COLUMN);
try {
byte[] decryptedPasswordBytes = cryptoUtil.base64DecodeAndDecrypt(password);
decryptPassword = new String(decryptedPasswordBytes, WFImplConstant.DEFAULT_CHARSET);
} catch (CryptoException | UnsupportedEncodingException e) {
throw new WorkflowImplException("Error while decrypting the password for BPEL Profile " +
name, e);
}
BPSProfile profileBean = new BPSProfile();
profileBean.setManagerHostURL(managerHostName);
profileBean.setWorkerHostURL(workerHostName);
profileBean.setProfileName(name);
profileBean.setUsername(user);
profileBean.setPassword(decryptPassword.toCharArray());
profiles.add(profileBean);
}
} catch (SQLException e) {
throw new WorkflowImplException("Error when executing the sql.", e);
} finally {
IdentityDatabaseUtil.closeAllConnections(connection, null, prepStmt);
}
return profiles;
}
/**
* Delete a BPS profile
*
* @param profileName Name of the profile to retrieve
* @throws WorkflowImplException
*/
public void removeBPSProfile(String profileName) throws WorkflowImplException {
Connection connection = IdentityDatabaseUtil.getDBConnection();
PreparedStatement prepStmt = null;
String query = SQLConstants.DELETE_BPS_PROFILES_QUERY;
try {
prepStmt = connection.prepareStatement(query);
prepStmt.setString(1, profileName);
prepStmt.executeUpdate();
connection.commit();
} catch (SQLException e) {
throw new WorkflowImplException("Error when executing the sql.", e);
} finally {
IdentityDatabaseUtil.closeAllConnections(connection, null, prepStmt);
}
}
private String encryptPassword(char[] passwordValue) throws CryptoException {
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
return cryptoUtil.encryptAndBase64Encode(toBytes(passwordValue));
}
private char[] decryptPassword(String passwordValue) throws UnsupportedEncodingException, CryptoException {
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
byte[] decryptedPasswordBytes = cryptoUtil.base64DecodeAndDecrypt(passwordValue);
return (new String(decryptedPasswordBytes, WFImplConstant.DEFAULT_CHARSET)).toCharArray();
}
/**
* Convert a char array into a byte array
*
* @param chars
* @return
*/
private byte[] toBytes(char[] chars) {
CharBuffer charBuffer = CharBuffer.wrap(chars);
ByteBuffer byteBuffer = Charset.forName(WFImplConstant.DEFAULT_CHARSET).encode(charBuffer);
byte[] bytes = Arrays.copyOfRange(byteBuffer.array(),
byteBuffer.position(), byteBuffer.limit());
Arrays.fill(charBuffer.array(), '\u0000');
Arrays.fill(byteBuffer.array(), (byte) 0);
return bytes;
}
}