Skip to content

Commit 9640164

Browse files
authored
feat: #7510 Display a dedicated message when receiving an HTTP 403 (#7575)
2 parents fd48db4 + 74b2d1a commit 9640164

File tree

8 files changed

+67
-13
lines changed

8 files changed

+67
-13
lines changed

core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.owasp.dependencycheck.utils.Downloader;
3535
import org.owasp.dependencycheck.utils.FileFilterBuilder;
3636
import org.owasp.dependencycheck.utils.FileUtils;
37+
import org.owasp.dependencycheck.utils.ForbiddenException;
3738
import org.owasp.dependencycheck.utils.InvalidSettingException;
3839
import org.owasp.dependencycheck.utils.ResourceNotFoundException;
3940
import org.owasp.dependencycheck.utils.Settings;
@@ -309,6 +310,12 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy
309310
LOGGER.info("invalid sha1-hash on {}", dependency.getFileName());
310311
} catch (FileNotFoundException fnfe) {
311312
LOGGER.debug("Artifact not found in repository: '{}", dependency.getFileName());
313+
} catch (ForbiddenException e) {
314+
final String message = "Connection to Central search refused. This is most likely not a problem with " +
315+
"Dependency-Check itself and is related to network connectivity. Please check " +
316+
"https://central.sonatype.org/faq/403-error-central/.";
317+
LOGGER.error(message);
318+
throw new AnalysisException(message, e);
312319
} catch (IOException ioe) {
313320
final String message = "Could not connect to Central search. Analysis failed.";
314321
LOGGER.error(message, ioe);
@@ -330,7 +337,8 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy
330337
* @throws TooManyRequestsException if Central has received too many
331338
* requests.
332339
*/
333-
protected List<MavenArtifact> fetchMavenArtifacts(Dependency dependency) throws IOException, TooManyRequestsException {
340+
protected List<MavenArtifact> fetchMavenArtifacts(Dependency dependency) throws IOException,
341+
TooManyRequestsException {
334342
IOException lastException = null;
335343
long sleepingTimeBetweenRetriesInMillis = BASE_RETRY_WAIT;
336344
int triesLeft = numberOfRetries;

core/src/main/java/org/owasp/dependencycheck/data/artifactory/ArtifactorySearch.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.owasp.dependencycheck.dependency.Dependency;
3434
import org.owasp.dependencycheck.utils.Checksum;
3535
import org.owasp.dependencycheck.utils.Downloader;
36+
import org.owasp.dependencycheck.utils.ForbiddenException;
3637
import org.owasp.dependencycheck.utils.ResourceNotFoundException;
3738
import org.owasp.dependencycheck.utils.Settings;
3839
import org.owasp.dependencycheck.utils.TooManyRequestsException;
@@ -44,7 +45,7 @@
4445
* Class of methods to search Artifactory for hashes and determine Maven GAV
4546
* from there.
4647
*
47-
* Data classes copied from JFrog's artifactory-client-java project.
48+
* <p>Data classes copied from JFrog's artifactory-client-java project.</p>
4849
*
4950
* @author nhenneaux
5051
*/
@@ -116,6 +117,8 @@ public List<MavenArtifact> search(Dependency dependency) throws IOException {
116117
throw new IOException(msg.append(" (400): Invalid URL").toString(), e);
117118
} catch (ResourceNotFoundException e) {
118119
throw new IOException(msg.append(" (404): Not found").toString(), e);
120+
} catch (ForbiddenException e) {
121+
throw new IOException(msg.append(" (403): Forbidden").toString(), e);
119122
}
120123
}
121124

core/src/main/java/org/owasp/dependencycheck/data/central/CentralSearch.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.apache.hc.core5.http.message.BasicHeader;
2222
import org.owasp.dependencycheck.utils.DownloadFailedException;
2323
import org.owasp.dependencycheck.utils.Downloader;
24+
import org.owasp.dependencycheck.utils.ForbiddenException;
2425
import org.owasp.dependencycheck.utils.ResourceNotFoundException;
2526
import org.owasp.dependencycheck.utils.TooManyRequestsException;
2627
import java.io.FileNotFoundException;
@@ -135,14 +136,14 @@ public CentralSearch(Settings settings) throws MalformedURLException {
135136
* @throws TooManyRequestsException if Central has received too many
136137
* requests.
137138
*/
138-
public List<MavenArtifact> searchSha1(String sha1) throws IOException, TooManyRequestsException {
139+
public List<MavenArtifact> searchSha1(String sha1) throws IOException, TooManyRequestsException, ForbiddenException {
139140
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
140141
throw new IllegalArgumentException("Invalid SHA1 format");
141142
}
142143
if (cache != null) {
143144
final List<MavenArtifact> cached = cache.get(sha1);
144145
if (cached != null) {
145-
LOGGER.debug("cache hit for Central: " + sha1);
146+
LOGGER.debug("cache hit for Central: {}", sha1);
146147
if (cached.isEmpty()) {
147148
throw new FileNotFoundException("Artifact not found in Central");
148149
}
@@ -180,6 +181,9 @@ public List<MavenArtifact> searchSha1(String sha1) throws IOException, TooManyRe
180181
} catch (URISyntaxException e) {
181182
final String errorMessage = "Could not convert central search URL to a URI " + e.getMessage();
182183
throw new IOException(errorMessage, e);
184+
} catch (ForbiddenException e) {
185+
final String errorMessage = "Forbidden access to MavenCentral " + e.getMessage();
186+
throw new ForbiddenException(errorMessage, e);
183187
}
184188
if (cache != null) {
185189
cache.put(sha1, result);

core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusV2Search.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.apache.hc.core5.http.message.BasicHeader;
3535
import org.owasp.dependencycheck.utils.DownloadFailedException;
3636
import org.owasp.dependencycheck.utils.Downloader;
37+
import org.owasp.dependencycheck.utils.ForbiddenException;
3738
import org.owasp.dependencycheck.utils.ResourceNotFoundException;
3839
import org.owasp.dependencycheck.utils.Settings;
3940

@@ -147,7 +148,7 @@ public MavenArtifact searchSha1(String sha1) throws IOException {
147148
throw new IOException("Could not connect to Nexus");
148149
} catch (ResourceNotFoundException e) {
149150
throw new FileNotFoundException("Artifact not found in Nexus");
150-
} catch (XPathExpressionException | URISyntaxException e) {
151+
} catch (XPathExpressionException | URISyntaxException | ForbiddenException e) {
151152
throw new IOException(e.getMessage(), e);
152153
}
153154
}

core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusV3Search.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.jetbrains.annotations.Nullable;
2828
import org.owasp.dependencycheck.utils.DownloadFailedException;
2929
import org.owasp.dependencycheck.utils.Downloader;
30+
import org.owasp.dependencycheck.utils.ForbiddenException;
3031
import org.owasp.dependencycheck.utils.ResourceNotFoundException;
3132
import org.owasp.dependencycheck.utils.Settings;
3233
import org.owasp.dependencycheck.utils.TooManyRequestsException;
@@ -146,7 +147,7 @@ private String retrievePageAndAddMatchingArtifact(CloseableHttpClient client, Li
146147
try {
147148
return Downloader.getInstance().fetchAndHandle(client, url, handler, List.of(new BasicHeader(HttpHeaders.ACCEPT,
148149
ContentType.APPLICATION_JSON)));
149-
} catch (TooManyRequestsException | ResourceNotFoundException | DownloadFailedException e) {
150+
} catch (TooManyRequestsException | ResourceNotFoundException | DownloadFailedException | ForbiddenException e) {
150151
if (LOGGER.isDebugEnabled()) {
151152
int responseCode = -1;
152153
String responseMessage = "";

core/src/test/java/org/owasp/dependencycheck/analyzer/CentralAnalyzerTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.junit.Test;
2222
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
2323
import org.owasp.dependencycheck.data.central.CentralSearch;
24+
import org.owasp.dependencycheck.utils.ForbiddenException;
2425
import org.owasp.dependencycheck.utils.TooManyRequestsException;
2526
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
2627
import org.owasp.dependencycheck.dependency.Dependency;
@@ -50,7 +51,7 @@ public class CentralAnalyzerTest extends BaseTest {
5051

5152
@Test
5253
@SuppressWarnings("PMD.NonStaticInitializer")
53-
public void testFetchMavenArtifactsWithoutException() throws IOException, TooManyRequestsException {
54+
public void testFetchMavenArtifactsWithoutException() throws IOException, TooManyRequestsException, ForbiddenException {
5455
CentralAnalyzer instance = new CentralAnalyzer();
5556
instance.setCentralSearch(centralSearch);
5657
when(dependency.getSha1sum()).thenReturn(SHA1_SUM);
@@ -64,7 +65,7 @@ public void testFetchMavenArtifactsWithoutException() throws IOException, TooMan
6465
@Test(expected = FileNotFoundException.class)
6566
@SuppressWarnings("PMD.NonStaticInitializer")
6667
public void testFetchMavenArtifactsRethrowsFileNotFoundException()
67-
throws IOException, TooManyRequestsException {
68+
throws IOException, TooManyRequestsException, ForbiddenException {
6869
CentralAnalyzer instance = new CentralAnalyzer();
6970
instance.setCentralSearch(centralSearch);
7071
when(dependency.getSha1sum()).thenReturn(SHA1_SUM);
@@ -75,7 +76,7 @@ public void testFetchMavenArtifactsRethrowsFileNotFoundException()
7576
@Test(expected = IOException.class)
7677
@SuppressWarnings("PMD.NonStaticInitializer")
7778
public void testFetchMavenArtifactsAlwaysThrowsIOException()
78-
throws IOException, TooManyRequestsException {
79+
throws IOException, TooManyRequestsException, ForbiddenException {
7980
getSettings().setInt(Settings.KEYS.ANALYZER_CENTRAL_RETRY_COUNT, 1);
8081
getSettings().setBoolean(Settings.KEYS.ANALYZER_CENTRAL_USE_CACHE, false);
8182
CentralAnalyzer instance = new CentralAnalyzer();

utils/src/main/java/org/owasp/dependencycheck/utils/Downloader.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ public CloseableHttpClient getHttpClient(boolean useProxy) {
649649
* @throws ResourceNotFoundException When HTTP status 404 is encountered
650650
*/
651651
public <T> T fetchAndHandle(@NotNull URL url, @NotNull HttpClientResponseHandler<T> handler)
652-
throws IOException, TooManyRequestsException, ResourceNotFoundException, URISyntaxException {
652+
throws IOException, TooManyRequestsException, ResourceNotFoundException, URISyntaxException, ForbiddenException {
653653
return fetchAndHandle(url, handler, Collections.emptyList(), true);
654654
}
655655

@@ -666,7 +666,7 @@ public <T> T fetchAndHandle(@NotNull URL url, @NotNull HttpClientResponseHandler
666666
* @throws ResourceNotFoundException When HTTP status 404 is encountered
667667
*/
668668
public <T> T fetchAndHandle(@NotNull URL url, @NotNull HttpClientResponseHandler<T> handler, @NotNull List<Header> hdr)
669-
throws IOException, TooManyRequestsException, ResourceNotFoundException, URISyntaxException {
669+
throws IOException, TooManyRequestsException, ResourceNotFoundException, URISyntaxException, ForbiddenException {
670670
return fetchAndHandle(url, handler, hdr, true);
671671
}
672672

@@ -684,7 +684,7 @@ public <T> T fetchAndHandle(@NotNull URL url, @NotNull HttpClientResponseHandler
684684
* @throws ResourceNotFoundException When HTTP status 404 is encountered
685685
*/
686686
public <T> T fetchAndHandle(@NotNull URL url, @NotNull HttpClientResponseHandler<T> handler, @NotNull List<Header> hdr, boolean useProxy)
687-
throws IOException, TooManyRequestsException, ResourceNotFoundException, URISyntaxException {
687+
throws IOException, TooManyRequestsException, ResourceNotFoundException, URISyntaxException, ForbiddenException {
688688
final T data;
689689
if ("file".equals(url.getProtocol())) {
690690
final Path p = Paths.get(url.toURI());
@@ -717,7 +717,8 @@ public <T> T fetchAndHandle(@NotNull URL url, @NotNull HttpClientResponseHandler
717717
* @throws ResourceNotFoundException When HTTP status 404 is encountered
718718
*/
719719
public <T> T fetchAndHandle(@NotNull CloseableHttpClient client, @NotNull URL url, @NotNull HttpClientResponseHandler<T> handler,
720-
@NotNull List<Header> hdr) throws IOException, TooManyRequestsException, ResourceNotFoundException {
720+
@NotNull List<Header> hdr) throws IOException, TooManyRequestsException,
721+
ResourceNotFoundException, ForbiddenException {
721722
try {
722723
final String theProtocol = url.getProtocol();
723724
if (!("http".equals(theProtocol) || "https".equals(theProtocol))) {
@@ -732,6 +733,9 @@ public <T> T fetchAndHandle(@NotNull CloseableHttpClient client, @NotNull URL ur
732733
} catch (HttpResponseException hre) {
733734
final String messageFormat = "%s - Server status: %d - Server reason: %s";
734735
switch (hre.getStatusCode()) {
736+
case 403:
737+
throw new ForbiddenException(String.format(messageFormat, url, hre.getStatusCode(),
738+
hre.getReasonPhrase()));
735739
case 404:
736740
throw new ResourceNotFoundException(String.format(messageFormat, url, hre.getStatusCode(), hre.getReasonPhrase()));
737741
case 429:
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
* https://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.owasp.dependencycheck.utils;
20+
21+
import java.io.IOException;
22+
23+
public class ForbiddenException extends IOException {
24+
25+
public ForbiddenException(String message) {
26+
super(message);
27+
}
28+
29+
public ForbiddenException(String message, ForbiddenException cause) {
30+
super(message, cause);
31+
}
32+
}

0 commit comments

Comments
 (0)