diff --git a/WaarpCommon/src/main/java/org/waarp/common/crypto/KeyObject.java b/WaarpCommon/src/main/java/org/waarp/common/crypto/KeyObject.java index c689bdcc72..b5af9cb642 100644 --- a/WaarpCommon/src/main/java/org/waarp/common/crypto/KeyObject.java +++ b/WaarpCommon/src/main/java/org/waarp/common/crypto/KeyObject.java @@ -388,6 +388,20 @@ public String decryptHexInString(String ciphertext) throws Exception { return new String(decryptHexInBytes(ciphertext), WaarpStringUtils.UTF8); } + /** + * Decrypt a String as HEX format representing a crypted String and + * returns the uncrypted String + * + * @param ciphertext + * + * @return the uncrypted String + * + * @throws Exception + */ + public String decryptHexInString(byte[] ciphertext) throws Exception { + return new String(decryptHexInBytes(ciphertext), WaarpStringUtils.UTF8); + } + /** * Decode from a file containing a HEX crypted string * diff --git a/WaarpCommon/src/test/java/org/waarp/common/crypto/DynamicKeyObjectTest.java b/WaarpCommon/src/test/java/org/waarp/common/crypto/DynamicKeyObjectTest.java index 4e4aaf5858..819c157e9c 100644 --- a/WaarpCommon/src/test/java/org/waarp/common/crypto/DynamicKeyObjectTest.java +++ b/WaarpCommon/src/test/java/org/waarp/common/crypto/DynamicKeyObjectTest.java @@ -55,6 +55,22 @@ public void simpleTest() { } } + @Test + public void testDecryptHexInString() throws Exception { + final INSTANCES keyAlgo = INSTANCES.DES; + final DynamicKeyObject dyn = new DynamicKeyObject( + keyAlgo.size, keyAlgo.name(), keyAlgo.name(), keyAlgo.name() + ); + + dyn.generateKey(); + final String original = "mypassword"; + final byte[] crypted = dyn.crypt(original); + final String cryptedHex = dyn.encodeHex(crypted); + final String decrypted = dyn.decryptHexInString(cryptedHex); + + assertEquals("decrypted password should be equal to the original", original, decrypted); + } + /** * test function * @@ -99,4 +115,4 @@ private static void test(String plaintext, int size, String algo) System.out.println(algo + ": Total time: " + (time2 - time1) + " ms, " + nb * 1000 / (time2 + 1 - time1) + " crypt or decrypt/s"); } -} \ No newline at end of file +} diff --git a/WaarpR66/src/main/java/org/waarp/openr66/protocol/http/restv2/resthandlers/RestHandlerHook.java b/WaarpR66/src/main/java/org/waarp/openr66/protocol/http/restv2/resthandlers/RestHandlerHook.java index 17af299dbf..1dca693c74 100644 --- a/WaarpR66/src/main/java/org/waarp/openr66/protocol/http/restv2/resthandlers/RestHandlerHook.java +++ b/WaarpR66/src/main/java/org/waarp/openr66/protocol/http/restv2/resthandlers/RestHandlerHook.java @@ -286,7 +286,7 @@ private boolean checkContentType(HttpRequest request, * @throws NotAllowedException if the user making the request does * not exist */ - private String checkCredentials(HttpRequest request) { + protected String checkCredentials(HttpRequest request) { final String authorization = request.headers().get(AUTHORIZATION); @@ -375,25 +375,7 @@ private String checkCredentials(HttpRequest request) { DAOFactory.closeDAO(hostDAO); } - String pswd; - try { - pswd = configuration.getCryptoKey().decryptInString(host.getHostkey()); - } catch (final Exception e) { - throw new InternalServerErrorException( - "An error occurred when decrypting the password", e); - } - - String key; - try { - key = hmac.cryptToHex(authDate + authUser + pswd); - } catch (final Exception e) { - throw new InternalServerErrorException( - "An error occurred when hashing the key", e); - } - - if (Arrays.equals(key.getBytes(), authKey.getBytes())) { - throw new NotAllowedException("Invalid password."); - } + validateHMACCredentials(host, authDate, authUser, authKey); return authUser; } @@ -401,6 +383,30 @@ private String checkCredentials(HttpRequest request) { throw new NotAllowedException("Missing credentials."); } + protected void validateHMACCredentials(Host host, String authDate, + String authUser, String authKey) + throws InternalServerErrorException { + String pswd; + try { + pswd = configuration.getCryptoKey().decryptHexInString(host.getHostkey()); + } catch (final Exception e) { + throw new InternalServerErrorException( + "An error occurred when decrypting the password", e); + } + + String key; + try { + key = hmac.cryptToHex(authDate + authUser + pswd); + } catch (final Exception e) { + throw new InternalServerErrorException( + "An error occurred when hashing the key", e); + } + + if (!key.equals(authKey)) { + throw new NotAllowedException("Invalid password."); + } + } + /** * Checks if the user given as argument is authorized to call the given * method. diff --git a/WaarpR66/src/test/java/org/waarp/openr66/protocol/http/restv2/resthandlers/RestHandlerHookTest.java b/WaarpR66/src/test/java/org/waarp/openr66/protocol/http/restv2/resthandlers/RestHandlerHookTest.java new file mode 100644 index 0000000000..40fd4ea6a6 --- /dev/null +++ b/WaarpR66/src/test/java/org/waarp/openr66/protocol/http/restv2/resthandlers/RestHandlerHookTest.java @@ -0,0 +1,70 @@ +package org.waarp.openr66.protocol.http.restv2.resthandlers; + +import org.junit.Test; +import org.waarp.common.crypto.Des; +import org.waarp.common.crypto.DynamicKeyObject; +import org.waarp.common.crypto.HmacSha256; +import org.waarp.openr66.pojo.Host; +import org.waarp.openr66.protocol.configuration.Configuration; + +import static org.junit.Assert.fail; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.ws.rs.InternalServerErrorException; + +/** + * RestHandlerHook + */ +public class RestHandlerHookTest { + + public static final class RestHandlerHookForTest extends RestHandlerHook { + public RestHandlerHookForTest(final boolean authenticated, + final HmacSha256 hmac, final long delay) { + super(authenticated, hmac, delay); + } + + public void testValidateHMACredentials(Host host, String authDate, + String authUser, String authKey) + throws InternalServerErrorException { + validateHMACCredentials(host, authDate, authUser, authKey); + } + } + + @Test + public void testCheckCredentialsWithHMAC() throws Exception{ + final HmacSha256 hmac = new HmacSha256(); + hmac.generateKey(); + + final Des dyn = new Des(); + dyn.generateKey(); + Des oldKey = Configuration.configuration.getCryptoKey(); + Configuration.configuration.setCryptoKey(dyn); + + final String user = "user"; + final String password = "mypassword"; + final String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").format(new Date()); + + try { + + final String hostkey = dyn.cryptToHex(password); + final String sig = hmac.cryptToHex(timestamp + user + password); + + final RestHandlerHookForTest hook = new RestHandlerHookForTest(true, hmac, 10000); + + try { + final Host host = new Host(user, "127.0.0.1", 1, hostkey.getBytes(), false, true); + + hook.testValidateHMACredentials(host, timestamp, user, sig); + } catch (InternalServerErrorException e) { + System.out.println(e); + fail("credentials validation failed, it should have succeeded"); + } + + } finally { + Configuration.configuration.setCryptoKey(oldKey); + } + + } +} diff --git a/doc/waarp-r66/source/changes.rst b/doc/waarp-r66/source/changes.rst index 33741d4c07..1ec1cff84a 100644 --- a/doc/waarp-r66/source/changes.rst +++ b/doc/waarp-r66/source/changes.rst @@ -32,6 +32,8 @@ Correctifs request [`#38 `__]) - Correction de la signature des requĂȘtes dans l'API REST v2 (pull request [`#42 `__]) +- Correction de l'authentification HMAC de l'API REST v2 (pull + request [`#43 `__]) Waarp R66 3.3.3 (2020-05-07) ============================