Skip to content

Commit

Permalink
Update Javadocs
Browse files Browse the repository at this point in the history
  • Loading branch information
spyrkob committed Oct 15, 2024
1 parent ff06f33 commit 5989012
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 92 deletions.
11 changes: 6 additions & 5 deletions core/src/main/java/org/wildfly/channel/ChannelImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import org.wildfly.channel.spi.MavenVersionsResolver;
import org.wildfly.channel.spi.SignatureResult;
import org.wildfly.channel.spi.SignatureValidator;
import org.wildfly.channel.spi.ValidationResource;
import org.wildfly.channel.spi.ArtifactIdentifier;
import org.wildfly.channel.version.VersionMatcher;

/**
Expand Down Expand Up @@ -82,6 +82,7 @@ public ChannelImpl(Channel channelDefinition) {
*
* @param factory
* @param channels
* @param signatureValidator - the validator used to check the signatures of resolved artifacts
* @throws UnresolvedRequiredManifestException - if a required manifest cannot be resolved either via maven coordinates or in the list of channels
* @throws CyclicDependencyException - if the required manifests form a cyclic dependency
*/
Expand Down Expand Up @@ -492,7 +493,7 @@ ResolveArtifactResult resolveArtifact(String groupId, String artifactId, String

private void validateGpgSignature(String groupId, String artifactId, String extension, String classifier,
String version, File artifact) {
final ValidationResource mavenArtifact = new ValidationResource.MavenResource(groupId, artifactId, extension,
final ArtifactIdentifier mavenArtifact = new ArtifactIdentifier.MavenResource(groupId, artifactId, extension,
classifier, version);
try {
final File signature = resolver.resolveArtifact(groupId, artifactId, extension + SIGNATURE_FILE_SUFFIX,
Expand All @@ -511,7 +512,7 @@ mavenArtifact, new FileInputStream(artifact), new FileInputStream(signature),

private void validateGpgSignature(URL artifactFile, URL signature) throws IOException {
final SignatureResult signatureResult = signatureValidator.validateSignature(
new ValidationResource.UrlResource(artifactFile),
new ArtifactIdentifier.UrlResource(artifactFile),
artifactFile.openStream(), signature.openStream(),
channelDefinition.getGpgUrls()
);
Expand All @@ -533,7 +534,7 @@ List<ResolveArtifactResult> resolveArtifacts(List<ArtifactCoordinate> coordinate
for (int i = 0; i < resolvedArtifacts.size(); i++) {
final File artifact = resolvedArtifacts.get(i);
final ArtifactCoordinate c = coordinates.get(i);
final ValidationResource.MavenResource mavenArtifact = new ValidationResource.MavenResource(c.getGroupId(), c.getArtifactId(),
final ArtifactIdentifier.MavenResource mavenArtifact = new ArtifactIdentifier.MavenResource(c.getGroupId(), c.getArtifactId(),
c.getExtension(), c.getClassifier(), c.getVersion());
final File signature = signatures.get(i);
try {
Expand All @@ -549,7 +550,7 @@ List<ResolveArtifactResult> resolveArtifacts(List<ArtifactCoordinate> coordinate
}
}
} catch (ArtifactTransferException e) {
final ValidationResource.MavenResource artifact = new ValidationResource.MavenResource(e.getUnresolvedArtifacts().stream().findFirst().get());
final ArtifactIdentifier.MavenResource artifact = new ArtifactIdentifier.MavenResource(e.getUnresolvedArtifacts().stream().findFirst().get());
throw new SignatureValidator.SignatureException(String.format("Unable to find required signature for %s:%s:%s",
artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()),
SignatureResult.noSignature(artifact));
Expand Down
11 changes: 10 additions & 1 deletion core/src/main/java/org/wildfly/channel/ChannelSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class ChannelSession implements AutoCloseable {
private final int versionResolutionParallelism;

/**
* Create a ChannelSession.
* Create a ChannelSession with a default rejecting signature validator.
*
* @param channelDefinitions the list of channels to resolve Maven artifact
* @param factory Factory to create {@code MavenVersionsResolver} that are performing the actual Maven resolution.
Expand All @@ -64,6 +64,15 @@ public ChannelSession(List<Channel> channelDefinitions, MavenVersionsResolver.Fa
this(channelDefinitions, factory, DEFAULT_SPLIT_ARTIFACT_PARALLELISM, SignatureValidator.REJECTING_VALIDATOR);
}

/**
* Create a ChannelSession with a default rejecting signature validator.
*
* @param channelDefinitions the list of channels to resolve Maven artifact
* @param factory Factory to create {@code MavenVersionsResolver} that are performing the actual Maven resolution.
* @param signatureValidator Validator to verify signatures of downloaded artifacts
* @throws UnresolvedRequiredManifestException - if a required manifest cannot be resolved either via maven coordinates or in the list of channels
* @throws CyclicDependencyException - if the required manifests form a cyclic dependency
*/
public ChannelSession(List<Channel> channelDefinitions, MavenVersionsResolver.Factory factory, SignatureValidator signatureValidator) {
this(channelDefinitions, factory, DEFAULT_SPLIT_ARTIFACT_PARALLELISM, signatureValidator);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@

import org.wildfly.channel.ArtifactCoordinate;

public interface ValidationResource {
/**
* An identifier of an artifact being validated. It can be either a Maven coordinate or an URL.
*/
public interface ArtifactIdentifier {

class UrlResource implements ValidationResource {
private URL resourceUrl;
class UrlResource implements ArtifactIdentifier {
private final URL resourceUrl;

public UrlResource(URL resourceUrl) {
this.resourceUrl = resourceUrl;
Expand All @@ -32,9 +35,14 @@ public UrlResource(URL resourceUrl) {
public URL getResourceUrl() {
return resourceUrl;
}

@Override
public String getDescription() {
return resourceUrl.toExternalForm();
}
}

class MavenResource extends ArtifactCoordinate implements ValidationResource {
class MavenResource extends ArtifactCoordinate implements ArtifactIdentifier {

public MavenResource(String groupId, String artifactId, String extension, String classifier, String version) {
super(groupId, artifactId, extension, classifier, version);
Expand All @@ -47,8 +55,24 @@ public MavenResource(ArtifactCoordinate artifactCoordinate) {
artifactCoordinate.getClassifier(),
artifactCoordinate.getVersion());
}

@Override
public String getDescription() {
StringBuilder sb = new StringBuilder();
sb.append(groupId).append(":").append(artifactId).append(":");
if (classifier != null && !classifier.isEmpty()) {
sb.append(classifier).append(":");
}
if (extension != null && !extension.isEmpty()) {
sb.append(extension).append(":");
}
sb.append(version);
return sb.toString();
}
}

String getDescription();

default boolean isMavenResource() {
return this instanceof MavenResource;
}
Expand Down
28 changes: 20 additions & 8 deletions core/src/main/java/org/wildfly/channel/spi/SignatureResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,41 @@
*/
package org.wildfly.channel.spi;

/**
* Represents a result of artifact verification
*/
public class SignatureResult {

private ValidationResource resource;
/**
* Identifier of the artifact that was being verified.
*/
private ArtifactIdentifier resource;
/**
* Identifier of the certificate used to verify the artifact.
*/
private String keyId;
/**
* Optional message with details of validation.
*/
private String message;

public static SignatureResult noMatchingCertificate(ValidationResource resource, String keyID) {
public static SignatureResult noMatchingCertificate(ArtifactIdentifier resource, String keyID) {
return new SignatureResult(Result.NO_MATCHING_CERT, resource, keyID, null);
}

public static SignatureResult revoked(ValidationResource resource, String keyID, String revocationReason) {
public static SignatureResult revoked(ArtifactIdentifier resource, String keyID, String revocationReason) {
return new SignatureResult(Result.REVOKED, resource, keyID, revocationReason);
}

public static SignatureResult expired(ValidationResource resource, String keyID) {
public static SignatureResult expired(ArtifactIdentifier resource, String keyID) {
return new SignatureResult(Result.EXPIRED, resource, keyID, null);
}

public static SignatureResult noSignature(ValidationResource resource) {
public static SignatureResult noSignature(ArtifactIdentifier resource) {
return new SignatureResult(Result.NO_SIGNATURE, resource, null, null);
}

public static SignatureResult invalid(ValidationResource resource) {
public static SignatureResult invalid(ArtifactIdentifier resource) {
return new SignatureResult(Result.INVALID, resource, null, null);
}

Expand All @@ -48,7 +60,7 @@ public static SignatureResult ok() {
return new SignatureResult(Result.OK, null, null, null);
}

private SignatureResult(Result result, ValidationResource resource, String keyID, String message) {
private SignatureResult(Result result, ArtifactIdentifier resource, String keyID, String message) {
this.result = result;
this.resource = resource;
this.keyId = keyID;
Expand All @@ -59,7 +71,7 @@ public Result getResult() {
return result;
}

public ValidationResource getResource() {
public ArtifactIdentifier getResource() {
return resource;
}

Expand Down
16 changes: 12 additions & 4 deletions core/src/main/java/org/wildfly/channel/spi/SignatureValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,29 @@
* Called to validate detached signatures of artifacts resolved in the channel
*/
public interface SignatureValidator {
/**
* A default validator, rejecting all artifacts
*/
SignatureValidator REJECTING_VALIDATOR = (artifactSource, artifactStream, signatureStream, gpgUrls) -> {
throw new SignatureException("Not implemented", SignatureResult.noSignature(artifactSource));
};

/**
* validates a signature of {@code artifact}. The locally downloaded {@code signature} has to be an armour encoded GPG signature.
* validates a signature of an artifact. The locally downloaded {@code signature} has to be an armour encoded GPG signature.
*
* @param artifact - {@code MavenArtifact} to validate. Includes a full GAV and the local artifact file.
* @param signature - local file containing armour encoded detached GPG signature for the {@code artifact}.
* @param artifactId - an identifier of the resource to be validated.
* @param artifactStream - an {@code InputStream} of the artifact to be verified.
* @param signatureStream - an {@code InputStream} of the armour encoded detached GPG signature for the artifact.
* @param gpgUrls - URLs of the keys defined in the channel. Empty collection if channel does not define any signatures.
* @return {@link SignatureResult} with the result of validation
* @throws SignatureException - if an unexpected error occurred when handling the keys.
*/
SignatureResult validateSignature(ValidationResource artifactSource, InputStream artifactStream, InputStream signatureStream, List<String> gpgUrls) throws SignatureException;
SignatureResult validateSignature(ArtifactIdentifier artifactId, InputStream artifactStream,
InputStream signatureStream, List<String> gpgUrls) throws SignatureException;

/**
* An exception signifying issue with an artifact signature validation.
*/
class SignatureException extends RuntimeException {
private final SignatureResult signatureResult;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@
import org.wildfly.channel.spi.MavenVersionsResolver;
import org.wildfly.channel.spi.SignatureResult;
import org.wildfly.channel.spi.SignatureValidator;
import org.wildfly.channel.spi.ValidationResource;
import org.wildfly.channel.spi.ArtifactIdentifier;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
Expand Down Expand Up @@ -504,7 +503,7 @@ public void invalidSignatureCausesError() throws Exception {
when(resolver.resolveArtifact("test.channels", "base-manifest",
ChannelManifest.EXTENSION + SIGNATURE_FILE_SUFFIX, ChannelManifest.CLASSIFIER, "1.0.0"))
.thenReturn(tempDir.resolve("test-manifest.yaml.asc").toFile());
when(signatureValidator.validateSignature(any(), any(), any(), any())).thenReturn(SignatureResult.invalid(mock(ValidationResource.class)));
when(signatureValidator.validateSignature(any(), any(), any(), any())).thenReturn(SignatureResult.invalid(mock(ArtifactIdentifier.class)));
assertThrows(SignatureValidator.SignatureException.class, () -> new ChannelSession(channels, factory));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.wildfly.channel.spi.MavenVersionsResolver;
import org.wildfly.channel.spi.SignatureResult;
import org.wildfly.channel.spi.SignatureValidator;
import org.wildfly.channel.spi.ValidationResource;

public class ChannelSessionTestCase {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.wildfly.channel;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand Down Expand Up @@ -26,14 +42,14 @@
import org.wildfly.channel.spi.MavenVersionsResolver;
import org.wildfly.channel.spi.SignatureResult;
import org.wildfly.channel.spi.SignatureValidator;
import org.wildfly.channel.spi.ValidationResource;
import org.wildfly.channel.spi.ArtifactIdentifier;

public class ChannelSessionWithSignatureValidationTestCase {

private static final ValidationResource.MavenResource ARTIFACT = new ValidationResource.MavenResource(
private static final ArtifactIdentifier.MavenResource ARTIFACT = new ArtifactIdentifier.MavenResource(
"org.wildfly", "wildfly-ee-galleon-pack", "zip", null, "25.0.1.Final");

private static final ValidationResource.MavenResource MANIFEST = new ValidationResource.MavenResource(
private static final ArtifactIdentifier.MavenResource MANIFEST = new ArtifactIdentifier.MavenResource(
"org.channels", "test-manifest", ChannelManifest.EXTENSION, ChannelManifest.CLASSIFIER, "1.0.0");

@TempDir
Expand Down Expand Up @@ -141,7 +157,7 @@ public void failedSignatureValidationThrowsException() throws Exception {
ARTIFACT.classifier, ARTIFACT.version))
.thenReturn(signatureFile);
// simulate a valid signature of the channel manifest, and invalid signature of the artifact
when(signatureValidator.validateSignature(eq(new ValidationResource.MavenResource(
when(signatureValidator.validateSignature(eq(new ArtifactIdentifier.MavenResource(
MANIFEST.groupId, MANIFEST.artifactId, MANIFEST.extension, MANIFEST.classifier, MANIFEST.version)),
any(), any(), any())).thenReturn(SignatureResult.ok());
when(signatureValidator.validateSignature(eq(ARTIFACT),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,28 @@

import java.util.List;

/**
* Local store of trusted public keys.
*
* Note: the keystore can reject a public key being added. In such case, the {@code GpgSignatureValidator} has to reject this key.
*/
public interface GpgKeystore {

/**
* resolve a public key from the store.
*
* @param keyID - a HEX form of the key ID
* @return - the resolved public key or {@code null} if the key was not found
*/
PGPPublicKey get(String keyID);

/**
* records the public keys in the store for future use.
*
* @param publicKey - list of trusted public keys
* @return true if the public keys have been added successfully
* false otherwise.
* @throws KeystoreOperationException if the keystore threw an error during the operation
*/
boolean add(List<PGPPublicKey> publicKey) throws KeystoreOperationException;
}
Loading

0 comments on commit 5989012

Please sign in to comment.