diff --git a/scm-core/src/main/java/sonia/scm/xml/EncryptionUtil.java b/scm-core/src/main/java/sonia/scm/xml/EncryptionUtil.java new file mode 100644 index 0000000000..43cebc8d68 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/xml/EncryptionUtil.java @@ -0,0 +1,51 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.xml; + +import com.google.common.base.Strings; +import sonia.scm.security.CipherUtil; + + +public class EncryptionUtil { + + private static final String PREFIX = "{enc}"; + + public static String decrypt(String value) { + if (!value.startsWith(PREFIX)) { + //Return value if not encrypted yet + return value; + } + + return CipherUtil.getInstance().decode(value.substring(PREFIX.length())); + } + + public static String encrypt(String value) { + return PREFIX.concat(CipherUtil.getInstance().encode(value)); + } + + public static boolean isEncrypted(String value) { + return !Strings.isNullOrEmpty(value) && value.startsWith(PREFIX); + } +} diff --git a/scm-core/src/main/java/sonia/scm/xml/XmlEncryptionAdapter.java b/scm-core/src/main/java/sonia/scm/xml/XmlEncryptionAdapter.java new file mode 100644 index 0000000000..f24a9ce589 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/xml/XmlEncryptionAdapter.java @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.xml; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +public class XmlEncryptionAdapter extends XmlAdapter { + + @Override + public String marshal(String v) { + if (!EncryptionUtil.isEncrypted(v)) { + v = EncryptionUtil.encrypt(v); + } + + return v; + } + + @Override + public String unmarshal(String v) { + if (EncryptionUtil.isEncrypted(v)) { + v = EncryptionUtil.decrypt(v); + } + + return v; + } +} diff --git a/scm-core/src/test/java/sonia/scm/xml/EncryptionUtilTest.java b/scm-core/src/test/java/sonia/scm/xml/EncryptionUtilTest.java new file mode 100644 index 0000000000..57db6b8075 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/xml/EncryptionUtilTest.java @@ -0,0 +1,67 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.xml; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class EncryptionUtilTest { + + private final static String API_TOKEN = "113bb79d12c179301b93e9ff1ad32181a0"; + + @Test + void shouldEncrypt() { + String encryptedToken = EncryptionUtil.encrypt(API_TOKEN); + + assertThat(API_TOKEN).isNotEqualTo(encryptedToken); + assertThat(encryptedToken).startsWith("{enc}"); + } + + @Test + void shouldReturnDecryptedApiToken() { + String encryptedToken = EncryptionUtil.encrypt(API_TOKEN); + String decryptedToken = EncryptionUtil.decrypt(encryptedToken); + + assertThat(decryptedToken).isEqualTo(API_TOKEN); + } + + @Test + void shouldReturnApiTokenIfNotEncrypted() { + String token = EncryptionUtil.decrypt(API_TOKEN); + + assertThat(token).isEqualTo(API_TOKEN); + } + + @Test + void shouldCheckIfTokenIsEncrypted() { + String encryptedToken = EncryptionUtil.encrypt(API_TOKEN); + boolean encrypted = EncryptionUtil.isEncrypted(encryptedToken); + boolean notEncrypted = EncryptionUtil.isEncrypted(API_TOKEN); + + assertThat(encrypted).isEqualTo(true); + assertThat(notEncrypted).isEqualTo(false); + } +} diff --git a/scm-core/src/test/java/sonia/scm/xml/XmlEncryptionAdapterTest.java b/scm-core/src/test/java/sonia/scm/xml/XmlEncryptionAdapterTest.java new file mode 100644 index 0000000000..a185878151 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/xml/XmlEncryptionAdapterTest.java @@ -0,0 +1,60 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.xml; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class XmlEncryptionAdapterTest { + + private final static String API_TOKEN = "113bb79d12c179301b93e9ff1ad32181a0"; + + private final XmlEncryptionAdapter xmlEncryptionAdapter = new XmlEncryptionAdapter(); + + @Test + void shouldEncryptTokenOnMarshalling() { + String marshalledToken = xmlEncryptionAdapter.marshal(API_TOKEN); + + assertThat(marshalledToken).isNotEqualTo(API_TOKEN); + assertThat(marshalledToken).startsWith("{enc}"); + } + + @Test + void shouldUnmarshallEncryptedToken() { + String marshalledToken = xmlEncryptionAdapter.marshal(API_TOKEN); + + String unmarshalledToken = xmlEncryptionAdapter.unmarshal(marshalledToken); + + assertThat(unmarshalledToken).isEqualTo(API_TOKEN); + } + + @Test + void shouldUnmarshallNotEncryptedToken() { + String unmarshalledToken = xmlEncryptionAdapter.unmarshal(API_TOKEN); + + assertThat(unmarshalledToken).isEqualTo(API_TOKEN); + } +}