[jboss-cvs] JBossAS SVN: r114613 - in projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src: main/java/org/jboss/security/auth/spi and 5 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Dec 19 07:38:58 EST 2013
Author: pskopek
Date: 2013-12-19 07:38:58 -0500 (Thu, 19 Dec 2013)
New Revision: 114613
Modified:
projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/Util.java
projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/auth/spi/LdapExtLoginModule.java
projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/mapping/providers/attribute/LdapAttributeMappingProvider.java
projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/plugins/vault/PicketBoxSecurityVault.java
projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/java/org/jboss/test/security/helpers/SecurityUtilUnitTestCase.java
projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/java/org/jboss/test/security/vault/SecurityVaultUnitTestCase.java
projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/resources/bin/askpass.sh
Log:
[SECURITY-774] Enable white-space in parameters for external password command
Modified: projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/Util.java
===================================================================
--- projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/Util.java 2013-12-19 11:41:15 UTC (rev 114612)
+++ projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/Util.java 2013-12-19 12:38:58 UTC (rev 114613)
@@ -37,7 +37,7 @@
/**
* Util.
- *
+ *
* @author Scott.Stark at jboss.org
* @author <a href="adrian at jboss.com">Adrian Brock</a>
* @version $Revision: 1.1 $
@@ -46,7 +46,7 @@
{
private static Logger log = Logger.getLogger(Util.class);
private static PasswordCache externalPasswordCache;
-
+
/**
* Execute a password load command to obtain the char[] contents of a
* password.
@@ -58,7 +58,11 @@
* platform command. The first line of the command output is used as the
* password.
* EXTC variant will cache the passwords for expiration_in_millis milliseconds.
- * Default cache expiration is 0 = infinity.
+ * Default cache expiration is 0 = infinity.
+ * '{CMD}...' or '{CMDC}...' for a general command to execute. The general
+ * command is a string delimited by ',' where the first part is the actual
+ * command and further parts represents its parameters. The comma can be
+ * backslashed in order to keep it as a part of the parameter.
* '{CLASS}classname[:ctorargs]' where the '[:ctorargs]' is an optional
* string delimited by the ':' from the classname that will be passed to the
* classname ctor. The ctorargs itself is a comma delimited list of strings.
@@ -90,7 +94,7 @@
if( password == null )
{
// Load the password
- if (passwordCmdType.startsWith("EXTC")) {
+ if (passwordCmdType.startsWith("EXTC") || passwordCmdType.startsWith("CMDC")) {
long timeOut = 0;
if (passwordCmdType.indexOf(':') > -1) {
try {
@@ -108,14 +112,14 @@
if (externalPasswordCache.contains(passwordCmd, timeOut)) {
password = externalPasswordCache.getPassword(passwordCmd);
} else {
- password = execPasswordCmd(passwordCmd);
+ password = switchCommandExecution(passwordCmdType, passwordCmd);
if (password != null) {
externalPasswordCache.storePassword(passwordCmd, password);
}
}
- } else if (passwordCmdType.startsWith("EXT")) {
- // non-cached EXT variant
- password = execPasswordCmd(passwordCmd);
+ } else if (passwordCmdType.startsWith("EXT") || passwordCmdType.startsWith("CMD")) {
+ // non-cached variant
+ password = switchCommandExecution(passwordCmdType, passwordCmd);
} else if (passwordCmdType.equals("CLASS")) {
password = invokePasswordClass(passwordCmd);
} else {
@@ -125,6 +129,17 @@
return password;
}
+ private static char[] switchCommandExecution(String passwordCmdType, String passwordCmd)
+ throws Exception
+ {
+ if (passwordCmdType.startsWith("EXT"))
+ return execPasswordCmd(passwordCmd);
+ else if (passwordCmdType.startsWith("CMD"))
+ return execPBBasedPasswordCommand(passwordCmd);
+ else
+ throw new IllegalArgumentException("Invalid password command type: " + passwordCmdType);
+ }
+
/**
* Execute a Runtime command to load a password.
* @param passwordCmd
@@ -132,7 +147,7 @@
* @throws Exception
*/
private static char[] execPasswordCmd(String passwordCmd)
- throws Exception
+ throws Exception
{
log.debug("Executing command: "+passwordCmd);
String password = execCmd(passwordCmd);
@@ -140,7 +155,7 @@
}
private static char[] invokePasswordClass(String passwordCmd)
- throws Exception
+ throws Exception
{
char[] password = null;
@@ -219,24 +234,47 @@
return line;
}
-
+ /**
+ * Execute a Runtime command to load a password.
+ * It uses ProcessBuilder to execute the command.
+ * @param passwordCmd
+ * @return the loaded password
+ * @throws Exception
+ */
+ private static char[] execPBBasedPasswordCommand(String passwordCmd) throws Exception
+ {
+ log.debug("Executing command: "+passwordCmd);
+ SecurityManager sm = System.getSecurityManager();
+ String password;
+ if( sm != null )
+ {
+ password = RuntimeActions.PB_BASED_PRIVILEGED.execCmd(passwordCmd);
+ }
+ else
+ {
+ password = RuntimeActions.PB_BASED_NON_PRIVILEGED.execCmd(passwordCmd);
+ }
+ return password.toCharArray();
+ }
+
+
interface RuntimeActions
{
RuntimeActions PRIVILEGED = new RuntimeActions()
{
public String execCmd(final String cmd)
- throws Exception
+ throws Exception
{
try
{
String line = AccessController.doPrivileged(
- new PrivilegedExceptionAction<String>()
- {
- public String run() throws Exception
+ new PrivilegedExceptionAction<String>()
{
- return NON_PRIVILEGED.execCmd(cmd);
+ public String run() throws Exception
+ {
+ return NON_PRIVILEGED.execCmd(cmd);
+ }
}
- }
);
return line;
}
@@ -249,7 +287,7 @@
RuntimeActions NON_PRIVILEGED = new RuntimeActions()
{
public String execCmd(final String cmd)
- throws Exception
+ throws Exception
{
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(cmd);
@@ -275,6 +313,93 @@
return line;
}
};
+ RuntimeActions PB_BASED_PRIVILEGED = new RuntimeActions()
+ {
+ public String execCmd(final String command)
+ throws Exception
+ {
+ try
+ {
+ String password = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<String>()
+ {
+ public String run() throws Exception
+ {
+ return PB_BASED_NON_PRIVILEGED.execCmd(command);
+ }
+ }
+ );
+ return password;
+ }
+ catch(PrivilegedActionException e)
+ {
+ throw e.getException();
+ }
+ }
+ };
+ RuntimeActions PB_BASED_NON_PRIVILEGED = new RuntimeActions()
+ {
+ public String execCmd(final String command) throws Exception
+ {
+ final String[] parsedCommand = parseCommand(command);
+ final ProcessBuilder builder = new ProcessBuilder(parsedCommand);
+ final Process process = builder.start();
+ final String line;
+ BufferedReader reader = null;
+ try
+ {
+ reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ line = reader.readLine();
+ }
+ finally
+ {
+ if (reader != null)
+ reader.close();
+ }
+
+ int exitCode = process.waitFor();
+ log.debug("Command exited with: "+exitCode);
+ return line;
+ }
+
+ protected String[] parseCommand(String command)
+ {
+ // comma can be backslashed
+ final String[] parsedCommand = command.split("(?<!\\\\),");
+ for (int k=0; k < parsedCommand.length; k++)
+ {
+ if (parsedCommand[k].indexOf('\\') != -1)
+ parsedCommand[k] = parsedCommand[k].replaceAll("\\\\,", ",");
+ }
+ return parsedCommand;
+ }
+ };
String execCmd(String cmd) throws Exception;
}
+
+ /**
+ * Checks whether password can be loaded by {@link #loadPassword(String)}.
+ * @param passwordCmd a potential password command
+ * @return true if password can be loaded by {@link #loadPassword(String)}, false otherwise.
+ */
+ public static boolean isPasswordCommand(String passwordCmd)
+ {
+ return (passwordCmd != null)
+ && (passwordCmd.startsWith("{EXT}")
+ || passwordCmd.startsWith("{EXTC}")
+ || passwordCmd.startsWith("{CMD}")
+ || passwordCmd.startsWith("{CMDC}")
+ || passwordCmd.startsWith("{CLASS}"));
+ }
+
+ /**
+ * Checks whether password can be loaded by {@link #loadPassword(String)}.
+ * @param passwordCmd a potential password command
+ * @return true if password can be loaded by {@link #loadPassword(String)}, false otherwise.
+ */
+ public static boolean isPasswordCommand(char[] passwordCmd)
+ {
+ return (passwordCmd != null) && isPasswordCommand(new String(passwordCmd));
+ }
+
}
Modified: projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/auth/spi/LdapExtLoginModule.java
===================================================================
--- projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/auth/spi/LdapExtLoginModule.java 2013-12-19 11:41:15 UTC (rev 114612)
+++ projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/auth/spi/LdapExtLoginModule.java 2013-12-19 12:38:58 UTC (rev 114613)
@@ -383,7 +383,7 @@
{
bindDN = (String) options.get(BIND_DN);
bindCredential = (String) options.get(BIND_CREDENTIAL);
- if ((bindCredential != null) && bindCredential.startsWith("{EXT}"))
+ if ((bindCredential != null) && Util.isPasswordCommand(bindCredential))
bindCredential = new String(Util.loadPassword(bindCredential));
String securityDomain = (String) options.get(SECURITY_DOMAIN_OPT);
if (securityDomain != null)
Modified: projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/mapping/providers/attribute/LdapAttributeMappingProvider.java
===================================================================
--- projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/mapping/providers/attribute/LdapAttributeMappingProvider.java 2013-12-19 11:41:15 UTC (rev 114612)
+++ projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/mapping/providers/attribute/LdapAttributeMappingProvider.java 2013-12-19 12:38:58 UTC (rev 114613)
@@ -139,7 +139,7 @@
return;
}
String bindCredential = (String) options.get(BIND_CREDENTIAL);
- if (bindCredential.startsWith("{EXT}"))
+ if (org.jboss.security.Util.isPasswordCommand(bindCredential))
try
{
bindCredential = new String(org.jboss.security.Util.loadPassword(bindCredential));
Modified: projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/plugins/vault/PicketBoxSecurityVault.java
===================================================================
--- projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/plugins/vault/PicketBoxSecurityVault.java 2013-12-19 11:41:15 UTC (rev 114612)
+++ projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/main/java/org/jboss/security/plugins/vault/PicketBoxSecurityVault.java 2013-12-19 12:38:58 UTC (rev 114613)
@@ -70,6 +70,10 @@
* password.
* EXTC variant will cache the passwords for expiration_in_millis milliseconds.
* Default cache expiration is 0 = infinity.
+ * '{CMD}...' or '{CMDC}...' for a general command to execute. The general
+ * command is a string delimited by ',' where the first part is the actual
+ * command and further parts represents its parameters. The comma can be
+ * backslashed in order to keep it as the part of a parameter.
* '{CLASS}classname[:ctorargs]' where the '[:ctorargs]' is an optional
* string delimited by the ':' from the classname that will be passed to the
* classname ctor. The ctorargs itself is a comma delimited list of strings.
@@ -125,10 +129,6 @@
public static final String PASS_MASK_PREFIX = "MASK-";
- public static final String PASS_CLASS_PREFIX = "{CLASS}";
-
- public static final String PASS_EXT_PREFIX = "{EXT";
-
public static final String PUBLIC_CERT = "PUBLIC_CERT";
public static final String KEY_SIZE = "KEY_SIZE";
@@ -169,9 +169,8 @@
if(password == null)
throw new SecurityVaultException("Option " + KEYSTORE_PASSWORD + "is null or empty");
if(password.startsWith(PASS_MASK_PREFIX) == false
- && password.startsWith(PASS_EXT_PREFIX) == false
- && password.startsWith(PASS_CLASS_PREFIX) == false)
- throw new SecurityVaultException("Keystore password should be either masked or prefixed with {EXT} or {CLASS}");
+ && Util.isPasswordCommand(password) == false)
+ throw new SecurityVaultException("Keystore password should be either masked or prefixed with one of {EXT}, {EXTC}, {CMD}, {CMDC}, {CLASS}");
String salt = (String) options.get(SALT);
if(salt == null)
Modified: projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/java/org/jboss/test/security/helpers/SecurityUtilUnitTestCase.java
===================================================================
--- projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/java/org/jboss/test/security/helpers/SecurityUtilUnitTestCase.java 2013-12-19 11:41:15 UTC (rev 114612)
+++ projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/java/org/jboss/test/security/helpers/SecurityUtilUnitTestCase.java 2013-12-19 12:38:58 UTC (rev 114613)
@@ -172,8 +172,39 @@
}
+ /**
+ * Test {CMD}org.jboss.test.security.helpers.ExecPasswordCmd
+ * @throws Exception
+ */
+ public void testCmdPassword() throws Exception
+ {
+ String passwordCmd = buildExtCommand("CMD", ',');
+ log.info("Executing password command:" + passwordCmd);
+ char[] password = Util.loadPassword(passwordCmd);
+ assertTrue("password3", Arrays.equals(password, "password3".toCharArray()));
+ String passwordCmdWithParam = passwordCmd + ",Parameter 1";
+ log.info("Executing password command:" + passwordCmdWithParam);
+ password = Util.loadPassword(passwordCmdWithParam);
+ assertTrue("passwordParameter 1", Arrays.equals(password, "passwordParameter 1".toCharArray()));
+
+ passwordCmdWithParam = passwordCmd + ",Parameter\\,1";
+ log.info("Executing password command:" + passwordCmdWithParam);
+ password = Util.loadPassword(passwordCmdWithParam);
+ assertTrue("passwordParameter,1", Arrays.equals(password, "passwordParameter,1".toCharArray()));
+
+ String passwordCmdWithTwoParams = passwordCmd + ",Parameter,1";
+ log.info("Executing password command:" + passwordCmdWithTwoParams);
+ password = Util.loadPassword(passwordCmdWithTwoParams);
+ assertTrue("passwordParameter", Arrays.equals(new String(password).substring(0, "passwordParameter".length()).toCharArray(), "passwordParameter".toCharArray()));
+ assertTrue("passwordParameter", new String(password).substring("passwordParameter".length()).matches("^\\d+$"));
+ }
+
private String buildExtCommand(String extOption) {
+ return buildExtCommand(extOption, ' ');
+ }
+
+ private String buildExtCommand(String extOption, char delim) {
// First check for java.exe or java as the binary
File java = new File(System.getProperty("java.home"), "/bin/java");
File javaExe = new File(System.getProperty("java.home"), "/bin/java.exe");
@@ -184,10 +215,10 @@
jre = javaExe.getAbsolutePath();
// Build the command to run this jre
String cmd = jre
- + " -cp "+System.getProperty("java.class.path")
- + " org.jboss.test.security.helpers.ExecPasswordCmd";
-
+ + delim + "-cp" + delim + System.getProperty("java.class.path")
+ + delim + "org.jboss.test.security.helpers.ExecPasswordCmd";
+
return "{" + extOption +"}"+cmd;
}
-
+
}
Modified: projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/java/org/jboss/test/security/vault/SecurityVaultUnitTestCase.java
===================================================================
--- projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/java/org/jboss/test/security/vault/SecurityVaultUnitTestCase.java 2013-12-19 11:41:15 UTC (rev 114612)
+++ projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/java/org/jboss/test/security/vault/SecurityVaultUnitTestCase.java 2013-12-19 12:38:58 UTC (rev 114613)
@@ -23,6 +23,7 @@
import junit.framework.TestCase;
+import org.jboss.security.Util;
import org.jboss.security.plugins.PBEUtils;
import org.jboss.security.vault.SecurityVault;
import org.jboss.security.vault.SecurityVaultException;
@@ -218,7 +219,7 @@
Map<String,Object> options = getVaultOptionsMap(
"target/vaults/vault2/vault.jks",
"target/vaults/vault2/vault_data",
- "vault", "12438567", 50, "{EXT}/bin/sh " + absolutePathToAskPass + " Enter passphrase for askpass test");
+ "vault", "12438567", 50, "{CMD}/bin/sh," + absolutePathToAskPass + ",Enter passphrase for askpass test");
String vaultBlock = "aBlock";
String attributeName = "anAttribute";
@@ -437,8 +438,7 @@
private String getMaskedPassword(String pwd, String salt, int iterationCount) throws Exception
{
- if (pwd.startsWith(PicketBoxSecurityVault.PASS_EXT_PREFIX)
- || pwd.startsWith(PicketBoxSecurityVault.PASS_CLASS_PREFIX))
+ if (Util.isPasswordCommand(pwd))
return pwd;
String algo = "PBEwithMD5andDES";
Modified: projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/resources/bin/askpass.sh
===================================================================
--- projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/resources/bin/askpass.sh 2013-12-19 11:41:15 UTC (rev 114612)
+++ projects/security/security-jboss-sx/branches/Branch_2_0/jbosssx/src/test/resources/bin/askpass.sh 2013-12-19 12:38:58 UTC (rev 114613)
@@ -1,2 +1,7 @@
#!/bin/sh
-echo vault22
\ No newline at end of file
+
+if [ "$1" = "Enter passphrase for askpass test" ]; then
+ echo vault22
+else
+ echo $1
+fi
More information about the jboss-cvs-commits
mailing list