Skip to content

Commit e986fff

Browse files
committed
Make sure Dispatcher gets non-null attributes and conf
Also, pass on masterPassword (if possible, exists) to Dispatcher.
1 parent 06aaedf commit e986fff

File tree

5 files changed

+118
-62
lines changed

5 files changed

+118
-62
lines changed

src/main/java/org/codehaus/plexus/components/secdispatcher/internal/DefaultSecDispatcher.java

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,20 @@ public String encrypt(String str, Map<String, String> attr) throws SecDispatcher
6868

6969
try {
7070
String res;
71-
SettingsSecurity sec = getSec();
7271
if (attr == null || attr.get(DISPATCHER_NAME_ATTR) == null) {
73-
String master = getMaster(sec);
72+
SettingsSecurity sec = getConfiguration(true);
73+
String master = getMasterPassword(sec, true);
7474
res = cipher.encrypt(str, master);
7575
} else {
7676
String type = attr.get(DISPATCHER_NAME_ATTR);
77-
Map<String, String> conf = SecUtil.getConfig(sec, type);
7877
Dispatcher dispatcher = dispatchers.get(type);
7978
if (dispatcher == null) throw new SecDispatcherException("no dispatcher for name " + type);
8079
res = ATTR_START
8180
+ attr.entrySet().stream()
8281
.map(e -> e.getKey() + "=" + e.getValue())
8382
.collect(Collectors.joining(","))
8483
+ ATTR_STOP;
85-
res += dispatcher.encrypt(str, attr, conf);
84+
res += dispatcher.encrypt(str, attr, prepareDispatcherConfig(type));
8685
}
8786
return cipher.decorate(res);
8887
} catch (PlexusCipherException e) {
@@ -96,23 +95,35 @@ public String decrypt(String str) throws SecDispatcherException {
9695
try {
9796
String bare = cipher.unDecorate(str);
9897
Map<String, String> attr = stripAttributes(bare);
99-
SettingsSecurity sec = getSec();
10098
if (attr == null || attr.get(DISPATCHER_NAME_ATTR) == null) {
101-
String master = getMaster(sec);
99+
SettingsSecurity sec = getConfiguration(true);
100+
String master = getMasterPassword(sec, true);
102101
return cipher.decrypt(bare, master);
103102
} else {
104103
String type = attr.get(DISPATCHER_NAME_ATTR);
105-
Map<String, String> conf = SecUtil.getConfig(sec, type);
106104
Dispatcher dispatcher = dispatchers.get(type);
107105
if (dispatcher == null) throw new SecDispatcherException("no dispatcher for name " + type);
108-
String pass = strip(bare);
109-
return dispatcher.decrypt(pass, attr, conf);
106+
return dispatcher.decrypt(strip(bare), attr, prepareDispatcherConfig(type));
110107
}
111108
} catch (PlexusCipherException e) {
112109
throw new SecDispatcherException(e.getMessage(), e);
113110
}
114111
}
115112

113+
private Map<String, String> prepareDispatcherConfig(String type) {
114+
HashMap<String, String> dispatcherConf = new HashMap<>();
115+
SettingsSecurity sec = getConfiguration(false);
116+
String master = getMasterPassword(sec, false);
117+
if (master != null) {
118+
dispatcherConf.put(Dispatcher.CONF_MASTER_PASSWORD, master);
119+
}
120+
Map<String, String> conf = SecUtil.getConfig(sec, type);
121+
if (conf != null) {
122+
dispatcherConf.putAll(conf);
123+
}
124+
return dispatcherConf;
125+
}
126+
116127
private String strip(String str) {
117128
int start = str.indexOf(ATTR_START);
118129
int stop = str.indexOf(ATTR_STOP);
@@ -151,27 +162,31 @@ private boolean isEncryptedString(String str) {
151162
return cipher.isEncryptedString(str);
152163
}
153164

154-
private SettingsSecurity getSec() throws SecDispatcherException {
165+
private SettingsSecurity getConfiguration(boolean mandatory) throws SecDispatcherException {
155166
String location = System.getProperty(SYSTEM_PROPERTY_CONFIGURATION_LOCATION, getConfigurationFile());
156-
String realLocation =
157-
location.charAt(0) == '~' ? System.getProperty("user.home") + location.substring(1) : location;
158-
159-
SettingsSecurity sec = SecUtil.read(realLocation, true);
160-
161-
if (sec == null)
162-
throw new SecDispatcherException(
163-
"cannot retrieve master password. Please check that " + realLocation + " exists and has data");
167+
location = location.charAt(0) == '~' ? System.getProperty("user.home") + location.substring(1) : location;
168+
SettingsSecurity sec = SecUtil.read(location, true);
169+
if (mandatory && sec == null)
170+
throw new SecDispatcherException("Please check that configuration file on path " + location + " exists");
164171

165172
return sec;
166173
}
167174

168-
private String getMaster(SettingsSecurity sec) throws SecDispatcherException {
175+
private String getMasterPassword(SettingsSecurity sec, boolean mandatory) throws SecDispatcherException {
176+
if (sec == null && !mandatory) {
177+
return null;
178+
}
179+
requireNonNull(sec, "configuration is null");
169180
String masterSource = requireNonNull(sec.getMasterSource(), "masterSource is null");
170181
for (MasterPasswordSource masterPasswordSource : masterPasswordSources.values()) {
171-
String master = masterPasswordSource.handle(masterSource);
172-
if (master != null) return master;
182+
String masterPassword = masterPasswordSource.handle(masterSource);
183+
if (masterPassword != null) return masterPassword;
184+
}
185+
if (mandatory) {
186+
throw new SecDispatcherException("master password could not be fetched");
187+
} else {
188+
return null;
173189
}
174-
throw new SecDispatcherException("master password could not be fetched");
175190
}
176191

177192
public String getConfigurationFile() {

src/main/java/org/codehaus/plexus/components/secdispatcher/internal/Dispatcher.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,18 @@
2525
*
2626
*/
2727
public interface Dispatcher {
28+
/**
29+
* Configuration key for masterPassword. It may be present, if SecDispatcher could
30+
* obtain it, but presence is not optional.
31+
*/
32+
String CONF_MASTER_PASSWORD = "masterPassword";
33+
2834
/**
2935
* encrypt given plaintext string
3036
*
3137
* @param str string to encrypt
3238
* @param attributes attributes, never {@code null}
33-
* @param config configuration from settings-security.xml, may be {@code null}
39+
* @param config configuration from settings-security.xml, never {@code null}
3440
* @return encrypted string
3541
*/
3642
String encrypt(String str, Map<String, String> attributes, Map<String, String> config)
@@ -41,7 +47,7 @@ String encrypt(String str, Map<String, String> attributes, Map<String, String> c
4147
*
4248
* @param str string to decrypt
4349
* @param attributes attributes, never {@code null}
44-
* @param config configuration from settings-security.xml, may be {@code null}
50+
* @param config configuration from settings-security.xml, never {@code null}
4551
* @return decrypted string
4652
*/
4753
String decrypt(String str, Map<String, String> attributes, Map<String, String> config)

src/main/java/org/codehaus/plexus/components/secdispatcher/internal/MasterPasswordSource.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ public interface MasterPasswordSource {
2626
* <li>if master password retrieval was attempted, but failed throw {@link SecDispatcherException}</li>
2727
* <li>happy path: return the master password.</li>
2828
* </ul>
29+
*
30+
* @param masterSource the source of master password, and opaque string.
31+
* @return the master password, or {@code null} if implementation does not handle this masterSource
32+
* @throws SecDispatcherException If implementation does handle this masterSource, but cannot obtain it
2933
*/
30-
String handle(String uri) throws SecDispatcherException;
34+
String handle(String masterSource) throws SecDispatcherException;
3135
}

src/main/java/org/codehaus/plexus/components/secdispatcher/internal/SecUtil.java

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@
1313

1414
package org.codehaus.plexus.components.secdispatcher.internal;
1515

16+
import javax.xml.stream.XMLStreamException;
17+
1618
import java.io.IOException;
1719
import java.io.InputStream;
1820
import java.net.URL;
1921
import java.nio.file.Files;
22+
import java.nio.file.NoSuchFileException;
2023
import java.nio.file.Paths;
2124
import java.util.HashMap;
2225
import java.util.List;
@@ -28,6 +31,8 @@
2831
import org.codehaus.plexus.components.secdispatcher.model.SettingsSecurity;
2932
import org.codehaus.plexus.components.secdispatcher.model.io.stax.SecurityConfigurationStaxReader;
3033

34+
import static java.util.Objects.requireNonNull;
35+
3136
/**
3237
*
3338
*
@@ -44,68 +49,57 @@ public class SecUtil {
4449

4550
public static SettingsSecurity read(String location, boolean cycle) throws SecDispatcherException {
4651
if (location == null) throw new SecDispatcherException("location to read from is null");
47-
4852
SettingsSecurity sec;
49-
5053
try {
5154
try (InputStream in = toStream(location)) {
5255
sec = new SecurityConfigurationStaxReader().read(in);
5356
}
54-
5557
if (cycle && sec.getRelocation() != null) return read(sec.getRelocation(), true);
56-
5758
return sec;
58-
} catch (Exception e) {
59-
throw new SecDispatcherException(e.getMessage(), e);
59+
} catch (NoSuchFileException e) {
60+
return null;
61+
} catch (IOException e) {
62+
throw new SecDispatcherException("IO Problem", e);
63+
} catch (XMLStreamException e) {
64+
throw new SecDispatcherException("Parsing error", e);
6065
}
6166
}
62-
// ---------------------------------------------------------------------------------------------------------------
63-
private static InputStream toStream(String resource) throws IOException {
64-
if (resource == null) return null;
6567

68+
private static InputStream toStream(String resource) throws IOException {
69+
requireNonNull(resource, "resource is null");
6670
int ind = resource.indexOf(PROTOCOL_DELIM);
67-
6871
if (ind > 1) {
6972
String protocol = resource.substring(0, ind);
7073
resource = resource.substring(ind + PROTOCOL_DELIM_LEN);
71-
7274
for (String p : URL_PROTOCOLS) {
7375
if (protocol.regionMatches(true, 0, p, 0, p.length())) {
7476
return new URL(p + PROTOCOL_DELIM + resource).openStream();
7577
}
7678
}
7779
}
78-
7980
return Files.newInputStream(Paths.get(resource));
8081
}
81-
// ---------------------------------------------------------------------------------------------------------------
82-
public static Map<String, String> getConfig(SettingsSecurity sec, String name) {
83-
if (name == null) return null;
8482

85-
List<Config> cl = sec.getConfigurations();
86-
87-
if (cl == null || cl.isEmpty()) return null;
88-
89-
for (Config cf : cl) {
90-
if (!name.equals(cf.getName())) {
91-
continue;
92-
}
93-
94-
List<ConfigProperty> pl = cf.getProperties();
95-
96-
if (pl == null || pl.isEmpty()) {
97-
return null;
98-
}
99-
100-
Map<String, String> res = new HashMap<>(pl.size());
101-
102-
for (ConfigProperty p : pl) {
103-
res.put(p.getName(), p.getValue());
83+
public static Map<String, String> getConfig(SettingsSecurity sec, String name) {
84+
if (sec != null && name != null) {
85+
List<Config> cl = sec.getConfigurations();
86+
if (!cl.isEmpty()) {
87+
for (Config cf : cl) {
88+
if (!name.equals(cf.getName())) {
89+
continue;
90+
}
91+
List<ConfigProperty> pl = cf.getProperties();
92+
if (pl.isEmpty()) {
93+
break;
94+
}
95+
Map<String, String> res = new HashMap<>(pl.size());
96+
for (ConfigProperty p : pl) {
97+
res.put(p.getName(), p.getValue());
98+
}
99+
return res;
100+
}
104101
}
105-
106-
return res;
107102
}
108-
109103
return null;
110104
}
111105
}

src/test/java/org/codehaus/plexus/components/secdispatcher/internal/DefaultSecDispatcherTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.codehaus.plexus.components.cipher.internal.DefaultPlexusCipher;
2323
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
24+
import org.codehaus.plexus.components.secdispatcher.SecDispatcherException;
2425
import org.codehaus.plexus.components.secdispatcher.internal.dispatcher.StaticDispatcher;
2526
import org.codehaus.plexus.components.secdispatcher.internal.sources.EnvMasterPasswordSource;
2627
import org.codehaus.plexus.components.secdispatcher.internal.sources.GpgAgentMasterPasswordSource;
@@ -172,4 +173,40 @@ void testDecryptWithDispatcher() throws Exception {
172173
assertNotNull(pass);
173174
assertEquals("decrypted", pass);
174175
}
176+
177+
@Test
178+
void testDecryptWithDispatcherConf() throws Exception {
179+
String bare = Base64.getEncoder().encodeToString("whatever".getBytes(StandardCharsets.UTF_8));
180+
DefaultSecDispatcher sd = new DefaultSecDispatcher(
181+
new DefaultPlexusCipher(),
182+
Map.of("static", new StaticMasterPasswordSource(masterPassword)),
183+
Map.of("magic", new Dispatcher() {
184+
@Override
185+
public String encrypt(String str, Map<String, String> attributes, Map<String, String> config)
186+
throws SecDispatcherException {
187+
throw new IllegalStateException("should not be called");
188+
}
189+
190+
@Override
191+
public String decrypt(String str, Map<String, String> attributes, Map<String, String> config)
192+
throws SecDispatcherException {
193+
assertEquals(bare, str);
194+
assertEquals(2, attributes.size());
195+
assertEquals("magic", attributes.get(SecDispatcher.DISPATCHER_NAME_ATTR));
196+
assertEquals("value", attributes.get("key"));
197+
198+
assertEquals(1, config.size());
199+
assertEquals(masterPassword, config.get(Dispatcher.CONF_MASTER_PASSWORD));
200+
201+
return "magic";
202+
}
203+
}),
204+
DefaultSecDispatcher.DEFAULT_CONFIGURATION);
205+
206+
assertEquals(Set.of("magic"), sd.availableDispatchers());
207+
String pass = sd.decrypt("{" + "[key=value," + SecDispatcher.DISPATCHER_NAME_ATTR + "=magic]"
208+
+ Base64.getEncoder().encodeToString("whatever".getBytes(StandardCharsets.UTF_8)) + "}");
209+
assertNotNull(pass);
210+
assertEquals("magic", pass);
211+
}
175212
}

0 commit comments

Comments
 (0)