You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2022/03/15 08:04:33 UTC
[maven-resolver] 02/19: Fix for MRESOLVER-242
This is an automated email from the ASF dual-hosted git repository.
michaelo pushed a commit to branch MRESOLVER-241
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit 2e123bfc6300b19cde7174c8bc52190f85c29816
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Tue Feb 22 10:37:34 2022 +0100
Fix for MRESOLVER-242
Makes resolver aware of signatures in very same way as
it became aware of checksums, but not implementing
signign/verification services yet.
---
.../aether/connector/basic/ChecksumValidator.java | 9 ++-
.../eclipse/aether/impl/guice/AetherModule.java | 19 +++++
.../impl/Maven2RepositoryLayoutFactory.java | 62 ++++++++++++---
.../DefaultSignatureAlgorithmFactorySelector.java | 89 ++++++++++++++++++++++
.../signature/GpgSignatureAlgorithmFactory.java | 52 +++++++++++++
.../spi/connector/layout/RepositoryLayout.java | 14 +++-
.../connector/signature/SignatureAlgorithm.java | 38 +++++++++
.../signature/SignatureAlgorithmFactory.java | 49 ++++++++++++
.../SignatureAlgorithmFactorySelector.java | 45 +++++++++++
.../SignatureAlgorithmFactorySupport.java | 59 ++++++++++++++
10 files changed, 422 insertions(+), 14 deletions(-)
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
index 87b6b3c..14ae450 100644
--- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
@@ -120,11 +120,14 @@ final class ChecksumValidator
{
return;
}
- if ( validateExternalChecksums( actualChecksums ) )
+ if ( !checksumLocations.isEmpty() )
{
- return;
+ if ( validateExternalChecksums( actualChecksums ) )
+ {
+ return;
+ }
+ checksumPolicy.onNoMoreChecksums();
}
- checksumPolicy.onNoMoreChecksums();
}
private boolean validateChecksums( Map<String, ?> actualChecksums, ChecksumKind kind, Map<String, ?> checksums )
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java
index 9629dc9..64a201b 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java
@@ -48,6 +48,8 @@ import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory;
import org.eclipse.aether.internal.impl.checksum.Sha256ChecksumAlgorithmFactory;
import org.eclipse.aether.internal.impl.checksum.Sha512ChecksumAlgorithmFactory;
import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector;
+import org.eclipse.aether.internal.impl.signature.DefaultSignatureAlgorithmFactorySelector;
+import org.eclipse.aether.internal.impl.signature.GpgSignatureAlgorithmFactory;
import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelector;
import org.eclipse.aether.internal.impl.synccontext.named.SimpleNamedLockFactorySelector;
@@ -90,6 +92,8 @@ import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithmFactory;
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithmFactorySelector;
import org.eclipse.aether.spi.connector.transport.TransporterProvider;
import org.eclipse.aether.spi.io.FileProcessor;
import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
@@ -184,6 +188,11 @@ public class AetherModule
bind( ChecksumAlgorithmFactorySelector.class )
.to( DefaultChecksumAlgorithmFactorySelector.class ).in ( Singleton.class );
+ bind( SignatureAlgorithmFactory.class ).annotatedWith( Names.named( GpgSignatureAlgorithmFactory.NAME ) )
+ .to( GpgSignatureAlgorithmFactory.class );
+ bind( SignatureAlgorithmFactorySelector.class )
+ .to( DefaultSignatureAlgorithmFactorySelector.class ).in ( Singleton.class );
+
bind( NamedLockFactorySelector.class ).to( SimpleNamedLockFactorySelector.class ).in( Singleton.class );
bind( SyncContextFactory.class ).to( DefaultSyncContextFactory.class ).in( Singleton.class );
bind( org.eclipse.aether.impl.SyncContextFactory.class )
@@ -241,6 +250,16 @@ public class AetherModule
@Provides
@Singleton
+ Map<String, SignatureAlgorithmFactory> provideSignatureTypes(
+ @Named( GpgSignatureAlgorithmFactory.NAME ) SignatureAlgorithmFactory gpg )
+ {
+ Map<String, SignatureAlgorithmFactory> checksumTypes = new HashMap<>();
+ checksumTypes.put( GpgSignatureAlgorithmFactory.NAME, gpg );
+ return Collections.unmodifiableMap( checksumTypes );
+ }
+
+ @Provides
+ @Singleton
Map<String, NameMapper> provideNameMappers(
@Named( StaticNameMapper.NAME ) NameMapper staticNameMapper,
@Named( GAVNameMapper.NAME ) NameMapper gavNameMapper,
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java
index d0b3de9..e95a011 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java
@@ -34,12 +34,15 @@ import javax.inject.Singleton;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector;
+import org.eclipse.aether.internal.impl.signature.DefaultSignatureAlgorithmFactorySelector;
import org.eclipse.aether.metadata.Metadata;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithmFactory;
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithmFactorySelector;
import org.eclipse.aether.transfer.NoRepositoryLayoutException;
import org.eclipse.aether.util.ConfigUtils;
@@ -55,14 +58,21 @@ public final class Maven2RepositoryLayoutFactory
{
static final String CONFIG_PROP_SIGNATURE_CHECKSUMS = "aether.checksums.forSignature";
+
static final String CONFIG_PROP_CHECKSUMS_ALGORITHMS = "aether.checksums.algorithms";
static final String DEFAULT_CHECKSUMS_ALGORITHMS = "SHA-1,MD5";
+ static final String CONFIG_PROP_SIGNATURE_ALGORITHMS = "aether.signatures.algorithms";
+
+ static final String DEFAULT_SIGNATURE_ALGORITHMS = "GPG";
+
private float priority;
private final ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector;
+ private final SignatureAlgorithmFactorySelector signatureAlgorithmFactorySelector;
+
public float getPriority()
{
return priority;
@@ -74,13 +84,15 @@ public final class Maven2RepositoryLayoutFactory
@Deprecated
public Maven2RepositoryLayoutFactory()
{
- this( new DefaultChecksumAlgorithmFactorySelector() );
+ this( new DefaultChecksumAlgorithmFactorySelector(), new DefaultSignatureAlgorithmFactorySelector() );
}
@Inject
- public Maven2RepositoryLayoutFactory( ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector )
+ public Maven2RepositoryLayoutFactory( ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector,
+ SignatureAlgorithmFactorySelector signatureAlgorithmFactorySelector )
{
this.checksumAlgorithmFactorySelector = requireNonNull( checksumAlgorithmFactorySelector );
+ this.signatureAlgorithmFactorySelector = requireNonNull( signatureAlgorithmFactorySelector );
}
/**
@@ -118,20 +130,37 @@ public final class Maven2RepositoryLayoutFactory
checksumsAlgorithms.add( checksumAlgorithmFactorySelector.select( checksumsAlgorithmName ) );
}
+ // no need for order here
+ List<String> signatureAlgorithmNames = Arrays.asList(
+ ConfigUtils.getString(
+ session, DEFAULT_SIGNATURE_ALGORITHMS, CONFIG_PROP_SIGNATURE_ALGORITHMS
+ ).split( "," )
+ );
+
+ List<SignatureAlgorithmFactory> signatureAlgorithms = new ArrayList<>( signatureAlgorithmNames.size() );
+ for ( String signatureAlgorithmName : signatureAlgorithmNames )
+ {
+ signatureAlgorithms.add( signatureAlgorithmFactorySelector.select( signatureAlgorithmName ) );
+ }
+
return forSignature
- ? new Maven2RepositoryLayout( checksumsAlgorithms )
- : new Maven2RepositoryLayoutEx( checksumsAlgorithms );
+ ? new Maven2RepositoryLayout( checksumsAlgorithms, signatureAlgorithms )
+ : new Maven2RepositoryLayoutEx( checksumsAlgorithms, signatureAlgorithms );
}
private static class Maven2RepositoryLayout
implements RepositoryLayout
{
- private final List<ChecksumAlgorithmFactory> checksumAlgorithms;
+ protected final List<ChecksumAlgorithmFactory> checksumAlgorithms;
- protected Maven2RepositoryLayout( List<ChecksumAlgorithmFactory> checksumAlgorithms )
+ protected final List<SignatureAlgorithmFactory> signatureAlgorithms;
+
+ protected Maven2RepositoryLayout( List<ChecksumAlgorithmFactory> checksumAlgorithms,
+ List<SignatureAlgorithmFactory> signatureAlgorithms )
{
this.checksumAlgorithms = Collections.unmodifiableList( checksumAlgorithms );
+ this.signatureAlgorithms = Collections.unmodifiableList( signatureAlgorithms );
}
private URI toUri( String path )
@@ -153,6 +182,12 @@ public final class Maven2RepositoryLayoutFactory
}
@Override
+ public List<SignatureAlgorithmFactory> getSignatureAlgorithmFactories()
+ {
+ return signatureAlgorithms;
+ }
+
+ @Override
public URI getLocation( Artifact artifact, boolean upload )
{
StringBuilder path = new StringBuilder( 128 );
@@ -206,6 +241,10 @@ public final class Maven2RepositoryLayoutFactory
@Override
public List<ChecksumLocation> getChecksumLocations( Artifact artifact, boolean upload, URI location )
{
+ if ( isChecksum( artifact.getExtension() ) )
+ {
+ return Collections.emptyList();
+ }
return getChecksumLocations( location );
}
@@ -225,15 +264,20 @@ public final class Maven2RepositoryLayoutFactory
return checksumLocations;
}
+ private boolean isChecksum( String extension )
+ {
+ return checksumAlgorithms.stream().anyMatch( a -> extension.endsWith( "." + a.getFileExtension() ) );
+ }
}
private static class Maven2RepositoryLayoutEx
extends Maven2RepositoryLayout
{
- protected Maven2RepositoryLayoutEx( List<ChecksumAlgorithmFactory> checksumAlgorithms )
+ protected Maven2RepositoryLayoutEx( List<ChecksumAlgorithmFactory> checksumAlgorithms,
+ List<SignatureAlgorithmFactory> signatureAlgorithms )
{
- super( checksumAlgorithms );
+ super( checksumAlgorithms, signatureAlgorithms );
}
@Override
@@ -248,7 +292,7 @@ public final class Maven2RepositoryLayoutFactory
private boolean isSignature( String extension )
{
- return extension.endsWith( ".asc" );
+ return signatureAlgorithms.stream().anyMatch( a -> extension.endsWith( "." + a.getFileExtension() ) );
}
}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/signature/DefaultSignatureAlgorithmFactorySelector.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/signature/DefaultSignatureAlgorithmFactorySelector.java
new file mode 100644
index 0000000..2455d52
--- /dev/null
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/signature/DefaultSignatureAlgorithmFactorySelector.java
@@ -0,0 +1,89 @@
+package org.eclipse.aether.internal.impl.signature;
+
+/*
+ * 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.
+ */
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithmFactory;
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithmFactorySelector;
+
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toList;
+
+/**
+ * Default implementation.
+ *
+ * @since 1.8.0
+ */
+@Singleton
+@Named
+public class DefaultSignatureAlgorithmFactorySelector
+ implements SignatureAlgorithmFactorySelector
+{
+ private final Map<String, SignatureAlgorithmFactory> factories;
+
+ /**
+ * Default ctor for SL.
+ */
+ @Deprecated
+ public DefaultSignatureAlgorithmFactorySelector()
+ {
+ this.factories = new HashMap<>();
+ this.factories.put( GpgSignatureAlgorithmFactory.NAME, new GpgSignatureAlgorithmFactory() );
+ }
+
+ @Inject
+ public DefaultSignatureAlgorithmFactorySelector( Map<String, SignatureAlgorithmFactory> factories )
+ {
+ this.factories = requireNonNull( factories );
+ }
+
+ @Override
+ public SignatureAlgorithmFactory select( String algorithmName )
+ {
+ requireNonNull( algorithmName, "algorithmMame must not be null" );
+ SignatureAlgorithmFactory factory = factories.get( algorithmName );
+ if ( factory == null )
+ {
+ throw new IllegalArgumentException(
+ String.format( "Unsupported signature algorithm %s, supported ones are %s",
+ algorithmName,
+ getSignatureAlgorithmFactories().stream()
+ .map( SignatureAlgorithmFactory::getName )
+ .collect( toList() )
+ )
+ );
+ }
+ return factory;
+ }
+
+ @Override
+ public List<SignatureAlgorithmFactory> getSignatureAlgorithmFactories()
+ {
+ return new ArrayList<>( factories.values() );
+ }
+}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/signature/GpgSignatureAlgorithmFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/signature/GpgSignatureAlgorithmFactory.java
new file mode 100644
index 0000000..2f7ac67
--- /dev/null
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/signature/GpgSignatureAlgorithmFactory.java
@@ -0,0 +1,52 @@
+package org.eclipse.aether.internal.impl.signature;
+
+/*
+ * 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.
+ */
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithm;
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithmFactorySupport;
+
+/**
+ * The GPG signature type.
+ *
+ * @since 1.8.0
+ */
+@Singleton
+@Named( GpgSignatureAlgorithmFactory.NAME )
+public class GpgSignatureAlgorithmFactory
+ extends SignatureAlgorithmFactorySupport
+{
+ public static final String NAME = "GPG";
+
+ @Inject
+ public GpgSignatureAlgorithmFactory()
+ {
+ super( NAME, "asc" );
+ }
+
+ @Override
+ public SignatureAlgorithm getAlgorithm()
+ {
+ throw new IllegalStateException( "not implemented" );
+ }
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/layout/RepositoryLayout.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/layout/RepositoryLayout.java
index 4a02b06..f461560 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/layout/RepositoryLayout.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/layout/RepositoryLayout.java
@@ -27,6 +27,7 @@ import static java.util.Objects.requireNonNull;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.metadata.Metadata;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
+import org.eclipse.aether.spi.connector.signature.SignatureAlgorithmFactory;
/**
* The layout for a remote repository whose artifacts/metadata can be addressed via URIs.
@@ -134,6 +135,13 @@ public interface RepositoryLayout
List<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories();
/**
+ * Returns immutable list of {@link SignatureAlgorithmFactory} this instance of layout uses, never {@code null}.
+ *
+ * @since 1.8.0
+ */
+ List<SignatureAlgorithmFactory> getSignatureAlgorithmFactories();
+
+ /**
* Gets the location within a remote repository where the specified artifact resides. The URI is relative to the
* root directory of the repository.
*
@@ -164,7 +172,8 @@ public interface RepositoryLayout
* being uploaded/created.
* @param location The relative URI to the artifact within the repository as previously obtained from
* {@link #getLocation(Artifact, boolean)}, must not be {@code null}.
- * @return The checksum files for the given artifact, possibly empty but never {@code null}.
+ * @return The checksum files for the given artifact, possibly empty but never {@code null}. If empty, that means
+ * that this layout does not provide checksums for given artifact.
*/
List<ChecksumLocation> getChecksumLocations( Artifact artifact, boolean upload, URI location );
@@ -177,7 +186,8 @@ public interface RepositoryLayout
* being uploaded/created.
* @param location The relative URI to the metadata within the repository as previously obtained from
* {@link #getLocation(Metadata, boolean)}, must not be {@code null}.
- * @return The checksum files for the given metadata, possibly empty but never {@code null}.
+ * @return The checksum files for the given metadata, possibly empty but never {@code null}. If empty, that means
+ * that this layout does not provide checksums for given artifact.
*/
List<ChecksumLocation> getChecksumLocations( Metadata metadata, boolean upload, URI location );
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithm.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithm.java
new file mode 100644
index 0000000..4ab960f
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithm.java
@@ -0,0 +1,38 @@
+package org.eclipse.aether.spi.connector.signature;
+
+/*
+ * 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.
+ */
+
+import java.io.Closeable;
+import java.nio.ByteBuffer;
+
+/**
+ * Implementation performing signature calculation for specific algorithm. Instances of this interface are stateful,
+ * non-thread safe, and should not be reused.
+ *
+ * @since 1.8.0
+ */
+public interface SignatureAlgorithm extends Closeable
+{
+ /**
+ * Updates the checksum algorithm inner state with input.
+ * TODO: figure out some API for this to suit signing.
+ */
+ void update( ByteBuffer input );
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactory.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactory.java
new file mode 100644
index 0000000..0c7bf7c
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactory.java
@@ -0,0 +1,49 @@
+package org.eclipse.aether.spi.connector.signature;
+
+/*
+ * 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.
+ */
+
+/**
+ * A component representing a signature factory: provides {@link SignatureAlgorithm} instances, name and extension to be
+ * used with this algorithm. While directly injecting components of this type is possible, it is not recommended. To
+ * obtain factory instances use {@link SignatureAlgorithmFactorySelector} instead.
+ *
+ * @since 1.8.0
+ */
+public interface SignatureAlgorithmFactory
+{
+ /**
+ * Returns the algorithm name, usually used as key, never {@code null} value. The name is a standard name of
+ * algorithm (if applicable) or any other designator that is algorithm commonly referred with. Example: "GPG".
+ */
+ String getName();
+
+ /**
+ * Returns the file extension to be used for given signature file (without leading dot), never {@code null}. The
+ * extension should be file and URL path friendly, and may differ from value returned by {@link #getName()}.
+ * Example: "asc".
+ */
+ String getFileExtension();
+
+ /**
+ * Each invocation of this method returns a new instance of algorithm, never {@code null} value.
+ * TODO: figure out some API for this to suit signing.
+ */
+ SignatureAlgorithm getAlgorithm();
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactorySelector.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactorySelector.java
new file mode 100644
index 0000000..27b04d0
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactorySelector.java
@@ -0,0 +1,45 @@
+package org.eclipse.aether.spi.connector.signature;
+
+/*
+ * 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.
+ */
+
+import java.util.Collection;
+
+/**
+ * Component performing selection of {@link SignatureAlgorithmFactory} based on known factory names.
+ *
+ * @since 1.8.0
+ */
+public interface SignatureAlgorithmFactorySelector
+{
+ /**
+ * Returns factory for given algorithm name, or throws if algorithm not supported.
+ *
+ * @throws IllegalArgumentException if asked algorithm name is not supported.
+ */
+ SignatureAlgorithmFactory select( String algorithmName );
+
+ /**
+ * Returns a collection of supported algorithm names. This set represents ALL the algorithms supported by Resolver,
+ * and is NOT in any relation to given repository layout used signatures, returned by method {@link
+ * org.eclipse.aether.spi.connector.layout.RepositoryLayout#getSignatureAlgorithmFactories()} (in fact, is super set
+ * of it).
+ */
+ Collection<SignatureAlgorithmFactory> getSignatureAlgorithmFactories();
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactorySupport.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactorySupport.java
new file mode 100644
index 0000000..2c6c7e3
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/signature/SignatureAlgorithmFactorySupport.java
@@ -0,0 +1,59 @@
+package org.eclipse.aether.spi.connector.signature;
+
+/*
+ * 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.
+ */
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Support class for {@link SignatureAlgorithmFactory} implementations.
+ *
+ * @since 1.8.0
+ */
+public abstract class SignatureAlgorithmFactorySupport
+ implements SignatureAlgorithmFactory
+{
+ private final String name;
+
+ private final String fileExtension;
+
+ public SignatureAlgorithmFactorySupport( String name, String fileExtension )
+ {
+ this.name = requireNonNull( name );
+ this.fileExtension = requireNonNull( fileExtension );
+ }
+
+ /**
+ * Returns the algorithm name, usually used as key, never {@code null} value.
+ */
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Returns the file extension to be used for given signature algorithm (without leading dot), never {@code null}.
+ */
+ @Override
+ public String getFileExtension()
+ {
+ return fileExtension;
+ }
+}