mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-16 10:32:34 +01:00
Merge release branch 4.20 to 4.22
* 4.20: fixed Password Exposure in IPMI Tool Command Execution (#12028) server: fix volume offering not updated after offering change (#12003) fix API Request Parameters Logged Credential Masking in ApiServer (#12020)
This commit is contained in:
commit
e23c7ef701
@ -39,6 +39,7 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@ -251,6 +252,12 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
|||||||
@Inject
|
@Inject
|
||||||
private MessageBus messageBus;
|
private MessageBus messageBus;
|
||||||
|
|
||||||
|
private static final Set<String> sensitiveFields = new HashSet<>(Arrays.asList(
|
||||||
|
"password", "secretkey", "apikey", "token",
|
||||||
|
"sessionkey", "accesskey", "signature",
|
||||||
|
"authorization", "credential", "secret"
|
||||||
|
));
|
||||||
|
|
||||||
private static final ConfigKey<Integer> IntegrationAPIPort = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED
|
private static final ConfigKey<Integer> IntegrationAPIPort = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED
|
||||||
, Integer.class
|
, Integer.class
|
||||||
, "integration.api.port"
|
, "integration.api.port"
|
||||||
@ -624,10 +631,23 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
|||||||
logger.error("invalid request, no command sent");
|
logger.error("invalid request, no command sent");
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("dumping request parameters");
|
logger.trace("dumping request parameters");
|
||||||
for (final Object key : params.keySet()) {
|
|
||||||
final String keyStr = (String)key;
|
for (final Object key : params.keySet()) {
|
||||||
final String[] value = (String[])params.get(key);
|
final String keyStr = (String) key;
|
||||||
logger.trace(" key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value[0]));
|
final String[] value = (String[]) params.get(key);
|
||||||
|
|
||||||
|
String lowerKeyStr = keyStr.toLowerCase();
|
||||||
|
boolean isSensitive = sensitiveFields.stream()
|
||||||
|
.anyMatch(lowerKeyStr::contains);
|
||||||
|
|
||||||
|
String logValue;
|
||||||
|
if (isSensitive) {
|
||||||
|
logValue = "******"; // mask sensitive values
|
||||||
|
} else {
|
||||||
|
logValue = (value == null) ? "'null'" : value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.trace(" key: " + keyStr + ", value: " + logValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent");
|
throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent");
|
||||||
|
|||||||
@ -1578,6 +1578,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volume = _volsDao.findById(volumeId);
|
||||||
if (newDiskOfferingId != null) {
|
if (newDiskOfferingId != null) {
|
||||||
volume.setDiskOfferingId(newDiskOfferingId);
|
volume.setDiskOfferingId(newDiskOfferingId);
|
||||||
_volumeMgr.saveVolumeDetails(newDiskOfferingId, volume.getId());
|
_volumeMgr.saveVolumeDetails(newDiskOfferingId, volume.getId());
|
||||||
@ -1592,7 +1593,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update size if volume has same size as before, else it is already updated
|
// Update size if volume has same size as before, else it is already updated
|
||||||
volume = _volsDao.findById(volumeId);
|
|
||||||
if (currentSize == volume.getSize() && currentSize != newSize) {
|
if (currentSize == volume.getSize() && currentSize != newSize) {
|
||||||
volume.setSize(newSize);
|
volume.setSize(newSize);
|
||||||
} else if (volume.getSize() != newSize) {
|
} else if (volume.getSize() != newSize) {
|
||||||
|
|||||||
@ -3121,7 +3121,7 @@
|
|||||||
"message.change.offering.confirm": "Please confirm that you wish to change the service offering of this virtual Instance.",
|
"message.change.offering.confirm": "Please confirm that you wish to change the service offering of this virtual Instance.",
|
||||||
"message.change.offering.for.volume": "Successfully changed offering for the volume",
|
"message.change.offering.for.volume": "Successfully changed offering for the volume",
|
||||||
"message.change.offering.for.volume.failed": "Change offering for the volume failed",
|
"message.change.offering.for.volume.failed": "Change offering for the volume failed",
|
||||||
"message.change.offering.processing": "Changing offering for the volume...",
|
"message.change.offering.for.volume.processing": "Changing offering for the volume...",
|
||||||
"message.change.password": "Please change your password.",
|
"message.change.password": "Please change your password.",
|
||||||
"message.change.scope.failed": "Scope change failed",
|
"message.change.scope.failed": "Scope change failed",
|
||||||
"message.change.scope.processing": "Scope change in progress",
|
"message.change.scope.processing": "Scope change in progress",
|
||||||
|
|||||||
@ -67,11 +67,13 @@ public final class ProcessRunner {
|
|||||||
public ProcessRunner(ExecutorService executor) {
|
public ProcessRunner(ExecutorService executor) {
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
commandLogReplacements.add(new Ternary<>("ipmitool", "-P\\s+\\S+", "-P *****"));
|
commandLogReplacements.add(new Ternary<>("ipmitool", "-P\\s+\\S+", "-P *****"));
|
||||||
|
commandLogReplacements.add(new Ternary<>("ipmitool", "(?i)password\\s+\\S+\\s+\\S+", "password **** ****"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes a process with provided list of commands with a max default timeout
|
* Executes a process with provided list of commands with a max default timeout
|
||||||
* of 5 minutes
|
* of 5 minutes
|
||||||
|
*
|
||||||
* @param commands list of string commands
|
* @param commands list of string commands
|
||||||
* @return returns process result
|
* @return returns process result
|
||||||
*/
|
*/
|
||||||
@ -82,6 +84,7 @@ public final class ProcessRunner {
|
|||||||
/**
|
/**
|
||||||
* Executes a process with provided list of commands with a given timeout that is less
|
* Executes a process with provided list of commands with a given timeout that is less
|
||||||
* than or equal to DEFAULT_MAX_TIMEOUT
|
* than or equal to DEFAULT_MAX_TIMEOUT
|
||||||
|
*
|
||||||
* @param commands list of string commands
|
* @param commands list of string commands
|
||||||
* @param timeOut timeout duration
|
* @param timeOut timeout duration
|
||||||
* @return returns process result
|
* @return returns process result
|
||||||
@ -109,14 +112,16 @@ public final class ProcessRunner {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
logger.debug("Waiting for a response from command [{}]. Defined timeout: [{}].", commandLog, timeOut.getStandardSeconds());
|
logger.debug("Waiting for a response from command [{}]. Defined timeout: [{}].", commandLog,
|
||||||
|
timeOut.getStandardSeconds());
|
||||||
retVal = processFuture.get(timeOut.getStandardSeconds(), TimeUnit.SECONDS);
|
retVal = processFuture.get(timeOut.getStandardSeconds(), TimeUnit.SECONDS);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
logger.warn("Failed to complete the requested command [{}] due to execution error.", commands, e);
|
logger.warn("Failed to complete the requested command [{}] due to execution error.", commandLog, e);
|
||||||
retVal = -2;
|
retVal = -2;
|
||||||
stdError = e.getMessage();
|
stdError = e.getMessage();
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
logger.warn("Failed to complete the requested command [{}] within timeout. Defined timeout: [{}].", commandLog, timeOut.getStandardSeconds(), e);
|
logger.warn("Failed to complete the requested command [{}] within timeout. Defined timeout: [{}].",
|
||||||
|
commandLog, timeOut.getStandardSeconds(), e);
|
||||||
retVal = -1;
|
retVal = -1;
|
||||||
stdError = "Operation timed out, aborted.";
|
stdError = "Operation timed out, aborted.";
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -60,4 +60,16 @@ public class ProcessRunnerTest {
|
|||||||
Assert.assertTrue(log.contains(password));
|
Assert.assertTrue(log.contains(password));
|
||||||
Assert.assertEquals(1, countSubstringOccurrences(log, password));
|
Assert.assertEquals(1, countSubstringOccurrences(log, password));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveCommandSensitiveInfoForLoggingIpmiPasswordCommand() {
|
||||||
|
String userId = "3";
|
||||||
|
String newPassword = "Sup3rSecr3t!";
|
||||||
|
String command = String.format("/usr/bin/ipmitool user set password %s %s", userId, newPassword);
|
||||||
|
String log = processRunner.removeCommandSensitiveInfoForLogging(command);
|
||||||
|
|
||||||
|
Assert.assertFalse(log.contains(userId));
|
||||||
|
Assert.assertFalse(log.contains(newPassword));
|
||||||
|
Assert.assertTrue(log.contains("password **** ****"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user