<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
  ~  Copyright (c) 2009, 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.
  -->

<!DOCTYPE html
     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
    <title>
        WSO2 ESB - Securing Confidential Information
    </title>
    <link href="css/esb-docs.css" rel="stylesheet" />
    <link href="styles/dist-docs.css" rel="stylesheet" type="text/css" media="all" />
  </head>

<body>
    [ <a href="docs_index.html"> Documentation Index </a> ]
<h1>WSO2 Enterprise Service Bus (ESB), Securing Confidential Information</h1>

<p>
    This guide describes how confidential information can be handled in a
    secured manner in the ESB environment. From the context of the ESB
    confidential information refers mainly to passwords. But confidential
    information could be anything and hence instructions given in this guide
    applies to all such confidential information elements.
</p>

<h2>Secret Providers</h2>

<p>The word 'secret' is used to refer to anything  which needs to be kept as a
secret. Eventhough the current usage is limited to passwords, API supports any type of data. Secret
retrieving is done through 'SecretCallbackHandler' implementations.
Currently there are a few implementations and more implementations can be added as needed.</p>
<ul>
  <li><strong>JBossEncryptionSecretCallbackHandler</strong></li>
</ul>

<p>This is the default implementation used within the JBoss Application Server to secure
database passwords. It uses a hardcoded pass phrase (Need to use same pass phrase
that have been used for encryption). Admin can encrypt passwords using a pass phrase
and hard code that in the 'JBossEncryptionSecretCallbackHandler'
and make the source code closed.</p>
<ul>
  <li><strong>JlineSecretCallbackHandler</strong></li>
</ul>

<p>This is a command line based approach. Jline provides a way of reading passwords
without echoing text - similar to jdk 6 scanners.</p>
<ul>
  <li><strong>JMXSecretCallbackHandler</strong></li>
</ul>

<p>This is only supported in Synapse. With this we must use a JMX Console to provide
secrets. This may be useful for any users that manage servers in a production
environment using JMX.</p>
<ul>
  <li><strong>HardCodedSecretCallbackHandler</strong></li>
</ul>

<p>Admin needs to hard code password and make source code closed. This can be used
to just provide keystore passwords and other secrets can be retrieved using
'SecretManagerSecretCallbackHandler' (described next)</p>
<ul>
  <li><strong>SecretManagerSecretCallbackHandler</strong></li>
</ul>

<p>All secrets are managed using the Secret Manager. Secret Manager can keep
any number of secret repositories. Those are arranged in a cascading manner. All
secrets are stored in one place - secret repositories. Secrets can be accessed by
providing aliases for them (no need to put encrypted values inline in
application configurations). Key stores required by the Secret Manager and secret
repositories are configurable. It can be done through the
'secret-conf.properties'. Currently, there is only one secret
repository and it is called the FileBaseSecretRepository. It uses cipher-text.properties
to keep secrets. It keeps aliases vs. its actual secret in encrypted format
(encrypted by a key in keystore)</p>

<p><strong>Example</strong></p>

<p><strong>secret-conf.properties</strong></p>
<pre>############################################################################
# Secret Securing Configuration
############################################################################
# The following property specifies a global password provider implementation
# which will be used globally if not overriden in specific configurations
#carbon.secretProvider=&lt;any implementation of org.apache.synapse.commons.security.secret.SecretCallbackHandler&gt;
#Examples:
#carbon.secretProvider=org.apache.synapse.commons.security.secret.handler.SecretManagerSecretCallbackHandler
#carbon.secretProvider=org.apache.synapse.commons.security.secret.handler.JMXSecretCallbackHandler
#carbon.secretProvider=org.apache.synapse.commons.security.secret.handler.JlineSecretCallbackHandler
#carbon.secretProvider=org.apache.synapse.commons.security.secret.handler.JBossEncryptionSecretCallbackHandler

#Secret Repositories configuration

secretRepositories=file
secretRepositories.file.provider=org.apache.synapse.commons.security.secret.repository.filebased.FileBaseSecretRepositoryProvider
secretRepositories.file.location=cipher-text.properties

#KeyStores configurations

keystore.identity.location=resources/security/wso2carbon.jks
keystore.identity.type=JKS
keystore.identity.alias=wso2carbon
keystore.identity.store.password=wso2carbon
#keystore.identity.store.secretProvider=&lt;any implementation of org.apache.synapse.commons.security.secret.SecretCallbackHandler&gt;
keystore.identity.key.password=wso2carbon
#keystore.identity.key.secretProvider=&lt;any implementation of org.apache.synapse.commons.security.secret.SecretCallbackHandler&gt;
#keystore.identity.parameters=enableHostnameVerifier=false;keyStoreCertificateFilePath=/home/esb.cer

keystore.trust.location=resources/security/client-truststore.jks
keystore.trust.type=JKS
keystore.trust.alias=wso2carbon
keystore.trust.store.password=wso2carbon
#keystore.trust.store.secretProvider=&lt;any implementation of org.apache.synapse.commons.security.secret.SecretCallbackHandler&gt;
</pre>

<p><strong>cipher-text.properties</strong></p>

<pre>aliases=esb

# configuration  per each plaintext
esb.secret=M6U74dMVvRm4XFMczki2qZ6CsTvnUuRTjSditlACR5vTISSMI7F/mCTVJGOGdKJjij+VWVhBtmAOkElyvR9TwlUECnZ1o5DNsTK6l8je+9amc/ziTQLP3Q1tzm/Ex1pzHsG6jPGGrv3O0B9pZTfYFqRvlcNhM7Ve3WvA3ibs4Yk=
esb.secret.alias=wso2carbon
esb.secret.keystore=identity</pre>

<p>For security operations (encrypt / decrypt), Secret Manager uses a KeyStore
and securing the keystore passwords can be done by any of above mentioned ways.
In the current implementation, there is only a one Secret Repository - A file
based Secret Repository. It is possible to implements secret repositories based
on database, directory servers, registry etc.</p>

<h2>General API for Retrieving Secrets</h2>

<p>Consider that an application has a configuration for passwords as</p>

<pre>  &lt;datasource&gt;
      &lt;password&gt;pass&lt;/password&gt;
      &lt;secretProvider&gt;any implementation of SecretCallbackHandler- class name&lt;/secretProvider&gt;
  &lt;/datasource&gt; </pre>

<p>For JBossEncryptionSecretCallbackHandler, 'password' should
contain an encrypted value. In any other case, it is just an alias- can keep
any human readable text. For example in Secret Manger, actual password is in
secret repositories. For file based repository, it is something like bellow.</p>
<pre>  
  aliases=pass
  pass.secret=EsY65tztE9R5b9pErVxLp8Br5d3ol6vRdWAkYHdc7XkZteGf37VJ+iNlCenqxYSEto0vcjpcmmzwf7K2wd9u3KQtVGKEoNLSe2LYZtrm3tKmGd6PX9YpdN72ml3JISNXPJ69yybFi6DVUIJfE5MFOd7gswWfCnkmZ3eJ6M1nuiI=</pre>

<p>To retrieve secret, it is needed to use following API and follow steps.</p>

<h3>Retrieving API</h3>

<p>Read the configuration parameter value of 'secret Provider' -
say 'secretProvider'</p>
<pre>// Create SecretCallbackHandler
 SecretCallbackHandler secretCallbackHanlder SecretCallbackHandlerFactory.createSecretCallbackHandler(secretProvider);

// Setup SecretLoadingModule with 
CallbackHandlersSecretLoadingModule secretLoadingModule = new SecretLoadingModule();
secretLoadingModule.init(new SecretCallbackHandler[]{secretCallbackHanlder});

// Create SecretCallbacks
SingleSecretCallback secretCallback = new SingleSecretCallback(aliases); // for above example 'aliases' is 'pass'

secretLoadingModule.load(new SecretCallback[]{secretCallback});

String actualPassword= secretCallback.getSecret();</pre>

<p>If you want to load multiple secrets at once you can use
'MultiSecretCallback'; or array of SingleSecretCallback s.</p>

<p>There is a simple way to avoid code duplication.</p>

<pre>SecretInformation secretInformation = SecretInformationFactory.createSecretInformation(secretProvider, aliasPassword, passwordPrompt);

String actualPassword = secretInformation.getResolvedSecret();</pre>

<h2>Adapting in OSGI Environment</h2>

<p>All 'SecretCallbackHandlers' other than the
'SecretManagerSecretCallbackHandler' are stateless enabling to be used
without any additional code. With 'SecretManagerSecretCallbackHandler',
it is best if there is only one 'SecretManager' instance. More
precisely, a single 'SecretManagerSecretCallbackHandler' instance.
For this, there is a carbon module called 'secretvault'. It just reads
'secret-conf.properties' and initiates a new
'SecretCallbackHandler' instance. This can be a
'SecretManagerSecretCallbackHandler' or any other
'SecretCallbackHandlers' instance that needs to be shared
globally. To acccess this instance one must follow the instuctions
given below.</p>

<p><strong>Step 1 - Adding Dependencies </strong></p>

<pre>&lt;dependency&gt;
    &lt;groupId&gt;org.apache.synapse&lt;/groupId&gt;
    &lt;artifactId&gt;synapse-commons&lt;/artifactId&gt;
    &lt;version&gt;1.10.0-SNAPSHOT&lt;/version&gt;
&lt;/dependency&gt; 

&lt;dependency&gt;
     &lt;groupId&gt;org.wso2.carbon&lt;/groupId&gt;
     &lt;artifactId&gt;org.wso2.carbon.securevault&lt;/artifactId&gt;
     &lt;version&gt;${carbon.version}&lt;/version&gt;
&lt;/dependency&gt;</pre>

<p><strong>Setp 2 - Listening to SecretCallbackHandlerService</strong></p>

<pre>
/** @scr.reference name="secret.callback.handler.service"
* interface="org.wso2.carbon.securevault.SecretCallbackHandlerService"
* cardinality="1..1" policy="dynamic"
* bind="setSecretCallbackHandlerService" unbind="unsetSecretCallbackHandlerService
*/

protected void setSecretCallbackHandlerService( SecretCallbackHandlerService secretCallbackHandlerService) {
            Logic on Set
}

protected void unsetSecretCallbackHandlerService(SecretCallbackHandlerService secretCallbackHandlerService) {
           Logic on Unset
}</pre>

<p>
The annotations at the top are required and the Maven SCR plugin must be used to build the code. Please refer
Maven 2 documentation on how to use the Maven SCR plugin. SCR plugin generates OSGi declarative service
descriptors by parsing the scr annotations stated in the source files.
</p>

<p><strong>Logic on Set </strong></p>

<p>If the secret that needs to be resolved can be accessed directlym, for example
passing as an argument, you can use the following logic.</p>

<pre>  SecretCallbackHandler secretProvider = secretCallbackHandlerService.getSecretCallbackHandler());
  SecretInformation secretInformation = SecretInformationFactory.createSecretInformation(secretProvider, aliasPassword, passwordPrompt);
  String actualPassword = secretInformation.getResolvedSecret();</pre>

<p>Now you can pass either an actual password or a SecretProvider or
SecretInformation to the code location that uses the password. But if the code that
performs secret resolution can not be accessed, for example, when using a configuration
such as follows - you cannot pass resolved password directly.</p>

<pre>  &lt;datasource&gt;
      &lt;password&gt;pass&lt;/password&gt;
      &lt;secretProvider&gt;any implementation of SecretCallbackHandler- class name&lt;/secretProvider&gt;
  &lt;/datasource&gt;</pre>

<p>You have to do following if the scenario is similar to the above.</p>

<pre>  if (secretCallbackHandlerService != null) {
      SecretCallbackHandler secretCallbackHandler = secretCallbackHandlerService.getSecretCallbackHandler();
      SharedSecretCallbackHandlerCache.getInstance().setSecretCallbackHandler(secretCallbackHandler);
  }</pre>
<p>Then you have to specify <strong>secretProvider</strong> in the configuration
as
<strong>org.apache.synapse.commons.security.secret.handler.SharedSecretCallbackHandler</strong>.
This is another <strong>SecretCallbackHandler</strong> that uses the handler
set in the <strong>SharedSecretCallbackHandlerCache</strong>. You need to
use <strong>Retrieving API</strong>. What we do here is using OSGI services in order
to share across any component and use the Singleton pattern to share across classes in a
single component and enable using the <strong>Retrieving API</strong> as it is.</p>

<h2>Ciphertool </h2>

<p>This is a simple tool to encrypt and decrypt simple texts.There are scripts
named ciphertool.sh &amp; ciphertool.bat available in the bin directory to launch the tool. The arguments
accepted by this tool with their meanings are shown bellow. </p>
<ul>
  <li>keystore - If keys are in a store , its location </li>
  <li>storepass - Password to access keyStore </li>
  <li>keypass - To get private key </li>
  <li>alias - Alias to identify key owner </li>
  <li>storetype - Type of keyStore, Default is JKS </li>
  <li>keyfile - If key is in a file </li>
  <li>opmode - encrypt or decrypt , Default is encrypt </li>
  <li>algorithm - encrypt or decrypt algorithm , Default is RSA </li>
  <li>source - Either cipher or plain text as an in-lined form </li>
  <li>outencode - Currently base64 and used for encoding the result</li>
  <li>inencode - Currently base64 and used to decode input </li>
  <li>trusted - Is KeyStore a trusted store? If this argument is provided, consider as a
    trusted store </li>
  <li>passphrase - if a simple symmetric encryption using a pass phrase shall
    be used </li>
</ul>

<p>An example </p>

<pre>ciphertool.bat -source testpass -keystore resources/security/client-truststore.jks -storepass wso2carbon -alias wo2carbon -outencode base64 -trusted</pre>
</body>
</html>
