├── .gitignore ├── INSTALL.md ├── LICENSE ├── README.md ├── Using_Crypt.md ├── bin ├── vault.bat └── vault.sh ├── examples ├── README.md ├── valve │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── org │ │ └── tomcat │ │ └── example │ │ └── MyValve.java └── webapp │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── org │ │ └── tomcat │ │ └── example │ │ ├── MyFilter.java │ │ └── MyServlet.java │ └── webapp │ ├── META-INF │ └── context.xml │ ├── WEB-INF │ └── web.xml │ └── resources │ └── examples.properties ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── apache │ │ └── tomcat │ │ └── vault │ │ ├── VaultInteraction.java │ │ ├── VaultInteractiveSession.java │ │ ├── VaultSession.java │ │ ├── VaultTool.java │ │ ├── security │ │ ├── Base64Utils.java │ │ ├── ExternalPasswordCache.java │ │ ├── PasswordCache.java │ │ ├── Util.java │ │ ├── plugins │ │ │ └── PBEUtils.java │ │ └── vault │ │ │ ├── PicketBoxSecurityVault.java │ │ │ ├── SecurityActions.java │ │ │ ├── SecurityVault.java │ │ │ ├── SecurityVaultData.java │ │ │ ├── SecurityVaultException.java │ │ │ └── SecurityVaultFactory.java │ │ └── util │ │ ├── EncryptionUtil.java │ │ ├── KeyStoreUtil.java │ │ ├── PropertyFileManager.java │ │ ├── PropertySourceVault.java │ │ ├── SecurityActions.java │ │ └── StringUtil.java └── resources │ └── org │ └── apache │ └── tomcat │ └── vault │ └── security │ ├── LocalStrings.properties │ ├── plugins │ └── LocalStrings.properties │ ├── resources │ └── LocalStrings.properties │ └── vault │ └── LocalStrings.properties └── test ├── java └── unit │ └── org │ └── apache │ └── tomcat │ └── vault │ ├── VaultToolTest.java │ └── util │ └── EncryptionUtilTest.java └── resources └── mockito-extensions └── org.mockito.plugins.MockMaker /.gitignore: -------------------------------------------------------------------------------- 1 | modules/system/layers/base/tomcat-vault/main/tomcat-vault.jar 2 | lib 3 | bin/tomcat-juli.jar 4 | target 5 | .idea 6 | **/*.iml 7 | vault.properties 8 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | PicketLink Vault extension for Apache Tomcat. 2 | 3 | See the LICENSE file distributed with this work for information 4 | regarding licensing. 5 | 6 | ===================================================================== 7 | 8 | Requirements: 9 | ------------- 10 | 11 | * Tomcat Vault tarball or source repository 12 | * Apache Tomcat 13 | * Apache Maven 14 | 15 | Prequisites: 16 | ------------ 17 | 18 | Configure the `CATALINA_BASE` environment variable to point to your Tomcat installation's `CATALINA_BASE`. 19 | 20 | Building and Configuring Your Vault: 21 | ------------------------------------ 22 | 23 | 1. Install Apache Tomcat (from an RPM, by hand, or however you prefer) 24 | 25 | 2. Compile Tomcat Vault from its source directory: 26 | 27 | ~~~ 28 | $ mvn package 29 | ~~~ 30 | 31 | 3. Copy the generated tomcat-vault JAR to `$CATALINA_BASE/lib/`: 32 | 33 | ~~~ 34 | $ cp lib/tomcat-vault.jar $CATALINA_BASE/lib/ 35 | ~~~ 36 | 37 | 4. Add the following line to `$CATALINA_BASE/conf/catalina.properties` so that Tomcat's Digester uses the tomcat-vault PropertySource implementation: 38 | 39 | ~~~ 40 | org.apache.tomcat.util.digester.PROPERTY_SOURCE=org.apache.tomcat.vault.util.PropertySourceVault 41 | org.apache.tomcat.util.digester.REPLACE_SYSTEM_PROPERTIES=true 42 | ~~~ 43 | 44 | 5. Setup your Vault using `./bin/vault.sh`. Here is an example creating a keystore for the Vault and initializing it in `/tmp/vault`: 45 | 46 | ~~~ 47 | # Make a directory for the Vault to live 48 | $ mkdir /tmp/vault 49 | 50 | # Create a keystore for the Vault 51 | $ keytool -genseckey -keystore /tmp/vault/vault.keystore -alias my_vault -storetype jceks -keyalg AES -keysize 128 -storepass my_password123 -keypass my_password123 -validity 730 52 | 53 | # Initialize the Vault and save vault.properties 54 | $ bin/vault.sh --keystore /tmp/vault/vault.keystore --keystore-password my_password123 --alias my_vault --enc-dir /tmp/vault/ --iteration 44 --salt 1234abcd -g $CATALINA_BASE/conf/vault.properties 55 | ~~~ 56 | 57 | **Note:** When creating a keystore with keytool the storepass and keypass argument values must match. 58 | 59 | **Note:** You can also initialize the Vault in an interactive mode by executing bin/vault.sh with no arguments. If you do this, then you will need to create a file named vault.properties in `$CATALINA_BASE/conf` containing your Vault information as below (all of these keys must be defined and **NOT** empty). This information is provided by the interactive session at the end of the initialization. 60 | 61 | ~~~ 62 | KEYSTORE_URL=.. 63 | KEYSTORE_PASSWORD=.. 64 | KEYSTORE_ALIAS=.. 65 | SALT=.. 66 | ITERATION_COUNT=.. 67 | ENC_FILE_DIR=.. 68 | ~~~ 69 | 70 | 7. Start Apache Tomcat! 71 | 72 | Using Your New Vault: 73 | --------------------- 74 | 75 | Now that the Vault has been initialized and Tomcat is loading it, you can start using the vault to store encrypted passwords in your configuration files. 76 | 77 | Before you can do this, you will need to add the attributes that you'd like to encrypt to your vault. An example of how to add a secured attribute is listed below: 78 | 79 | ~~~ 80 | # Add a secured attribute to the Vault 81 | $ bin/vault.sh --keystore /tmp/vault/vault.keystore --keystore-password my_password123 --alias my_vault --enc-dir /tmp/vault/ --iteration 120 --salt 1234abcd --vault-block my_block --attribute manager_password --sec-attr P@SSW0#D 82 | ~~~ 83 | 84 | Once the attribute has been added to the Vault, simply replace whatever property value you would like to hide in any Apache Tomcat configuration file with `${attribute_name}`. As an example, let's say that you wanted to use the password that we put into the Vault above (P@SSW0#D) as your tomcat user's password in the manager-gui role. To do that you would change the user in tomcat-users.xml from: 85 | 86 | ~~~ 87 | 88 | ~~~ 89 | 90 | to: 91 | 92 | ~~~ 93 | 94 | ~~~ 95 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vault for Apache Tomcat 2 | Tomcat-vault is a PicketLink vault extension for Apache Tomcat. It allows you to place sensitive information, such as passwords, inside of a vault instead of the Tomcat configuration files. 3 | 4 | # Installation 5 | See the [INSTALL](./INSTALL.md) file for instructions on installation and usage. 6 | 7 | # How it works 8 | At start up, the Tomcat digester module parses configuration files and references the vault keystore when a ${parameter} is found within a Tomcat configuration file. If the ${parameter} is found within the vault, then the ${parameter} is replaced with the value of the corresponding attribute. 9 | 10 | # HOW TO TEST 11 | simply run `mvn test` in the directory that contains pom.xml file 12 | 13 | # Links 14 | Tomcat System Properties : 15 | https://tomcat.apache.org/tomcat-9.0-doc/config/systemprops.html 16 | -------------------------------------------------------------------------------- /Using_Crypt.md: -------------------------------------------------------------------------------- 1 | ## Using CRYPT With the Vault 2 | 3 | A new feature was added to the Vault which allows users to utilize encrypted values in configuration files which are **not** stored in the vault. 4 | 5 | ### Installing the Vault 6 | 7 | See the [INSTALL](./INSTALL.md) file for instructions on installation and usage of the vault (minus the CRYPT feature, which is fully documented here). 8 | 9 | ### Using the CRYPT feature 10 | 11 | #### Configuring Tomcat 12 | 13 | Configure Tomcat to use your password from an encrypted or plain text string: 14 | 15 | - **Encrypted**: Add the encryption password to the vault: 16 | 17 | ~~~ 18 | $ bin/vault.sh --keystore /path/to/vault.keystore --keystore-password my_password123 --alias my_vault --enc-dir /path/to/vault/encryption_dir/ --iteration 120 --salt 1234abcd --vault-block my_block --attribute my_encryption_password --sec-attr MyEncryptionPassword 19 | ~~~ 20 | 21 | then, put the VAULT reference in your vault.properties as follows: 22 | 23 | ~~~ 24 | ENCRYPTION_PASSWORD=VAULT::my_block::my_encryption_password:: 25 | ~~~ 26 | 27 | - **Plain Text**: Add the password to conf/catalina.properties, or pass it in as a system property to java: 28 | 29 | ~~~ 30 | org.apache.tomcat.vault.util.ENCRYPTION_PASSWORD=MyEncryptionPassword 31 | ~~~ 32 | 33 | **Note: Setting ENCRYPTION_PASSWORD in vault.properties will override org.apache.tomcat.vault.util.ENCRYPTION_PASSWORD.** 34 | 35 | Now that you have a password configured, you can encrypt some value and put the resulting string in your configuration file to be decrypted on the fly: 36 | 37 | #### Encrypting Values for Use 38 | 39 | You can encrypt values one of two ways. 40 | 41 | Method 1, using a plain text encryption password: 42 | ~~~ 43 | $ bin/vault.sh --encrypt MyEncryptionPassword MyPassword 44 | ========================================================================= 45 | 46 | Tomcat Vault 47 | 48 | VAULT_HOME: /path/to/tomcat-vault/lib 49 | 50 | JAVA: java 51 | 52 | ========================================================================= 53 | 54 | Encrypted value: CRYPT::a33AiwJkF4dMx9Uq9oxElYT6LdjXLJxf 55 | ~~~ 56 | 57 | Method 2, using an encryption password which is stored in the vault: 58 | 59 | ~~~ 60 | $ bin/vault.sh --keystore /path/to/vault.keystore --keystore-password my_password123 --alias my_vault --enc-dir /path/to/vault/encryption_dir/ --encrypt VAULT::my_block::my_encryption_password:: MyPassword 61 | ========================================================================= 62 | 63 | Tomcat Vault 64 | 65 | VAULT_HOME: /path/to/tomcat-vault/lib 66 | 67 | JAVA: java 68 | 69 | ========================================================================= 70 | 71 | Dec 06, 2017 12:54:30 PM org.apache.tomcat.vault.security.vault.PicketBoxSecurityVault init 72 | INFO: Default Security Vault Implementation Initialized and Ready 73 | Encrypted value: CRYPT::z9zbQSywH7iqmNJOW/wM++TKfF13U8/e 74 | ~~~ 75 | 76 | #### Two Usage Examples 77 | 78 | Once you have the encrypted string (copied from the command output above), place that string into your configuration inside of brackets, such as ${}, so that Tomcat's Digester correctly interpolates it. 79 | 80 | An XML example would look like: 81 | 82 | ~~~ 83 | $ tail -n2 conf/tomcat-users.xml | head -n1 84 | 85 | ~~~ 86 | 87 | A properties file example would look like: 88 | 89 | ~~~ 90 | $ tail -n1 conf/catalina.properties 91 | test.property=${CRYPT::a33AiwJkF4dMx9Uq9oxElYT6LdjXLJxf} 92 | ~~~ 93 | 94 | Note that the properties file does **not** need quotations marks. 95 | -------------------------------------------------------------------------------- /bin/vault.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ------------------------------------------------------------------------- 3 | rem Vault tool script for Windows 4 | rem ------------------------------------------------------------------------- 5 | rem 6 | rem A tool for management securing sensitive strings 7 | 8 | @if not "%ECHO%" == "" echo %ECHO% 9 | @if "%OS%" == "Windows_NT" setlocal 10 | 11 | if "%OS%" == "Windows_NT" ( 12 | set "DIRNAME=%~dp0%" 13 | ) else ( 14 | set DIRNAME=.\ 15 | ) 16 | 17 | pushd "%DIRNAME%.." 18 | set "VAULT_HOME=%CD%" 19 | popd 20 | 21 | rem Setup Tomcat specific properties 22 | if "x%JAVA_HOME%" == "x" ( 23 | set JAVA=java 24 | echo JAVA_HOME is not set. Unexpected results may occur. 25 | echo Set JAVA_HOME to the directory of your local JDK to avoid this message. 26 | ) else ( 27 | set "JAVA=%JAVA_HOME%\bin\java" 28 | ) 29 | 30 | rem Find tomcat-vault.jar, or we can't continue 31 | set "VAULT_RUNJAR=%VAULT_HOME%\lib\tomcat-vault.jar" 32 | if not exist "%VAULT_RUNJAR%" ( 33 | echo Could not locate "%VAULT_RUNJAR%". 34 | echo Please check that you are in the bin directory when running this script. 35 | goto END 36 | ) 37 | 38 | rem Set classpath with Tomcat jars 39 | if "x%VAULT_CLASSPATH%" == "x" ( 40 | set "VAULT_CLASSPATH=%VAULT_RUNJAR%;%VAULT_HOME%\lib\tomcat-util.jar;%VAULT_HOME%\bin\tomcat-juli.jar" 41 | ) 42 | 43 | rem Display our environment 44 | set help=F 45 | if "%*" == "-h" set help=T 46 | if "%*" == "--help" set help=T 47 | if "%help%" == "F" ( 48 | echo ========================================================================= 49 | echo. 50 | echo Tomcat Vault Tool 51 | echo. 52 | echo VAULT_HOME: "%VAULT_HOME%" 53 | echo. 54 | echo JAVA: "%JAVA%" 55 | echo. 56 | echo JAVA_OPTS: "%JAVA_OPTS%" 57 | echo. 58 | echo ========================================================================= 59 | echo. 60 | ) 61 | 62 | "%JAVA%" %JAVA_OPTS% ^ 63 | -cp "%VAULT_CLASSPATH%" ^ 64 | org.apache.tomcat.vault.VaultTool ^ 65 | %* 66 | 67 | :END 68 | -------------------------------------------------------------------------------- /bin/vault.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | DIRNAME=`dirname "$0"` 4 | PROGNAME=`basename "$0"` 5 | GREP="grep" 6 | 7 | # Use the maximum available, or set MAX_FD != -1 to use that 8 | MAX_FD="maximum" 9 | 10 | # 11 | # Helper to complain. 12 | # 13 | warn() { 14 | echo "${PROGNAME}: $*" 15 | } 16 | 17 | # 18 | # Helper to puke. 19 | # 20 | die() { 21 | warn $* 22 | exit 1 23 | } 24 | 25 | # OS specific support (must be 'true' or 'false'). 26 | cygwin=false; 27 | darwin=false; 28 | linux=false; 29 | case "`uname`" in 30 | CYGWIN*) 31 | cygwin=true 32 | ;; 33 | 34 | Darwin*) 35 | darwin=true 36 | ;; 37 | 38 | Linux) 39 | linux=true 40 | ;; 41 | esac 42 | 43 | # For Cygwin, ensure paths are in UNIX format before anything is touched 44 | if $cygwin ; then 45 | [ -n "$VAULT_HOME" ] && 46 | VAULT_HOME=`cygpath --unix "$VAULT_HOME"` 47 | [ -n "$JAVA_HOME" ] && 48 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 49 | [ -n "$JAVAC_JAR" ] && 50 | JAVAC_JAR=`cygpath --unix "$JAVAC_JAR"` 51 | fi 52 | 53 | # Setup VAULT_HOME 54 | VAULT_HOME=`cd "$DIRNAME/.."; pwd` 55 | export VAULT_HOME 56 | 57 | # Setup the JVM 58 | if [ "x$JAVA" = "x" ]; then 59 | if [ "x$JAVA_HOME" != "x" ]; then 60 | JAVA="$JAVA_HOME/bin/java" 61 | else 62 | JAVA="java" 63 | fi 64 | fi 65 | 66 | # Setup the classpath for vault that contains the tomcat jars 67 | if [ "x$VAULT_CLASSPATH" = "x" ]; then 68 | if [ -d "$VAULT_HOME/share/java" ];then 69 | # rpm or zip install 70 | VAULT_HOME="$VAULT_HOME/share/java" 71 | VAULT_CLASSPATH="$VAULT_HOME/tomcat/tomcat-util.jar:$VAULT_HOME/../tomcat/bin/tomcat-juli.jar" 72 | elif [ -d "$VAULT_HOME/lib" ];then 73 | VAULT_CLASSPATH="$VAULT_HOME/lib/tomcat-util.jar:$VAULT_HOME/bin/tomcat-juli.jar" 74 | VAULT_HOME="$VAULT_HOME/lib" 75 | else 76 | VAULT_HOME="/usr/share/java" 77 | VAULT_CLASSPATH="/usr/share/java/tomcat/tomcat-util.jar:/usr/share/tomcat/bin/tomcat-juli.jar" 78 | fi 79 | fi 80 | 81 | ### 82 | # Setup the Tomcat Vault Tool classpath 83 | ### 84 | 85 | # For Cygwin, switch paths to Windows format before running java 86 | if $cygwin; then 87 | VAULT_HOME=`cygpath --path --windows "$VAULT_HOME"` 88 | VAULT_CLASSPATH=`cygpath --path --windows "$VAULT_CLASSPATH"` 89 | fi 90 | 91 | # Display our environment 92 | if [[ "$@" != "-h" && "$@" != "--help" ]]; then 93 | echo "=========================================================================" 94 | echo "" 95 | echo " Tomcat Vault" 96 | echo "" 97 | echo " VAULT_HOME: $VAULT_HOME" 98 | echo "" 99 | echo " JAVA: $JAVA" 100 | echo "" 101 | echo "=========================================================================" 102 | echo "" 103 | fi 104 | 105 | eval \"$JAVA\" $JAVA_OPTS \ 106 | -cp \"$VAULT_HOME/tomcat-vault.jar:$VAULT_CLASSPATH\" \ 107 | org.apache.tomcat.vault.VaultTool \ 108 | '"$@"' 109 | 110 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # just an example to use the vault with a web.xml and context.xml 2 | to use the example: 3 | 4 | build the valve and copy the jar in the ${catalina.base}/lib directory. 5 | 6 | build the webapp and copy the war in the ${catalina.base}/webapps directory. 7 | 8 | the trace output is going in the catalina.out and in the header vault.param 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/valve/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.tomcat.example 5 | demo 6 | jar 7 | 1.0-SNAPSHOT 8 | demo Maven Webapp 9 | http://maven.apache.org 10 | 11 | 9.0.96 12 | 13 | 14 | 15 | org.apache.tomcat 16 | tomcat-servlet-api 17 | ${tomcat.version} 18 | provided 19 | 20 | 21 | org.apache.tomcat 22 | tomcat-catalina 23 | ${tomcat.version} 24 | provided 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/valve/src/main/java/org/tomcat/example/MyValve.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomcat.example; 18 | 19 | import java.io.IOException; 20 | import java.io.PrintWriter; 21 | import java.util.Enumeration; 22 | import java.io.IOException; 23 | 24 | import javax.servlet.ServletException; 25 | import org.apache.catalina.valves.ValveBase; 26 | import org.apache.catalina.connector.Request; 27 | import org.apache.catalina.connector.Response; 28 | 29 | /* 30 | * RequestDumperValve valve. 31 | * Read header and dump them in catalina.out 32 | */ 33 | 34 | public class MyValve 35 | extends ValveBase { 36 | 37 | private String vaultparam = "default"; 38 | public String getVaultparam() { 39 | return vaultparam; 40 | } 41 | public void setVaultparam(String vaultparam) { 42 | this.vaultparam = vaultparam; 43 | } 44 | 45 | public void invoke(Request request, Response response) throws IOException, ServletException { 46 | System.out.println("in the valve from the context.xml in webapp: Vaultparam: " + vaultparam); 47 | getNext().invoke(request, response); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/webapp/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.tomcat.example 5 | demo 6 | war 7 | 1.0-SNAPSHOT 8 | demo Maven Webapp 9 | http://maven.apache.org 10 | 11 | 9.0.36 12 | 13 | 14 | 15 | org.apache.tomcat 16 | tomcat-servlet-api 17 | ${tomcat.version} 18 | provided 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/webapp/src/main/java/org/tomcat/example/MyFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.tomcat.example; 19 | 20 | import java.io.IOException; 21 | 22 | import javax.servlet.Filter; 23 | import javax.servlet.FilterChain; 24 | import javax.servlet.FilterConfig; 25 | import javax.servlet.ServletException; 26 | import javax.servlet.ServletRequest; 27 | import javax.servlet.ServletResponse; 28 | 29 | import javax.servlet.http.HttpServletRequest; 30 | import javax.servlet.http.HttpServletResponse; 31 | 32 | /* 33 | * example to read a parameter processed by the vault logic 34 | */ 35 | public class MyFilter implements Filter { 36 | 37 | String vaultparam; 38 | 39 | @Override 40 | public void init(FilterConfig filterConfig) { 41 | vaultparam = filterConfig.getInitParameter("vault.param"); 42 | System.out.println("init() from web.xml filter parameter vault.param: " + vaultparam); 43 | } 44 | 45 | @Override 46 | public void doFilter( 47 | ServletRequest request, 48 | ServletResponse response, 49 | FilterChain chain) 50 | throws IOException, ServletException { 51 | 52 | HttpServletResponse httpResponse = (HttpServletResponse) response; 53 | httpResponse.addHeader("myHeader", "myHeaderValue"); 54 | httpResponse.addHeader("vault.param", vaultparam); 55 | chain.doFilter(request, httpResponse); 56 | } 57 | 58 | @Override 59 | public void destroy() { 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/webapp/src/main/java/org/tomcat/example/MyServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.tomcat.example; 19 | 20 | import java.io.IOException; 21 | import java.io.PrintWriter; 22 | import java.util.Enumeration; 23 | import java.util.Properties; 24 | 25 | import javax.servlet.ServletException; 26 | 27 | import javax.servlet.http.HttpServlet; 28 | import javax.servlet.http.HttpServletRequest; 29 | import javax.servlet.http.HttpServletResponse; 30 | 31 | public class MyServlet extends HttpServlet { 32 | public void doGet(HttpServletRequest request, HttpServletResponse response) 33 | throws IOException, ServletException { 34 | // Set the response message's MIME type 35 | response.setContentType("text/html;charset=UTF-8"); 36 | // Allocate a output writer to write the response message into the network socket 37 | PrintWriter out = response.getWriter(); 38 | 39 | // Read properties 40 | Properties properties = new Properties(); 41 | properties.load(getServletContext().getResourceAsStream("/resources/examples.properties")); 42 | Enumeration enumeration =properties.propertyNames(); 43 | while (enumeration.hasMoreElements()) { 44 | String key = (String) enumeration.nextElement(); 45 | System.out.println("properties file in webapps Key: "+key+" Value: "+ properties.getProperty(key)); 46 | System.out.println("system properties in (conf/catalina.properties ) Key: "+key+" Value: "+ System.getProperty(key)); 47 | } 48 | 49 | // Write the response message, in an HTML page 50 | try { 51 | out.println(""); 52 | out.println(""); 53 | out.println(""); 54 | out.println("Hello, World"); 55 | out.println(""); 56 | out.println("

Hello, world!

"); 57 | out.println(""); 58 | out.println(""); 59 | } finally { 60 | out.close(); // Always close the output writer 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /examples/webapp/src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/webapp/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Demo Web Application 7 | 8 | ExampleServlet 9 | org.tomcat.example.MyServlet 10 | 11 | 12 | ExampleServlet 13 | /* 14 | 15 | 16 | 17 | 18 | 19 | ExampleFilter 20 | ExampleFilter 21 | org.tomcat.example.MyFilter 22 | 23 | vault.param 24 | ${VAULT::my_block::manager_password::} 25 | 26 | 27 | 28 | ExampleFilter 29 | / 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/webapp/src/main/webapp/resources/examples.properties: -------------------------------------------------------------------------------- 1 | # Properties file example 2 | vault.param=${VAULT::my_block::manager_password::} 3 | crypt.param=${CRYPT::8/wCemUmdjS9viL9xRHBYuWCyGTiB4UU} 4 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.apache.tomcat 8 | tomcat-vault 9 | 1.1.10.Final 10 | Vault extension for Apache Tomcat 11 | 12 | 13 | 9.0.76 14 | 1.8 15 | 1.8 16 | 17 | 18 | 19 | 20 | org.apache.tomcat 21 | tomcat-util 22 | ${tomcat.version} 23 | provided 24 | 25 | 26 | org.apache.tomcat 27 | tomcat-juli 28 | ${tomcat.version} 29 | provided 30 | 31 | 32 | org.apache.tomcat 33 | tomcat-catalina 34 | ${tomcat.version} 35 | provided 36 | 37 | 38 | commons-cli 39 | commons-cli 40 | 1.5.0 41 | 42 | 43 | org.jasypt 44 | jasypt 45 | 1.9.2 46 | 47 | 48 | junit 49 | junit 50 | 4.13.2 51 | test 52 | 53 | 54 | org.junit.vintage 55 | junit-vintage-engine 56 | 5.10.2 57 | test 58 | 59 | 60 | org.mockito 61 | mockito-core 62 | 4.11.0 63 | test 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-surefire-plugin 71 | 3.0.0-M5 72 | 73 | false 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-assembly-plugin 79 | false 80 | 81 | 82 | bin 83 | 84 | single 85 | 86 | package 87 | 88 | 89 | jar-with-dependencies 90 | 91 | 92 | 93 | 94 | 95 | 96 | org.apache.maven.plugins 97 | maven-antrun-plugin 98 | 1.7 99 | 100 | 101 | copy-dependencies 102 | package 103 | 104 | run 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | maven-clean-plugin 120 | 3.0.0 121 | 122 | 123 | 124 | ${project.basedir}/lib/ 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | jboss-public-jboss-repo-group 134 | JBoss Public Repository Group 135 | https://repository.jboss.org/nexus/content/groups/public-jboss/ 136 | 137 | false 138 | 139 | 140 | 141 | 142 | 143 | jboss-public-jboss-repo-group 144 | JBoss Public Repository Group 145 | https://repository.jboss.org/nexus/content/groups/public/ 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /src/main/java/org/apache/tomcat/vault/VaultInteraction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source. 3 | * Copyright 2011, Red Hat, Inc., and individual contributors 4 | * as indicated by the @author tags. See the copyright.txt file in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * This is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this software; if not, write to the Free 19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 | */ 22 | 23 | package org.apache.tomcat.vault; 24 | 25 | import org.apache.tomcat.vault.security.vault.SecurityVault; 26 | 27 | import java.io.Console; 28 | import java.util.Scanner; 29 | 30 | /** 31 | * Interaction with initialized {@link SecurityVault} via the {@link VaultTool} 32 | * 33 | * @author Anil Saldhana 34 | */ 35 | public class VaultInteraction { 36 | 37 | private VaultSession vaultNISession; 38 | 39 | public VaultInteraction(VaultSession vaultSession) { 40 | this.vaultNISession = vaultSession; 41 | } 42 | 43 | public void start() { 44 | Console console = System.console(); 45 | 46 | if (console == null) { 47 | System.err.println("No console."); 48 | System.exit(1); 49 | } 50 | 51 | Scanner in = new Scanner(System.in); 52 | while (true) { 53 | String commandStr = "Please enter a Digit:: 0: Store a secured attribute " + " 1: Check whether a secured attribute exists " 54 | + " 2: Remove a secured attribute " 55 | + " Other: Exit"; 56 | 57 | System.out.println(commandStr); 58 | int choice = in.nextInt(); 59 | switch (choice) { 60 | case 0: 61 | System.out.println("Task: Store a secured attribute"); 62 | char[] attributeValue = VaultInteractiveSession.getSensitiveValue("Please enter secured attribute value (such as password)"); 63 | String vaultBlock = null; 64 | 65 | while (vaultBlock == null || vaultBlock.length() == 0) { 66 | vaultBlock = console.readLine("Enter Vault Block:"); 67 | } 68 | 69 | String attributeName = null; 70 | 71 | while (attributeName == null || attributeName.length() == 0) { 72 | attributeName = console.readLine("Enter Attribute Name:"); 73 | } 74 | try { 75 | vaultNISession.addSecuredAttribute(vaultBlock, attributeName, attributeValue); 76 | } catch (Exception e) { 77 | System.out.println("Exception occurred:" + e.getLocalizedMessage()); 78 | } 79 | break; 80 | case 1: 81 | System.out.println("Task: Verify whether a secured attribute exists"); 82 | try { 83 | vaultBlock = null; 84 | 85 | while (vaultBlock == null || vaultBlock.length() == 0) { 86 | vaultBlock = console.readLine("Enter Vault Block:"); 87 | } 88 | 89 | attributeName = null; 90 | 91 | while (attributeName == null || attributeName.length() == 0) { 92 | attributeName = console.readLine("Enter Attribute Name:"); 93 | } 94 | if (!vaultNISession.checkSecuredAttribute(vaultBlock, attributeName)) 95 | System.out.println("No value has been store for (" + vaultBlock + ", " + attributeName + ")"); 96 | else 97 | System.out.println("A value exists for (" + vaultBlock + ", " + attributeName + ")"); 98 | } catch (Exception e) { 99 | System.out.println("Exception occurred:" + e.getLocalizedMessage()); 100 | } 101 | break; 102 | case 2: 103 | System.out.println("Task: Remove a secured attribute"); 104 | try { 105 | vaultBlock = null; 106 | 107 | while (vaultBlock == null || vaultBlock.length() == 0) { 108 | vaultBlock = console.readLine("Enter Vault Block:"); 109 | } 110 | 111 | attributeName = null; 112 | 113 | while (attributeName == null || attributeName.length() == 0) { 114 | attributeName = console.readLine("Enter Attribute Name:"); 115 | } 116 | vaultNISession.removeSecuredAttribute(vaultBlock, attributeName); 117 | } catch (Exception e) { 118 | System.out.println("Exception occurred:" + e.getLocalizedMessage()); 119 | } 120 | break; 121 | default: 122 | System.exit(0); 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/org/apache/tomcat/vault/VaultInteractiveSession.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source. 3 | * Copyright 2011, Red Hat, Inc., and individual contributors 4 | * as indicated by the @author tags. See the copyright.txt file in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * This is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this software; if not, write to the Free 19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 | */ 22 | 23 | package org.apache.tomcat.vault; 24 | 25 | import java.io.Console; 26 | import java.util.Arrays; 27 | 28 | /** 29 | * An interactive session for {@link VaultTool} 30 | * 31 | * @author Anil Saldhana 32 | */ 33 | public class VaultInteractiveSession { 34 | 35 | private String salt, keystoreURL, encDir, keystoreAlias; 36 | private int iterationCount = 0; 37 | 38 | // vault non-interactive session 39 | private VaultSession vaultNISession = null; 40 | 41 | public VaultInteractiveSession() { 42 | } 43 | 44 | public void start() { 45 | Console console = System.console(); 46 | 47 | if (console == null) { 48 | System.err.println("No console."); 49 | System.exit(1); 50 | } 51 | 52 | while (encDir == null || encDir.length() == 0) { 53 | encDir = console 54 | .readLine("Enter directory to store encrypted files:"); 55 | } 56 | 57 | while (keystoreURL == null || keystoreURL.length() == 0) { 58 | keystoreURL = console.readLine("Enter Keystore URL:"); 59 | } 60 | 61 | char[] keystorePasswd = getSensitiveValue("Enter Keystore password"); 62 | 63 | try { 64 | while (salt == null || salt.length() != 8) { 65 | salt = console.readLine("Enter 8 character salt:"); 66 | } 67 | 68 | String ic = console.readLine("Enter iteration count as a number (Eg: 44):"); 69 | iterationCount = Integer.parseInt(ic); 70 | vaultNISession = new VaultSession(keystoreURL, new String(keystorePasswd), encDir, salt, iterationCount); 71 | 72 | while (keystoreAlias == null || keystoreAlias.length() == 0) { 73 | keystoreAlias = console.readLine("Enter Keystore Alias:"); 74 | } 75 | 76 | System.out.println("Initializing Vault"); 77 | vaultNISession.startVaultSession(keystoreAlias); 78 | vaultNISession.vaultConfigurationDisplay(); 79 | 80 | System.out.println("Vault is initialized and ready for use"); 81 | System.out.println("Handshake with Vault complete"); 82 | 83 | VaultInteraction vaultInteraction = new VaultInteraction(vaultNISession); 84 | vaultInteraction.start(); 85 | } catch (Exception e) { 86 | System.out.println("Exception encountered: " + e.getLocalizedMessage()); 87 | } 88 | } 89 | 90 | public static char[] getSensitiveValue(String passwordPrompt) { 91 | while (true) { 92 | if (passwordPrompt == null) 93 | passwordPrompt = "Enter your password"; 94 | 95 | Console console = System.console(); 96 | 97 | char[] passwd = console.readPassword(passwordPrompt + ": "); 98 | char[] passwd1 = console.readPassword(passwordPrompt + " again: "); 99 | boolean noMatch = !Arrays.equals(passwd, passwd1); 100 | if (noMatch) 101 | System.out.println("Values entered don't match"); 102 | else { 103 | System.out.println("Values match"); 104 | return passwd; 105 | } 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/org/apache/tomcat/vault/VaultSession.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source. 3 | * Copyright 2012, Red Hat, Inc., and individual contributors 4 | * as indicated by the @author tags. See the copyright.txt file in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * This is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this software; if not, write to the Free 19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 | */ 22 | 23 | package org.apache.tomcat.vault; 24 | 25 | import org.apache.tomcat.vault.security.plugins.PBEUtils; 26 | import org.apache.tomcat.vault.security.vault.PicketBoxSecurityVault; 27 | import org.apache.tomcat.vault.security.vault.SecurityVault; 28 | import org.apache.tomcat.vault.security.vault.SecurityVaultException; 29 | import org.apache.tomcat.vault.security.vault.SecurityVaultFactory; 30 | 31 | import javax.crypto.SecretKey; 32 | import javax.crypto.SecretKeyFactory; 33 | import javax.crypto.spec.PBEKeySpec; 34 | import javax.crypto.spec.PBEParameterSpec; 35 | import java.io.File; 36 | import java.io.PrintStream; 37 | import java.nio.charset.Charset; 38 | import java.util.HashMap; 39 | import java.util.Map; 40 | 41 | import org.jasypt.util.text.BasicTextEncryptor; 42 | 43 | /** 44 | * Non-interactive session for {@link VaultTool} 45 | * 46 | * @author Peter Skopek 47 | */ 48 | public final class VaultSession { 49 | 50 | public static final String VAULT_ENC_ALGORITHM = "PBEwithMD5andDES"; 51 | 52 | static final Charset CHARSET = Charset.forName("UTF-8"); 53 | 54 | private String keystoreURL; 55 | private String keystorePassword; 56 | private String keystoreMaskedPassword; 57 | private String encryptionDirectory; 58 | private String salt; 59 | private int iterationCount; 60 | 61 | private SecurityVault vault; 62 | private String vaultAlias; 63 | private byte[] handshakeKey; 64 | 65 | /** 66 | * Constructor to create VaultSession. 67 | * 68 | * @param keystoreURL 69 | * @param keystorePassword 70 | * @param encryptionDirectory 71 | * @param salt 72 | * @param iterationCount 73 | * @throws Exception 74 | */ 75 | public VaultSession(String keystoreURL, String keystorePassword, String encryptionDirectory, String salt, int iterationCount) 76 | throws Exception { 77 | this.keystoreURL = keystoreURL; 78 | this.keystorePassword = keystorePassword; 79 | this.encryptionDirectory = encryptionDirectory; 80 | this.salt = salt; 81 | this.iterationCount = iterationCount; 82 | validate(); 83 | } 84 | 85 | /** 86 | * Validate fields sent to this class's constructor. 87 | */ 88 | private void validate() throws Exception { 89 | validateKeystoreURL(); 90 | validateEncryptionDirectory(); 91 | validateSalt(); 92 | validateIterationCount(); 93 | validateKeystorePassword(); 94 | } 95 | 96 | protected void validateKeystoreURL() throws Exception { 97 | 98 | File f = new File(keystoreURL); 99 | if (!f.exists()) { 100 | throw new Exception("Keystore [" + keystoreURL + "] doesn't exist." 101 | + "\nkeystore could be created: keytool -genseckey -alias vault -storetype jceks -keyalg AES -keysize 128 -keystore " 102 | + keystoreURL); 103 | } else if (!f.canWrite() || !f.isFile()) { 104 | throw new Exception("Keystore [" + keystoreURL + "] is not writable or not a file."); 105 | } 106 | } 107 | 108 | protected void validateKeystorePassword() throws Exception { 109 | if (keystorePassword == null) { 110 | throw new Exception("Keystore password has to be specified."); 111 | } 112 | } 113 | 114 | protected void validateEncryptionDirectory() throws Exception { 115 | if (encryptionDirectory == null) { 116 | throw new Exception("Encryption directory has to be specified."); 117 | } 118 | if (!encryptionDirectory.endsWith("/") || encryptionDirectory.endsWith("\\")) { 119 | encryptionDirectory = encryptionDirectory + (System.getProperty("file.separator", "/")); 120 | } 121 | File d = new File(encryptionDirectory); 122 | if (!d.exists()) { 123 | if (!d.mkdirs()) { 124 | throw new Exception("Cannot create encryption directory " + d.getAbsolutePath()); 125 | } 126 | } 127 | if (!d.isDirectory()) { 128 | throw new Exception("Encryption directory is not a directory or doesn't exist. (" + encryptionDirectory + ")"); 129 | } 130 | } 131 | 132 | protected void validateIterationCount() throws Exception { 133 | if (iterationCount < 1 && iterationCount > Integer.MAX_VALUE) { 134 | throw new Exception("Iteration count has to be withing 1 - " + Integer.MAX_VALUE + ", but is " + iterationCount 135 | + "."); 136 | } 137 | } 138 | 139 | protected void validateSalt() throws Exception { 140 | if (salt == null || salt.length() != 8) { 141 | throw new Exception("Salt has to be exactly 8 characters long."); 142 | } 143 | } 144 | 145 | /** 146 | * Method to compute masked password based on class attributes. 147 | * 148 | * @return masked password prefixed with {link @PicketBoxSecurityVault.PASS_MASK_PREFIX}. 149 | * @throws Exception 150 | */ 151 | private String computeMaskedPassword() throws Exception { 152 | 153 | // Create the PBE secret key 154 | SecretKeyFactory factory = SecretKeyFactory.getInstance(VAULT_ENC_ALGORITHM); 155 | 156 | char[] password = "somearbitrarycrazystringthatdoesnotmatter".toCharArray(); 157 | PBEParameterSpec cipherSpec = new PBEParameterSpec(salt.getBytes(), iterationCount); 158 | PBEKeySpec keySpec = new PBEKeySpec(password); 159 | SecretKey cipherKey = factory.generateSecret(keySpec); 160 | 161 | String maskedPass = PBEUtils.encode64(keystorePassword.getBytes(), VAULT_ENC_ALGORITHM, cipherKey, cipherSpec); 162 | 163 | return PicketBoxSecurityVault.PASS_MASK_PREFIX + maskedPass; 164 | } 165 | 166 | /** 167 | * Initialize the underlying vault. 168 | * 169 | * @throws Exception 170 | */ 171 | private void initSecurityVault() throws Exception { 172 | try { 173 | this.vault = SecurityVaultFactory.get(); 174 | this.vault.init(getVaultOptionsMap()); 175 | handshake(); 176 | } catch (SecurityVaultException e) { 177 | throw new Exception("Exception encountered: " + e.getLocalizedMessage(), e); 178 | } 179 | } 180 | 181 | /** 182 | * Start the vault with given alias. 183 | * 184 | * @param vaultAlias 185 | * @throws Exception 186 | */ 187 | public void startVaultSession(String vaultAlias) throws Exception { 188 | if (vaultAlias == null) { 189 | throw new Exception("Vault alias has to be specified."); 190 | } 191 | this.keystoreMaskedPassword = computeMaskedPassword(); 192 | this.vaultAlias = vaultAlias; 193 | initSecurityVault(); 194 | } 195 | 196 | private Map getVaultOptionsMap() { 197 | Map options = new HashMap(); 198 | options.put(PicketBoxSecurityVault.KEYSTORE_URL, keystoreURL); 199 | options.put(PicketBoxSecurityVault.KEYSTORE_PASSWORD, keystoreMaskedPassword); 200 | options.put(PicketBoxSecurityVault.KEYSTORE_ALIAS, vaultAlias); 201 | options.put(PicketBoxSecurityVault.SALT, salt); 202 | options.put(PicketBoxSecurityVault.ITERATION_COUNT, Integer.toString(iterationCount)); 203 | options.put(PicketBoxSecurityVault.ENC_FILE_DIR, encryptionDirectory); 204 | return options; 205 | } 206 | 207 | private void handshake() throws SecurityVaultException { 208 | Map handshakeOptions = new HashMap(); 209 | handshakeOptions.put(PicketBoxSecurityVault.PUBLIC_CERT, vaultAlias); 210 | handshakeKey = vault.handshake(handshakeOptions); 211 | } 212 | 213 | /** 214 | * Add secured attribute to specified vault block. This method can be called only after successful 215 | * startVaultSession() call. 216 | * 217 | * @param vaultBlock 218 | * @param attributeName 219 | * @param attributeValue 220 | */ 221 | public void addSecuredAttribute(String vaultBlock, String attributeName, char[] attributeValue) throws Exception { 222 | if (handshakeKey == null) { 223 | throw new Exception("addSecuredAttribute method has to be called after successful startVaultSession() call."); 224 | } 225 | vault.store(vaultBlock, attributeName, attributeValue, handshakeKey); 226 | attributeCreatedDisplay(vaultBlock, attributeName); 227 | } 228 | 229 | /** 230 | * Check whether secured attribute is already set for given vault block and attribute name. This method can be called only after 231 | * successful startVaultSession() call. 232 | * 233 | * @param vaultBlock 234 | * @param attributeName 235 | * @return true is password already exists for given vault block and attribute name. 236 | * @throws Exception 237 | */ 238 | public boolean checkSecuredAttribute(String vaultBlock, String attributeName) throws Exception { 239 | if (handshakeKey == null) { 240 | throw new Exception("checkSecuredAttribute method has to be called after successful startVaultSession() call."); 241 | } 242 | return vault.exists(vaultBlock, attributeName); 243 | } 244 | 245 | /** 246 | * Remove secured attribute with given vault block and attribute name. This method can be called only after 247 | * successful startVaultSession() call. 248 | * 249 | * @param vaultBlock 250 | * @param attributeName 251 | * @throws Exception 252 | */ 253 | public void removeSecuredAttribute(String vaultBlock, String attributeName) throws Exception { 254 | if (handshakeKey == null) { 255 | throw new Exception("checkSecuredAttribute method has to be called after successful startVaultSession() call."); 256 | } 257 | vault.remove(vaultBlock, attributeName, handshakeKey); 258 | } 259 | 260 | /** 261 | * Encrypt a value using the CRYPT feature. 262 | * 263 | * @param encryptionPassword Encryption password; could be stored in the vault 264 | * @param valueToEncrypt 265 | * 266 | * @throws Exception if there is an issue retrieving the encryptionPassword from the vault. 267 | */ 268 | public void encryptValueWithCRYPT(String encryptionPassword, String valueToEncrypt) throws Exception { 269 | String decryptedPassword = null; 270 | 271 | // if the encryptionPassword is in the VAULT, decrypt it 272 | // This logic came from o.a.t.vault.util.PropertySourceVault, may need to move to a helper 273 | // class to reduce duplication. 274 | if (encryptionPassword.startsWith("VAULT::")) { 275 | String vaultdata[] = encryptionPassword.split("::"); 276 | if (vaultdata.length == 3) { 277 | if (vault.isInitialized()) { 278 | try { 279 | decryptedPassword = new String(vault.retrieve(vaultdata[1], vaultdata[2], null)); 280 | } catch (SecurityVaultException e) { 281 | System.out.println(e.getMessage()); 282 | } 283 | } 284 | } 285 | } else { 286 | decryptedPassword = encryptionPassword; 287 | } 288 | 289 | BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); 290 | textEncryptor.setPassword(decryptedPassword); 291 | System.out.println("Encrypted value: CRYPT::" + textEncryptor.encrypt(valueToEncrypt)); 292 | } 293 | 294 | /** 295 | * Display info about stored secured attribute. 296 | * 297 | * @param vaultBlock 298 | * @param attributeName 299 | */ 300 | private void attributeCreatedDisplay(String vaultBlock, String attributeName) { 301 | String keyAsString = new String(handshakeKey, CHARSET); 302 | System.out.println("Secured attribute value has been stored in vault. "); 303 | System.out.println("Please make note of the following:"); 304 | System.out.println("********************************************"); 305 | System.out.println("Vault Block:" + vaultBlock); 306 | System.out.println("Attribute Name:" + attributeName); 307 | System.out.println("Shared Key:" + keyAsString); 308 | System.out.println("Configuration should be done as follows:"); 309 | System.out.println("VAULT::" + vaultBlock + "::" + attributeName + "::" + keyAsString); 310 | System.out.println("********************************************"); 311 | } 312 | 313 | /** 314 | * Display info about vault itself in form of AS7 configuration file. 315 | */ 316 | public void vaultConfigurationDisplay() { 317 | System.out.println("Vault Configuration in tomcat properties file:"); 318 | System.out.println("********************************************"); 319 | outputConfig(System.out); 320 | System.out.println("********************************************"); 321 | } 322 | 323 | /** 324 | * Print AS7 configuration file to stream. 325 | * 326 | * @param out stream to print config. 327 | */ 328 | public void outputConfig(PrintStream out) { 329 | out.println("KEYSTORE_URL=" + keystoreURL.replace("\\", "/")); 330 | out.println("KEYSTORE_PASSWORD=" + keystoreMaskedPassword); 331 | out.println("KEYSTORE_ALIAS=" + vaultAlias); 332 | out.println("SALT=" + salt); 333 | out.println("ITERATION_COUNT=" + iterationCount); 334 | out.println("ENC_FILE_DIR=" + encryptionDirectory.replace("\\", "/")); 335 | } 336 | 337 | } 338 | -------------------------------------------------------------------------------- /src/main/java/org/apache/tomcat/vault/VaultTool.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source. 3 | * Copyright 2011, Red Hat, Inc., and individual contributors 4 | * as indicated by the @author tags. See the copyright.txt file in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * This is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this software; if not, write to the Free 19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 | */ 22 | 23 | package org.apache.tomcat.vault; 24 | 25 | import org.apache.commons.cli.*; 26 | import org.apache.tomcat.vault.security.vault.SecurityVault; 27 | import org.apache.tomcat.vault.security.Util; 28 | 29 | import java.io.Console; 30 | import java.io.PrintStream; 31 | import java.util.InputMismatchException; 32 | import java.util.Scanner; 33 | 34 | import org.jasypt.util.text.BasicTextEncryptor; 35 | 36 | /** 37 | * Command Line Tool for the default implementation of the {@link SecurityVault} 38 | * 39 | * @author Anil Saldhana 40 | * @author Peter Skopek 41 | */ 42 | public class VaultTool { 43 | 44 | public static final String KEYSTORE_PARAM = "keystore"; 45 | public static final String KEYSTORE_PASSWORD_PARAM = "keystore-password"; 46 | public static final String ENC_DIR_PARAM = "enc-dir"; 47 | public static final String SALT_PARAM = "salt"; 48 | public static final String ITERATION_PARAM = "iteration"; 49 | public static final String ALIAS_PARAM = "alias"; 50 | public static final String VAULT_BLOCK_PARAM = "vault-block"; 51 | public static final String ATTRIBUTE_PARAM = "attribute"; 52 | public static final String SEC_ATTR_VALUE_PARAM = "sec-attr"; 53 | public static final String CHECK_SEC_ATTR_EXISTS_PARAM = "check-sec-attr"; 54 | public static final String REMOVE_SEC_ATTR = "remove-sec-attr"; 55 | public static final String GENERATE_CONFIG_FILE = "generate-config"; 56 | public static final String HELP_PARAM = "help"; 57 | public static final String CRYPT = "encrypt"; 58 | 59 | private static boolean skipSummary = false; 60 | 61 | private VaultInteractiveSession session = null; 62 | private VaultSession nonInteractiveSession = null; 63 | 64 | private Options options = null; 65 | private CommandLineParser parser = null; 66 | private CommandLine cmdLine = null; 67 | 68 | public void setSession(VaultInteractiveSession sess) { 69 | session = sess; 70 | } 71 | 72 | public VaultInteractiveSession getSession() { 73 | return session; 74 | } 75 | 76 | public static void main(String[] args) { 77 | 78 | if (Util.isFIPS()) { 79 | System.err.println("Security Vault can't be used in FIPS mode."); 80 | System.exit(1); 81 | } 82 | 83 | VaultTool tool = null; 84 | 85 | if (args != null && args.length > 0) { 86 | int returnVal = 0; 87 | try { 88 | tool = new VaultTool(args); 89 | returnVal = tool.execute(); 90 | if (!skipSummary) { 91 | tool.summary(); 92 | } 93 | } catch (Exception e) { 94 | System.err.println("Problem occurred:"); 95 | System.err.println(e.getMessage()); 96 | System.exit(1); 97 | } 98 | System.exit(returnVal); 99 | } else { 100 | tool = new VaultTool(); 101 | 102 | Console console = System.console(); 103 | 104 | if (console == null) { 105 | System.err.println("No console."); 106 | System.exit(1); 107 | } 108 | 109 | Scanner in = new Scanner(System.in); 110 | while (true) { 111 | String commandStr = "Please enter a Digit:: 0: Start Interactive Session " 112 | + " 1: Remove Interactive Session " + " Other: Exit"; 113 | 114 | System.out.println(commandStr); 115 | int choice = -1; 116 | 117 | try { 118 | choice = in.nextInt(); 119 | } catch (InputMismatchException e) { 120 | System.err.println("'" + in.next() + "' is not a digit. Restart and enter a digit."); 121 | System.exit(3); 122 | } 123 | 124 | switch (choice) { 125 | case 0: 126 | System.out.println("Starting an interactive session"); 127 | VaultInteractiveSession vsession = new VaultInteractiveSession(); 128 | tool.setSession(vsession); 129 | vsession.start(); 130 | break; 131 | case 1: 132 | System.out.println("Removing the current interactive session"); 133 | tool.setSession(null); 134 | break; 135 | default: 136 | System.exit(0); 137 | } 138 | } 139 | 140 | } 141 | 142 | } 143 | 144 | public VaultTool(String[] args) { 145 | initOptions(); 146 | parser = new PosixParser(); 147 | try { 148 | cmdLine = parser.parse(options, args, true); 149 | } catch (MissingArgumentException e) { 150 | Option opt = e.getOption(); 151 | for (String s : args) { 152 | String optionSpecified = s.replaceAll("^-+", ""); 153 | if (optionSpecified.equals(opt.getLongOpt()) || 154 | optionSpecified.equals(opt.getOpt())) { 155 | System.err.println("Missing argument for option: " + optionSpecified); 156 | System.exit(2); 157 | } 158 | } 159 | } catch (ParseException e) { 160 | System.err.println(e.getMessage()); 161 | System.exit(2); 162 | } 163 | } 164 | 165 | public VaultTool() { 166 | } 167 | 168 | /** 169 | * Build options for non-interactive VaultTool usage scenario. 170 | * 171 | * @return 172 | */ 173 | private void initOptions() { 174 | options = new Options(); 175 | options.addOption("k", KEYSTORE_PARAM, true, "Keystore URL"); 176 | options.addOption("p", KEYSTORE_PASSWORD_PARAM, true, "Keystore password"); 177 | options.addOption("e", ENC_DIR_PARAM, true, "Directory containing encrypted files"); 178 | options.addOption("s", SALT_PARAM, true, "8 character salt"); 179 | options.addOption("i", ITERATION_PARAM, true, "Iteration count"); 180 | options.addOption("A", ALIAS_PARAM, true, "Vault keystore alias"); 181 | options.addOption("b", VAULT_BLOCK_PARAM, true, "Vault block"); 182 | options.addOption("a", ATTRIBUTE_PARAM, true, "Attribute name"); 183 | 184 | OptionGroup og = new OptionGroup(); 185 | Option x = new Option("x", SEC_ATTR_VALUE_PARAM, true, "Secured attribute value (such as password) to store"); 186 | Option c = new Option("c", CHECK_SEC_ATTR_EXISTS_PARAM, false, "Check whether the secured attribute already exists in the vault"); 187 | Option r = new Option("r", REMOVE_SEC_ATTR, false, "Remove the secured attribute from the vault"); 188 | Option g = new Option("g", GENERATE_CONFIG_FILE, true, "Path for generated config file"); 189 | Option h = new Option("h", HELP_PARAM, false, "Help"); 190 | Option E = new Option("E", CRYPT, false, "Encrypt value using CRYPT feature"); 191 | og.addOption(x); 192 | og.addOption(c); 193 | og.addOption(r); 194 | og.addOption(g); 195 | og.addOption(h); 196 | og.addOption(E); 197 | og.setRequired(true); 198 | options.addOptionGroup(og); 199 | } 200 | 201 | private int execute() throws Exception { 202 | 203 | if (cmdLine.hasOption(HELP_PARAM)) { 204 | // Just print the usage. Printing summary is not required here. 205 | skipSummary = true; 206 | printUsage(); 207 | return 100; 208 | } 209 | 210 | // If using the CRYPT feature without specifying a keystore, you don't need the vault 211 | if (cmdLine.hasOption(CRYPT) && !cmdLine.hasOption((KEYSTORE_PARAM))) { 212 | // Regardless of the return here, we do not need to print summary for this command option. 213 | // Also, if we forget setting skipSummary, the nonInteractiveSession will cause an NPE since there is no vault. 214 | skipSummary = true; 215 | if (cmdLine.getArgs().length == 2) { 216 | // Check to see if they tried to specify a VAULT value without a keystore :) 217 | if (cmdLine.getArgs()[0].startsWith("VAULT::")) { 218 | System.out.println("You have specified a value stored in the vault, but have not supplied the " + 219 | "required vault options."); 220 | System.out.println("Please retry with a plain text value, or with the appropriate vault options."); 221 | return 100; 222 | } 223 | 224 | BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); 225 | textEncryptor.setPassword(cmdLine.getArgs()[0]); 226 | System.out.println("Encrypted value: CRYPT::" + textEncryptor.encrypt(cmdLine.getArgs()[1])); 227 | return 0; 228 | } else { 229 | System.out.println("Arguments: encryption password, value to encrypt"); 230 | return 100; 231 | } 232 | } 233 | 234 | String keystoreURL = cmdLine.getOptionValue(KEYSTORE_PARAM, "vault.keystore"); 235 | String keystorePassword = cmdLine.getOptionValue(KEYSTORE_PASSWORD_PARAM, ""); 236 | if (!cmdLine.hasOption(KEYSTORE_PASSWORD_PARAM)) { 237 | keystorePassword = new String(System.console().readPassword("Enter keystore password: ")); 238 | } 239 | 240 | String encryptionDirectory = cmdLine.getOptionValue(ENC_DIR_PARAM, "vault"); 241 | String salt = cmdLine.getOptionValue(SALT_PARAM, "12345678"); 242 | int iterationCount = Integer.parseInt(cmdLine.getOptionValue(ITERATION_PARAM, "23")); 243 | 244 | nonInteractiveSession = new VaultSession(keystoreURL, keystorePassword, encryptionDirectory, salt, iterationCount); 245 | 246 | nonInteractiveSession.startVaultSession(cmdLine.getOptionValue(ALIAS_PARAM, "vault")); 247 | 248 | String vaultBlock = cmdLine.getOptionValue(VAULT_BLOCK_PARAM, "vb"); 249 | String attributeName = cmdLine.getOptionValue(ATTRIBUTE_PARAM, "password"); 250 | 251 | if (cmdLine.hasOption(CHECK_SEC_ATTR_EXISTS_PARAM)) { 252 | // check password 253 | if (nonInteractiveSession.checkSecuredAttribute(vaultBlock, attributeName)) { 254 | System.out.println("Secured attribute already exists."); 255 | return 0; 256 | } else { 257 | System.out.println("Secured attribute does not exist."); 258 | return 5; 259 | } 260 | } else if (cmdLine.hasOption(SEC_ATTR_VALUE_PARAM)) { 261 | // add password 262 | String password = cmdLine.getOptionValue(SEC_ATTR_VALUE_PARAM, "password"); 263 | nonInteractiveSession.addSecuredAttribute(vaultBlock, attributeName, password.toCharArray()); 264 | return 0; 265 | } else if (cmdLine.hasOption(REMOVE_SEC_ATTR)) { 266 | nonInteractiveSession.removeSecuredAttribute(vaultBlock, attributeName); 267 | return 0; 268 | } else if (cmdLine.hasOption(GENERATE_CONFIG_FILE)) { 269 | PrintStream ps = new PrintStream(cmdLine.getOptionValue(GENERATE_CONFIG_FILE, "vault.properties")); 270 | try { 271 | nonInteractiveSession.outputConfig(ps); 272 | } finally { 273 | ps.close(); 274 | } 275 | return 0; 276 | } else if (cmdLine.hasOption(CRYPT)) { 277 | // Regardless of the return here, we do not need to print summary for this command option 278 | skipSummary = true; 279 | // We need the encryption password and a value to encrypt 280 | if (cmdLine.getArgs().length == 2) { 281 | nonInteractiveSession.encryptValueWithCRYPT(cmdLine.getArgs()[0], cmdLine.getArgs()[1]); 282 | return 0; 283 | } else { 284 | System.out.println("Arguments: encryption password, value to encrypt"); 285 | return 100; 286 | } 287 | } 288 | // Printing summary is not required here 289 | skipSummary = true; 290 | return 100; 291 | } 292 | 293 | private void summary() { 294 | nonInteractiveSession.vaultConfigurationDisplay(); 295 | } 296 | 297 | private void printUsage() { 298 | HelpFormatter help = new HelpFormatter(); 299 | String suffix = (VaultTool.isWindows() ? ".bat" : ".sh"); 300 | help.printHelp("vault" + suffix + " | ", options, true); 301 | } 302 | 303 | public static boolean isWindows() { 304 | String opsys = System.getProperty("os.name").toLowerCase(); 305 | return (opsys.indexOf("win") >= 0); 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /src/main/java/org/apache/tomcat/vault/security/Base64Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2005, JBoss Inc., and individual contributors as indicated 4 | * by the @authors tag. See the copyright.txt in the distribution for a 5 | * full listing of individual contributors. 6 | * 7 | * This is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this software; if not, write to the Free 19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 | */ 22 | 23 | package org.apache.tomcat.vault.security; 24 | 25 | import org.apache.tomcat.util.res.StringManager; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | 29 | /** 30 | * Base64 encoding/decoding utilities. This implementation is not MIME compliant (rfc1421). The padding in this implementation 31 | * (if used) is a prefix of the output. 32 | * 33 | * @author Scott.Stark@jboss.org 34 | * @author Josef Cacek 35 | */ 36 | public class Base64Utils { 37 | 38 | private static final StringManager msm = StringManager.getManager("org.apache.tomcat.vault.security.resources"); 39 | 40 | private static final String base64Str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"; 41 | private static final char[] base64Table = base64Str.toCharArray(); 42 | public static final String BASE64_ENCODING = "BASE64"; 43 | public static final String BASE16_ENCODING = "HEX"; 44 | public static final char PAD = '_'; 45 | public static final String REGEX = "^" + PAD + "{0,2}[" + base64Str + "]*$"; 46 | 47 | public static String tob64(byte[] buffer) { 48 | return tob64(buffer, false); 49 | } 50 | 51 | public static String tob64(byte[] buffer, boolean usePadding) { 52 | int len = buffer.length, pos = len % 3, c; 53 | byte b0 = 0, b1 = 0, b2 = 0; 54 | StringBuffer sb = new StringBuffer(); 55 | 56 | int i = 0; 57 | if (usePadding) { 58 | for (i = pos; i != 0; i = (i + 1) % 3) { 59 | sb.append(PAD); 60 | } 61 | i = 0; 62 | } 63 | switch (pos) { 64 | case 2: 65 | b1 = buffer[i++]; 66 | c = ((b0 & 3) << 4) | ((b1 & 0xf0) >>> 4); 67 | sb.append(base64Table[c]); 68 | case 1: 69 | b2 = buffer[i++]; 70 | c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >>> 6); 71 | sb.append(base64Table[c]); 72 | c = b2 & 0x3f; 73 | sb.append(base64Table[c]); 74 | break; 75 | } 76 | 77 | while (pos < len) { 78 | b0 = buffer[pos++]; 79 | b1 = buffer[pos++]; 80 | b2 = buffer[pos++]; 81 | c = (b0 & 0xfc) >>> 2; 82 | sb.append(base64Table[c]); 83 | c = ((b0 & 3) << 4) | ((b1 & 0xf0) >>> 4); 84 | sb.append(base64Table[c]); 85 | c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >>> 6); 86 | sb.append(base64Table[c]); 87 | c = b2 & 0x3f; 88 | sb.append(base64Table[c]); 89 | } 90 | 91 | return sb.toString(); 92 | } 93 | 94 | public static byte[] fromb64(String str) throws NumberFormatException { 95 | if (str.length() == 0) { 96 | return new byte[0]; 97 | } 98 | 99 | while (str.length() % 4 != 0) { 100 | str = PAD + str; 101 | } 102 | if (!str.matches(REGEX)) { 103 | throw new IllegalArgumentException(msm.getString("invalidBase64String", str)); 104 | } 105 | ByteArrayOutputStream bos = new ByteArrayOutputStream((str.length() * 3) / 4); 106 | for (int i = 0, n = str.length(); i < n; ) { 107 | int pos0 = base64Str.indexOf(str.charAt(i++)); 108 | int pos1 = base64Str.indexOf(str.charAt(i++)); 109 | int pos2 = base64Str.indexOf(str.charAt(i++)); 110 | int pos3 = base64Str.indexOf(str.charAt(i++)); 111 | if (pos0 > -1) { 112 | bos.write(((pos1 & 0x30) >>> 4) | (pos0 << 2)); 113 | } 114 | if (pos1 > -1) { 115 | bos.write(((pos2 & 0x3c) >>> 2) | ((pos1 & 0xf) << 4)); 116 | } 117 | bos.write(((pos2 & 3) << 6) | pos3); 118 | } 119 | return bos.toByteArray(); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/apache/tomcat/vault/security/ExternalPasswordCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2005, JBoss Inc., and individual contributors as indicated 4 | * by the @authors tag. See the copyright.txt in the distribution for a 5 | * full listing of individual contributors. 6 | * 7 | * This is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this software; if not, write to the Free 19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 | */ 22 | 23 | package org.apache.tomcat.vault.security; 24 | 25 | import org.apache.juli.logging.Log; 26 | import org.apache.juli.logging.LogFactory; 27 | import org.apache.tomcat.util.res.StringManager; 28 | 29 | import java.security.MessageDigest; 30 | import java.security.NoSuchAlgorithmException; 31 | import java.util.Collections; 32 | import java.util.HashMap; 33 | import java.util.Map; 34 | 35 | /** 36 | * External command password cache. 37 | * Singleton password cache. 38 | * 39 | * @author Peter Skopek (pskopek_at_redhat_dot_com) 40 | * @version $Revision:$ 41 | */ 42 | public class ExternalPasswordCache implements PasswordCache { 43 | 44 | private static final StringManager sm = StringManager.getManager(ExternalPasswordCache.class.getPackage().getName()); 45 | private static final Log log = LogFactory.getLog(ExternalPasswordCache.class); 46 | 47 | private static final ExternalPasswordCache PASSWORD_CACHE = new ExternalPasswordCache(); 48 | 49 | private Map cache; 50 | private MessageDigest md5Digest = null; 51 | 52 | private ExternalPasswordCache() { 53 | cache = Collections.synchronizedMap(new HashMap()); 54 | try { 55 | md5Digest = MessageDigest.getInstance("MD5"); 56 | } catch (NoSuchAlgorithmException e) { 57 | // Cannot get MD5 algorithm instance for hashing password commands. Using NULL. 58 | log.error(sm.getString("externalPasswordCache.cannotGetMD5AlgorithmInstance")); 59 | } 60 | } 61 | 62 | public static ExternalPasswordCache getExternalPasswordCacheInstance() { 63 | SecurityManager sm = System.getSecurityManager(); 64 | if (sm != null) { 65 | sm.checkPermission(new RuntimePermission(ExternalPasswordCache.class.getName() + ".getExternalPasswordCacheInstance")); 66 | } 67 | return PASSWORD_CACHE; 68 | } 69 | 70 | /* (non-Javadoc) 71 | * @see org.jboss.security.PasswordCache#contains(java.lang.String) 72 | */ 73 | @Override 74 | public boolean contains(String key, long timeOut) { 75 | String transformedKey = transformKey(key); 76 | PasswordRecord pr = cache.get(transformedKey); 77 | if (pr != null && (timeOut == 0 || System.currentTimeMillis() - pr.timeOut < timeOut)) { 78 | return true; 79 | } 80 | return false; 81 | } 82 | 83 | /* (non-Javadoc) 84 | * @see org.jboss.security.PasswordCache#getPassword(java.lang.String) 85 | */ 86 | @Override 87 | public char[] getPassword(String key) { 88 | String newKey = transformKey(key); 89 | log.trace(sm.getString("externalPasswordCache.retrievingPasswordFromCache", newKey)); 90 | PasswordRecord pr = cache.get(newKey); 91 | return pr.password; 92 | } 93 | 94 | /* (non-Javadoc) 95 | * @see org.jboss.security.PasswordCache#storePassword(java.lang.String, char[]) 96 | */ 97 | @Override 98 | public void storePassword(String key, char[] password) { 99 | String newKey = transformKey(key); 100 | log.trace(sm.getString("externalPasswordCache.storingPasswordToCache", newKey)); 101 | PasswordRecord pr = new PasswordRecord(); 102 | pr.timeOut = System.currentTimeMillis(); 103 | pr.password = password; 104 | cache.put(newKey, pr); 105 | } 106 | 107 | private String transformKey(String key) { 108 | String newKey = key; 109 | if (md5Digest != null) { 110 | md5Digest.reset(); 111 | byte[] bt = key.getBytes(); 112 | byte[] md5 = md5Digest.digest(bt); 113 | newKey = new String(Base64Utils.tob64(md5)); 114 | } 115 | return newKey; 116 | } 117 | 118 | /** 119 | * Get number of cached passwords. 120 | * Mainly for testing purpose. 121 | */ 122 | public int getCachedPasswordsCount() { 123 | return cache.size(); 124 | } 125 | 126 | /* (non-Javadoc) 127 | * @see org.jboss.security.PasswordCache#reset() 128 | */ 129 | @Override 130 | public void reset() { 131 | log.trace(sm.getString("externalPasswordCache.resettingCache")); 132 | cache.clear(); 133 | } 134 | 135 | 136 | } 137 | 138 | class PasswordRecord { 139 | 140 | long timeOut; 141 | char[] password; 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/org/apache/tomcat/vault/security/PasswordCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source 3 | * Copyright 2005, JBoss Inc., and individual contributors as indicated 4 | * by the @authors tag. See the copyright.txt in the distribution for a 5 | * full listing of individual contributors. 6 | * 7 | * This is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this software; if not, write to the Free 19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 | */ 22 | 23 | package org.apache.tomcat.vault.security; 24 | 25 | /** 26 | * Interface to cache passwords retrieved from external commands. 27 | * 28 | * @author Peter Skopek (pskopek_at_redhat_dot_com) 29 | * @version $Revision:$ 30 | */ 31 | public interface PasswordCache { 32 | 33 | /** 34 | * Checks whether the cache already contains given key. Non zero timeOut will be checked to expire cache entry. 35 | * 36 | * @param key 37 | * @param timeOut 38 | * @return 39 | */ 40 | public boolean contains(String key, long timeOut); 41 | 42 | /** 43 | * Get password from the cache. 44 | * Returns null if there is no such key in the cache. 45 | * 46 | * @param key 47 | * @return 48 | */ 49 | char[] getPassword(String key); 50 | 51 | /** 52 | * Store password to the cache. 53 | * 54 | * @param key 55 | * @param password 56 | */ 57 | public void storePassword(String key, char[] password); 58 | 59 | /** 60 | * Reset the cache (clean whole cache and start all over again). 61 | */ 62 | public void reset(); 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/apache/tomcat/vault/security/Util.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JBoss, Home of Professional Open Source. 3 | * Copyright 2006, Red Hat Middleware LLC, and individual contributors 4 | * as indicated by the @author tags. See the copyright.txt file in the 5 | * distribution for a full listing of individual contributors. 6 | * 7 | * This is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation; either version 2.1 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this software; if not, write to the Free 19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 | */ 22 | 23 | package org.apache.tomcat.vault.security; 24 | 25 | import org.apache.juli.logging.Log; 26 | import org.apache.juli.logging.LogFactory; 27 | import org.apache.tomcat.util.res.StringManager; 28 | 29 | import java.io.BufferedReader; 30 | import java.io.InputStream; 31 | import java.io.InputStreamReader; 32 | import java.security.AccessController; 33 | import java.security.PrivilegedActionException; 34 | import java.security.PrivilegedExceptionAction; 35 | import java.security.Provider; 36 | import java.security.Security; 37 | import java.util.StringTokenizer; 38 | 39 | /** 40 | * Util. 41 | * 42 | * @author Scott.Stark@jboss.org 43 | * @author Adrian Brock 44 | * @version $Revision: 1.1 $ 45 | */ 46 | public class Util { 47 | 48 | private static final StringManager strm = StringManager.getManager(Util.class.getPackage().getName()); 49 | private static final Log log = LogFactory.getLog(Util.class); 50 | private static final StringManager msm = StringManager.getManager("org.apache.tomcat.vault.security.resources"); 51 | 52 | private static PasswordCache externalPasswordCache; 53 | 54 | /** 55 | * Execute a password load command to obtain the char[] contents of a 56 | * password. 57 | * 58 | * @param passwordCmd - A command to execute to obtain the plaintext 59 | * password. The format is one of: 60 | * '{EXT}...' where the '...' is the exact command 61 | * '{EXTC[:expiration_in_millis]}...' where the '...' is the exact command 62 | * line that will be passed to the Runtime.exec(String) method to execute a 63 | * platform command. The first line of the command output is used as the 64 | * password. 65 | * EXTC variant will cache the passwords for expiration_in_millis milliseconds. 66 | * Default cache expiration is 0 = infinity. 67 | * '{CMD}...' or '{CMDC[:expiration_in_millis]}...' for a general command to execute. The general 68 | * command is a string delimited by ',' where the first part is the actual 69 | * command and further parts represents its parameters. The comma can be 70 | * backslashed in order to keep it as a part of the parameter. 71 | * @return the password characters 72 | * @throws Exception 73 | */ 74 | public static char[] loadPassword(String passwordCmd) 75 | throws Exception { 76 | SecurityManager sm = System.getSecurityManager(); 77 | if (sm != null) { 78 | sm.checkPermission(new RuntimePermission(Util.class.getName() + ".loadPassword")); 79 | } 80 | char[] password = null; 81 | String passwordCmdType = null; 82 | 83 | // Look for a {...} prefix indicating a password command 84 | if (passwordCmd.charAt(0) == '{') { 85 | StringTokenizer tokenizer = new StringTokenizer(passwordCmd, "{}"); 86 | passwordCmdType = tokenizer.nextToken(); 87 | passwordCmd = tokenizer.nextToken(); 88 | } else { 89 | // Its just the password string 90 | password = passwordCmd.toCharArray(); 91 | } 92 | 93 | if (password == null) { 94 | // Load the password 95 | if (passwordCmdType.startsWith("EXTC") || passwordCmdType.startsWith("CMDC")) { 96 | long timeOut = 0; 97 | if (passwordCmdType.indexOf(':') > -1) { 98 | try { 99 | String[] token = passwordCmdType.split(":"); 100 | timeOut = Long.parseLong(token[1]); 101 | } catch (Throwable e) { 102 | // ignore 103 | log.error(strm.getString("util.parsingTimeoutNumber")); 104 | } 105 | } 106 | if (externalPasswordCache == null) { 107 | externalPasswordCache = ExternalPasswordCache 108 | .getExternalPasswordCacheInstance(); 109 | } 110 | if (externalPasswordCache.contains(passwordCmd, timeOut)) { 111 | password = externalPasswordCache.getPassword(passwordCmd); 112 | } else { 113 | password = switchCommandExecution(passwordCmdType, passwordCmd); 114 | if (password != null) { 115 | externalPasswordCache.storePassword(passwordCmd, password); 116 | } 117 | } 118 | } else if (passwordCmdType.startsWith("EXT") || passwordCmdType.startsWith("CMD")) { 119 | // non-cached variant 120 | password = switchCommandExecution(passwordCmdType, passwordCmd); 121 | } else { 122 | throw new IllegalArgumentException(msm.getString("invalidPasswordCommandType", passwordCmdType)); 123 | } 124 | } 125 | return password; 126 | } 127 | 128 | private static char[] switchCommandExecution(String passwordCmdType, String passwordCmd) 129 | throws Exception { 130 | if (passwordCmdType.startsWith("EXT")) 131 | return execPasswordCmd(passwordCmd); 132 | else if (passwordCmdType.startsWith("CMD")) 133 | return execPBBasedPasswordCommand(passwordCmd); 134 | else 135 | throw new IllegalArgumentException(msm.getString("invalidPasswordCommandType", passwordCmdType)); 136 | } 137 | 138 | /** 139 | * Execute a Runtime command to load a password. 140 | * 141 | * @param passwordCmd 142 | * @return 143 | * @throws Exception 144 | */ 145 | private static char[] execPasswordCmd(String passwordCmd) 146 | throws Exception { 147 | log.trace(strm.getString("util.beginExecPasswordCmd", passwordCmd)); 148 | String password = execCmd(passwordCmd); 149 | return password.toCharArray(); 150 | } 151 | 152 | private static String execCmd(String cmd) throws Exception { 153 | SecurityManager sm = System.getSecurityManager(); 154 | String line; 155 | if (sm != null) { 156 | line = RuntimeActions.PRIVILEGED.execCmd(cmd); 157 | } else { 158 | line = RuntimeActions.NON_PRIVILEGED.execCmd(cmd); 159 | } 160 | return line; 161 | } 162 | 163 | /** 164 | * Execute a Runtime command to load a password. 165 | * It uses ProcessBuilder to execute the command. 166 | * 167 | * @param passwordCmd 168 | * @return the loaded password 169 | * @throws Exception 170 | */ 171 | private static char[] execPBBasedPasswordCommand(String passwordCmd) throws Exception { 172 | log.trace(strm.getString("util.beginExecPasswordCmd", passwordCmd)); 173 | SecurityManager sm = System.getSecurityManager(); 174 | String password; 175 | if (sm != null) { 176 | password = RuntimeActions.PB_BASED_PRIVILEGED.execCmd(passwordCmd); 177 | } else { 178 | password = RuntimeActions.PB_BASED_NON_PRIVILEGED.execCmd(passwordCmd); 179 | } 180 | return password.toCharArray(); 181 | } 182 | 183 | 184 | interface RuntimeActions { 185 | RuntimeActions PRIVILEGED = new RuntimeActions() { 186 | public String execCmd(final String cmd) 187 | throws Exception { 188 | try { 189 | String line = AccessController.doPrivileged( 190 | new PrivilegedExceptionAction() { 191 | public String run() throws Exception { 192 | return NON_PRIVILEGED.execCmd(cmd); 193 | } 194 | } 195 | ); 196 | return line; 197 | } catch (PrivilegedActionException e) { 198 | throw e.getException(); 199 | } 200 | } 201 | }; 202 | RuntimeActions NON_PRIVILEGED = new RuntimeActions() { 203 | public String execCmd(final String cmd) 204 | throws Exception { 205 | Runtime rt = Runtime.getRuntime(); 206 | Process p = rt.exec(cmd); 207 | InputStream stdin = null; 208 | String line; 209 | BufferedReader reader = null; 210 | try { 211 | stdin = p.getInputStream(); 212 | reader = new BufferedReader(new InputStreamReader(stdin)); 213 | line = reader.readLine(); 214 | } finally { 215 | if (reader != null) 216 | reader.close(); 217 | if (stdin != null) 218 | stdin.close(); 219 | } 220 | 221 | int exitCode = p.waitFor(); 222 | log.trace(strm.getString("util.endExecPasswordCmd", exitCode)); 223 | return line; 224 | } 225 | }; 226 | RuntimeActions PB_BASED_PRIVILEGED = new RuntimeActions() { 227 | public String execCmd(final String command) 228 | throws Exception { 229 | try { 230 | String password = AccessController.doPrivileged( 231 | new PrivilegedExceptionAction() { 232 | public String run() throws Exception { 233 | return PB_BASED_NON_PRIVILEGED.execCmd(command); 234 | } 235 | } 236 | ); 237 | return password; 238 | } catch (PrivilegedActionException e) { 239 | throw e.getException(); 240 | } 241 | } 242 | }; 243 | RuntimeActions PB_BASED_NON_PRIVILEGED = new RuntimeActions() { 244 | public String execCmd(final String command) throws Exception { 245 | final String[] parsedCommand = parseCommand(command); 246 | final ProcessBuilder builder = new ProcessBuilder(parsedCommand); 247 | final Process process = builder.start(); 248 | final String line; 249 | BufferedReader reader = null; 250 | try { 251 | reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 252 | line = reader.readLine(); 253 | } finally { 254 | if (reader != null) 255 | reader.close(); 256 | } 257 | 258 | int exitCode = process.waitFor(); 259 | log.trace(strm.getString("util.endExecPasswordCmd", exitCode)); 260 | return line; 261 | } 262 | 263 | protected String[] parseCommand(String command) { 264 | // comma can be backslashed 265 | final String[] parsedCommand = command.split("(? 287 | || passwordCmd.startsWith("{CMD}") 288 | || passwordCmd.startsWith("{CMDC")); // it has to be without closing brace to cover :