This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit ae2cc2b1ecc50b75849fc6169ae5267a5a2d6fba Author: Benoit Tellier <[email protected]> AuthorDate: Fri Dec 3 09:55:30 2021 +0700 JAMES-3674 Move DigestUtil into DefaultUser --- .../apache/james/user/lib/model/DefaultUser.java | 46 +++++- .../org/apache/james/user/lib/util/DigestUtil.java | 163 --------------------- .../james/user/lib/model/DefaultUserTest.java | 74 +++++++++- .../apache/james/user/lib/util/DigestUtilTest.java | 92 ------------ 4 files changed, 113 insertions(+), 262 deletions(-) diff --git a/server/data/data-library/src/main/java/org/apache/james/user/lib/model/DefaultUser.java b/server/data/data-library/src/main/java/org/apache/james/user/lib/model/DefaultUser.java index 4212e9a..164ff05 100644 --- a/server/data/data-library/src/main/java/org/apache/james/user/lib/model/DefaultUser.java +++ b/server/data/data-library/src/main/java/org/apache/james/user/lib/model/DefaultUser.java @@ -19,12 +19,20 @@ package org.apache.james.user.lib.model; +import static java.nio.charset.StandardCharsets.ISO_8859_1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.io.Serializable; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import javax.mail.MessagingException; +import javax.mail.internet.MimeUtility; + import org.apache.james.core.Username; import org.apache.james.user.api.model.User; -import org.apache.james.user.lib.util.DigestUtil; /** * Implementation of User Interface. Instances of this class do not allow the @@ -84,7 +92,7 @@ public class DefaultUser implements User, Serializable { public boolean verifyPassword(String pass) { try { String credentials = getCredentials(currentAlgorithm, pass); - String hashGuess = DigestUtil.digestString(credentials, currentAlgorithm); + String hashGuess = digestString(credentials, currentAlgorithm); return hashedPassword.equals(hashGuess); } catch (NoSuchAlgorithmException nsae) { throw new RuntimeException("Security error: " + nsae); @@ -95,7 +103,7 @@ public class DefaultUser implements User, Serializable { public boolean setPassword(String newPass) { try { String newCredentials = getCredentials(preferredAlgorithm, newPass); - hashedPassword = DigestUtil.digestString(newCredentials, preferredAlgorithm); + hashedPassword = digestString(newCredentials, preferredAlgorithm); currentAlgorithm = preferredAlgorithm; return true; } catch (NoSuchAlgorithmException nsae) { @@ -128,4 +136,36 @@ public class DefaultUser implements User, Serializable { public Algorithm getHashAlgorithm() { return currentAlgorithm; } + + /** + * Calculate digest of given String using given algorithm. Encode digest in + * MIME-like base64. + * + * @param pass + * the String to be hashed + * @param algorithm + * the algorithm to be used + * @return String Base-64 encoding of digest + * + * @throws NoSuchAlgorithmException + * if the algorithm passed in cannot be found + */ + static String digestString(String pass, Algorithm algorithm) throws NoSuchAlgorithmException { + MessageDigest md; + ByteArrayOutputStream bos; + + try { + md = MessageDigest.getInstance(algorithm.getName()); + byte[] digest = md.digest(pass.getBytes(ISO_8859_1)); + bos = new ByteArrayOutputStream(); + OutputStream encodedStream = MimeUtility.encode(bos, "base64"); + encodedStream.write(digest); + if (!algorithm.isLegacy()) { + encodedStream.close(); + } + return bos.toString(ISO_8859_1); + } catch (IOException | MessagingException e) { + throw new RuntimeException("Fatal error", e); + } + } } diff --git a/server/data/data-library/src/main/java/org/apache/james/user/lib/util/DigestUtil.java b/server/data/data-library/src/main/java/org/apache/james/user/lib/util/DigestUtil.java deleted file mode 100644 index b0a2257..0000000 --- a/server/data/data-library/src/main/java/org/apache/james/user/lib/util/DigestUtil.java +++ /dev/null @@ -1,163 +0,0 @@ -/**************************************************************** - * 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.james.user.lib.util; - -import static java.nio.charset.StandardCharsets.ISO_8859_1; - -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Locale; - -import javax.mail.MessagingException; -import javax.mail.internet.MimeUtility; - -import org.apache.james.user.lib.model.Algorithm; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Computes and verifies digests of files and strings - */ -public class DigestUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(DigestUtil.class); - - /** - * Command line interface. Use -help for arguments. - * - * @param args - * the arguments passed in on the command line - */ - public static void main(String[] args) { - - String alg = "SHA"; - boolean file = false; - - if (args.length == 0 || args.length > 4) { - printUsage(); - return; - } - - for (int i = 0; i < args.length; i++) { - String currArg = args[i].toLowerCase(Locale.US); - if (currArg.equals("-help") || currArg.equals("-usage")) { - printUsage(); - return; - } - if (currArg.equals("-alg")) { - alg = args[i + 1]; - } - if (currArg.equals("-file")) { - file = true; - } - } - - if (file) { - digestFile(args[args.length - 1], alg); - } else { - try { - String hash = digestString(args[args.length - 1], Algorithm.of(alg)); - System.out.println("Hash is: " + hash); - } catch (NoSuchAlgorithmException nsae) { - System.out.println("No such algorithm available"); - } - } - } - - /** - * Print the command line usage string. - */ - public static void printUsage() { - System.out.println("Usage: " + "java org.apache.james.security.DigestUtil" + " [-alg algorithm]" + " [-file] filename|string"); - } - - /** - * Calculate digest of given file with given algorithm. Writes digest to - * file named filename.algorithm . - * - * @param filename - * the String name of the file to be hashed - * @param algorithm - * the algorithm to be used to compute the digest - */ - public static void digestFile(String filename, String algorithm) { - byte[] b = new byte[65536]; - int read; - try (FileInputStream fis = new FileInputStream(filename)) { - MessageDigest md = MessageDigest.getInstance(algorithm); - while (fis.available() > 0) { - read = fis.read(b); - md.update(b, 0, read); - } - byte[] digest = md.digest(); - String fileNameBuffer = filename + "." + algorithm; - try (FileOutputStream fos = new FileOutputStream(fileNameBuffer)) { - OutputStream encodedStream = MimeUtility.encode(fos, "base64"); - encodedStream.write(digest); - fos.flush(); - } - } catch (Exception e) { - LOGGER.error("Error computing Digest", e); - } - } - - /** - * Calculate digest of given String using given algorithm. Encode digest in - * MIME-like base64. - * - * @param pass - * the String to be hashed - * @param algorithm - * the algorithm to be used - * @return String Base-64 encoding of digest - * - * @throws NoSuchAlgorithmException - * if the algorithm passed in cannot be found - */ - public static String digestString(String pass, Algorithm algorithm) throws NoSuchAlgorithmException { - - MessageDigest md; - ByteArrayOutputStream bos; - - try { - md = MessageDigest.getInstance(algorithm.getName()); - byte[] digest = md.digest(pass.getBytes(ISO_8859_1)); - bos = new ByteArrayOutputStream(); - OutputStream encodedStream = MimeUtility.encode(bos, "base64"); - encodedStream.write(digest); - if (!algorithm.isLegacy()) { - encodedStream.close(); - } - return bos.toString(ISO_8859_1); - } catch (IOException | MessagingException e) { - throw new RuntimeException("Fatal error", e); - } - } - - /** - * Private constructor to prevent instantiation of the class - */ - private DigestUtil() { - } -} diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/model/DefaultUserTest.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/model/DefaultUserTest.java index 1a11d3d..3a79d64 100644 --- a/server/data/data-library/src/test/java/org/apache/james/user/lib/model/DefaultUserTest.java +++ b/server/data/data-library/src/test/java/org/apache/james/user/lib/model/DefaultUserTest.java @@ -19,14 +19,20 @@ package org.apache.james.user.lib.model; -import org.apache.james.core.Username; -import org.junit.Before; -import org.junit.Test; - import static org.apache.james.user.lib.model.Algorithm.HashingMode.LEGACY; import static org.apache.james.user.lib.model.Algorithm.HashingMode.PLAIN; import static org.assertj.core.api.Assertions.assertThat; +import java.util.Optional; +import java.util.stream.Stream; + +import org.apache.james.core.Username; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + public class DefaultUserTest { private DefaultUser user; @@ -61,4 +67,64 @@ public class DefaultUserTest { assertThat(user.verifyPassword("secret2")).isTrue(); assertThat(user.verifyPassword("secret")).isFalse(); } + + private static Stream<Arguments> sha1LegacyTestBed() { + return Stream.of( + Arguments.of("myPassword", "VBPuJHI7uixaa6LQGWx4s+5G"), + Arguments.of("otherPassword", "ks40t+AjBnHsMaC1Is/6+mtb"), + Arguments.of("", "2jmj7l5rSw0yVb/vlWAYkK/Y"), + Arguments.of("a", "hvfkN/qlp/zhXR3cuerq6jd2")); + } + + @ParameterizedTest + @MethodSource("sha1LegacyTestBed") + void testSha1Legacy(String password, String expectedHash) throws Exception { + assertThat(DefaultUser.digestString(Optional.ofNullable(password).orElse(""), Algorithm.of("SHA-1", "legacy"))) + .isEqualTo(expectedHash); + } + + private static Stream<Arguments> sha512LegacyTestBed() { + return Stream.of( + Arguments.of("myPassword", "RQrQPbk5XfzLXgMGb9fxbPuith4j1RY3NxRHFFkFLskKmkvzoVHmAOqKrtNuO4who9OKsXBYOXSd\r\nEw2kOA8U"), + Arguments.of("otherPassword", "6S2kG/b6oHgWBXQjKDKTayXWu2cs9374lxFrL9uVpmYUlq0lw/ZFU9svMtYVDV5aVjJqRbLWZ/df\r\neaaJwYxk"), + Arguments.of("", "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGl\r\nODJ6+Sfa"), + Arguments.of("a", "H0D8ktokFpR1CXnubPWC8tXX0o4YM13gWrxU0FYOD1MChgxlK/CNVgJSql50IQVG82n7u86MEs/H\r\nlXsmUv6a")); + } + + @ParameterizedTest + @MethodSource("sha512LegacyTestBed") + void testSha512Legacy(String password, String expectedHash) throws Exception { + assertThat(DefaultUser.digestString(password, Algorithm.of("SHA-512", "legacy"))) + .isEqualTo(expectedHash); + } + + private static Stream<Arguments> sha1TestBed() { + return Stream.of( + Arguments.of("myPassword", "VBPuJHI7uixaa6LQGWx4s+5GKNE=\r\n"), + Arguments.of("otherPassword", "ks40t+AjBnHsMaC1Is/6+mtb05s=\r\n"), + Arguments.of("", "2jmj7l5rSw0yVb/vlWAYkK/YBwk=\r\n"), + Arguments.of("a", "hvfkN/qlp/zhXR3cuerq6jd2Z7g=\r\n")); + } + + @ParameterizedTest + @MethodSource("sha1TestBed") + void testSha1(String password, String expectedHash) throws Exception { + assertThat(DefaultUser.digestString(Optional.ofNullable(password).orElse(""), Algorithm.of("SHA-1"))) + .isEqualTo(expectedHash); + } + + private static Stream<Arguments> sha512TestBed() { + return Stream.of( + Arguments.of("myPassword", "RQrQPbk5XfzLXgMGb9fxbPuith4j1RY3NxRHFFkFLskKmkvzoVHmAOqKrtNuO4who9OKsXBYOXSd\r\nEw2kOA8USA==\r\n"), + Arguments.of("otherPassword", "6S2kG/b6oHgWBXQjKDKTayXWu2cs9374lxFrL9uVpmYUlq0lw/ZFU9svMtYVDV5aVjJqRbLWZ/df\r\neaaJwYxkhQ==\r\n"), + Arguments.of("", "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGl\r\nODJ6+SfaPg==\r\n"), + Arguments.of("a", "H0D8ktokFpR1CXnubPWC8tXX0o4YM13gWrxU0FYOD1MChgxlK/CNVgJSql50IQVG82n7u86MEs/H\r\nlXsmUv6adQ==\r\n")); + } + + @ParameterizedTest + @MethodSource("sha512TestBed") + void testSha512(String password, String expectedHash) throws Exception { + assertThat(DefaultUser.digestString(password, Algorithm.of("SHA-512"))) + .isEqualTo(expectedHash); + } } diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/util/DigestUtilTest.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/util/DigestUtilTest.java deleted file mode 100644 index 1825fc6..0000000 --- a/server/data/data-library/src/test/java/org/apache/james/user/lib/util/DigestUtilTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************** - * 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.james.user.lib.util; - -import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; - -import java.util.Optional; -import java.util.stream.Stream; - -import org.apache.james.user.lib.model.Algorithm; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class DigestUtilTest { - private static Stream<Arguments> sha1LegacyTestBed() { - return Stream.of( - Arguments.of("myPassword", "VBPuJHI7uixaa6LQGWx4s+5G"), - Arguments.of("otherPassword", "ks40t+AjBnHsMaC1Is/6+mtb"), - Arguments.of("", "2jmj7l5rSw0yVb/vlWAYkK/Y"), - Arguments.of("a", "hvfkN/qlp/zhXR3cuerq6jd2")); - } - - @ParameterizedTest - @MethodSource("sha1LegacyTestBed") - void testSha1Legacy(String password, String expectedHash) throws Exception { - assertThat(DigestUtil.digestString(Optional.ofNullable(password).orElse(""), Algorithm.of("SHA-1", "legacy"))) - .isEqualTo(expectedHash); - } - - private static Stream<Arguments> sha512LegacyTestBed() { - return Stream.of( - Arguments.of("myPassword", "RQrQPbk5XfzLXgMGb9fxbPuith4j1RY3NxRHFFkFLskKmkvzoVHmAOqKrtNuO4who9OKsXBYOXSd\r\nEw2kOA8U"), - Arguments.of("otherPassword", "6S2kG/b6oHgWBXQjKDKTayXWu2cs9374lxFrL9uVpmYUlq0lw/ZFU9svMtYVDV5aVjJqRbLWZ/df\r\neaaJwYxk"), - Arguments.of("", "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGl\r\nODJ6+Sfa"), - Arguments.of("a", "H0D8ktokFpR1CXnubPWC8tXX0o4YM13gWrxU0FYOD1MChgxlK/CNVgJSql50IQVG82n7u86MEs/H\r\nlXsmUv6a")); - } - - @ParameterizedTest - @MethodSource("sha512LegacyTestBed") - void testSha512Legacy(String password, String expectedHash) throws Exception { - assertThat(DigestUtil.digestString(password, Algorithm.of("SHA-512", "legacy"))) - .isEqualTo(expectedHash); - } - - private static Stream<Arguments> sha1TestBed() { - return Stream.of( - Arguments.of("myPassword", "VBPuJHI7uixaa6LQGWx4s+5GKNE=\r\n"), - Arguments.of("otherPassword", "ks40t+AjBnHsMaC1Is/6+mtb05s=\r\n"), - Arguments.of("", "2jmj7l5rSw0yVb/vlWAYkK/YBwk=\r\n"), - Arguments.of("a", "hvfkN/qlp/zhXR3cuerq6jd2Z7g=\r\n")); - } - - @ParameterizedTest - @MethodSource("sha1TestBed") - void testSha1(String password, String expectedHash) throws Exception { - assertThat(DigestUtil.digestString(Optional.ofNullable(password).orElse(""), Algorithm.of("SHA-1"))) - .isEqualTo(expectedHash); - } - - private static Stream<Arguments> sha512TestBed() { - return Stream.of( - Arguments.of("myPassword", "RQrQPbk5XfzLXgMGb9fxbPuith4j1RY3NxRHFFkFLskKmkvzoVHmAOqKrtNuO4who9OKsXBYOXSd\r\nEw2kOA8USA==\r\n"), - Arguments.of("otherPassword", "6S2kG/b6oHgWBXQjKDKTayXWu2cs9374lxFrL9uVpmYUlq0lw/ZFU9svMtYVDV5aVjJqRbLWZ/df\r\neaaJwYxkhQ==\r\n"), - Arguments.of("", "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGl\r\nODJ6+SfaPg==\r\n"), - Arguments.of("a", "H0D8ktokFpR1CXnubPWC8tXX0o4YM13gWrxU0FYOD1MChgxlK/CNVgJSql50IQVG82n7u86MEs/H\r\nlXsmUv6adQ==\r\n")); - } - - @ParameterizedTest - @MethodSource("sha512TestBed") - void testSha512(String password, String expectedHash) throws Exception { - assertThat(DigestUtil.digestString(password, Algorithm.of("SHA-512"))) - .isEqualTo(expectedHash); - } -} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
