Procházet zdrojové kódy

hash macro support

Jason Rivard před 8 roky
rodič
revize
30d9e1d473

+ 181 - 0
server/src/main/java/password/pwm/util/macro/InternalMacros.java

@@ -26,9 +26,12 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.PwmEnvironment;
 import password.pwm.config.PwmSetting;
+import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.ContextManager;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureEngine;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -47,6 +50,8 @@ public abstract class InternalMacros {
         defaultMacros.put(PwmAppName.class, MacroImplementation.Scope.Static);
         defaultMacros.put(PwmContextPath.class, MacroImplementation.Scope.System);
         defaultMacros.put(EncodingMacro.class, MacroImplementation.Scope.Static);
+        defaultMacros.put(CasingMacro.class, MacroImplementation.Scope.Static);
+        defaultMacros.put(HashingMacro.class, MacroImplementation.Scope.Static);
 
         INTERNAL_MACROS = Collections.unmodifiableMap(defaultMacros);
     }
@@ -183,6 +188,182 @@ public abstract class InternalMacros {
         }
     }
 
+    public static class HashingMacro extends AbstractMacro {
+        private static final Pattern PATTERN = Pattern.compile("@Hash:[^:]+:\\[\\[.*\\]\\]@");
+        // @Hash:HASH_TYPE:[[value]]@
+
+
+        @Override
+        public Sequence getSequence()
+        {
+            return Sequence.post;
+        }
+
+        private enum HashType {
+            md5,
+            sha1,
+            sha256,
+            sha512,
+
+            ;
+
+            private String hash(final String input) throws MacroParseException {
+                switch (this) {
+                    case md5:
+                        return doHash(input, PwmHashAlgorithm.MD5);
+
+                    case sha1:
+                        return doHash(input, PwmHashAlgorithm.SHA1);
+
+                    case sha256:
+                        return doHash(input, PwmHashAlgorithm.SHA256);
+
+                    case sha512:
+                        return doHash(input, PwmHashAlgorithm.SHA512);
+
+                    default:
+                        throw new MacroParseException("unimplemented hashtype '" + this.toString() + "' for Hash macro");
+                }
+            }
+
+            private String doHash(final String input, final PwmHashAlgorithm pwmHashAlgorithm)
+                    throws MacroParseException
+            {
+                if (StringUtil.isEmpty(input)) {
+                    return "";
+                }
+                final byte[] inputBytes = input.getBytes(PwmConstants.DEFAULT_CHARSET);
+                final String hashOutput;
+                try {
+                    hashOutput = SecureEngine.hash(inputBytes, pwmHashAlgorithm);
+                } catch (PwmUnrecoverableException e) {
+                    throw new MacroParseException("error during hash operation: " + e.getMessage());
+                }
+                return hashOutput.toLowerCase();
+            }
+
+            private static HashType forString(final String input) {
+                for (final HashType encodeType : HashType.values()) {
+                    if (encodeType.toString().equalsIgnoreCase(input)) {
+                        return encodeType;
+                    }
+                }
+                return null;
+            }
+        }
+
+
+        public Pattern getRegExPattern() {
+            return PATTERN;
+        }
+
+        public String replaceValue(
+                final String matchValue,
+                final MacroRequestInfo macroRequestInfo
+        )
+                throws MacroParseException
+        {
+            if (matchValue == null || matchValue.length() < 1) {
+                return "";
+            }
+
+            final String[] colonParts = matchValue.split(":");
+
+            if (colonParts.length < 3) {
+                throw new MacroParseException("not enough arguments for Encode macro");
+            }
+
+            final String encodeMethodStr = colonParts[1];
+            final HashType encodeType = HashType.forString(encodeMethodStr);
+            if (encodeType == null) {
+                throw new MacroParseException("unknown encodeType '" + encodeMethodStr + "' for Encode macro");
+            }
+
+            String value = matchValue; // can't use colonParts[2] as it may be split if value contains a colon.
+            value = value.replaceAll("^@Hash:[^:]+:\\[\\[","");
+            value = value.replaceAll("\\]\\]@$","");
+            return encodeType.hash(value);
+        }
+    }
+
+    public static class CasingMacro extends AbstractMacro {
+        private static final Pattern PATTERN = Pattern.compile("@Case:[^:]+:\\[\\[.*\\]\\]@");
+        // @Case:CASE_TYPE:[[value]]@
+
+
+        @Override
+        public Sequence getSequence()
+        {
+            return Sequence.post;
+        }
+
+        private enum CaseType {
+            upper,
+            lower,
+
+            ;
+
+            private String hash(final String input) throws MacroParseException {
+                switch (this) {
+                    case upper:
+                        return StringUtil.isEmpty(input)
+                                ? ""
+                                : input.toUpperCase();
+
+                    case lower:
+                        return StringUtil.isEmpty(input)
+                                ? ""
+                                : input.toLowerCase();
+
+                    default:
+                        throw new MacroParseException("unimplemented casetype '" + this.toString() + "' for Case macro");
+                }
+            }
+
+            private static CaseType forString(final String input) {
+                for (final CaseType encodeType : CaseType.values()) {
+                    if (encodeType.toString().equalsIgnoreCase(input)) {
+                        return encodeType;
+                    }
+                }
+                return null;
+            }
+        }
+
+
+        public Pattern getRegExPattern() {
+            return PATTERN;
+        }
+
+        public String replaceValue(
+                final String matchValue,
+                final MacroRequestInfo macroRequestInfo
+        )
+                throws MacroParseException
+        {
+            if (matchValue == null || matchValue.length() < 1) {
+                return "";
+            }
+
+            final String[] colonParts = matchValue.split(":");
+
+            if (colonParts.length < 3) {
+                throw new MacroParseException("not enough arguments for Case macro");
+            }
+
+            final String encodeMethodStr = colonParts[1];
+            final CaseType encodeType = CaseType.forString(encodeMethodStr);
+            if (encodeType == null) {
+                throw new MacroParseException("unknown caseType '" + encodeMethodStr + "' for Case macro");
+            }
+
+            String value = matchValue; // can't use colonParts[2] as it may be split if value contains a colon.
+            value = value.replaceAll("^@Case:[^:]+:\\[\\[","");
+            value = value.replaceAll("\\]\\]@$","");
+            return encodeType.hash(value);
+        }
+    }
+
     public static class PwmAppName extends InternalAbstractMacro {
         private static final Pattern PATTERN = Pattern.compile("@PwmAppName@" );
 

+ 10 - 0
server/src/main/webapp/public/resources/text/macroHelp.html

@@ -223,6 +223,16 @@
             <span class="documentationParameter">urlParameter</span> and <span class="documentationParameter">base64</span>.
         </td>
     </tr>
+    <tr>
+        <td class="key">
+            <span style="white-space: pre">@Hash:<span class="documentationParameter">type</span>:[[<span class="documentationParameter">value</span>]]@</span>
+        </td>
+        <td>
+            Hash a value using the specified hash type, where <span class="documentationParameter">type</span> is the type of hash and where <span class="documentationParameter">value</span> is
+            the value to hash.  The value may include other macros.  Hash types permitted are <span class="documentationParameter">md5</span>,
+            <span class="documentationParameter">sha1</span>, <span class="documentationParameter">sha256</span>, and <span class="documentationParameter">sha512</span>.
+        </td>
+    </tr>
 </table>
     <div class="footnote">Parameters that need to include a literal <span class="documentationParameter">@</span> or <span class="documentationParameter">:</span> character must escape these characters with a preceding <span class="documentationParameter">/</span> such as <span class="documentationParameter">/@</span> or <span class="documentationParameter">/:</span></div>
 <br/>

+ 30 - 0
server/src/test/java/password/pwm/util/macro/MacroTest.java

@@ -63,6 +63,36 @@ public class MacroTest {
         }
     }
 
+    @Test
+    public void testStaticHashMacros() throws Exception
+    {
+        final MacroMachine macroMachine = MacroMachine.forStatic();
+
+        { // md5 macro
+            final String goal = "f96b697d7cb7938d525a2f31aaf161d0";
+            final String expanded = macroMachine.expandMacros("@Hash:md5:[[message digest]]@");
+            Assert.assertEquals(goal,expanded);
+        }
+
+        { // sha1 macro
+            final String goal = "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8";
+            final String expanded = macroMachine.expandMacros("@Hash:sha1:[[password]]@");
+            Assert.assertEquals(goal,expanded);
+        }
+
+        { // sha256 macro
+            final String goal = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8";
+            final String expanded = macroMachine.expandMacros("@Hash:sha256:[[password]]@");
+            Assert.assertEquals(goal,expanded);
+        }
+
+        { // sha512 macro
+            final String goal = "b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86";
+            final String expanded = macroMachine.expandMacros("@Hash:sha512:[[password]]@");
+            Assert.assertEquals(goal,expanded);
+        }
+    }
+
     @Test
     public void testUserMacros() throws Exception
     {