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="&sect-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="&sect-num;.6 Pre-defined Variables" anchor="predefinedvars">


Reply via email to