View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl.resolution;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.nio.file.Files;
24  import java.nio.file.Paths;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.concurrent.atomic.AtomicReference;
30  
31  import org.eclipse.aether.DefaultRepositorySystemSession;
32  import org.eclipse.aether.RepositorySystemSession;
33  import org.eclipse.aether.artifact.Artifact;
34  import org.eclipse.aether.artifact.DefaultArtifact;
35  import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory;
36  import org.eclipse.aether.internal.test.util.TestUtils;
37  import org.eclipse.aether.repository.ArtifactRepository;
38  import org.eclipse.aether.repository.RemoteRepository;
39  import org.eclipse.aether.resolution.ArtifactRequest;
40  import org.eclipse.aether.resolution.ArtifactResult;
41  import org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
42  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
43  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
44  import org.eclipse.aether.util.artifact.ArtifactIdUtils;
45  import org.junit.jupiter.api.BeforeEach;
46  import org.junit.jupiter.api.Test;
47  
48  import static java.util.stream.Collectors.toList;
49  import static org.junit.jupiter.api.Assertions.*;
50  
51  /**
52   * UT for {@link TrustedChecksumsArtifactResolverPostProcessor}.
53   */
54  public class TrustedChecksumsArtifactResolverPostProcessorTest implements TrustedChecksumsSource {
55      private static final String TRUSTED_SOURCE_NAME = "test";
56  
57      private Artifact artifactWithoutTrustedChecksum;
58  
59      private Artifact artifactWithTrustedChecksum;
60  
61      private String artifactTrustedChecksum;
62  
63      protected DefaultRepositorySystemSession session;
64  
65      protected ChecksumAlgorithmFactory checksumAlgorithmFactory = new Sha1ChecksumAlgorithmFactory();
66  
67      private TrustedChecksumsArtifactResolverPostProcessor subject;
68  
69      private TrustedChecksumsSource.Writer trustedChecksumsWriter;
70  
71      @BeforeEach
72      void prepareSubject() throws IOException {
73          Files.createDirectories(Paths.get(System.getProperty("java.io.tmpdir"))); // hack for Surefire
74          // make the two artifacts, BOTH as resolved
75          File tmp = Files.createTempFile("artifact", "tmp").toFile();
76          artifactWithoutTrustedChecksum = new DefaultArtifact("test:test:1.0").setFile(tmp);
77          artifactWithTrustedChecksum = new DefaultArtifact("test:test:2.0").setFile(tmp);
78          artifactTrustedChecksum = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; // empty file
79  
80          session = TestUtils.newSession();
81          ChecksumAlgorithmFactorySelector selector = new ChecksumAlgorithmFactorySelector() {
82              @Override
83              public ChecksumAlgorithmFactory select(String algorithmName) {
84                  if (checksumAlgorithmFactory.getName().equals(algorithmName)) {
85                      return checksumAlgorithmFactory;
86                  }
87                  throw new IllegalArgumentException("no alg factory for " + algorithmName);
88              }
89  
90              @Override
91              public List<ChecksumAlgorithmFactory> selectList(Collection<String> algorithmNames) {
92                  return algorithmNames.stream().map(this::select).collect(toList());
93              }
94  
95              @Override
96              public Collection<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories() {
97                  return Collections.singletonList(checksumAlgorithmFactory);
98              }
99  
100             @Override
101             public boolean isChecksumExtension(String extension) {
102                 throw new RuntimeException("not implemented");
103             }
104         };
105         subject = new TrustedChecksumsArtifactResolverPostProcessor(
106                 selector, Collections.singletonMap(TRUSTED_SOURCE_NAME, this));
107         trustedChecksumsWriter = null;
108         session.setConfigProperty("aether.artifactResolver.postProcessor.trustedChecksums", Boolean.TRUE.toString());
109     }
110 
111     // -- TrustedChecksumsSource interface BEGIN
112 
113     @Override
114     public Map<String, String> getTrustedArtifactChecksums(
115             RepositorySystemSession session,
116             Artifact artifact,
117             ArtifactRepository artifactRepository,
118             List<ChecksumAlgorithmFactory> checksumAlgorithmFactories) {
119         if (ArtifactIdUtils.toId(artifactWithTrustedChecksum).equals(ArtifactIdUtils.toId(artifact))) {
120             return Collections.singletonMap(checksumAlgorithmFactory.getName(), artifactTrustedChecksum);
121         } else {
122             return Collections.emptyMap();
123         }
124     }
125 
126     @Override
127     public Writer getTrustedArtifactChecksumsWriter(RepositorySystemSession session) {
128         return trustedChecksumsWriter;
129     }
130 
131     // -- TrustedChecksumsSource interface END
132 
133     private ArtifactResult createArtifactResult(Artifact artifact) {
134         ArtifactResult artifactResult = new ArtifactResult(new ArtifactRequest().setArtifact(artifact));
135         artifactResult.setArtifact(artifact);
136         artifactResult.setRepository(
137                 new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/").build());
138         return artifactResult;
139     }
140 
141     // UTs below
142 
143     @Test
144     void haveMatchingChecksumPass() {
145         ArtifactResult artifactResult = createArtifactResult(artifactWithTrustedChecksum);
146         assertTrue(artifactResult.isResolved());
147 
148         subject.postProcess(session, Collections.singletonList(artifactResult));
149         assertTrue(artifactResult.isResolved());
150     }
151 
152     @Test
153     void haveNoChecksumPass() {
154         ArtifactResult artifactResult = createArtifactResult(artifactWithoutTrustedChecksum);
155         assertTrue(artifactResult.isResolved());
156 
157         subject.postProcess(session, Collections.singletonList(artifactResult));
158         assertTrue(artifactResult.isResolved());
159     }
160 
161     @Test
162     void haveNoChecksumFailIfMissingEnabledFail() {
163         session.setConfigProperty(
164                 "aether.artifactResolver.postProcessor.trustedChecksums.failIfMissing", Boolean.TRUE.toString());
165         ArtifactResult artifactResult = createArtifactResult(artifactWithoutTrustedChecksum);
166         assertTrue(artifactResult.isResolved());
167 
168         subject.postProcess(session, Collections.singletonList(artifactResult));
169         assertFalse(artifactResult.isResolved());
170         assertFalse(artifactResult.getExceptions().isEmpty());
171         assertTrue(artifactResult
172                 .getExceptions()
173                 .get(0)
174                 .getMessage()
175                 .contains("Missing from " + TRUSTED_SOURCE_NAME + " trusted"));
176     }
177 
178     @Test
179     void haveMismatchingChecksumFail() {
180         artifactTrustedChecksum = "foobar";
181         ArtifactResult artifactResult = createArtifactResult(artifactWithTrustedChecksum);
182         assertTrue(artifactResult.isResolved());
183 
184         subject.postProcess(session, Collections.singletonList(artifactResult));
185         assertFalse(artifactResult.isResolved());
186         assertFalse(artifactResult.getExceptions().isEmpty());
187         assertTrue(artifactResult.getExceptions().get(0).getMessage().contains("trusted checksum mismatch"));
188         assertTrue(artifactResult
189                 .getExceptions()
190                 .get(0)
191                 .getMessage()
192                 .contains(TRUSTED_SOURCE_NAME + "=" + artifactTrustedChecksum));
193     }
194 
195     @Test
196     void recordCalculatedChecksum() {
197         AtomicReference<String> recordedChecksum = new AtomicReference<>(null);
198         this.trustedChecksumsWriter = new Writer() {
199             @Override
200             public void addTrustedArtifactChecksums(
201                     Artifact artifact,
202                     ArtifactRepository artifactRepository,
203                     List<ChecksumAlgorithmFactory> checksumAlgorithmFactories,
204                     Map<String, String> trustedArtifactChecksums) {
205                 recordedChecksum.set(trustedArtifactChecksums.get(checksumAlgorithmFactory.getName()));
206             }
207         };
208         session.setConfigProperty(
209                 "aether.artifactResolver.postProcessor.trustedChecksums.record", Boolean.TRUE.toString());
210         ArtifactResult artifactResult = createArtifactResult(artifactWithTrustedChecksum);
211         assertTrue(artifactResult.isResolved());
212 
213         subject.postProcess(session, Collections.singletonList(artifactResult));
214         assertTrue(artifactResult.isResolved());
215 
216         String checksum = recordedChecksum.get();
217         assertNotNull(checksum);
218         assertEquals(checksum, artifactTrustedChecksum);
219     }
220 }