mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	utils,ui: obfuscate sensitive log info, use POST for configureOutOfBandManagement (#9126)
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
		
							parent
							
								
									87b55af197
								
							
						
					
					
						commit
						d77998c2d4
					
				| @ -150,6 +150,7 @@ export default { | ||||
|       message: 'label.outofbandmanagement.configure', | ||||
|       docHelp: 'adminguide/hosts.html#out-of-band-management', | ||||
|       dataView: true, | ||||
|       post: true, | ||||
|       args: ['hostid', 'address', 'port', 'username', 'password', 'driver'], | ||||
|       mapping: { | ||||
|         hostid: { | ||||
|  | ||||
| @ -19,13 +19,9 @@ | ||||
| 
 | ||||
| package org.apache.cloudstack.utils.process; | ||||
| 
 | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.common.io.CharStreams; | ||||
| import org.apache.log4j.Logger; | ||||
| import org.joda.time.Duration; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.Callable; | ||||
| import java.util.concurrent.ExecutionException; | ||||
| @ -33,7 +29,16 @@ import java.util.concurrent.ExecutorService; | ||||
| import java.util.concurrent.Future; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import java.util.concurrent.TimeoutException; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.apache.log4j.Logger; | ||||
| import org.joda.time.Duration; | ||||
| 
 | ||||
| import com.cloud.utils.Ternary; | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.common.io.CharStreams; | ||||
| 
 | ||||
| public final class ProcessRunner { | ||||
|     public static final Logger LOG = Logger.getLogger(ProcessRunner.class); | ||||
| @ -41,9 +46,26 @@ public final class ProcessRunner { | ||||
|     // Default maximum timeout of 5 minutes for any command | ||||
|     public static final Duration DEFAULT_MAX_TIMEOUT = new Duration(5 * 60 * 1000); | ||||
|     private final ExecutorService executor; | ||||
|     private final List<Ternary<String, String, String>> commandLogReplacements = new ArrayList<>(); | ||||
| 
 | ||||
|     String removeCommandSensitiveInfoForLogging(String command) { | ||||
|         String commandLog = command.trim(); | ||||
| 
 | ||||
|         for (Ternary<String, String, String> replacement : commandLogReplacements) { | ||||
|             if (commandLog.contains(replacement.first())) { | ||||
|                 Pattern pattern = Pattern.compile(replacement.second()); | ||||
|                 Matcher matcher = pattern.matcher(commandLog); | ||||
|                 if (matcher.find()) { | ||||
|                     commandLog = matcher.replaceAll(replacement.third()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return commandLog; | ||||
|     } | ||||
| 
 | ||||
|     public ProcessRunner(ExecutorService executor) { | ||||
|         this.executor = executor; | ||||
|         commandLogReplacements.add(new Ternary<>("ipmitool", "-P\\s+\\S+", "-P *****")); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -72,14 +94,13 @@ public final class ProcessRunner { | ||||
|         int retVal = -2; | ||||
|         String stdOutput = null; | ||||
|         String stdError = null; | ||||
| 
 | ||||
|         String oneLineCommand = StringUtils.join(commands, " "); | ||||
|         String commandLog = removeCommandSensitiveInfoForLogging(StringUtils.join(commands, " ")); | ||||
| 
 | ||||
|         try { | ||||
|             LOG.debug(String.format("Preparing command [%s] to execute.", oneLineCommand)); | ||||
|             LOG.debug(String.format("Preparing command [%s] to execute.", commandLog)); | ||||
|             final Process process = new ProcessBuilder().command(commands).start(); | ||||
| 
 | ||||
|             LOG.debug(String.format("Submitting command [%s].", oneLineCommand)); | ||||
|             LOG.debug(String.format("Submitting command [%s].", commandLog)); | ||||
|             final Future<Integer> processFuture = executor.submit(new Callable<Integer>() { | ||||
|                 @Override | ||||
|                 public Integer call() throws Exception { | ||||
| @ -87,14 +108,14 @@ public final class ProcessRunner { | ||||
|                 } | ||||
|             }); | ||||
|             try { | ||||
|                 LOG.debug(String.format("Waiting for a response from command [%s]. Defined timeout: [%s].", oneLineCommand, timeOut.getStandardSeconds())); | ||||
|                 LOG.debug(String.format("Waiting for a response from command [%s]. Defined timeout: [%s].", commandLog, timeOut.getStandardSeconds())); | ||||
|                 retVal = processFuture.get(timeOut.getStandardSeconds(), TimeUnit.SECONDS); | ||||
|             } catch (ExecutionException e) { | ||||
|                 LOG.warn(String.format("Failed to complete the requested command [%s] due to execution error.", oneLineCommand), e); | ||||
|                 LOG.warn(String.format("Failed to complete the requested command [%s] due to execution error.", commands), e); | ||||
|                 retVal = -2; | ||||
|                 stdError = e.getMessage(); | ||||
|             } catch (TimeoutException e) { | ||||
|                 LOG.warn(String.format("Failed to complete the requested command [%s] within timeout. Defined timeout: [%s].", oneLineCommand, timeOut.getStandardSeconds()), e); | ||||
|                 LOG.warn(String.format("Failed to complete the requested command [%s] within timeout. Defined timeout: [%s].", commandLog, timeOut.getStandardSeconds()), e); | ||||
|                 retVal = -1; | ||||
|                 stdError = "Operation timed out, aborted."; | ||||
|             } finally { | ||||
| @ -105,10 +126,10 @@ public final class ProcessRunner { | ||||
|                 process.destroy(); | ||||
|             } | ||||
| 
 | ||||
|             LOG.debug(String.format("Process standard output for command [%s]: [%s].", oneLineCommand, stdOutput)); | ||||
|             LOG.debug(String.format("Process standard error output command [%s]: [%s].", oneLineCommand, stdError)); | ||||
|             LOG.debug(String.format("Process standard output for command [%s]: [%s].", commandLog, stdOutput)); | ||||
|             LOG.debug(String.format("Process standard error output command [%s]: [%s].", commandLog, stdError)); | ||||
|         } catch (IOException | InterruptedException e) { | ||||
|             LOG.error(String.format("Exception caught error running command [%s].", oneLineCommand), e); | ||||
|             LOG.error(String.format("Exception caught error running command [%s].", commandLog), e); | ||||
|             stdError = e.getMessage(); | ||||
|         } | ||||
|         return new ProcessResult(stdOutput, stdError, retVal); | ||||
|  | ||||
| @ -0,0 +1,63 @@ | ||||
| // Licensed to the Apache Software Foundation (ASF) under one | ||||
| // or more contributor license agreements.  See the NOTICE file | ||||
| // distributed with this work for additional information | ||||
| // regarding copyright ownership.  The ASF licenses this file | ||||
| // to you under the Apache License, Version 2.0 (the | ||||
| // "License"); you may not use this file except in compliance | ||||
| // with the License.  You may obtain a copy of the License at | ||||
| // | ||||
| //   http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, | ||||
| // software distributed under the License is distributed on an | ||||
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||
| // KIND, either express or implied.  See the License for the | ||||
| // specific language governing permissions and limitations | ||||
| // under the License. | ||||
| 
 | ||||
| package org.apache.cloudstack.utils.process; | ||||
| 
 | ||||
| import java.util.concurrent.ExecutorService; | ||||
| 
 | ||||
| import org.junit.Assert; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| import org.mockito.InjectMocks; | ||||
| import org.mockito.Mockito; | ||||
| import org.mockito.junit.MockitoJUnitRunner; | ||||
| 
 | ||||
| @RunWith(MockitoJUnitRunner.class) | ||||
| public class ProcessRunnerTest { | ||||
| 
 | ||||
|     @InjectMocks | ||||
|     ProcessRunner processRunner = new ProcessRunner(Mockito.mock(ExecutorService.class)); | ||||
| 
 | ||||
|     private int countSubstringOccurrences(String mainString, String subString) { | ||||
|         int count = 0; | ||||
|         int index = 0; | ||||
|         while ((index = mainString.indexOf(subString, index)) != -1) { | ||||
|             count++; | ||||
|             index += subString.length(); | ||||
|         } | ||||
|         return count; | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void testRemoveCommandSensitiveInfoForLoggingIpmi() { | ||||
|         String password = "R@ndomP@ss"; | ||||
|         String command = String.format("/usr/bin/ipmitool -H host -p 1234 -U Admin " + | ||||
|                 "-P %s chassis power status", password); | ||||
|         String log = processRunner.removeCommandSensitiveInfoForLogging(command); | ||||
|         Assert.assertFalse(log.contains(password)); | ||||
| 
 | ||||
|         String command1 = String.format("%s -D %s", command, password); | ||||
|         log = processRunner.removeCommandSensitiveInfoForLogging(command1); | ||||
|         Assert.assertTrue(log.contains(password)); | ||||
|         Assert.assertEquals(1, countSubstringOccurrences(log, password)); | ||||
| 
 | ||||
|         String command2 = command.replace("ipmitool", "impit00l"); | ||||
|         log = processRunner.removeCommandSensitiveInfoForLogging(command2); | ||||
|         Assert.assertTrue(log.contains(password)); | ||||
|         Assert.assertEquals(1, countSubstringOccurrences(log, password)); | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user