This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-vfs.git
The following commit(s) were added to refs/heads/master by this push:
new b1dd62d15 [VFS-861] Http5FileProvider Basic authentication fails:
UserAuthenticationData.setData(Type, char[]) should clone its array input
b1dd62d15 is described below
commit b1dd62d1571c9ef68dece57b0e54a7467bb3b629
Author: Gary Gregory <[email protected]>
AuthorDate: Thu Mar 5 20:44:13 2026 -0500
[VFS-861] Http5FileProvider Basic authentication fails:
UserAuthenticationData.setData(Type, char[]) should clone its array
input
---
.../vfs2/provider/http4/Http4FileProvider.java | 36 +++-----
.../vfs2/provider/http5/Http5FileProvider.java | 35 +++----
.../commons/vfs2/util/UserAuthenticatorUtils.java | 8 +-
.../vfs2/provider/http4/Http4BasicAuthTest.java | 101 +++++++++++++++++++++
.../vfs2/provider/http5/Http5BasicAuthTest.java | 101 +++++++++++++++++++++
.../apache/commons/vfs2/util/NHttpFileServer.java | 77 ++++++++++++----
src/changes/changes.xml | 1 +
7 files changed, 289 insertions(+), 70 deletions(-)
diff --git
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java
index 2f7da5307..6a64f0c2c 100644
---
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java
+++
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java
@@ -236,41 +236,30 @@ public class Http4FileProvider extends
AbstractOriginatingFileProvider {
protected HttpClientContext createHttpClientContext(final
Http4FileSystemConfigBuilder builder,
final GenericFileName rootName, final FileSystemOptions
fileSystemOptions,
final UserAuthenticationData authData) {
-
final HttpClientContext clientContext = HttpClientContext.create();
final CredentialsProvider credsProvider = new
BasicCredentialsProvider();
clientContext.setCredentialsProvider(credsProvider);
-
- final String username =
StringUtils.valueOf(UserAuthenticatorUtils.getData(authData,
- UserAuthenticationData.USERNAME,
CharSequenceUtils.toCharArray(rootName.getUserName())));
- final String password =
StringUtils.valueOf(UserAuthenticatorUtils.getData(authData,
- UserAuthenticationData.PASSWORD,
CharSequenceUtils.toCharArray(rootName.getPassword())));
-
- if (!StringUtils.isEmpty(username)) {
- credsProvider.setCredentials(new AuthScope(rootName.getHostName(),
rootName.getPort()),
- new UsernamePasswordCredentials(username, password));
+ final String rootUserName = rootName.getUserName();
+ final String userName =
StringUtils.valueOf(UserAuthenticatorUtils.getData(authData,
UserAuthenticationData.USERNAME,
+ rootUserName != null ?
CharSequenceUtils.toCharArray(rootUserName) : null));
+ if (!StringUtils.isEmpty(userName)) {
+ final String rootPassword = rootName.getPassword();
+ final String password =
StringUtils.valueOf(UserAuthenticatorUtils.getData(authData,
UserAuthenticationData.PASSWORD,
+ rootPassword != null ?
CharSequenceUtils.toCharArray(rootPassword) : null));
+ credsProvider.setCredentials(new AuthScope(rootName.getHostName(),
rootName.getPort()), new UsernamePasswordCredentials(userName, password));
}
-
final HttpHost proxyHost = getProxyHttpHost(builder,
fileSystemOptions);
-
if (proxyHost != null) {
final UserAuthenticator proxyAuth =
builder.getProxyAuthenticator(fileSystemOptions);
-
if (proxyAuth != null) {
final UserAuthenticationData proxyAuthData =
UserAuthenticatorUtils.authenticate(proxyAuth,
- new UserAuthenticationData.Type[]
{UserAuthenticationData.USERNAME, UserAuthenticationData.PASSWORD});
-
+ new UserAuthenticationData.Type[]
{UserAuthenticationData.USERNAME, UserAuthenticationData.PASSWORD});
if (proxyAuthData != null) {
final UsernamePasswordCredentials proxyCreds = new
UsernamePasswordCredentials(
- StringUtils.valueOf(
-
UserAuthenticatorUtils.getData(proxyAuthData, UserAuthenticationData.USERNAME,
null)),
- StringUtils.valueOf(
-
UserAuthenticatorUtils.getData(proxyAuthData, UserAuthenticationData.PASSWORD,
null)));
-
- credsProvider.setCredentials(new
AuthScope(proxyHost.getHostName(), proxyHost.getPort()),
- proxyCreds);
+
StringUtils.valueOf(UserAuthenticatorUtils.getData(proxyAuthData,
UserAuthenticationData.USERNAME, null)),
+
StringUtils.valueOf(UserAuthenticatorUtils.getData(proxyAuthData,
UserAuthenticationData.PASSWORD, null)));
+ credsProvider.setCredentials(new
AuthScope(proxyHost.getHostName(), proxyHost.getPort()), proxyCreds);
}
-
if (builder.isPreemptiveAuth(fileSystemOptions)) {
final AuthCache authCache = new BasicAuthCache();
final BasicScheme basicAuth = new BasicScheme();
@@ -279,7 +268,6 @@ public class Http4FileProvider extends
AbstractOriginatingFileProvider {
}
}
}
-
return clientContext;
}
diff --git
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http5/Http5FileProvider.java
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http5/Http5FileProvider.java
index aff0121fe..4ef767545 100644
---
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http5/Http5FileProvider.java
+++
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http5/Http5FileProvider.java
@@ -227,42 +227,32 @@ public class Http5FileProvider extends
AbstractOriginatingFileProvider {
protected HttpClientContext createHttpClientContext(final
Http5FileSystemConfigBuilder builder,
final GenericFileName rootName, final FileSystemOptions
fileSystemOptions,
final UserAuthenticationData authData) {
-
final HttpClientContext clientContext = HttpClientContext.create();
final BasicCredentialsProvider credsProvider = new
BasicCredentialsProvider();
clientContext.setCredentialsProvider(credsProvider);
-
- final String username =
StringUtils.valueOf(UserAuthenticatorUtils.getData(authData,
- UserAuthenticationData.USERNAME,
CharSequenceUtils.toCharArray(rootName.getUserName())));
- final char[] password = UserAuthenticatorUtils.getData(authData,
- UserAuthenticationData.PASSWORD,
CharSequenceUtils.toCharArray(rootName.getPassword()));
-
- if (!StringUtils.isEmpty(username)) {
- // set root port
+ final String rootUser = rootName.getUserName();
+ final String userName =
StringUtils.valueOf(UserAuthenticatorUtils.getData(authData,
UserAuthenticationData.USERNAME,
+ rootUser != null ? CharSequenceUtils.toCharArray(rootUser) :
null));
+ if (!StringUtils.isEmpty(userName)) {
+ final String rootPassword = rootName.getPassword();
+ final char[] password = UserAuthenticatorUtils.getData(authData,
UserAuthenticationData.PASSWORD,
+ rootPassword != null ?
CharSequenceUtils.toCharArray(rootPassword) : null);
credsProvider.setCredentials(new AuthScope(rootName.getHostName(),
rootName.getPort()),
- new UsernamePasswordCredentials(username, password));
+ new UsernamePasswordCredentials(userName,
password.clone()));
}
-
final HttpHost proxyHost = getProxyHttpHost(builder,
fileSystemOptions);
-
if (proxyHost != null) {
final UserAuthenticator proxyAuth =
builder.getProxyAuthenticator(fileSystemOptions);
-
if (proxyAuth != null) {
final UserAuthenticationData proxyAuthData =
UserAuthenticatorUtils.authenticate(proxyAuth,
- new UserAuthenticationData.Type[]
{UserAuthenticationData.USERNAME, UserAuthenticationData.PASSWORD});
-
+ new UserAuthenticationData.Type[]
{UserAuthenticationData.USERNAME, UserAuthenticationData.PASSWORD});
if (proxyAuthData != null) {
final UsernamePasswordCredentials proxyCreds = new
UsernamePasswordCredentials(
- StringUtils.valueOf(
-
UserAuthenticatorUtils.getData(proxyAuthData, UserAuthenticationData.USERNAME,
null)),
+
StringUtils.valueOf(UserAuthenticatorUtils.getData(proxyAuthData,
UserAuthenticationData.USERNAME, null)),
UserAuthenticatorUtils.getData(proxyAuthData,
UserAuthenticationData.PASSWORD, null));
-
// set proxy host port
- credsProvider.setCredentials(new
AuthScope(proxyHost.getHostName(), proxyHost.getPort()),
- proxyCreds);
+ credsProvider.setCredentials(new
AuthScope(proxyHost.getHostName(), proxyHost.getPort()), proxyCreds);
}
-
if (builder.isPreemptiveAuth(fileSystemOptions)) {
final AuthCache authCache = new BasicAuthCache();
final BasicScheme basicAuth = new BasicScheme();
@@ -271,18 +261,15 @@ public class Http5FileProvider extends
AbstractOriginatingFileProvider {
}
}
}
-
return clientContext;
}
private HttpRoutePlanner createHttpRoutePlanner(final
Http5FileSystemConfigBuilder builder,
final FileSystemOptions fileSystemOptions) {
final HttpHost proxyHost = getProxyHttpHost(builder,
fileSystemOptions);
-
if (proxyHost != null) {
return new DefaultProxyRoutePlanner(proxyHost);
}
-
return new SystemDefaultRoutePlanner(ProxySelector.getDefault());
}
diff --git
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/UserAuthenticatorUtils.java
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/UserAuthenticatorUtils.java
index 07ce7f386..cf4c62a89 100644
---
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/UserAuthenticatorUtils.java
+++
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/UserAuthenticatorUtils.java
@@ -67,12 +67,12 @@ public final class UserAuthenticatorUtils {
*
* @param data The UserAuthenticationData.
* @param type The type of the element to retrieve.
- * @param overriddenValue The default value.
+ * @param overrideValue The override value.
* @return The data of the given type as a character array or null if the
data is not available.
*/
- public static char[] getData(final UserAuthenticationData data, final
UserAuthenticationData.Type type, final char[] overriddenValue) {
- if (overriddenValue != null) {
- return overriddenValue;
+ public static char[] getData(final UserAuthenticationData data, final
UserAuthenticationData.Type type, final char[] overrideValue) {
+ if (overrideValue != null) {
+ return overrideValue;
}
return data != null ? data.getData(type) : null;
}
diff --git
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4/Http4BasicAuthTest.java
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4/Http4BasicAuthTest.java
new file mode 100644
index 000000000..8a3a56167
--- /dev/null
+++
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4/Http4BasicAuthTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.vfs2.provider.http4;
+
+import static org.apache.commons.vfs2.VfsTestUtils.getTestDirectory;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.vfs2.*;
+import org.apache.commons.vfs2.auth.StaticUserAuthenticator;
+import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder;
+import org.apache.commons.vfs2.util.NHttpFileServer;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests HTTP Basic Authentication
https://issues.apache.org/jira/browse/VFS-861.
+ */
+public class Http4BasicAuthTest {
+
+ private static final String TEST_USERNAME = "USER";
+
+ private static final String TEST_PASSWORD = "PWD";
+
+ private static NHttpFileServer server;
+
+ private static String baseUri;
+
+ @BeforeAll
+ static void startServer() throws Exception {
+ server = NHttpFileServer.startWithBasicAuth(0, new
File(getTestDirectory()), 5000, TEST_USERNAME, TEST_PASSWORD);
+ baseUri = AbstractProviderTestConfig.getLocalHostUriString("http4",
server.getPort());
+ }
+
+ @AfterAll
+ static void stopServer() throws InterruptedException {
+ if (server != null) {
+ server.shutdown(5, TimeUnit.SECONDS);
+ }
+ }
+
+ private FileSystemOptions authOptions() throws FileSystemException {
+ final FileSystemOptions opts = new FileSystemOptions();
+ final StaticUserAuthenticator auth = new StaticUserAuthenticator(null,
TEST_USERNAME, TEST_PASSWORD);
+
DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, auth);
+ return opts;
+ }
+
+ @Test
+ void testResolveFile() throws FileSystemException {
+ final FileSystemOptions opts = authOptions();
+ try (FileObject file = VFS.getManager().resolveFile(baseUri +
"/read-tests/file1.txt", opts)) {
+ assertNotNull(file);
+ assertTrue(file.exists(), "file1.txt should exist");
+ assertEquals(FileType.FILE, file.getType());
+ assertNotNull(file.getContent(), "Content should be readable when
credentials are correct");
+ }
+ }
+
+ @Test
+ void testResolveFolder() throws FileSystemException {
+ final FileSystemOptions opts = authOptions();
+ try (FileObject folder = VFS.getManager().resolveFile(baseUri +
"/read-tests", opts)) {
+ assertNotNull(folder);
+ assertTrue(folder.exists(), "read-tests folder should exist");
+ }
+ }
+
+ @Test
+ void testResolveFolderWithTrailingSlash() throws FileSystemException {
+ final FileSystemOptions opts = authOptions();
+ try (FileObject folder = VFS.getManager().resolveFile(baseUri +
"/read-tests/", opts)) {
+ assertNotNull(folder);
+ assertTrue(folder.exists(), "read-tests/ folder should exist");
+ }
+ }
+
+ @Test
+ void testUnauthenticatedRequestReturns401() {
+ assertThrows(FileSystemException.class, () ->
VFS.getManager().resolveFile(baseUri + "/read-tests/file1.txt", new
FileSystemOptions()).exists(),
+ "Expected FileSystemException when accessing a resource
without credentials");
+ }
+}
diff --git
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http5/Http5BasicAuthTest.java
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http5/Http5BasicAuthTest.java
new file mode 100644
index 000000000..2dbe827f3
--- /dev/null
+++
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http5/Http5BasicAuthTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.vfs2.provider.http5;
+
+import static org.apache.commons.vfs2.VfsTestUtils.getTestDirectory;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.vfs2.*;
+import org.apache.commons.vfs2.auth.StaticUserAuthenticator;
+import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder;
+import org.apache.commons.vfs2.util.NHttpFileServer;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests HTTP Basic Authentication
https://issues.apache.org/jira/browse/VFS-861.
+ */
+public class Http5BasicAuthTest {
+
+ private static final String TEST_USERNAME = "USER";
+
+ private static final String TEST_PASSWORD = "PWD";
+
+ private static NHttpFileServer server;
+
+ private static String baseUri;
+
+ @BeforeAll
+ static void startServer() throws Exception {
+ server = NHttpFileServer.startWithBasicAuth(0, new
File(getTestDirectory()), 5000, TEST_USERNAME, TEST_PASSWORD);
+ baseUri = AbstractProviderTestConfig.getLocalHostUriString("http5",
server.getPort());
+ }
+
+ @AfterAll
+ static void stopServer() throws InterruptedException {
+ if (server != null) {
+ server.shutdown(5, TimeUnit.SECONDS);
+ }
+ }
+
+ private FileSystemOptions authOptions() throws FileSystemException {
+ final FileSystemOptions opts = new FileSystemOptions();
+ final StaticUserAuthenticator auth = new StaticUserAuthenticator(null,
TEST_USERNAME, TEST_PASSWORD);
+
DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, auth);
+ return opts;
+ }
+
+ @Test
+ void testResolveFile() throws FileSystemException {
+ final FileSystemOptions opts = authOptions();
+ try (FileObject file = VFS.getManager().resolveFile(baseUri +
"/read-tests/file1.txt", opts)) {
+ assertNotNull(file);
+ assertTrue(file.exists(), "file1.txt should exist");
+ assertEquals(FileType.FILE, file.getType());
+ assertNotNull(file.getContent(), "Content should be readable when
credentials are correct");
+ }
+ }
+
+ @Test
+ void testResolveFolder() throws FileSystemException {
+ final FileSystemOptions opts = authOptions();
+ try (FileObject folder = VFS.getManager().resolveFile(baseUri +
"/read-tests", opts)) {
+ assertNotNull(folder);
+ assertTrue(folder.exists(), "read-tests folder should exist");
+ }
+ }
+
+ @Test
+ void testResolveFolderWithTrailingSlash() throws FileSystemException {
+ final FileSystemOptions opts = authOptions();
+ try (FileObject folder = VFS.getManager().resolveFile(baseUri +
"/read-tests/", opts)) {
+ assertNotNull(folder);
+ assertTrue(folder.exists(), "read-tests/ folder should exist");
+ }
+ }
+
+ @Test
+ void testUnauthenticatedRequestReturns401() {
+ assertThrows(FileSystemException.class, () ->
VFS.getManager().resolveFile(baseUri + "/read-tests/file1.txt", new
FileSystemOptions()).exists(),
+ "Expected FileSystemException when accessing a resource
without credentials");
+ }
+}
diff --git
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/util/NHttpFileServer.java
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/util/NHttpFileServer.java
index bca332ab8..2bd3e26cd 100644
---
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/util/NHttpFileServer.java
+++
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/util/NHttpFileServer.java
@@ -23,11 +23,13 @@ import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
+import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
@@ -56,12 +58,14 @@ import
org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer;
import org.apache.hc.core5.http.nio.ssl.BasicServerTlsStrategy;
import org.apache.hc.core5.http.nio.ssl.FixedPortStrategy;
+import org.apache.hc.core5.http.nio.support.AbstractAsyncServerAuthFilter;
import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.protocol.HttpCoreContext;
import org.apache.hc.core5.http.protocol.HttpDateGenerator;
import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.net.URIAuthority;
import org.apache.hc.core5.reactor.IOReactorConfig;
import org.apache.hc.core5.reactor.IOReactorStatus;
import org.apache.hc.core5.reactor.ListenerEndpoint;
@@ -73,6 +77,38 @@ import org.apache.hc.core5.util.TimeValue;
*/
public final class NHttpFileServer {
+ private static final class BasicAuthFilter extends
AbstractAsyncServerAuthFilter<String> {
+
+ private final String expectedCredentials;
+
+ private final String realm;
+
+ BasicAuthFilter(final String username, final String password, final
String realm) {
+ super(true);
+ this.expectedCredentials = username + ":" + password;
+ this.realm = realm;
+ }
+
+ @Override
+ protected boolean authenticate(final String challengeResponse, final
URIAuthority authority, final String requestUri, final HttpContext context) {
+ return expectedCredentials.equals(challengeResponse);
+ }
+
+ @Override
+ protected String generateChallenge(final String challengeResponse,
final URIAuthority authority, final String requestUri, final HttpContext
context) {
+ return "Basic realm=\"" + realm + "\"";
+ }
+
+ @Override
+ protected String parseChallengeResponse(final String
authorizationValue, final HttpContext context) throws HttpException {
+ if (authorizationValue == null ||
!authorizationValue.startsWith("Basic ")) {
+ return null;
+ }
+ final byte[] decoded =
Base64.getDecoder().decode(authorizationValue.substring(6));
+ return new String(decoded, StandardCharsets.UTF_8);
+ }
+ }
+
private static class HttpFileHandler implements
AsyncServerRequestHandler<Message<HttpRequest, Void>> {
private final File docRoot;
@@ -90,7 +126,6 @@ public final class NHttpFileServer {
if (!method.equals("GET") && !method.equals("HEAD") &&
!method.equals("POST")) {
throw new MethodNotSupportedException(method + " method not
supported");
}
-
final URI requestUri;
try {
requestUri = request.getUri();
@@ -101,22 +136,18 @@ public final class NHttpFileServer {
final File file = new File(docRoot, path);
final ContentType mimeType = ContentType.TEXT_HTML;
if (!file.exists()) {
-
final String msg = "File " + file.getPath() + " not found";
println(msg);
responseTrigger.submitResponse(
AsyncResponseBuilder.create(HttpStatus.SC_NOT_FOUND).setEntity("<html><body><h1>"
+ msg + "</h1></body></html>", mimeType).build(),
context);
-
} else if (!file.canRead()) {
final String msg = "Cannot read file " + file.getPath();
println(msg);
responseTrigger.submitResponse(
AsyncResponseBuilder.create(HttpStatus.SC_FORBIDDEN).setEntity("<html><body><h1>"
+ msg + "</h1></body></html>", mimeType).build(),
context);
-
} else {
-
ContentType contentType;
final String fileName =
file.getName().toLowerCase(Locale.ROOT);
// The following causes a failure on Linux and macOS in HttpProviderTestCase:
@@ -134,9 +165,7 @@ public final class NHttpFileServer {
contentType = ContentType.TEXT_HTML;
final HttpCoreContext coreContext =
HttpCoreContext.adapt(context);
final EndpointDetails endpoint =
coreContext.getEndpointDetails();
-
println(endpoint + " | serving file " + file.getPath());
-
// @formatter:off
responseTrigger.submitResponse(
AsyncResponseBuilder.create(HttpStatus.SC_OK)
@@ -154,7 +183,6 @@ public final class NHttpFileServer {
throws HttpException {
return new BasicRequestConsumer<>(entityDetails != null ? new
NoopEntityConsumer() : null);
}
-
}
public static final boolean DEBUG =
Boolean.getBoolean(NHttpFileServer.class.getSimpleName() + ".debug");
@@ -184,12 +212,24 @@ public final class NHttpFileServer {
return new NHttpFileServer(port, docRoot).start();
}
+ public static NHttpFileServer startWithBasicAuth(final int port, final
File docRoot, final long waitMillis, final String username, final String
password)
+ throws KeyManagementException, UnrecoverableKeyException,
NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException,
+ InterruptedException, ExecutionException {
+ return new NHttpFileServer(port, docRoot).withBasicAuth(username,
password).start();
+ }
+
private final File docRoot;
private ListenerEndpoint listenerEndpoint;
private final int port;
+ private String authRealm;
+
+ private String authUsername;
+
+ private String authPassword;
+
private HttpAsyncServer server;
private NHttpFileServer(final int port, final File docRoot) {
@@ -222,7 +262,6 @@ public final class NHttpFileServer {
server.initiateShutdown();
server.awaitShutdown(TimeValue.of(gracePeriod, timeUnit));
}
-
}
private NHttpFileServer start() throws KeyManagementException,
UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException,
CertificateException,
@@ -240,23 +279,19 @@ public final class NHttpFileServer {
sslContext = SSLContexts.custom().loadKeyMaterial(url,
"nopassword".toCharArray(), "nopassword".toCharArray()).build();
bootstrap.setTlsStrategy(new BasicServerTlsStrategy(sslContext,
new FixedPortStrategy(port)));
}
-
// @formatter:off
final IOReactorConfig config = IOReactorConfig.custom()
.setSoTimeout(15, TimeUnit.SECONDS)
.setTcpNoDelay(true)
.build();
// @formatter:on
-
- server = bootstrap
- .setExceptionCallback(Exception::printStackTrace)
- .setIOReactorConfig(config)
- .register("*", new HttpFileHandler(docRoot)).create();
-
+
bootstrap.setExceptionCallback(Exception::printStackTrace).setIOReactorConfig(config).register("*",
new HttpFileHandler(docRoot));
+ if (authUsername != null) {
+ bootstrap.addFilterFirst("auth", new BasicAuthFilter(authUsername,
authPassword, authRealm));
+ }
+ server = bootstrap.create();
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
-
server.start();
-
final Future<ListenerEndpoint> future = server.listen(new
InetSocketAddress(port));
listenerEndpoint = future.get();
println("Serving " + docRoot + " on " + listenerEndpoint.getAddress()
@@ -264,4 +299,10 @@ public final class NHttpFileServer {
return this;
}
+ public NHttpFileServer withBasicAuth(final String username, final String
password) {
+ this.authRealm = "restricted";
+ this.authUsername = username;
+ this.authPassword = password;
+ return this;
+ }
}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 56fce4ff3..25082af56 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -63,6 +63,7 @@ The <action> type attribute can be add,update,fix,remove.
<action type="fix" dev="ggregory" due-to="Vaishnavi Kumbhar, Gary
Gregory" issue="VFS-861">Http5FileProvider Basic authentication fails:
UserAuthenticationData.setData(Type, char[]) should clone its array
input.</action>
<action type="fix" dev="ggregory" due-to="Gary Gregory">Deprecate
UserAuthenticatorUtils.toChar(String).</action>
<action type="fix" dev="ggregory" due-to="Gary Gregory">Deprecate
UserAuthenticatorUtils.toString(String).</action>
+ <action type="fix" dev="ggregory" due-to="Vaishnavi Kumbhar, Gary
Gregory" issue="VFS-861">Http5FileProvider Basic authentication fails:
UserAuthenticationData.setData(Type, char[]) should clone its array
input.</action>
<!-- ADD -->
<action type="add" dev="ggregory" due-to="Gary Gregory">Add
org.apache.commons.vfs2.provider.ftp.FTPClientWrapper.sendOptions(String,
String).</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add
FtpFileSystemConfigBuilder.getControlEncodingCharset(FileSystemOptions) and
deprecate getControlEncoding(FileSystemOptions).</action>