Thursday, January 30, 2014

Secure custom properties file using secure vault.






The WSO2 secure vault is an implementation of synapse secure vault (modified version), it  is used to secure plain text password which is contains in configuration  files of WSO2 products.  Please go through the below link to get more information[1].

[1]http://docs.wso2.org/display/Carbon420/WSO2+Carbon+Secure+Vault

Here I'm going to show you, how can we secure the password in configuration property  file. This is very useful when we write custom extensions for WSO2 products.

Lets assume that our new custom module has flowing properties  file(myconf-test.properties) and need to secure the plain text password using the WSO2 secure vault.

myconf.module.serverUrl=http://localhost:9443/servies
myconf.module.remote=true
myconf.module.username=admin
myconf.module.password=admin

1.) Create file myconf-test.properties inside the [product_home]/repository/conf/ and add the above content.

2) If you haven't done before,  run the following command at least one time inside the
[product_home]/bin to generate the secret-conf.properties file with default values,  at the sametime cipher-text.properties and other WSO2 config files(according to the default settings in cipher-tool.properties)  also will be updated.  If you have already execute this command you can directly start with step 2.
sh ciphertool.sh -Dconfigure
i). Now you have to provide the answers for the following questions ?
[Please Enter Primary KeyStore Password of Carbon Server : ]

Answer: wso2carbon

ii) If you check the secret-conf.properties, you should see that file has updated with following settings.
   Note:~ Content of the file will be changed depending on the product.


keystore.identity.location=/home/ajith/wso2/product/wso2greg-4.6.0/repository/resources/security/wso2carbon.jks
keystore.identity.type=JKS
keystore.identity.store.password=identity.store.password
keystore.identity.store.secretProvider=org.wso2.carbon.securevault.DefaultSecretCallbackHandler
secretRepositories.file.provider=org.wso2.securevault.secret.repository.FileBaseSecretRepositoryProvider
secretRepositories.file.location=repository/conf/security/cipher-text.properties
secretRepositories=file
keystore.identity.key.password=identity.key.password
carbon.secretProvider=org.wso2.securevault.secret.handler.SecretManagerSecretCallbackHandler
keystore.identity.key.secretProvider=org.wso2.carbon.securevault.DefaultSecretCallbackHandler
keystore.identity.alias=wso2carbon


2.) Go to the [product_home]/bin and execute the following command to generate the encrypted value for the clear text  password.


sh ciphertool.sh 

i) It will prompt following  console for input value.  Answer: wso2carbon


[Please Enter Primary KeyStore Password of Carbon Server : ]

ii)Then it will appear second console for  following input value.
     (Answer: According to our property file, the plain text password is "admin".)

[Enter Plain text value :]
[Please Enter value Again :]

iii) Now you should see the following output on the console.

Encryption is done Successfully


Encrypted value is : 
MpfXhKP+iJSImA/KNa+DoOXCPQAyF3JLhlFNAdG6F3naWK+N1/WEWOJkFx4kK34i1VtkywNN9SiC
MRQGTFw+nqzK5/INgcFFdoxv49lM/FJw8CyXKQ0JWdxw5QJPtrjJzvGp6Rj6xt4ysb6HdG5uNG+a
1E0lqdmzGUYQ6oejIlk=

3). Open the cipher-text.properties file, which is under [product_home]/repository/conf/security and add the following entry.

myconf.module.password=MpfXhKP+iJSImA/KNa+DoOXCPQAyF3JLhlFNAdG6F3naWK+N1/WEWOJkFx4kK34i1VtkywNN9SiC
MRQGTFw+nqzK5/INgcFFdoxv49lM/FJw8CyXKQ0JWdxw5QJPtrjJzvGp6Rj6xt4ysb6HdG5uNG+a
1E0lqdmzGUYQ6oejIlk=

4). Open the myconf-test.properties file and update the key/value of password field.

myconf.module.serverUrl=http://localhost:9443/servies
myconf.module.remote=true
myconf.module.username=admin
myconf.module.password=secretAlias:myconf.module.password

5). You can use the following Java class to resolve the the password at your custom extension code.

(  Note: If you open from IDE , please point the [product_home]/repository/components/plugins
             to class path.)

ModuleProperties.java

/*
*  Copyright (c) 2005-2010, 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.sampl.rxt.populator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.governance.generic.stub.beans.xsd.ContentArtifactsBean;
import org.wso2.carbon.governance.generic.ui.clients.ManageGenericArtifactServiceClient;
import org.wso2.carbon.governance.generic.ui.utils.DropDownDataPopulator;

import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;

public class WSDLPopulator implements DropDownDataPopulator {

    private static final Log log = LogFactory.getLog(WSDLPopulator.class);
    String[] out = new String[1];

    @Override
    public String[] getList(HttpServletRequest httpServletRequest, ServletConfig servletConfig) {

        try {
            ManageGenericArtifactServiceClient client =
                    new ManageGenericArtifactServiceClient(servletConfig, httpServletRequest.getSession());

            ContentArtifactsBean artifactsBean = client.listContentArtifacts("application/wsdl+xml");
            if (artifactsBean.getName() != null && artifactsBean.getName().length > 0) {
                return artifactsBean.getName();
            } else {
                out[0] = "None";
            }

        } catch (Exception e) {
            log.error("An error occurred while obtaining the WSDL list", e);
        }
        return out;
    }
}

6). You can checkout the complete sample from the following SVN location[1].

 [i].Open the build.xml and change the value of the "product.home" property to your  product home directory.

Execute the ant command inside the project home (SecureVaultSample) to build the jar file.

[i]https://svn.wso2.org/repos/wso2/people/ajith/blog/SecureVaultSample/

7). Put the jar file which is under target to [product_home]/repository/components/lib.

8). Start the server . (sh wso2server.sh)

9).  When starting the server, it will prompt the following command input to enter the key store password. The answer is "wso2carbon". Then  server will start successfully.


[Enter KeyStore and Private Key Password :]

10). If you planing to  start the server as  background process , then you need to do the following steps before start the server.

i. Create a file named "password-tmp.txt" in <PRODUCT_HOME>/ directory. Add "wso2carbon" (the primary keystore password) to this file and save. By default, the password provider assumes that both private key and keystore passwords are the same. If not, the private key password must be entered in the second line of the file.

ii. Keystore password will be picked up from the "password-tmp.txt" file. Once the server starts, this file is automatically deleted from the file system. Make sure to add this temporary file back whenever you start the sever as a background process. If you name of the password file "password-persist.txt" instead of "password-tmp.txt", then the file will not be deleted after the server starts. Therefore, it will not be required to provide the password in subsequent startups.

11. Finally, if you initialize the ModuleProperties class in your custom extension code (new ModuleProperties() ) you should be able to get the resolved password from that Object.

The summary of the process showing in following diagram.