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        subject = new TrustedChecksumsArtifactResolverPostProcessor( selector,
113                Collections.singletonMap( TRUSTED_SOURCE_NAME, this ) );
114        trustedChecksumsWriter = null;
115        session.setConfigProperty( "aether.artifactResolver.postProcessor.trustedChecksums", Boolean.TRUE.toString() );
116    }
117
118    // -- TrustedChecksumsSource interface BEGIN
119
120    @Override
121    public Map<String, String> getTrustedArtifactChecksums( RepositorySystemSession session, Artifact artifact,
122                                                            ArtifactRepository artifactRepository,
123                                                            List<ChecksumAlgorithmFactory> checksumAlgorithmFactories )
124    {
125        if ( ArtifactIdUtils.toId( artifactWithTrustedChecksum ).equals( ArtifactIdUtils.toId( artifact ) ) )
126        {
127            return Collections.singletonMap( checksumAlgorithmFactory.getName(), artifactTrustedChecksum );
128        }
129        else
130        {
131            return Collections.emptyMap();
132        }
133    }
134
135    @Override
136    public Writer getTrustedArtifactChecksumsWriter( RepositorySystemSession session )
137    {
138        return trustedChecksumsWriter;
139    }
140
141    // -- TrustedChecksumsSource interface END
142
143    private ArtifactResult createArtifactResult( Artifact artifact )
144    {
145        ArtifactResult artifactResult = new ArtifactResult( new ArtifactRequest().setArtifact( artifact ) );
146        artifactResult.setArtifact( artifact );
147        return artifactResult;
148    }
149
150    // UTs below
151
152    @Test
153    public void haveMatchingChecksumPass()
154    {
155        ArtifactResult artifactResult = createArtifactResult( artifactWithTrustedChecksum );
156        assertThat( artifactResult.isResolved(), equalTo( true ) );
157
158        subject.postProcess( session, Collections.singletonList( artifactResult ) );
159        assertThat( artifactResult.isResolved(), equalTo( true ) );
160    }
161
162    @Test
163    public void haveNoChecksumPass()
164    {
165        ArtifactResult artifactResult = createArtifactResult( artifactWithoutTrustedChecksum );
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    {
175        session.setConfigProperty( "aether.artifactResolver.postProcessor.trustedChecksums.failIfMissing",
176                Boolean.TRUE.toString() );
177        ArtifactResult artifactResult = createArtifactResult( artifactWithoutTrustedChecksum );
178        assertThat( artifactResult.isResolved(), equalTo( true ) );
179
180        subject.postProcess( session, Collections.singletonList( artifactResult ) );
181        assertThat( artifactResult.isResolved(), equalTo( false ) );
182        assertThat( artifactResult.getExceptions(), not( empty() ) );
183        assertThat( artifactResult.getExceptions().get( 0 ).getMessage(),
184                containsString( "Missing from " + TRUSTED_SOURCE_NAME + " trusted" ) );
185    }
186
187    @Test
188    public void haveMismatchingChecksumFail()
189    {
190        artifactTrustedChecksum = "foobar";
191        ArtifactResult artifactResult = createArtifactResult( artifactWithTrustedChecksum );
192        assertThat( artifactResult.isResolved(), equalTo( true ) );
193
194        subject.postProcess( session, Collections.singletonList( artifactResult ) );
195        assertThat( artifactResult.isResolved(), equalTo( false ) );
196        assertThat( artifactResult.getExceptions(), not( empty() ) );
197        assertThat( artifactResult.getExceptions().get( 0 ).getMessage(),
198                containsString( "trusted checksum mismatch" ) );
199        assertThat( artifactResult.getExceptions().get( 0 ).getMessage(),
200                containsString( TRUSTED_SOURCE_NAME + "=" + artifactTrustedChecksum ) );
201    }
202
203    @Test
204    public void recordCalculatedChecksum()
205    {
206        AtomicReference<String> recordedChecksum = new AtomicReference<>(null);
207        this.trustedChecksumsWriter = new Writer()
208        {
209            @Override
210            public void addTrustedArtifactChecksums( Artifact artifact, ArtifactRepository artifactRepository,
211                                                     List<ChecksumAlgorithmFactory> checksumAlgorithmFactories,
212                                                     Map<String, String> trustedArtifactChecksums )
213            {
214                recordedChecksum.set( trustedArtifactChecksums.get( checksumAlgorithmFactory.getName() ) );
215            }
216        };
217        session.setConfigProperty( "aether.artifactResolver.postProcessor.trustedChecksums.record",
218                Boolean.TRUE.toString() );
219        ArtifactResult artifactResult = createArtifactResult( artifactWithTrustedChecksum );
220        assertThat( artifactResult.isResolved(), equalTo( true ) );
221
222        subject.postProcess( session, Collections.singletonList( artifactResult ) );
223        assertThat( artifactResult.isResolved(), equalTo( true ) );
224
225        String checksum = recordedChecksum.get();
226        assertThat( checksum, notNullValue() );
227        assertThat( checksum, equalTo( artifactTrustedChecksum ) );
228    }
229}