001package org.eclipse.aether.internal.impl.resolution; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.IOException; 024import java.nio.file.Files; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.List; 028import java.util.Map; 029import java.util.concurrent.atomic.AtomicReference; 030 031import org.eclipse.aether.DefaultRepositorySystemSession; 032import org.eclipse.aether.RepositorySystemSession; 033import org.eclipse.aether.artifact.Artifact; 034import org.eclipse.aether.artifact.DefaultArtifact; 035import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory; 036import org.eclipse.aether.internal.test.util.TestUtils; 037import org.eclipse.aether.repository.ArtifactRepository; 038import org.eclipse.aether.resolution.ArtifactRequest; 039import org.eclipse.aether.resolution.ArtifactResult; 040import org.eclipse.aether.spi.checksums.TrustedChecksumsSource; 041import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; 042import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector; 043import org.eclipse.aether.util.artifact.ArtifactIdUtils; 044import org.junit.Before; 045import org.junit.Test; 046 047import static java.util.stream.Collectors.toList; 048import static org.hamcrest.MatcherAssert.assertThat; 049import static org.hamcrest.Matchers.containsString; 050import static org.hamcrest.Matchers.empty; 051import static org.hamcrest.Matchers.equalTo; 052import static org.hamcrest.Matchers.not; 053import static org.hamcrest.Matchers.notNullValue; 054 055/** 056 * UT for {@link TrustedChecksumsArtifactResolverPostProcessor}. 057 */ 058public class TrustedChecksumsArtifactResolverPostProcessorTest implements TrustedChecksumsSource 059{ 060 private static final String TRUSTED_SOURCE_NAME = "test"; 061 062 private Artifact artifactWithoutTrustedChecksum; 063 064 private Artifact artifactWithTrustedChecksum; 065 066 private String artifactTrustedChecksum; 067 068 protected DefaultRepositorySystemSession session; 069 070 protected ChecksumAlgorithmFactory checksumAlgorithmFactory = new Sha1ChecksumAlgorithmFactory(); 071 072 private TrustedChecksumsArtifactResolverPostProcessor subject; 073 074 private TrustedChecksumsSource.Writer trustedChecksumsWriter; 075 076 @Before 077 public void prepareSubject() throws IOException 078 { 079 // make the two artifacts, BOTH as resolved 080 File tmp = Files.createTempFile( "artifact", "tmp" ).toFile(); 081 artifactWithoutTrustedChecksum = new DefaultArtifact( "test:test:1.0" ).setFile( tmp ); 082 artifactWithTrustedChecksum = new DefaultArtifact( "test:test:2.0" ).setFile( tmp ); 083 artifactTrustedChecksum = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; // empty file 084 085 session = TestUtils.newSession(); 086 ChecksumAlgorithmFactorySelector selector = new ChecksumAlgorithmFactorySelector() 087 { 088 @Override 089 public ChecksumAlgorithmFactory select( String algorithmName ) 090 { 091 if ( checksumAlgorithmFactory.getName().equals( algorithmName ) ) 092 { 093 return checksumAlgorithmFactory; 094 } 095 throw new IllegalArgumentException("no alg factory for " + algorithmName); 096 } 097 098 @Override 099 public List<ChecksumAlgorithmFactory> selectList( Collection<String> algorithmNames ) 100 { 101 return algorithmNames.stream() 102 .map( this::select ) 103 .collect( toList() ); 104 } 105 106 @Override 107 public Collection<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories() 108 { 109 return Collections.singletonList( checksumAlgorithmFactory ); 110 } 111 112 @Override 113 public boolean isChecksumExtension( String extension ) 114 { 115 throw new RuntimeException( "not implemented" ); 116 } 117 }; 118 subject = new TrustedChecksumsArtifactResolverPostProcessor( selector, 119 Collections.singletonMap( TRUSTED_SOURCE_NAME, this ) ); 120 trustedChecksumsWriter = null; 121 session.setConfigProperty( "aether.artifactResolver.postProcessor.trustedChecksums", Boolean.TRUE.toString() ); 122 } 123 124 // -- TrustedChecksumsSource interface BEGIN 125 126 @Override 127 public Map<String, String> getTrustedArtifactChecksums( RepositorySystemSession session, Artifact artifact, 128 ArtifactRepository artifactRepository, 129 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories ) 130 { 131 if ( ArtifactIdUtils.toId( artifactWithTrustedChecksum ).equals( ArtifactIdUtils.toId( artifact ) ) ) 132 { 133 return Collections.singletonMap( checksumAlgorithmFactory.getName(), artifactTrustedChecksum ); 134 } 135 else 136 { 137 return Collections.emptyMap(); 138 } 139 } 140 141 @Override 142 public Writer getTrustedArtifactChecksumsWriter( RepositorySystemSession session ) 143 { 144 return trustedChecksumsWriter; 145 } 146 147 // -- TrustedChecksumsSource interface END 148 149 private ArtifactResult createArtifactResult( Artifact artifact ) 150 { 151 ArtifactResult artifactResult = new ArtifactResult( new ArtifactRequest().setArtifact( artifact ) ); 152 artifactResult.setArtifact( artifact ); 153 return artifactResult; 154 } 155 156 // UTs below 157 158 @Test 159 public void haveMatchingChecksumPass() 160 { 161 ArtifactResult artifactResult = createArtifactResult( artifactWithTrustedChecksum ); 162 assertThat( artifactResult.isResolved(), equalTo( true ) ); 163 164 subject.postProcess( session, Collections.singletonList( artifactResult ) ); 165 assertThat( artifactResult.isResolved(), equalTo( true ) ); 166 } 167 168 @Test 169 public void haveNoChecksumPass() 170 { 171 ArtifactResult artifactResult = createArtifactResult( artifactWithoutTrustedChecksum ); 172 assertThat( artifactResult.isResolved(), equalTo( true ) ); 173 174 subject.postProcess( session, Collections.singletonList( artifactResult ) ); 175 assertThat( artifactResult.isResolved(), equalTo( true ) ); 176 } 177 178 @Test 179 public void haveNoChecksumFailIfMissingEnabledFail() 180 { 181 session.setConfigProperty( "aether.artifactResolver.postProcessor.trustedChecksums.failIfMissing", 182 Boolean.TRUE.toString() ); 183 ArtifactResult artifactResult = createArtifactResult( artifactWithoutTrustedChecksum ); 184 assertThat( artifactResult.isResolved(), equalTo( true ) ); 185 186 subject.postProcess( session, Collections.singletonList( artifactResult ) ); 187 assertThat( artifactResult.isResolved(), equalTo( false ) ); 188 assertThat( artifactResult.getExceptions(), not( empty() ) ); 189 assertThat( artifactResult.getExceptions().get( 0 ).getMessage(), 190 containsString( "Missing from " + TRUSTED_SOURCE_NAME + " trusted" ) ); 191 } 192 193 @Test 194 public void haveMismatchingChecksumFail() 195 { 196 artifactTrustedChecksum = "foobar"; 197 ArtifactResult artifactResult = createArtifactResult( artifactWithTrustedChecksum ); 198 assertThat( artifactResult.isResolved(), equalTo( true ) ); 199 200 subject.postProcess( session, Collections.singletonList( artifactResult ) ); 201 assertThat( artifactResult.isResolved(), equalTo( false ) ); 202 assertThat( artifactResult.getExceptions(), not( empty() ) ); 203 assertThat( artifactResult.getExceptions().get( 0 ).getMessage(), 204 containsString( "trusted checksum mismatch" ) ); 205 assertThat( artifactResult.getExceptions().get( 0 ).getMessage(), 206 containsString( TRUSTED_SOURCE_NAME + "=" + artifactTrustedChecksum ) ); 207 } 208 209 @Test 210 public void recordCalculatedChecksum() 211 { 212 AtomicReference<String> recordedChecksum = new AtomicReference<>(null); 213 this.trustedChecksumsWriter = new Writer() 214 { 215 @Override 216 public void addTrustedArtifactChecksums( Artifact artifact, ArtifactRepository artifactRepository, 217 List<ChecksumAlgorithmFactory> checksumAlgorithmFactories, 218 Map<String, String> trustedArtifactChecksums ) 219 { 220 recordedChecksum.set( trustedArtifactChecksums.get( checksumAlgorithmFactory.getName() ) ); 221 } 222 }; 223 session.setConfigProperty( "aether.artifactResolver.postProcessor.trustedChecksums.record", 224 Boolean.TRUE.toString() ); 225 ArtifactResult artifactResult = createArtifactResult( artifactWithTrustedChecksum ); 226 assertThat( artifactResult.isResolved(), equalTo( true ) ); 227 228 subject.postProcess( session, Collections.singletonList( artifactResult ) ); 229 assertThat( artifactResult.isResolved(), equalTo( true ) ); 230 231 String checksum = recordedChecksum.get(); 232 assertThat( checksum, notNullValue() ); 233 assertThat( checksum, equalTo( artifactTrustedChecksum ) ); 234 } 235}