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.resolution.ArtifactRequest;
39  import org.eclipse.aether.resolution.ArtifactResult;
40  import org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
41  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
42  import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
43  import org.eclipse.aether.util.artifact.ArtifactIdUtils;
44  import org.junit.Before;
45  import org.junit.Test;
46  
47  import static java.util.stream.Collectors.toList;
48  import static org.hamcrest.MatcherAssert.assertThat;
49  import static org.hamcrest.Matchers.containsString;
50  import static org.hamcrest.Matchers.empty;
51  import static org.hamcrest.Matchers.equalTo;
52  import static org.hamcrest.Matchers.not;
53  import static org.hamcrest.Matchers.notNullValue;
54  
55  /**
56   * UT for {@link TrustedChecksumsArtifactResolverPostProcessor}.
57   */
58  public class TrustedChecksumsArtifactResolverPostProcessorTest implements TrustedChecksumsSource {
59      private static final String TRUSTED_SOURCE_NAME = "test";
60  
61      private Artifact artifactWithoutTrustedChecksum;
62  
63      private Artifact artifactWithTrustedChecksum;
64  
65      private String artifactTrustedChecksum;
66  
67      protected DefaultRepositorySystemSession session;
68  
69      protected ChecksumAlgorithmFactory checksumAlgorithmFactory = new Sha1ChecksumAlgorithmFactory();
70  
71      private TrustedChecksumsArtifactResolverPostProcessor subject;
72  
73      private TrustedChecksumsSource.Writer trustedChecksumsWriter;
74  
75      @Before
76      public void prepareSubject() throws IOException {
77          Files.createDirectories(Paths.get(System.getProperty("java.io.tmpdir"))); // hack for Surefire
78          // make the two artifacts, BOTH as resolved
79          File tmp = Files.createTempFile("artifact", "tmp").toFile();
80          artifactWithoutTrustedChecksum = new DefaultArtifact("test:test:1.0").setFile(tmp);
81          artifactWithTrustedChecksum = new DefaultArtifact("test:test:2.0").setFile(tmp);
82          artifactTrustedChecksum = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; // empty file
83  
84          session = TestUtils.newSession();
85          ChecksumAlgorithmFactorySelector selector = new ChecksumAlgorithmFactorySelector() {
86              @Override
87              public ChecksumAlgorithmFactory select(String algorithmName) {
88                  if (checksumAlgorithmFactory.getName().equals(algorithmName)) {
89                      return checksumAlgorithmFactory;
90                  }
91                  throw new IllegalArgumentException("no alg factory for " + algorithmName);
92              }
93  
94              @Override
95              public List<ChecksumAlgorithmFactory> selectList(Collection<String> algorithmNames) {
96                  return algorithmNames.stream().map(this::select).collect(toList());
97              }
98  
99              @Override
100             public Collection<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories() {
101                 return Collections.singletonList(checksumAlgorithmFactory);
102             }
103 
104             @Override
105             public boolean isChecksumExtension(String extension) {
106                 throw new RuntimeException("not implemented");
107             }
108         };
109         subject = new TrustedChecksumsArtifactResolverPostProcessor(
110                 selector, Collections.singletonMap(TRUSTED_SOURCE_NAME, this));
111         trustedChecksumsWriter = null;
112         session.setConfigProperty("aether.artifactResolver.postProcessor.trustedChecksums", Boolean.TRUE.toString());
113     }
114 
115     // -- TrustedChecksumsSource interface BEGIN
116 
117     @Override
118     public Map<String, String> getTrustedArtifactChecksums(
119             RepositorySystemSession session,
120             Artifact artifact,
121             ArtifactRepository artifactRepository,
122             List<ChecksumAlgorithmFactory> checksumAlgorithmFactories) {
123         if (ArtifactIdUtils.toId(artifactWithTrustedChecksum).equals(ArtifactIdUtils.toId(artifact))) {
124             return Collections.singletonMap(checksumAlgorithmFactory.getName(), artifactTrustedChecksum);
125         } else {
126             return Collections.emptyMap();
127         }
128     }
129 
130     @Override
131     public Writer getTrustedArtifactChecksumsWriter(RepositorySystemSession session) {
132         return trustedChecksumsWriter;
133     }
134 
135     // -- TrustedChecksumsSource interface END
136 
137     private ArtifactResult createArtifactResult(Artifact artifact, String scope) {
138         ArtifactResult artifactResult = new ArtifactResult(new ArtifactRequest().setArtifact(artifact));
139         artifactResult.setArtifact(artifact);
140         return artifactResult;
141     }
142 
143     // UTs below
144 
145     @Test
146     public void unresolvedArtifact() {
147         ArtifactResult artifactResult = createArtifactResult(artifactWithTrustedChecksum, "project/compile")
148                 .setArtifact(null);
149         assertThat(artifactResult.isResolved(), equalTo(false));
150 
151         subject.postProcess(session, Collections.singletonList(artifactResult)); // no NPE
152     }
153 
154     @Test
155     public void haveMatchingChecksumPass() {
156         ArtifactResult artifactResult = createArtifactResult(artifactWithTrustedChecksum, "project/compile");
157         assertThat(artifactResult.isResolved(), equalTo(true));
158 
159         subject.postProcess(session, Collections.singletonList(artifactResult));
160         assertThat(artifactResult.isResolved(), equalTo(true));
161     }
162 
163     @Test
164     public void haveNoChecksumPass() {
165         ArtifactResult artifactResult = createArtifactResult(artifactWithoutTrustedChecksum, "project/compile");
166         assertThat(artifactResult.isResolved(), equalTo(true));
167 
168         subject.postProcess(session, Collections.singletonList(artifactResult));
169         assertThat(artifactResult.isResolved(), equalTo(true));
170     }
171 
172     @Test
173     public void haveNoChecksumFailIfMissingEnabledFail() {
174         session.setConfigProperty(
175                 "aether.artifactResolver.postProcessor.trustedChecksums.failIfMissing", Boolean.TRUE.toString());
176         ArtifactResult artifactResult = createArtifactResult(artifactWithoutTrustedChecksum, "plugin");
177         assertThat(artifactResult.isResolved(), equalTo(true));
178 
179         subject.postProcess(session, Collections.singletonList(artifactResult));
180         assertThat(artifactResult.isResolved(), equalTo(false));
181         assertThat(artifactResult.getExceptions(), not(empty()));
182         assertThat(
183                 artifactResult.getExceptions().get(0).getMessage(),
184                 containsString("Missing from " + TRUSTED_SOURCE_NAME + " trusted"));
185     }
186 
187     @Test
188     public void haveMismatchingChecksumFail() {
189         artifactTrustedChecksum = "foobar";
190         ArtifactResult artifactResult = createArtifactResult(artifactWithTrustedChecksum, "project/compile");
191         assertThat(artifactResult.isResolved(), equalTo(true));
192 
193         subject.postProcess(session, Collections.singletonList(artifactResult));
194         assertThat(artifactResult.isResolved(), equalTo(false));
195         assertThat(artifactResult.getExceptions(), not(empty()));
196         assertThat(artifactResult.getExceptions().get(0).getMessage(), containsString("trusted checksum mismatch"));
197         assertThat(
198                 artifactResult.getExceptions().get(0).getMessage(),
199                 containsString(TRUSTED_SOURCE_NAME + "=" + artifactTrustedChecksum));
200     }
201 
202     @Test
203     public void recordCalculatedChecksum() {
204         AtomicReference<String> recordedChecksum = new AtomicReference<>(null);
205         this.trustedChecksumsWriter = new Writer() {
206             @Override
207             public void addTrustedArtifactChecksums(
208                     Artifact artifact,
209                     ArtifactRepository artifactRepository,
210                     List<ChecksumAlgorithmFactory> checksumAlgorithmFactories,
211                     Map<String, String> trustedArtifactChecksums) {
212                 recordedChecksum.set(trustedArtifactChecksums.get(checksumAlgorithmFactory.getName()));
213             }
214         };
215         session.setConfigProperty(
216                 "aether.artifactResolver.postProcessor.trustedChecksums.record", Boolean.TRUE.toString());
217         ArtifactResult artifactResult = createArtifactResult(artifactWithTrustedChecksum, "project/compile");
218         assertThat(artifactResult.isResolved(), equalTo(true));
219 
220         subject.postProcess(session, Collections.singletonList(artifactResult));
221         assertThat(artifactResult.isResolved(), equalTo(true));
222 
223         String checksum = recordedChecksum.get();
224         assertThat(checksum, notNullValue());
225         assertThat(checksum, equalTo(artifactTrustedChecksum));
226     }
227 }