Skip to content

Commit ab0942e

Browse files
authored
4.x: Unified logic, no more extra logic in SecDispatcher; made self-describable (#75)
Hence, moved version to 4.x. Changes: * "master pw" is **really just one (of possibly multiple) dispatchers**, so moved "master password" into dispatchers. Now SecDispatcher is really just a "dispatcher" with one `Dispatcher` implementation OOTB * similarly, old sec behaviour is moved to dispatcher as "legacy" to support mvn3 encrypted passwords (only decrypting) * dispatcher passwords now minimally include "name" attribute (and more, if dispatcher adds it), master dispatcher adds "cipher" as well, this allows future proof working if new Cipher added and user makes it default: non-reencoded passwords will still work with old cipher. * `Dispatcher` and `MasterSource` interfaces have corresponding "meta" interfaces where they can "describe themselves" * added support for pinentry as well * configuration validation now performs "deep validation" and produces useful report * this is no more OOTB ready-to-use JSR330 component. As we know from history, it WAS before, and it provided a "bad" default configuration path that was NEVER used, and forced Maven instead to _always redefine_ the component to make it usable within Maven (to make it use maven expected config). So, it is now the integrator duty to "properly integrate" this component, recommended way is to create JSR330 Provider with it. Also, the "system property override" of configuration path was removed, whatever integrating app needs is doable from it's own Provider implementation. Self describe and validation in action: https://asciinema.org/a/9kmtQWhKJC9elFp3tiDlxpOTE
1 parent 75f4891 commit ab0942e

28 files changed

+1752
-514
lines changed

pom.xml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111

1212
<artifactId>plexus-sec-dispatcher</artifactId>
13-
<version>3.0.1-SNAPSHOT</version>
13+
<version>4.0.0-SNAPSHOT</version>
1414

1515
<name>Plexus Security Dispatcher Component</name>
1616

@@ -35,9 +35,16 @@
3535
<properties>
3636
<javaVersion>17</javaVersion>
3737
<project.build.outputTimestamp>2024-09-29T15:16:00Z</project.build.outputTimestamp>
38+
39+
<version.slf4j>2.0.16</version.slf4j>
3840
</properties>
3941

4042
<dependencies>
43+
<dependency>
44+
<groupId>org.slf4j</groupId>
45+
<artifactId>slf4j-api</artifactId>
46+
<version>${version.slf4j}</version>
47+
</dependency>
4148
<dependency>
4249
<groupId>org.codehaus.plexus</groupId>
4350
<artifactId>plexus-cipher</artifactId>
@@ -62,6 +69,12 @@
6269
<artifactId>junit-jupiter</artifactId>
6370
<scope>test</scope>
6471
</dependency>
72+
<dependency>
73+
<groupId>org.slf4j</groupId>
74+
<artifactId>slf4j-simple</artifactId>
75+
<version>${version.slf4j}</version>
76+
<scope>test</scope>
77+
</dependency>
6578
</dependencies>
6679

6780
<build>
@@ -75,7 +88,7 @@
7588
<artifactId>modello-maven-plugin</artifactId>
7689
<version>2.4.0</version>
7790
<configuration>
78-
<version>3.0.0</version>
91+
<version>4.0.0</version>
7992
<models>
8093
<model>src/main/mdo/settings-security.mdo</model>
8194
</models>
@@ -96,6 +109,9 @@
96109
<groupId>org.apache.maven.plugins</groupId>
97110
<artifactId>maven-surefire-plugin</artifactId>
98111
<configuration>
112+
<systemPropertyVariables>
113+
<masterPassword>masterPw</masterPassword>
114+
</systemPropertyVariables>
99115
<environmentVariables>
100116
<MASTER_PASSWORD>masterPw</MASTER_PASSWORD>
101117
</environmentVariables>

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

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
1212
*/
1313

14-
package org.codehaus.plexus.components.secdispatcher.internal;
14+
package org.codehaus.plexus.components.secdispatcher;
1515

1616
import java.util.Map;
1717

18-
import org.codehaus.plexus.components.secdispatcher.SecDispatcherException;
18+
import static java.util.Objects.requireNonNull;
1919

2020
/**
2121
* Dispatcher.
@@ -26,31 +26,51 @@
2626
*/
2727
public interface Dispatcher {
2828
/**
29-
* Configuration key for masterPassword. It may be present, if SecDispatcher could
30-
* obtain it, but presence is optional. Still, dispatcher may throw and fail the operation
31-
* if it requires it.
29+
* The "encrypt payload" prepared by dispatcher.
3230
*/
33-
String CONF_MASTER_PASSWORD = "masterPassword";
31+
final class EncryptPayload {
32+
private final Map<String, String> attributes;
33+
private final String encrypted;
34+
35+
public EncryptPayload(Map<String, String> attributes, String encrypted) {
36+
this.attributes = requireNonNull(attributes);
37+
this.encrypted = requireNonNull(encrypted);
38+
}
39+
40+
public Map<String, String> getAttributes() {
41+
return attributes;
42+
}
43+
44+
public String getEncrypted() {
45+
return encrypted;
46+
}
47+
}
3448

3549
/**
36-
* encrypt given plaintext string
50+
* Encrypt given plaintext string. Implementation must return at least same attributes it got, but may add more
51+
* attributes to returned payload.
3752
*
38-
* @param str string to encrypt
53+
* @param str string to encrypt, never {@code null}
3954
* @param attributes attributes, never {@code null}
4055
* @param config configuration from settings-security.xml, never {@code null}
41-
* @return encrypted string
56+
* @return encrypted string and attributes in {@link EncryptPayload}
4257
*/
43-
String encrypt(String str, Map<String, String> attributes, Map<String, String> config)
58+
EncryptPayload encrypt(String str, Map<String, String> attributes, Map<String, String> config)
4459
throws SecDispatcherException;
4560

4661
/**
47-
* decrypt given encrypted string
62+
* Decrypt given encrypted string.
4863
*
49-
* @param str string to decrypt
64+
* @param str string to decrypt, never {@code null}
5065
* @param attributes attributes, never {@code null}
5166
* @param config configuration from settings-security.xml, never {@code null}
5267
* @return decrypted string
5368
*/
5469
String decrypt(String str, Map<String, String> attributes, Map<String, String> config)
5570
throws SecDispatcherException;
71+
72+
/**
73+
* Validates dispatcher configuration.
74+
*/
75+
SecDispatcher.ValidationResponse validateConfiguration(Map<String, String> config);
5676
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package org.codehaus.plexus.components.secdispatcher;
2+
3+
import java.util.Collection;
4+
import java.util.List;
5+
import java.util.Optional;
6+
7+
import static java.util.Objects.requireNonNull;
8+
9+
/**
10+
* Meta description of dispatcher.
11+
*/
12+
public interface DispatcherMeta {
13+
final class Field {
14+
private final String key;
15+
private final boolean optional;
16+
private final String defaultValue;
17+
private final String description;
18+
private final List<Field> options;
19+
20+
private Field(String key, boolean optional, String defaultValue, String description, List<Field> options) {
21+
this.key = requireNonNull(key);
22+
this.optional = optional;
23+
this.defaultValue = defaultValue;
24+
this.description = requireNonNull(description);
25+
this.options = options;
26+
}
27+
28+
/**
29+
* The key to be used in configuration map for field.
30+
*/
31+
public String getKey() {
32+
return key;
33+
}
34+
35+
/**
36+
* Is configuration optional?
37+
*/
38+
public boolean isOptional() {
39+
return optional;
40+
}
41+
42+
/**
43+
* Optional default value of the configuration.
44+
*/
45+
public Optional<String> getDefaultValue() {
46+
return Optional.ofNullable(defaultValue);
47+
}
48+
49+
/**
50+
* The human description of the configuration.
51+
*/
52+
public String getDescription() {
53+
return description;
54+
}
55+
56+
/**
57+
* Optional list of options, if this configuration accepts limited values. Each option is represented
58+
* as field, where {@link #getKey()} represents the value to be used, and {@link #displayName()} represents
59+
* the description of option. The {@link #getDefaultValue()}, if present represents the value to be used
60+
* instead of {@link #getKey()}.
61+
*/
62+
public Optional<List<Field>> getOptions() {
63+
return Optional.ofNullable(options);
64+
}
65+
66+
public static Builder builder(String key) {
67+
return new Builder(key);
68+
}
69+
70+
public static final class Builder {
71+
private final String key;
72+
private boolean optional;
73+
private String defaultValue;
74+
private String description;
75+
private List<Field> options;
76+
77+
private Builder(String key) {
78+
this.key = requireNonNull(key);
79+
}
80+
81+
public Builder optional(boolean optional) {
82+
this.optional = optional;
83+
return this;
84+
}
85+
86+
public Builder defaultValue(String defaultValue) {
87+
this.defaultValue = defaultValue;
88+
return this;
89+
}
90+
91+
public Builder description(String description) {
92+
this.description = requireNonNull(description);
93+
return this;
94+
}
95+
96+
public Builder options(List<Field> options) {
97+
this.options = requireNonNull(options);
98+
return this;
99+
}
100+
101+
public Field build() {
102+
return new Field(key, optional, defaultValue, description, options);
103+
}
104+
}
105+
}
106+
107+
/**
108+
* Option to hide this instance from users, like for migration or legacy purposes.
109+
*/
110+
default boolean isHidden() {
111+
return false;
112+
}
113+
114+
/**
115+
* The name of the dispatcher.
116+
*/
117+
String name();
118+
119+
/**
120+
* Returns the display (human) name of the dispatcher.
121+
*/
122+
String displayName();
123+
124+
/**
125+
* Returns the configuration fields of the dispatcher.
126+
*/
127+
Collection<Field> fields();
128+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2008 Sonatype, Inc. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7+
*
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the Apache License Version 2.0 is distributed on an
10+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12+
*/
13+
14+
package org.codehaus.plexus.components.secdispatcher;
15+
16+
/**
17+
* Source of master password.
18+
*/
19+
public interface MasterSource {
20+
/**
21+
* Handles the config to get master password. Implementation may do one of the following things:
22+
* <ul>
23+
* <li>if the config cannot be handled by given source, return {@code null}</li>
24+
* <li>otherwise, if master password retrieval based on config was attempted but failed, throw {@link SecDispatcherException}</li>
25+
* <li>happy path: return the master password.</li>
26+
* </ul>
27+
*
28+
* @param config the source of master password, and opaque string.
29+
* @return the master password, or {@code null} if implementation does not handle this config
30+
* @throws SecDispatcherException If implementation does handle this masterSource, but cannot obtain master password
31+
*/
32+
String handle(String config) throws SecDispatcherException;
33+
34+
/**
35+
* Validates master source configuration.
36+
* <ul>
37+
* <li>if the config cannot be handled by given source, return {@code null}</li>
38+
* <li>otherwise, implementation performs validation and returns non-{@code null} validation response</li>
39+
* </ul>
40+
*/
41+
SecDispatcher.ValidationResponse validateConfiguration(String config);
42+
}
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,22 @@
1111
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
1212
*/
1313

14-
package org.codehaus.plexus.components.secdispatcher.internal.sources;
14+
package org.codehaus.plexus.components.secdispatcher;
1515

16-
import org.codehaus.plexus.components.secdispatcher.SecDispatcherException;
17-
import org.codehaus.plexus.components.secdispatcher.internal.MasterPasswordSource;
16+
import java.util.Optional;
1817

19-
import static java.util.Objects.requireNonNull;
20-
21-
public class StaticMasterPasswordSource implements MasterPasswordSource {
22-
private final String masterPassword;
23-
24-
public StaticMasterPasswordSource(String masterPassword) {
25-
this.masterPassword = requireNonNull(masterPassword);
26-
}
18+
/**
19+
* Source of master password.
20+
*/
21+
public interface MasterSourceMeta {
22+
/**
23+
* String describing what this source does.
24+
*/
25+
String description();
2726

28-
@Override
29-
public String handle(String masterSource) throws SecDispatcherException {
30-
return masterPassword;
31-
}
27+
/**
28+
* Optional "config template" that may serve as basis to configure this master source. The template cannot be
29+
* "reused" as is as configuration.
30+
*/
31+
Optional<String> configTemplate();
3232
}

0 commit comments

Comments
 (0)