Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unified, no more logic than dispatch in SecDispatcher, and is self-describable #75

Merged
merged 27 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</parent>

<artifactId>plexus-sec-dispatcher</artifactId>
<version>3.0.1-SNAPSHOT</version>
<version>4.0.0-SNAPSHOT</version>

<name>Plexus Security Dispatcher Component</name>

Expand All @@ -35,9 +35,16 @@
<properties>
<javaVersion>17</javaVersion>
<project.build.outputTimestamp>2024-09-29T15:16:00Z</project.build.outputTimestamp>

<version.slf4j>2.0.16</version.slf4j>
slachiewicz marked this conversation as resolved.
Show resolved Hide resolved
</properties>

<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${version.slf4j}</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-cipher</artifactId>
Expand All @@ -62,6 +69,12 @@
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${version.slf4j}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand All @@ -75,7 +88,7 @@
<artifactId>modello-maven-plugin</artifactId>
<version>2.4.0</version>
<configuration>
<version>3.0.0</version>
<version>4.0.0</version>
<models>
<model>src/main/mdo/settings-security.mdo</model>
</models>
Expand All @@ -96,6 +109,9 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<masterPassword>masterPw</masterPassword>
</systemPropertyVariables>
<environmentVariables>
<MASTER_PASSWORD>masterPw</MASTER_PASSWORD>
</environmentVariables>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

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

import java.util.Map;

import org.codehaus.plexus.components.secdispatcher.SecDispatcherException;
import static java.util.Objects.requireNonNull;

/**
* Dispatcher.
Expand All @@ -26,31 +26,51 @@
*/
public interface Dispatcher {
/**
* Configuration key for masterPassword. It may be present, if SecDispatcher could
* obtain it, but presence is optional. Still, dispatcher may throw and fail the operation
* if it requires it.
* The "encrypt payload" prepared by dispatcher.
*/
String CONF_MASTER_PASSWORD = "masterPassword";
final class EncryptPayload {
private final Map<String, String> attributes;
private final String encrypted;

public EncryptPayload(Map<String, String> attributes, String encrypted) {
this.attributes = requireNonNull(attributes);
this.encrypted = requireNonNull(encrypted);
}

public Map<String, String> getAttributes() {
return attributes;
}

public String getEncrypted() {
return encrypted;
}
}

/**
* encrypt given plaintext string
* Encrypt given plaintext string. Implementation must return at least same attributes it got, but may add more
* attributes to returned payload.
*
* @param str string to encrypt
* @param str string to encrypt, never {@code null}
* @param attributes attributes, never {@code null}
* @param config configuration from settings-security.xml, never {@code null}
* @return encrypted string
* @return encrypted string and attributes in {@link EncryptPayload}
*/
String encrypt(String str, Map<String, String> attributes, Map<String, String> config)
EncryptPayload encrypt(String str, Map<String, String> attributes, Map<String, String> config)
throws SecDispatcherException;

/**
* decrypt given encrypted string
* Decrypt given encrypted string.
*
* @param str string to decrypt
* @param str string to decrypt, never {@code null}
* @param attributes attributes, never {@code null}
* @param config configuration from settings-security.xml, never {@code null}
* @return decrypted string
*/
String decrypt(String str, Map<String, String> attributes, Map<String, String> config)
throws SecDispatcherException;

/**
* Validates dispatcher configuration.
*/
SecDispatcher.ValidationResponse validateConfiguration(Map<String, String> config);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package org.codehaus.plexus.components.secdispatcher;

import java.util.Collection;
import java.util.List;
import java.util.Optional;

import static java.util.Objects.requireNonNull;

/**
* Meta description of dispatcher.
*/
public interface DispatcherMeta {
final class Field {
private final String key;
private final boolean optional;
private final String defaultValue;
private final String description;
private final List<Field> options;

private Field(String key, boolean optional, String defaultValue, String description, List<Field> options) {
this.key = requireNonNull(key);
this.optional = optional;
this.defaultValue = defaultValue;
this.description = requireNonNull(description);
this.options = options;
}

/**
* The key to be used in configuration map for field.
*/
public String getKey() {
return key;
}

/**
* Is configuration optional?
*/
public boolean isOptional() {
return optional;
}

/**
* Optional default value of the configuration.
*/
public Optional<String> getDefaultValue() {
return Optional.ofNullable(defaultValue);
}

/**
* The human description of the configuration.
*/
public String getDescription() {
return description;
}

/**
* Optional list of options, if this configuration accepts limited values. Each option is represented
* as field, where {@link #getKey()} represents the value to be used, and {@link #displayName()} represents
* the description of option. The {@link #getDefaultValue()}, if present represents the value to be used
* instead of {@link #getKey()}.
*/
public Optional<List<Field>> getOptions() {
return Optional.ofNullable(options);
}

public static Builder builder(String key) {
return new Builder(key);
}

public static final class Builder {
private final String key;
private boolean optional;
private String defaultValue;
private String description;
private List<Field> options;

private Builder(String key) {
this.key = requireNonNull(key);
}

public Builder optional(boolean optional) {
this.optional = optional;
return this;
}

public Builder defaultValue(String defaultValue) {
this.defaultValue = defaultValue;
return this;
}

public Builder description(String description) {
this.description = requireNonNull(description);
return this;
}

public Builder options(List<Field> options) {
this.options = requireNonNull(options);
return this;
}

public Field build() {
return new Field(key, optional, defaultValue, description, options);
}
}
}

/**
* Option to hide this instance from users, like for migration or legacy purposes.
*/
default boolean isHidden() {
return false;
}

/**
* The name of the dispatcher.
*/
String name();

/**
* Returns the display (human) name of the dispatcher.
*/
String displayName();

/**
* Returns the configuration fields of the dispatcher.
*/
Collection<Field> fields();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2008 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

package org.codehaus.plexus.components.secdispatcher;

/**
* Source of master password.
*/
public interface MasterSource {
/**
* Handles the config to get master password. Implementation may do one of the following things:
* <ul>
* <li>if the config cannot be handled by given source, return {@code null}</li>
* <li>otherwise, if master password retrieval based on config was attempted but failed, throw {@link SecDispatcherException}</li>
* <li>happy path: return the master password.</li>
* </ul>
*
* @param config the source of master password, and opaque string.
* @return the master password, or {@code null} if implementation does not handle this config
* @throws SecDispatcherException If implementation does handle this masterSource, but cannot obtain master password
*/
String handle(String config) throws SecDispatcherException;

/**
* Validates master source configuration.
* <ul>
* <li>if the config cannot be handled by given source, return {@code null}</li>
* <li>otherwise, implementation performs validation and returns non-{@code null} validation response</li>
* </ul>
*/
SecDispatcher.ValidationResponse validateConfiguration(String config);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

package org.codehaus.plexus.components.secdispatcher.internal.sources;
package org.codehaus.plexus.components.secdispatcher;

import org.codehaus.plexus.components.secdispatcher.SecDispatcherException;
import org.codehaus.plexus.components.secdispatcher.internal.MasterPasswordSource;
import java.util.Optional;

import static java.util.Objects.requireNonNull;

public class StaticMasterPasswordSource implements MasterPasswordSource {
private final String masterPassword;

public StaticMasterPasswordSource(String masterPassword) {
this.masterPassword = requireNonNull(masterPassword);
}
/**
* Source of master password.
*/
public interface MasterSourceMeta {
/**
* String describing what this source does.
*/
String description();

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