This is an automated email from the ASF dual-hosted git repository. cstamas pushed a commit to branch maven-4.0.x in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/maven-4.0.x by this push: new 113ed24bf6 GH-10210: fix too eager decrypt of legacy passwords (#11138) (#11158) 113ed24bf6 is described below commit 113ed24bf6cdf08084725a6fba385e08a9ea8e9b Author: Tamas Cservenak <ta...@cservenak.net> AuthorDate: Mon Sep 22 18:40:20 2025 +0200 GH-10210: fix too eager decrypt of legacy passwords (#11138) (#11158) Accept ONLY documented forms of them. Fixes #10210 Backport of c999cff6c33bc6402fb712b42da9531234a5862f --- .../apache/maven/impl/DefaultSettingsBuilder.java | 16 +++++ .../it/MavenITgh10210SettingsXmlDecryptTest.java | 78 ++++++++++++++++++++++ .../org/apache/maven/it/TestSuiteOrdering.java | 1 + .../HOME/.m2/settings-security.xml | 3 + .../gh-10210-settings-xml-decrypt/pom.xml | 40 +++++++++++ .../settings-fails.xml | 42 ++++++++++++ .../settings-passes.xml | 42 ++++++++++++ .../src/main/resources/file.properties | 7 ++ 8 files changed, 229 insertions(+) diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java index 76695f4b1f..be7dd9e863 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java @@ -268,6 +268,22 @@ private Settings decrypt( UnaryOperator<String> decryptFunction = str -> { if (str != null && !str.isEmpty() && !str.contains("${") && secDispatcher.isAnyEncryptedString(str)) { if (secDispatcher.isLegacyEncryptedString(str)) { + // the call above return true for too broad types of strings, original idea with 2.x sec-dispatcher + // was to make it possible to add "descriptions" to encrypted passwords. Maven 4 is + // limiting itself to decryption of ONLY the simplest cases of legacy passwords, those having form + // as documented on page: https://maven.apache.org/guides/mini/guide-encryption.html + // Examples of decrypted legacy passwords: + // <password>{COQLCE6DU6GtcS5P=}</password> + // <password>Oleg reset this password on 2009-03-11 {COQLCE6DU6GtcS5P=}</password> + + // In short, secDispatcher#isLegacyEncryptedString(str) did return true, but we apply more scrutiny + // and check does string start with "{" or contains " {" (whitespace before opening curly braces), + // and that it ends with "}" strictly. Otherwise, we refuse it. + if ((!str.startsWith("{") && !str.contains(" {")) || !str.endsWith("}")) { + // this is not a legacy password we care for + return str; + } + // add a problem preMaven4Passwords.incrementAndGet(); } diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh10210SettingsXmlDecryptTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh10210SettingsXmlDecryptTest.java new file mode 100644 index 0000000000..8742ff9388 --- /dev/null +++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh10210SettingsXmlDecryptTest.java @@ -0,0 +1,78 @@ +/* + * 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.maven.it; + +import java.io.File; +import java.nio.file.Files; +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +/** + * This is a test set for <a href="https://github.com/apache/maven/issues/10210">GH-10210</a>. + */ +class MavenITgh10210SettingsXmlDecryptTest extends AbstractMavenIntegrationTestCase { + + MavenITgh10210SettingsXmlDecryptTest() { + super("(4.0.0-rc4,)"); // fixed post 4.0.0-rc-4 + } + + @Test + void testItPass() throws Exception { + File testDir = extractResources("/gh-10210-settings-xml-decrypt"); + + Verifier verifier = new Verifier(testDir.getAbsolutePath()); + verifier.setUserHomeDirectory(testDir.toPath().resolve("HOME")); + verifier.addCliArgument("-s"); + verifier.addCliArgument("settings-passes.xml"); + verifier.addCliArgument("process-resources"); + verifier.execute(); + + Assert.assertEquals( + Arrays.asList( + "prop1=%{foo}.txt", + "prop2=${foo}.txt", + "prop3=whatever {foo}.txt", + "prop4=whatever", + "prop5=Hello Oleg {L6L/HbmrY+cH+sNkphnq3fguYepTpM04WlIXb8nB1pk=} is this a password?", + "prop6=password", + "prop7=password"), + Files.readAllLines(testDir.toPath().resolve("target/classes/file.properties"))); + } + + @Test + void testItFail() throws Exception { + File testDir = extractResources("/gh-10210-settings-xml-decrypt"); + + Verifier verifier = new Verifier(testDir.getAbsolutePath()); + verifier.setUserHomeDirectory(testDir.toPath().resolve("HOME")); + verifier.addCliArgument("-s"); + verifier.addCliArgument("settings-fails.xml"); + verifier.addCliArgument("process-resources"); + try { + verifier.execute(); + } catch (VerificationException e) { + Assert.assertTrue( + verifier.loadLogContent() + .contains( + "Could not decrypt password (fix the corrupted password or remove it, if unused) {L6L/HbmrY+cH+sNkphn-this password is corrupted intentionally-q3fguYepTpM04WlIXb8nB1pk=}")); + } + } +} diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java b/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java index cc0ee65b99..207595094a 100644 --- a/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java +++ b/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java @@ -105,6 +105,7 @@ public TestSuiteOrdering() { */ suite.addTestSuite(MavenITgh11055DIServiceInjectionTest.class); suite.addTestSuite(MavenITgh11084ReactorReaderPreferConsumerPomTest.class); + suite.addTestSuite(MavenITgh10210SettingsXmlDecryptTest.class); suite.addTestSuite(MavenITgh10312TerminallyDeprecatedMethodInGuiceTest.class); suite.addTestSuite(MavenITgh10937QuotedPipesInMavenOptsTest.class); suite.addTestSuite(MavenITgh2532DuplicateDependencyEffectiveModelTest.class); diff --git a/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/HOME/.m2/settings-security.xml b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/HOME/.m2/settings-security.xml new file mode 100644 index 0000000000..f88e932cf8 --- /dev/null +++ b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/HOME/.m2/settings-security.xml @@ -0,0 +1,3 @@ +<settingsSecurity> + <master>{KDvsYOFLlXgH4LU8tvpzAGg5otiosZXvfdQq0yO86LU=}</master> +</settingsSecurity> \ No newline at end of file diff --git a/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/pom.xml b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/pom.xml new file mode 100644 index 0000000000..d6c72b24a4 --- /dev/null +++ b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/pom.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.its.gh-10210</groupId> + <artifactId>test</artifactId> + <version>1.0</version> + <packaging>jar</packaging> + + <name>Maven Integration Test :: gh-10210</name> + <description>Empty POM, as settings.xml decrypt failure will fail the build anyway.</description> + + <build> + <resources> + <resource> + <filtering>true</filtering> + <directory>src/main/resources</directory> + </resource> + </resources> + </build> + +</project> diff --git a/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/settings-fails.xml b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/settings-fails.xml new file mode 100644 index 0000000000..dd3f44f0e9 --- /dev/null +++ b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/settings-fails.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- +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. +--> + +<settings xmlns='http://maven.apache.org/SETTINGS/1.2.0'> + <profiles> + <profile> + <id>just-some-random-profile</id> + <properties> + <!-- These are all not legacy passwords --> + <prop1>%{foo}.txt</prop1> + <prop2>${foo}.txt</prop2> + <prop3>whatever {foo}.txt</prop3> + <prop4>whatever</prop4> + <prop5>Hello Oleg {L6L/HbmrY+cH+sNkphnq3fguYepTpM04WlIXb8nB1pk=} is this a password?</prop5> + <!-- Legacy passwords --> + <prop6>{L6L/HbmrY+cH+sNkphn-this password is corrupted intentionally-q3fguYepTpM04WlIXb8nB1pk=}</prop6> + <prop7>Hello Oleg {L6L/HbmrY+cH+sNkphnq3fguYepTpM04WlIXb8nB1pk=}</prop7> + </properties> + </profile> + </profiles> + <activeProfiles> + <activeProfile>just-some-random-profile</activeProfile> + </activeProfiles> +</settings> diff --git a/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/settings-passes.xml b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/settings-passes.xml new file mode 100644 index 0000000000..dcfb8e5c51 --- /dev/null +++ b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/settings-passes.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- +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. +--> + +<settings xmlns='http://maven.apache.org/SETTINGS/1.2.0'> + <profiles> + <profile> + <id>just-some-random-profile</id> + <properties> + <!-- These are all not legacy passwords --> + <prop1>%{foo}.txt</prop1> + <prop2>${foo}.txt</prop2> + <prop3>whatever {foo}.txt</prop3> + <prop4>whatever</prop4> + <prop5>Hello Oleg {L6L/HbmrY+cH+sNkphnq3fguYepTpM04WlIXb8nB1pk=} is this a password?</prop5> + <!-- Legacy passwords --> + <prop6>{L6L/HbmrY+cH+sNkphnq3fguYepTpM04WlIXb8nB1pk=}</prop6> + <prop7>Hello Oleg {L6L/HbmrY+cH+sNkphnq3fguYepTpM04WlIXb8nB1pk=}</prop7> + </properties> + </profile> + </profiles> + <activeProfiles> + <activeProfile>just-some-random-profile</activeProfile> + </activeProfiles> +</settings> diff --git a/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/src/main/resources/file.properties b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/src/main/resources/file.properties new file mode 100644 index 0000000000..0ccd6e3c49 --- /dev/null +++ b/its/core-it-suite/src/test/resources/gh-10210-settings-xml-decrypt/src/main/resources/file.properties @@ -0,0 +1,7 @@ +prop1=${prop1} +prop2=${prop2} +prop3=${prop3} +prop4=${prop4} +prop5=${prop5} +prop6=${prop6} +prop7=${prop7}