Author: pmouawad Date: Tue Nov 7 08:25:42 2017 New Revision: 1814464 URL: http://svn.apache.org/viewvc?rev=1814464&view=rev Log: Bug 61724 - Add __digest function to provide computing of Hashes (SHA-XXX, MDX) Bugzilla Id: 61724
Added: jmeter/trunk/src/functions/org/apache/jmeter/functions/DigestEncode.java (with props) Modified: jmeter/trunk/src/core/org/apache/jmeter/functions/AbstractFunction.java jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties jmeter/trunk/xdocs/changes.xml jmeter/trunk/xdocs/usermanual/functions.xml Modified: jmeter/trunk/src/core/org/apache/jmeter/functions/AbstractFunction.java URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/functions/AbstractFunction.java?rev=1814464&r1=1814463&r2=1814464&view=diff ============================================================================== --- jmeter/trunk/src/core/org/apache/jmeter/functions/AbstractFunction.java (original) +++ jmeter/trunk/src/core/org/apache/jmeter/functions/AbstractFunction.java Tue Nov 7 08:25:42 2017 @@ -20,6 +20,7 @@ package org.apache.jmeter.functions; import java.util.Collection; +import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.engine.util.CompoundVariable; import org.apache.jmeter.samplers.SampleResult; import org.apache.jmeter.samplers.Sampler; @@ -140,4 +141,23 @@ public abstract class AbstractFunction i ); } } + + /** + * Utility method to store value in a variable + * + * @param value value of variable to update + * @param values array of {@link CompoundVariable} from which variable name will be extracted + * @param index index of variable in values array + */ + protected final void addVariableValue(String value, CompoundVariable[] values, int index) { + if (values.length > index) { + String variableName = values[index].execute().trim(); + if (StringUtils.isNotEmpty(variableName)) { + JMeterVariables vars = getVariables(); + if (vars != null) { + vars.put(variableName, value); + } + } + } + } } Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1814464&r1=1814463&r2=1814464&view=diff ============================================================================== --- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original) +++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Tue Nov 7 08:25:42 2017 @@ -95,6 +95,7 @@ aggregate_report_rate=Throughput aggregate_report_stddev=Std. Dev. aggregate_report_total_label=TOTAL ajp_sampler_title=AJP/1.3 Sampler +algorithm_string=Digest algorithm als_message=Note\: The Access Log Parser is generic in design and allows you to plugin als_message2=your own parser. To do so, implement the LogParser, add the jar to the als_message3=/lib directory and enter the class in the sampler. @@ -934,6 +935,7 @@ run_threadgroup_no_timers=Start no pause running_test=Running test runtime_controller_title=Runtime Controller runtime_seconds=Runtime (seconds) +salt_string=Salt to be used for hashing (optional) sample_result_save_configuration=Sample Result Save Configuration sample_scope=Apply to: sample_scope_all=Main sample and sub-samples @@ -1024,6 +1026,7 @@ server=Server Name or IP\: servername=Servername \: session_argument_name=Session Argument Name setup_thread_group_title=setUp Thread Group +sha_string=String to be hashed should_save=You should save your test plan before running it. \nIf you are using supporting data files (ie, for CSV Data Set or __StringFromFile), \nthen it is particularly important to first save your test script. \nDo you want to save your test plan first? shutdown=Shutdown simple_config_element=Simple Config Element @@ -1224,6 +1227,7 @@ update=Update update_per_iter=Update Once Per Iteration upload=File Upload upper_bound=Upper Bound +upper_case=Upper case result, defaults to false (optional) url=URL url_config_get=GET url_config_http=HTTP Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1814464&r1=1814463&r2=1814464&view=diff ============================================================================== --- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original) +++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Tue Nov 7 08:25:42 2017 @@ -90,6 +90,7 @@ aggregate_report_xx_pct1_line={0}% centi aggregate_report_xx_pct2_line={0}% centile aggregate_report_xx_pct3_line={0}% centile ajp_sampler_title=Requ\u00EAte AJP/1.3 +algorithm_string=Algorithm de hash als_message=Note \: Le parseur de log d'acc\u00E8s est g\u00E9n\u00E9rique et vous permet de se brancher \u00E0 als_message2=votre propre parseur. Pour se faire, impl\u00E9menter le LogParser, ajouter le jar au als_message3=r\u00E9pertoire /lib et entrer la classe (fichier .class) dans l'\u00E9chantillon (sampler). @@ -924,6 +925,7 @@ run_threadgroup_no_timers=Lancer sans pa running_test=Lancer test runtime_controller_title=Contr\u00F4leur Dur\u00E9e d'ex\u00E9cution runtime_seconds=Temps d'ex\u00E9cution (secondes) \: +salt_string=Sel \u00e0 utiliser pour le hash sample_result_save_configuration=Sauvegarder la configuration de la sauvegarde des \u00E9chantillons sample_scope=Appliquer sur sample_scope_all=L'\u00E9chantillon et ses ressources li\u00E9es @@ -1014,6 +1016,7 @@ server=Nom ou IP du serveur \: servername=Nom du serveur \: session_argument_name=Nom des arguments de la session setup_thread_group_title=Groupe d'unit\u00E9s de d\u00E9but +sha_string=Sel \u00e0 utiliser pour le hash should_save=Vous devez enregistrer le plan de test avant de le lancer. \nSi vous utilisez des fichiers de donn\u00E9es (i.e. Source de donn\u00E9es CSV ou la fonction __StringFromFile), \nalors c'est particuli\u00E8rement important d'enregistrer d'abord votre script de test. \nVoulez-vous enregistrer maintenant votre plan de test ? shutdown=Eteindre simple_config_element=Configuration Simple @@ -1214,6 +1217,7 @@ update=Mettre \u00E0 jour update_per_iter=Mettre \u00E0 jour une fois par it\u00E9ration upload=Fichier \u00E0 uploader upper_bound=Borne sup\u00E9rieure +upper_case=R\u00e9sultat en majuscules, par d\u00e9faut \u00e0 false (facultatif) url=URL url_config_get=GET url_config_http=HTTP Added: jmeter/trunk/src/functions/org/apache/jmeter/functions/DigestEncode.java URL: http://svn.apache.org/viewvc/jmeter/trunk/src/functions/org/apache/jmeter/functions/DigestEncode.java?rev=1814464&view=auto ============================================================================== --- jmeter/trunk/src/functions/org/apache/jmeter/functions/DigestEncode.java (added) +++ jmeter/trunk/src/functions/org/apache/jmeter/functions/DigestEncode.java Tue Nov 7 08:25:42 2017 @@ -0,0 +1,134 @@ +/* + * 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.jmeter.functions; + +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.StringUtils; +import org.apache.jmeter.engine.util.CompoundVariable; +import org.apache.jmeter.functions.AbstractFunction; +import org.apache.jmeter.functions.InvalidVariableException; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.samplers.Sampler; +import org.apache.jmeter.util.JMeterUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +/** + * Digest Encode Function that provides computing of different SHA-XXX, can + * uppercase the result and store it in a variable.<br/> + * Algorithm names can be specified using MessageDigest Algorithms names at + * <a href= + * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html" + * >StandardNames</a> + * + * @since 4.0 + */ +public class DigestEncode extends AbstractFunction { + + private static final Logger log = LoggerFactory.getLogger(DigestEncode.class); + private static final String UTF_8 = "UTF-8"; + + /** + * The algorithm names in this section can be specified when generating an + * instance of MessageDigest: MD5 SHA-1 SHA-256 SHA-384 SHA-512 + */ + private static final List<String> desc = new LinkedList<>(); + private static final String KEY = "__digest"; + + // Number of parameters expected - used to reject invalid calls + private static final int MIN_PARAMETER_COUNT = 2; + private static final int MAX_PARAMETER_COUNT = 5; + + static { + desc.add(JMeterUtils.getResString("algorithm_string")); + desc.add(JMeterUtils.getResString("sha_string")); + desc.add(JMeterUtils.getResString("salt_string")); + desc.add(JMeterUtils.getResString("upper_case")); + desc.add(JMeterUtils.getResString("function_name_paropt")); + } + + private CompoundVariable[] values; + + @Override + public String execute(SampleResult previousResult, Sampler currentSampler) throws InvalidVariableException { + String digestAlgorithm = values[0].execute(); + String stringToEncode = values[1].execute(); + String salt = null; + if (values.length > 2) { + salt = values[2].execute(); + } + String encodedString = null; + try { + MessageDigest md = MessageDigest.getInstance(digestAlgorithm); + md.update(stringToEncode.getBytes(UTF_8)); + if (StringUtils.isNotEmpty(salt)) { + md.update(salt.getBytes(UTF_8)); + } + byte[] bytes = md.digest(); + encodedString = uppercase(new String(Hex.encodeHex(bytes)), values, 3); + addVariableValue(encodedString, values, 4); + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + log.error("Error calling {} function with value {}, digest algorithm {}, salt {}, ", KEY, stringToEncode, + digestAlgorithm, salt, e); + } + return encodedString; + } + + /** + * Upper case value if optional parameter value is true + * + * @param encodedString + * @param index + * @return + */ + private String uppercase(String encodedString, CompoundVariable[] values, int index) { + if (values.length > index) { + String shouldUpperCase = values[index].execute(); + boolean shouldDoUpperCase = Boolean.TRUE.toString().equalsIgnoreCase(shouldUpperCase); + if (shouldDoUpperCase) { + return encodedString.toUpperCase(); + } + } + return encodedString; + } + + @Override + public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException { + checkParameterCount(parameters, MIN_PARAMETER_COUNT, MAX_PARAMETER_COUNT); + values = parameters.toArray(new CompoundVariable[parameters.size()]); + } + + @Override + public String getReferenceKey() { + return KEY; + } + + @Override + public List<String> getArgumentDesc() { + return desc; + } +} \ No newline at end of file Propchange: jmeter/trunk/src/functions/org/apache/jmeter/functions/DigestEncode.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jmeter/trunk/src/functions/org/apache/jmeter/functions/DigestEncode.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: jmeter/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1814464&r1=1814463&r2=1814464&view=diff ============================================================================== --- jmeter/trunk/xdocs/changes.xml [utf-8] (original) +++ jmeter/trunk/xdocs/changes.xml [utf-8] Tue Nov 7 08:25:42 2017 @@ -118,6 +118,7 @@ Summary <ul> <li><bug>61561</bug>Function helper dialog should display exception in result</li> <li><bug>61593</bug>Remove Detail, Add, Add from Clipboard, Delete buttons in Function Helper GUI</li> + <li><bug>61724</bug>Add <code>__digest</code> function to provide computing of Hashes (SHA-XXX, MDX). Based on a contribution by orimarko at gmail.com</li> </ul> <h3>I18N</h3> @@ -222,6 +223,7 @@ Summary <li>Vincent Herilier (https://github.com/vherilier)</li> <li>Aleksei Balan (abalanonline at gmail.com)</li> <li>Graham Russell (graham at ham1.co.uk)</li> + <li>orimarko at gmail.com</li> </ul> <p>We also thank bug reporters who helped us improve JMeter. <br/> For this release we want to give special thanks to the following reporters for the clear reports and tests made after our fixes:</p> Modified: jmeter/trunk/xdocs/usermanual/functions.xml URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/functions.xml?rev=1814464&r1=1814463&r2=1814464&view=diff ============================================================================== --- jmeter/trunk/xdocs/usermanual/functions.xml (original) +++ jmeter/trunk/xdocs/usermanual/functions.xml Tue Nov 7 08:25:42 2017 @@ -120,6 +120,7 @@ Alternatively, just use <code>/</code> i <tr><td>Input</td><td> <a href="#__CSVRead">CSVRead</a></td><td>read from CSV delimited file</td><td>1.9</td></tr> <tr><td>Input</td><td> <a href="#__XPath">XPath</a></td><td>Use an XPath expression to read from a file</td><td>2.0.3</td></tr> <tr><td>Calculation</td><td> <a href="#__counter">counter</a></td><td>generate an incrementing number</td><td>1.X</td></tr> + <tr><td>Calculation</td><td> <a href="#__digest">digest</a></td><td>Generate a digest (SHA-1, SHA-256, MD5...)</td><td>4.0</td></tr> <tr><td>Calculation</td><td> <a href="#__intSum">intSum</a></td><td>add int numbers</td><td>1.8.1</td></tr> <tr><td>Calculation</td><td> <a href="#__longSum">longSum</a></td><td>add long numbers</td><td>2.3.2</td></tr> <tr><td>Calculation</td><td> <a href="#__Random">Random</a></td><td>generate a random number</td><td>1.9</td></tr> @@ -1565,7 +1566,39 @@ becomes: <property name="Name of variable" required="No">The name of the variable to set.</property> </properties> </component> - +<component index="§-num;.5.34" name="__digest"> + <description> + <p>The digest function returns an encrypted value in the + specific hash algorithm with the optional salt, upper case + and variable name.</p> + </description> + <properties> + <property name="Algorithm" required="Yes"> + The algorithm to be used to encrypt + For possible algorithms See MessageDigest in + <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">StandardNames</a> + <ul> + <li>MD2</li> + <li>MD5</li> + <li>SHA-1</li> + <li>SHA-224</li> + <li>SHA-256</li> + <li>SHA-384</li> + <li>SHA-512</li> + </ul> + <note>Spaces are taken into account for <code>Salt to add</code> and <code>String to encode</code></note> + </property> + <property name="String to encode" required="Yes"> The String + that will be encrypted </property> + <property name="Salt to add" required="No"> Salt to be added + to string (after it)</property> + <property name="Upper Case value" required="No"> Result will + be in lower case by default. Choose true to upper case + results. </property> + <property name="Name of variable" required="No">The name of + the variable to set.</property> + </properties> +</component> </subsection> <subsection name="§-num;.6 Pre-defined Variables" anchor="predefinedvars">