From 15616a8263eea912e2027a0eba3cd3d15a01c9f8 Mon Sep 17 00:00:00 2001 From: Torsten Friebe Date: Fri, 7 Jun 2024 13:11:27 +0200 Subject: [PATCH] #1616 fixes the missing salt read from file when comparing the given password --- .../org/deegree/console/security/LogBean.java | 4 ++-- .../console/security/PasswordFile.java | 3 ++- .../console/security/SaltedPassword.java | 19 +++++++++++-------- .../console/security/PasswordFileTest.java | 13 +++++++++++-- .../console/security/SaltedPasswordTest.java | 15 ++++++++++++--- 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/LogBean.java b/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/LogBean.java index 24c618d288..9912a8850b 100644 --- a/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/LogBean.java +++ b/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/LogBean.java @@ -113,7 +113,7 @@ public String getNewPassword2() { return newPassword2; } - public String logIn() throws NoSuchAlgorithmException, IOException { + public String logIn() throws IOException { SaltedPassword storedPassword = passwordFile.getCurrentContent(); if (storedPassword == null) { @@ -125,7 +125,7 @@ public String logIn() throws NoSuchAlgorithmException, IOException { SaltedPassword givenPassword = new SaltedPassword(currentPassword, storedPassword.getSalt()); loggedIn = storedPassword.equals(givenPassword); - LOG.debug("Provided password matches stored password. Successfully logged in."); + LOG.debug("Provided password matches stored password: {}", loggedIn); return FacesContext.getCurrentInstance().getViewRoot().getViewId(); } diff --git a/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/PasswordFile.java b/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/PasswordFile.java index 4ac847e329..6f2adffd54 100644 --- a/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/PasswordFile.java +++ b/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/PasswordFile.java @@ -28,6 +28,7 @@ package org.deegree.console.security; import static java.lang.Character.digit; +import static org.deegree.console.security.SaltedPassword.SHA256_PREFIX; import java.io.BufferedReader; import java.io.File; @@ -96,7 +97,7 @@ private SaltedPassword parseSaltedPassword(String encoded) throws IOException { } String[] parts = encoded.split("\\$"); - return new SaltedPassword(parts[3].getBytes(StandardCharsets.UTF_8), parts[2]); + return new SaltedPassword(parts[3].getBytes(StandardCharsets.UTF_8), SHA256_PREFIX + parts[2]); } /** diff --git a/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/SaltedPassword.java b/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/SaltedPassword.java index f058d228c4..f89d9b34bd 100644 --- a/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/SaltedPassword.java +++ b/deegree-services/deegree-webservices/src/main/java/org/deegree/console/security/SaltedPassword.java @@ -71,10 +71,12 @@ * @see Unix crypt using SHA-256 * and SHA-512 */ -public class SaltedPassword { +public final class SaltedPassword { private static final String CHARSET = StandardCharsets.UTF_8.toString(); + static final String SHA256_PREFIX = "$5$"; + private final byte[] saltedAndHashedPassword; private final String salt; @@ -86,19 +88,20 @@ public SaltedPassword(byte[] saltedAndHashedPassword, String salt) { public SaltedPassword(String plainPassword, String salt) throws UnsupportedEncodingException { byte[] plainPasswordBinary = plainPassword.getBytes(CHARSET); - String saltedPassword = generateHashedAndSaltedPassword(plainPasswordBinary); + String saltedPassword = Sha2Crypt.sha256Crypt(plainPasswordBinary, salt); int delimiterPos = nthIndexOf(saltedPassword, "$", 3); - this.salt = saltedPassword.substring(0, delimiterPos); this.saltedAndHashedPassword = saltedPassword.substring(delimiterPos + 1, saltedPassword.length()) .getBytes(StandardCharsets.UTF_8); + this.salt = salt; } public SaltedPassword(String plainPassword) throws UnsupportedEncodingException { - this(plainPassword, null); - } - - private String generateHashedAndSaltedPassword(byte[] plainPassword) { - return Sha2Crypt.sha256Crypt(plainPassword); + byte[] plainPasswordBinary = plainPassword.getBytes(CHARSET); + String saltedPassword = Sha2Crypt.sha256Crypt(plainPasswordBinary); + int delimiterPos = nthIndexOf(saltedPassword, "$", 3); + this.salt = saltedPassword.substring(0, delimiterPos); + this.saltedAndHashedPassword = saltedPassword.substring(delimiterPos + 1, saltedPassword.length()) + .getBytes(StandardCharsets.UTF_8); } public byte[] getSaltedAndHashedPassword() { diff --git a/deegree-services/deegree-webservices/src/test/java/org/deegree/console/security/PasswordFileTest.java b/deegree-services/deegree-webservices/src/test/java/org/deegree/console/security/PasswordFileTest.java index 64424fd901..c0a1c1ee97 100644 --- a/deegree-services/deegree-webservices/src/test/java/org/deegree/console/security/PasswordFileTest.java +++ b/deegree-services/deegree-webservices/src/test/java/org/deegree/console/security/PasswordFileTest.java @@ -1,9 +1,11 @@ package org.deegree.console.security; import static org.deegree.console.security.LogBean.PASSWORD_FILE; +import static org.deegree.console.security.SaltedPassword.SHA256_PREFIX; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertTrue; import java.io.File; @@ -22,6 +24,11 @@ */ public class PasswordFileTest { + /** + * This unit tests can validate if the existing console.pw file contains a password in + * the new extended password format introduced with deegree version 3.6. + * @throws IOException in case of errors + */ @Test @Ignore public void getCurrentContentFromWorkspaceRoot() throws IOException { @@ -31,14 +38,16 @@ public void getCurrentContentFromWorkspaceRoot() throws IOException { assertTrue(passwordFileFQN.isFile()); PasswordFile passwordFile = new PasswordFile(passwordFileFQN); assertTrue(passwordFile.exists()); - assertThat(passwordFile.getCurrentContent().toString(), not(isEmptyOrNullString())); + SaltedPassword saltedPassword = passwordFile.getCurrentContent(); + assertThat(saltedPassword.toString(), not(isEmptyOrNullString())); + assertThat(saltedPassword.getSalt(), startsWith(SHA256_PREFIX)); } /** * Attention: Enabling this unit test will overwrite the content of the console.pw * file! This test is intended as an example how to create a valid console.pw file * with the new extended passwort format introduced with deegree version 3.6. - * @throws IOException + * @throws IOException in case of errors * @since 3.6 * @see SaltedPassword */ diff --git a/deegree-services/deegree-webservices/src/test/java/org/deegree/console/security/SaltedPasswordTest.java b/deegree-services/deegree-webservices/src/test/java/org/deegree/console/security/SaltedPasswordTest.java index 3f8ac054bd..a21ff84098 100644 --- a/deegree-services/deegree-webservices/src/test/java/org/deegree/console/security/SaltedPasswordTest.java +++ b/deegree-services/deegree-webservices/src/test/java/org/deegree/console/security/SaltedPasswordTest.java @@ -5,8 +5,10 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; +import static org.deegree.console.security.SaltedPassword.SHA256_PREFIX; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertTrue; /** * @author Torsten Friebe @@ -18,7 +20,7 @@ public class SaltedPasswordTest { public void testCreatingFromPlainPassword() throws UnsupportedEncodingException { SaltedPassword plainpassword = new SaltedPassword("foo"); String saltedPassword = new String(plainpassword.getSaltedAndHashedPassword(), StandardCharsets.UTF_8); - assertThat(plainpassword.getSalt(), startsWith("$5$")); + assertThat(plainpassword.getSalt(), startsWith(SHA256_PREFIX)); assertThat(saltedPassword, is(notNullValue())); } @@ -31,6 +33,15 @@ public void testCreatingFromSaltedPassword() { assertThat(saltedpassword.getSalt(), is(salt)); } + @Test + public void testCreateNewPasswordWithSaltFromOtherPassword() throws UnsupportedEncodingException { + String plainpassword = "foo"; + SaltedPassword storedPassword = new SaltedPassword(plainpassword); + String saltFromStoredPassword = storedPassword.getSalt(); + SaltedPassword givenPassword = new SaltedPassword(plainpassword, saltFromStoredPassword); + assertTrue(storedPassword.equals(givenPassword)); + } + @Test public void testSaltedPasswordAsParts() throws UnsupportedEncodingException { SaltedPassword password = new SaltedPassword("foo"); @@ -46,6 +57,4 @@ public void testSaltedPasswordAsParts() throws UnsupportedEncodingException { assertThat(parts[3], hasLength(43)); } - - } \ No newline at end of file