!55 [sync] PR-49: Fix CVE-2017-12196,CVE-2019-10184 and CVE-2019-10212
From: @openeuler-sync-bot Reviewed-by: @wangchong1995924 Signed-off-by: @wangchong1995924
This commit is contained in:
commit
5da1458d56
151
CVE-2017-12196-1.patch
Normal file
151
CVE-2017-12196-1.patch
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
From facb33a5cedaf4b7b96d3840a08210370a806870 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Stuart Douglas <stuart.w.douglas@gmail.com>
|
||||||
|
Date: Tue, 3 Oct 2017 13:29:48 +0200
|
||||||
|
Subject: [PATCH] UNDERTOW-1190 client can use bogus uri in digest
|
||||||
|
authentication
|
||||||
|
|
||||||
|
---
|
||||||
|
.../impl/DigestAuthenticationMechanism.java | 19 +++++++-
|
||||||
|
.../DigestAuthenticationAuthTestCase.java | 45 ++++++++++++++++++-
|
||||||
|
.../security/digest/DigestAuthTestCase.java | 7 +--
|
||||||
|
3 files changed, 65 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/core/src/main/java/io/undertow/security/impl/DigestAuthenticationMechanism.java b/core/src/main/java/io/undertow/security/impl/DigestAuthenticationMechanism.java
|
||||||
|
index e5a75bd834..e01724b44b 100644
|
||||||
|
--- a/core/src/main/java/io/undertow/security/impl/DigestAuthenticationMechanism.java
|
||||||
|
+++ b/core/src/main/java/io/undertow/security/impl/DigestAuthenticationMechanism.java
|
||||||
|
@@ -42,6 +42,7 @@
|
||||||
|
import io.undertow.util.HeaderMap;
|
||||||
|
import io.undertow.util.Headers;
|
||||||
|
import io.undertow.util.HexConverter;
|
||||||
|
+import io.undertow.util.StatusCodes;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
@@ -181,7 +182,7 @@ public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exch
|
||||||
|
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exchange, final SecurityContext securityContext) {
|
||||||
|
+ private AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exchange, final SecurityContext securityContext) {
|
||||||
|
DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY);
|
||||||
|
Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader();
|
||||||
|
// Step 1 - Verify the set of tokens received to ensure valid values.
|
||||||
|
@@ -231,7 +232,21 @@ public AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exch
|
||||||
|
return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
- // TODO - Validate the URI
|
||||||
|
+ if(parsedHeader.containsKey(DigestAuthorizationToken.DIGEST_URI)) {
|
||||||
|
+ String uri = parsedHeader.get(DigestAuthorizationToken.DIGEST_URI);
|
||||||
|
+ String requestURI = exchange.getRequestURI();
|
||||||
|
+ if(!exchange.getQueryString().isEmpty()) {
|
||||||
|
+ requestURI = requestURI + "?" + exchange.getQueryString();
|
||||||
|
+ }
|
||||||
|
+ if(!uri.equals(requestURI)) {
|
||||||
|
+ //just end the auth process
|
||||||
|
+ exchange.setStatusCode(StatusCodes.BAD_REQUEST);
|
||||||
|
+ exchange.endExchange();
|
||||||
|
+ return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (parsedHeader.containsKey(DigestAuthorizationToken.OPAQUE)) {
|
||||||
|
if (!OPAQUE_VALUE.equals(parsedHeader.get(DigestAuthorizationToken.OPAQUE))) {
|
||||||
|
diff --git a/core/src/test/java/io/undertow/server/security/DigestAuthenticationAuthTestCase.java b/core/src/test/java/io/undertow/server/security/DigestAuthenticationAuthTestCase.java
|
||||||
|
index f9fa2b6aa4..d1aff564e1 100644
|
||||||
|
--- a/core/src/test/java/io/undertow/server/security/DigestAuthenticationAuthTestCase.java
|
||||||
|
+++ b/core/src/test/java/io/undertow/server/security/DigestAuthenticationAuthTestCase.java
|
||||||
|
@@ -163,7 +163,7 @@ private static String createAuthorizationLine(final String userName, final Strin
|
||||||
|
sb.append(DigestAuthorizationToken.USERNAME.getName()).append("=").append("\"userOne\"").append(",");
|
||||||
|
sb.append(DigestAuthorizationToken.REALM.getName()).append("=\"").append(REALM_NAME).append("\",");
|
||||||
|
sb.append(DigestAuthorizationToken.NONCE.getName()).append("=\"").append(nonce).append("\",");
|
||||||
|
- sb.append(DigestAuthorizationToken.DIGEST_URI.getName()).append("=\"/\",");
|
||||||
|
+ sb.append(DigestAuthorizationToken.DIGEST_URI.getName()).append("=\"" + uri + "\",");
|
||||||
|
String nonceCountHex = toHex(nonceCount);
|
||||||
|
String response = createResponse(userName, REALM_NAME, password, method, uri, nonce, nonceCountHex, cnonce);
|
||||||
|
sb.append(DigestAuthorizationToken.RESPONSE.getName()).append("=\"").append(response).append("\",");
|
||||||
|
@@ -243,6 +243,49 @@ static void _testDigestSuccess() throws Exception {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /**
|
||||||
|
+ * Test for a successful authentication.
|
||||||
|
+ *
|
||||||
|
+ * Also makes two additional calls to demonstrate nonce re-use with an incrementing nonce count.
|
||||||
|
+ */
|
||||||
|
+ @Test
|
||||||
|
+ public void testDigestBadUri() throws Exception {
|
||||||
|
+ _testDigestBadUri();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ static void _testDigestBadUri() throws Exception {
|
||||||
|
+ TestHttpClient client = new TestHttpClient();
|
||||||
|
+ HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL());
|
||||||
|
+ HttpResponse result = client.execute(get);
|
||||||
|
+ assertEquals(StatusCodes.UNAUTHORIZED, result.getStatusLine().getStatusCode());
|
||||||
|
+ Header[] values = result.getHeaders(WWW_AUTHENTICATE.toString());
|
||||||
|
+ String value = getAuthHeader(DIGEST, values);
|
||||||
|
+
|
||||||
|
+ Map<DigestWWWAuthenticateToken, String> parsedHeader = DigestWWWAuthenticateToken.parseHeader(value.substring(7));
|
||||||
|
+ assertEquals(REALM_NAME, parsedHeader.get(DigestWWWAuthenticateToken.REALM));
|
||||||
|
+ assertEquals(DigestAlgorithm.MD5.getToken(), parsedHeader.get(DigestWWWAuthenticateToken.ALGORITHM));
|
||||||
|
+ assertEquals(DigestQop.AUTH.getToken(), parsedHeader.get(DigestWWWAuthenticateToken.MESSAGE_QOP));
|
||||||
|
+
|
||||||
|
+ String clientNonce = createNonce();
|
||||||
|
+ int nonceCount = 1;
|
||||||
|
+ String nonce = parsedHeader.get(DigestWWWAuthenticateToken.NONCE);
|
||||||
|
+ String opaque = parsedHeader.get(DigestWWWAuthenticateToken.OPAQUE);
|
||||||
|
+ assertNotNull(opaque);
|
||||||
|
+ // Send 5 requests with an incrementing nonce count on each call.
|
||||||
|
+ for (int i = 0; i < 5; i++) {
|
||||||
|
+ client = new TestHttpClient();
|
||||||
|
+ get = new HttpGet(DefaultServer.getDefaultServerURL());
|
||||||
|
+
|
||||||
|
+ int thisNonceCount = nonceCount++;
|
||||||
|
+ String authorization = createAuthorizationLine("userOne", "passwordOne", "GET", "/badUri", nonce, thisNonceCount,
|
||||||
|
+ clientNonce, opaque);
|
||||||
|
+
|
||||||
|
+ get.addHeader(AUTHORIZATION.toString(), authorization);
|
||||||
|
+ result = client.execute(get);
|
||||||
|
+ assertEquals(StatusCodes.BAD_REQUEST, result.getStatusLine().getStatusCode());
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
/**
|
||||||
|
* Test for a failed authentication where a bad username is provided.
|
||||||
|
*/
|
||||||
|
diff --git a/servlet/src/test/java/io/undertow/servlet/test/security/digest/DigestAuthTestCase.java b/servlet/src/test/java/io/undertow/servlet/test/security/digest/DigestAuthTestCase.java
|
||||||
|
index d2ac85e0c6..7164634c47 100644
|
||||||
|
--- a/servlet/src/test/java/io/undertow/servlet/test/security/digest/DigestAuthTestCase.java
|
||||||
|
+++ b/servlet/src/test/java/io/undertow/servlet/test/security/digest/DigestAuthTestCase.java
|
||||||
|
@@ -119,7 +119,8 @@ public void testAuthType() throws Exception {
|
||||||
|
|
||||||
|
public void testCall(final String path, final String expectedResponse) throws Exception {
|
||||||
|
TestHttpClient client = new TestHttpClient();
|
||||||
|
- String url = DefaultServer.getDefaultServerURL() + "/servletContext/secured/" + path;
|
||||||
|
+ String servletPath = "/servletContext/secured/" + path;
|
||||||
|
+ String url = DefaultServer.getDefaultServerURL() + servletPath;
|
||||||
|
HttpGet get = new HttpGet(url);
|
||||||
|
HttpResponse result = client.execute(get);
|
||||||
|
assertEquals(StatusCodes.UNAUTHORIZED, result.getStatusLine().getStatusCode());
|
||||||
|
@@ -134,7 +135,7 @@ public void testCall(final String path, final String expectedResponse) throws Ex
|
||||||
|
|
||||||
|
String nonce = parsedHeader.get(DigestWWWAuthenticateToken.NONCE);
|
||||||
|
|
||||||
|
- String clientResponse = createResponse("user1", REALM_NAME, "password1", "GET", "/", nonce);
|
||||||
|
+ String clientResponse = createResponse("user1", REALM_NAME, "password1", "GET", servletPath, nonce);
|
||||||
|
|
||||||
|
client = new TestHttpClient();
|
||||||
|
get = new HttpGet(url);
|
||||||
|
@@ -143,7 +144,7 @@ public void testCall(final String path, final String expectedResponse) throws Ex
|
||||||
|
sb.append(DigestAuthorizationToken.USERNAME.getName()).append("=").append("\"user1\"").append(",");
|
||||||
|
sb.append(DigestAuthorizationToken.REALM.getName()).append("=\"").append(REALM_NAME).append("\",");
|
||||||
|
sb.append(DigestAuthorizationToken.NONCE.getName()).append("=\"").append(nonce).append("\",");
|
||||||
|
- sb.append(DigestAuthorizationToken.DIGEST_URI.getName()).append("=\"/\",");
|
||||||
|
+ sb.append(DigestAuthorizationToken.DIGEST_URI.getName()).append("=\"" + servletPath + "\",");
|
||||||
|
sb.append(DigestAuthorizationToken.RESPONSE.getName()).append("=\"").append(clientResponse).append("\"");
|
||||||
|
|
||||||
|
get.addHeader(AUTHORIZATION.toString(), sb.toString());
|
||||||
38
CVE-2017-12196-2.patch
Normal file
38
CVE-2017-12196-2.patch
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
From 8804170ce3186bdd83b486959399ec7ac0f59d0f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Stuart Douglas <stuart.w.douglas@gmail.com>
|
||||||
|
Date: Mon, 11 Dec 2017 10:51:51 +1100
|
||||||
|
Subject: [PATCH] UNDERTOW-1190 handle absolute URI in the digest mechanism
|
||||||
|
|
||||||
|
---
|
||||||
|
.../impl/DigestAuthenticationMechanism.java | 18 ++++++++++++++----
|
||||||
|
1 file changed, 14 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/core/src/main/java/io/undertow/security/impl/DigestAuthenticationMechanism.java b/core/src/main/java/io/undertow/security/impl/DigestAuthenticationMechanism.java
|
||||||
|
index e01724b44b..972a0cb0e4 100644
|
||||||
|
--- a/core/src/main/java/io/undertow/security/impl/DigestAuthenticationMechanism.java
|
||||||
|
+++ b/core/src/main/java/io/undertow/security/impl/DigestAuthenticationMechanism.java
|
||||||
|
@@ -239,10 +239,20 @@ private AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exc
|
||||||
|
requestURI = requestURI + "?" + exchange.getQueryString();
|
||||||
|
}
|
||||||
|
if(!uri.equals(requestURI)) {
|
||||||
|
- //just end the auth process
|
||||||
|
- exchange.setStatusCode(StatusCodes.BAD_REQUEST);
|
||||||
|
- exchange.endExchange();
|
||||||
|
- return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
|
||||||
|
+ //it is possible we were given an absolute URI
|
||||||
|
+ //we reconstruct the URI from the host header to make sure they match up
|
||||||
|
+ //I am not sure if this is overly strict, however I think it is better
|
||||||
|
+ //to be safe than sorry
|
||||||
|
+ requestURI = exchange.getRequestURL();
|
||||||
|
+ if(!exchange.getQueryString().isEmpty()) {
|
||||||
|
+ requestURI = requestURI + "?" + exchange.getQueryString();
|
||||||
|
+ }
|
||||||
|
+ if(!uri.equals(requestURI)) {
|
||||||
|
+ //just end the auth process
|
||||||
|
+ exchange.setStatusCode(StatusCodes.BAD_REQUEST);
|
||||||
|
+ exchange.endExchange();
|
||||||
|
+ return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
|
||||||
23
CVE-2019-10184-pre.patch
Normal file
23
CVE-2019-10184-pre.patch
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
From 16833ca1ea7e2235e40129078f94f935b3f7e446 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Stuart Douglas <stuart.w.douglas@gmail.com>
|
||||||
|
Date: Thu, 15 Sep 2016 09:50:02 +1000
|
||||||
|
Subject: [PATCH] UNDERTOW-837 Incorrect welcome file rewrite outside of the
|
||||||
|
root directory
|
||||||
|
|
||||||
|
---
|
||||||
|
.../io/undertow/servlet/handlers/ServletInitialHandler.java | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/servlet/src/main/java/io/undertow/servlet/handlers/ServletInitialHandler.java b/servlet/src/main/java/io/undertow/servlet/handlers/ServletInitialHandler.java
|
||||||
|
index 3873ea6c32..0e8e3ecb15 100644
|
||||||
|
--- a/servlet/src/main/java/io/undertow/servlet/handlers/ServletInitialHandler.java
|
||||||
|
+++ b/servlet/src/main/java/io/undertow/servlet/handlers/ServletInitialHandler.java
|
||||||
|
@@ -170,7 +170,7 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception {
|
||||||
|
//this can only happen if the path ends with a /
|
||||||
|
//otherwise there would be a redirect instead
|
||||||
|
exchange.setRelativePath(info.getRewriteLocation());
|
||||||
|
- exchange.setRequestPath(exchange.getRequestPath() + info.getRewriteLocation());
|
||||||
|
+ exchange.setRequestPath(exchange.getResolvedPath() + info.getRewriteLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
final HttpServletResponseImpl response = new HttpServletResponseImpl(exchange, servletContext);
|
||||||
345
CVE-2019-10184.patch
Normal file
345
CVE-2019-10184.patch
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
From d2715e3afa13f50deaa19643676816ce391551e9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lin Gao <aoingl@gmail.com>
|
||||||
|
Date: Wed, 24 Jul 2019 22:03:01 +0800
|
||||||
|
Subject: [PATCH] [UNDERTOW-1578] 401 Unauthorized should be returned when
|
||||||
|
requesting a protected directory without trailing slash
|
||||||
|
|
||||||
|
---
|
||||||
|
.../servlet/core/DeploymentManagerImpl.java | 2 +
|
||||||
|
.../servlet/handlers/RedirectDirHandler.java | 71 ++++++++
|
||||||
|
.../handlers/ServletInitialHandler.java | 29 +--
|
||||||
|
.../SecurityRedirectTestCase.java | 168 ++++++++++++++++++
|
||||||
|
4 files changed, 244 insertions(+), 26 deletions(-)
|
||||||
|
create mode 100644 servlet/src/main/java/io/undertow/servlet/handlers/RedirectDirHandler.java
|
||||||
|
create mode 100644 servlet/src/test/java/io/undertow/servlet/test/defaultservlet/SecurityRedirectTestCase.java
|
||||||
|
|
||||||
|
diff --git a/servlet/src/main/java/io/undertow/servlet/core/DeploymentManagerImpl.java b/servlet/src/main/java/io/undertow/servlet/core/DeploymentManagerImpl.java
|
||||||
|
index 1906c4eaa0..9c49c4ad53 100644
|
||||||
|
--- a/servlet/src/main/java/io/undertow/servlet/core/DeploymentManagerImpl.java
|
||||||
|
+++ b/servlet/src/main/java/io/undertow/servlet/core/DeploymentManagerImpl.java
|
||||||
|
@@ -71,6 +71,7 @@
|
||||||
|
import io.undertow.servlet.api.ThreadSetupHandler;
|
||||||
|
import io.undertow.servlet.api.WebResourceCollection;
|
||||||
|
import io.undertow.servlet.handlers.CrawlerSessionManagerHandler;
|
||||||
|
+import io.undertow.servlet.handlers.RedirectDirHandler;
|
||||||
|
import io.undertow.servlet.handlers.ServletDispatchingHandler;
|
||||||
|
import io.undertow.servlet.handlers.ServletHandler;
|
||||||
|
import io.undertow.servlet.handlers.ServletInitialHandler;
|
||||||
|
@@ -218,6 +219,7 @@ public Void call(HttpServerExchange exchange, Object ignore) throws Exception {
|
||||||
|
|
||||||
|
HttpHandler wrappedHandlers = ServletDispatchingHandler.INSTANCE;
|
||||||
|
wrappedHandlers = wrapHandlers(wrappedHandlers, deploymentInfo.getInnerHandlerChainWrappers());
|
||||||
|
+ wrappedHandlers = new RedirectDirHandler(wrappedHandlers, deployment.getServletPaths());
|
||||||
|
if(!deploymentInfo.isSecurityDisabled()) {
|
||||||
|
HttpHandler securityHandler = setupSecurityHandlers(wrappedHandlers);
|
||||||
|
wrappedHandlers = new PredicateHandler(DispatcherTypePredicate.REQUEST, securityHandler, wrappedHandlers);
|
||||||
|
diff --git a/servlet/src/main/java/io/undertow/servlet/handlers/RedirectDirHandler.java b/servlet/src/main/java/io/undertow/servlet/handlers/RedirectDirHandler.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000..576eb11a87
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/servlet/src/main/java/io/undertow/servlet/handlers/RedirectDirHandler.java
|
||||||
|
@@ -0,0 +1,71 @@
|
||||||
|
+/*
|
||||||
|
+ * JBoss, Home of Professional Open Source.
|
||||||
|
+ * Copyright 2019 Red Hat, Inc., and individual contributors
|
||||||
|
+ * as indicated by the @author tags.
|
||||||
|
+ *
|
||||||
|
+ * Licensed 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
|
||||||
|
+ *
|
||||||
|
+ * http://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 io.undertow.servlet.handlers;
|
||||||
|
+
|
||||||
|
+import io.undertow.server.HttpHandler;
|
||||||
|
+import io.undertow.server.HttpServerExchange;
|
||||||
|
+import io.undertow.util.Headers;
|
||||||
|
+import io.undertow.util.Methods;
|
||||||
|
+import io.undertow.util.RedirectBuilder;
|
||||||
|
+import io.undertow.util.StatusCodes;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Handler that redirects the directory requests without trailing slash to the one append trailing slash.
|
||||||
|
+ *
|
||||||
|
+ * @author Lin Gao
|
||||||
|
+ */
|
||||||
|
+public class RedirectDirHandler implements HttpHandler {
|
||||||
|
+
|
||||||
|
+ private static final String HTTP2_UPGRADE_PREFIX = "h2";
|
||||||
|
+
|
||||||
|
+ private final HttpHandler next;
|
||||||
|
+ private final ServletPathMatches paths;
|
||||||
|
+
|
||||||
|
+ public RedirectDirHandler(HttpHandler next, ServletPathMatches paths) {
|
||||||
|
+ this.next = next;
|
||||||
|
+ this.paths = paths;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void handleRequest(HttpServerExchange exchange) throws Exception {
|
||||||
|
+ final String path = exchange.getRelativePath();
|
||||||
|
+ final ServletPathMatch info = paths.getServletHandlerByPath(path);
|
||||||
|
+ // https://issues.jboss.org/browse/WFLY-3439
|
||||||
|
+ // if the request is an upgrade request then we don't want to redirect
|
||||||
|
+ // as there is a good chance the web socket client won't understand the redirect
|
||||||
|
+ // we make an exception for HTTP2 upgrade requests, as this would have already be handled at
|
||||||
|
+ // the connector level if it was going to be handled.
|
||||||
|
+ String upgradeString = exchange.getRequestHeaders().getFirst(Headers.UPGRADE);
|
||||||
|
+ boolean isUpgradeRequest = upgradeString != null && !upgradeString.startsWith(HTTP2_UPGRADE_PREFIX);
|
||||||
|
+ if (info.getType() == ServletPathMatch.Type.REDIRECT && !isUpgradeRequest) {
|
||||||
|
+ // UNDERTOW-89
|
||||||
|
+ // we redirect on GET requests to the root context to add an / to the end
|
||||||
|
+ if (exchange.getRequestMethod().equals(Methods.GET) || exchange.getRequestMethod().equals(Methods.HEAD)) {
|
||||||
|
+ exchange.setStatusCode(StatusCodes.FOUND);
|
||||||
|
+ } else {
|
||||||
|
+ exchange.setStatusCode(StatusCodes.TEMPORARY_REDIRECT);
|
||||||
|
+ }
|
||||||
|
+ exchange.getResponseHeaders().put(Headers.LOCATION,
|
||||||
|
+ RedirectBuilder.redirect(exchange, exchange.getRelativePath() + "/", true));
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ next.handleRequest(exchange);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/servlet/src/main/java/io/undertow/servlet/handlers/ServletInitialHandler.java b/servlet/src/main/java/io/undertow/servlet/handlers/ServletInitialHandler.java
|
||||||
|
index 82a3ad7360..7edc7e493c 100644
|
||||||
|
--- a/servlet/src/main/java/io/undertow/servlet/handlers/ServletInitialHandler.java
|
||||||
|
+++ b/servlet/src/main/java/io/undertow/servlet/handlers/ServletInitialHandler.java
|
||||||
|
@@ -39,11 +39,8 @@
|
||||||
|
import io.undertow.servlet.spec.HttpServletResponseImpl;
|
||||||
|
import io.undertow.servlet.spec.RequestDispatcherImpl;
|
||||||
|
import io.undertow.servlet.spec.ServletContextImpl;
|
||||||
|
-import io.undertow.util.Headers;
|
||||||
|
import io.undertow.util.HttpString;
|
||||||
|
-import io.undertow.util.Methods;
|
||||||
|
import io.undertow.util.Protocols;
|
||||||
|
-import io.undertow.util.RedirectBuilder;
|
||||||
|
import io.undertow.util.StatusCodes;
|
||||||
|
import org.xnio.ChannelListener;
|
||||||
|
import org.xnio.Option;
|
||||||
|
@@ -80,8 +77,6 @@
|
||||||
|
*/
|
||||||
|
public class ServletInitialHandler implements HttpHandler, ServletDispatcher {
|
||||||
|
|
||||||
|
- private static final String HTTP2_UPGRADE_PREFIX = "h2";
|
||||||
|
-
|
||||||
|
private static final RuntimePermission PERMISSION = new RuntimePermission("io.undertow.servlet.CREATE_INITIAL_HANDLER");
|
||||||
|
|
||||||
|
private final HttpHandler next;
|
||||||
|
@@ -149,30 +144,12 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ServletPathMatch info = paths.getServletHandlerByPath(path);
|
||||||
|
- //https://issues.jboss.org/browse/WFLY-3439
|
||||||
|
- //if the request is an upgrade request then we don't want to redirect
|
||||||
|
- //as there is a good chance the web socket client won't understand the redirect
|
||||||
|
- //we make an exception for HTTP2 upgrade requests, as this would have already be handled at
|
||||||
|
- //the connector level if it was going to be handled.
|
||||||
|
- String upgradeString = exchange.getRequestHeaders().getFirst(Headers.UPGRADE);
|
||||||
|
- boolean isUpgradeRequest = upgradeString != null && !upgradeString.startsWith(HTTP2_UPGRADE_PREFIX);
|
||||||
|
- if (info.getType() == ServletPathMatch.Type.REDIRECT && !isUpgradeRequest) {
|
||||||
|
- //UNDERTOW-89
|
||||||
|
- //we redirect on GET requests to the root context to add an / to the end
|
||||||
|
- if(exchange.getRequestMethod().equals(Methods.GET) || exchange.getRequestMethod().equals(Methods.HEAD)) {
|
||||||
|
- exchange.setStatusCode(StatusCodes.FOUND);
|
||||||
|
- } else {
|
||||||
|
- exchange.setStatusCode(StatusCodes.TEMPORARY_REDIRECT);
|
||||||
|
- }
|
||||||
|
- exchange.getResponseHeaders().put(Headers.LOCATION, RedirectBuilder.redirect(exchange, exchange.getRelativePath() + "/", true));
|
||||||
|
- return;
|
||||||
|
- } else if (info.getType() == ServletPathMatch.Type.REWRITE) {
|
||||||
|
- //this can only happen if the path ends with a /
|
||||||
|
- //otherwise there would be a redirect instead
|
||||||
|
+ if (info.getType() == ServletPathMatch.Type.REWRITE) {
|
||||||
|
+ // this can only happen if the path ends with a /
|
||||||
|
+ // otherwise there would be a redirect instead
|
||||||
|
exchange.setRelativePath(info.getRewriteLocation());
|
||||||
|
exchange.setRequestPath(exchange.getResolvedPath() + info.getRewriteLocation());
|
||||||
|
}
|
||||||
|
-
|
||||||
|
final HttpServletResponseImpl response = new HttpServletResponseImpl(exchange, servletContext);
|
||||||
|
final HttpServletRequestImpl request = new HttpServletRequestImpl(exchange, servletContext);
|
||||||
|
final ServletRequestContext servletRequestContext = new ServletRequestContext(servletContext.getDeployment(), request, response, info);
|
||||||
|
diff --git a/servlet/src/test/java/io/undertow/servlet/test/defaultservlet/SecurityRedirectTestCase.java b/servlet/src/test/java/io/undertow/servlet/test/defaultservlet/SecurityRedirectTestCase.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000..8fa9323177
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/servlet/src/test/java/io/undertow/servlet/test/defaultservlet/SecurityRedirectTestCase.java
|
||||||
|
@@ -0,0 +1,168 @@
|
||||||
|
+/*
|
||||||
|
+ * JBoss, Home of Professional Open Source.
|
||||||
|
+ * Copyright 2019 Red Hat, Inc., and individual contributors
|
||||||
|
+ * as indicated by the @author tags.
|
||||||
|
+ *
|
||||||
|
+ * Licensed 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
|
||||||
|
+ *
|
||||||
|
+ * http://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 io.undertow.servlet.test.defaultservlet;
|
||||||
|
+
|
||||||
|
+import static io.undertow.util.Headers.AUTHORIZATION;
|
||||||
|
+import static io.undertow.util.Headers.BASIC;
|
||||||
|
+import static io.undertow.util.Headers.LOCATION;
|
||||||
|
+import static io.undertow.util.Headers.WWW_AUTHENTICATE;
|
||||||
|
+import static org.junit.Assert.assertEquals;
|
||||||
|
+
|
||||||
|
+import java.io.IOException;
|
||||||
|
+
|
||||||
|
+import javax.servlet.ServletException;
|
||||||
|
+
|
||||||
|
+import org.apache.http.Header;
|
||||||
|
+import org.apache.http.HttpResponse;
|
||||||
|
+import org.apache.http.client.HttpClient;
|
||||||
|
+import org.apache.http.client.methods.HttpGet;
|
||||||
|
+import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
+import org.junit.Assert;
|
||||||
|
+import org.junit.BeforeClass;
|
||||||
|
+import org.junit.Test;
|
||||||
|
+import org.junit.runner.RunWith;
|
||||||
|
+
|
||||||
|
+import io.undertow.server.handlers.PathHandler;
|
||||||
|
+import io.undertow.servlet.api.DeploymentInfo;
|
||||||
|
+import io.undertow.servlet.api.DeploymentManager;
|
||||||
|
+import io.undertow.servlet.api.LoginConfig;
|
||||||
|
+import io.undertow.servlet.api.SecurityConstraint;
|
||||||
|
+import io.undertow.servlet.api.ServletContainer;
|
||||||
|
+import io.undertow.servlet.api.WebResourceCollection;
|
||||||
|
+import io.undertow.servlet.test.path.ServletPathMappingTestCase;
|
||||||
|
+import io.undertow.servlet.test.security.constraint.ServletIdentityManager;
|
||||||
|
+import io.undertow.servlet.test.util.TestClassIntrospector;
|
||||||
|
+import io.undertow.servlet.test.util.TestResourceLoader;
|
||||||
|
+import io.undertow.testutils.DefaultServer;
|
||||||
|
+import io.undertow.testutils.HttpClientUtils;
|
||||||
|
+import io.undertow.util.FlexBase64;
|
||||||
|
+import io.undertow.util.StatusCodes;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * TestCase on redirect with or without trailing slash when requesting protected path.
|
||||||
|
+ *
|
||||||
|
+ * @author Lin Gao
|
||||||
|
+ */
|
||||||
|
+@RunWith(DefaultServer.class)
|
||||||
|
+public class SecurityRedirectTestCase {
|
||||||
|
+
|
||||||
|
+ @BeforeClass
|
||||||
|
+ public static void setup() throws ServletException {
|
||||||
|
+
|
||||||
|
+ final PathHandler root = new PathHandler();
|
||||||
|
+ final ServletContainer container = ServletContainer.Factory.newInstance();
|
||||||
|
+
|
||||||
|
+ ServletIdentityManager identityManager = new ServletIdentityManager();
|
||||||
|
+ identityManager.addUser("user1", "password1", "role1");
|
||||||
|
+
|
||||||
|
+ DeploymentInfo builder = new DeploymentInfo()
|
||||||
|
+ .setClassIntrospecter(TestClassIntrospector.INSTANCE)
|
||||||
|
+ .setClassLoader(ServletPathMappingTestCase.class.getClassLoader())
|
||||||
|
+ .setContextPath("/servletContext")
|
||||||
|
+ .setDeploymentName("servletContext.war")
|
||||||
|
+ .setResourceManager(new TestResourceLoader(SecurityRedirectTestCase.class))
|
||||||
|
+ .addWelcomePages("index.html")
|
||||||
|
+ .setIdentityManager(identityManager)
|
||||||
|
+ .setLoginConfig(new LoginConfig("BASIC", "Test Realm"))
|
||||||
|
+ .addSecurityConstraint(new SecurityConstraint()
|
||||||
|
+ .addRoleAllowed("role1")
|
||||||
|
+ .addWebResourceCollection(new WebResourceCollection()
|
||||||
|
+ .addUrlPatterns("/index.html", "/filterpath/*")));
|
||||||
|
+
|
||||||
|
+ DeploymentManager manager = container.addDeployment(builder);
|
||||||
|
+ manager.deploy();
|
||||||
|
+ root.addPrefixPath(builder.getContextPath(), manager.start());
|
||||||
|
+ DefaultServer.setRootHandler(root);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @SuppressWarnings("deprecation")
|
||||||
|
+ @Test
|
||||||
|
+ public void testSecurityWithWelcomeFileRedirect() throws IOException {
|
||||||
|
+ // disable following redirect
|
||||||
|
+ HttpClient client = HttpClientBuilder.create().disableRedirectHandling().build();
|
||||||
|
+ try {
|
||||||
|
+ HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + "/servletContext");
|
||||||
|
+ HttpResponse result = client.execute(get);
|
||||||
|
+ Assert.assertEquals(StatusCodes.FOUND, result.getStatusLine().getStatusCode());
|
||||||
|
+ Header[] values = result.getHeaders(LOCATION.toString());
|
||||||
|
+ assertEquals(1, values.length);
|
||||||
|
+ assertEquals(DefaultServer.getDefaultServerURL() + "/servletContext/", values[0].getValue());
|
||||||
|
+ HttpClientUtils.readResponse(result);
|
||||||
|
+
|
||||||
|
+ get = new HttpGet(DefaultServer.getDefaultServerURL() + "/servletContext/");
|
||||||
|
+ result = client.execute(get);
|
||||||
|
+ Assert.assertEquals(StatusCodes.UNAUTHORIZED, result.getStatusLine().getStatusCode());
|
||||||
|
+
|
||||||
|
+ values = result.getHeaders(WWW_AUTHENTICATE.toString());
|
||||||
|
+ assertEquals(1, values.length);
|
||||||
|
+ assertEquals(BASIC + " realm=\"Test Realm\"", values[0].getValue());
|
||||||
|
+ HttpClientUtils.readResponse(result);
|
||||||
|
+
|
||||||
|
+ get = new HttpGet(DefaultServer.getDefaultServerURL() + "/servletContext/");
|
||||||
|
+ get.addHeader(AUTHORIZATION.toString(), BASIC + " " + FlexBase64.encodeString("user1:password1".getBytes(), false));
|
||||||
|
+ result = client.execute(get);
|
||||||
|
+ String response = HttpClientUtils.readResponse(result);
|
||||||
|
+ Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
|
||||||
|
+ Assert.assertTrue(response.contains("Redirected home page"));
|
||||||
|
+ } finally {
|
||||||
|
+ client.getConnectionManager().shutdown();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @SuppressWarnings("deprecation")
|
||||||
|
+ @Test
|
||||||
|
+ public void testSecurityWithoutWelcomeFileRedirect() throws IOException {
|
||||||
|
+ // disable following redirect
|
||||||
|
+ HttpClient client = HttpClientBuilder.create().disableRedirectHandling().build();
|
||||||
|
+ try {
|
||||||
|
+ HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + "/servletContext/filterpath");
|
||||||
|
+ HttpResponse result = client.execute(get);
|
||||||
|
+ Assert.assertEquals(StatusCodes.UNAUTHORIZED, result.getStatusLine().getStatusCode());
|
||||||
|
+ HttpClientUtils.readResponse(result);
|
||||||
|
+
|
||||||
|
+ get = new HttpGet(DefaultServer.getDefaultServerURL() + "/servletContext/filterpath/");
|
||||||
|
+ result = client.execute(get);
|
||||||
|
+ Assert.assertEquals(StatusCodes.UNAUTHORIZED, result.getStatusLine().getStatusCode());
|
||||||
|
+
|
||||||
|
+ Header[] values = result.getHeaders(WWW_AUTHENTICATE.toString());
|
||||||
|
+ assertEquals(1, values.length);
|
||||||
|
+ assertEquals(BASIC + " realm=\"Test Realm\"", values[0].getValue());
|
||||||
|
+ HttpClientUtils.readResponse(result);
|
||||||
|
+
|
||||||
|
+ get = new HttpGet(DefaultServer.getDefaultServerURL() + "/servletContext/filterpath");
|
||||||
|
+ get.addHeader(AUTHORIZATION.toString(), BASIC + " " + FlexBase64.encodeString("user1:password1".getBytes(), false));
|
||||||
|
+ result = client.execute(get);
|
||||||
|
+ Assert.assertEquals(StatusCodes.FOUND, result.getStatusLine().getStatusCode());
|
||||||
|
+ values = result.getHeaders(LOCATION.toString());
|
||||||
|
+ assertEquals(1, values.length);
|
||||||
|
+ assertEquals(DefaultServer.getDefaultServerURL() + "/servletContext/filterpath/", values[0].getValue());
|
||||||
|
+ HttpClientUtils.readResponse(result);
|
||||||
|
+
|
||||||
|
+ get = new HttpGet(DefaultServer.getDefaultServerURL() + "/servletContext/filterpath/filtered.txt");
|
||||||
|
+ get.addHeader(AUTHORIZATION.toString(), BASIC + " " + FlexBase64.encodeString("user1:password1".getBytes(), false));
|
||||||
|
+ result = client.execute(get);
|
||||||
|
+ String response = HttpClientUtils.readResponse(result);
|
||||||
|
+ Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
|
||||||
|
+ Assert.assertTrue(response.equals("Stuart"));
|
||||||
|
+ } finally {
|
||||||
|
+ client.getConnectionManager().shutdown();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
26
CVE-2019-10212.patch
Normal file
26
CVE-2019-10212.patch
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
From 8b63e258502f9f55b33b2e0b02a2e24cf5d2f1c1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Paramvir Jindal <pjindal@pjindal.pnq.csb>
|
||||||
|
Date: Fri, 11 Oct 2019 11:51:22 +0530
|
||||||
|
Subject: [PATCH] UNDERTOW-1576: BASIC auth password is output as plain text at
|
||||||
|
DEBUG level logging in BasicAuthenticationMechanism
|
||||||
|
|
||||||
|
---
|
||||||
|
.../undertow/security/impl/BasicAuthenticationMechanism.java | 4 ++--
|
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/core/src/main/java/io/undertow/security/impl/BasicAuthenticationMechanism.java b/core/src/main/java/io/undertow/security/impl/BasicAuthenticationMechanism.java
|
||||||
|
index 7042e8ff66..94e786427e 100644
|
||||||
|
--- a/core/src/main/java/io/undertow/security/impl/BasicAuthenticationMechanism.java
|
||||||
|
+++ b/core/src/main/java/io/undertow/security/impl/BasicAuthenticationMechanism.java
|
||||||
|
@@ -151,9 +151,9 @@ public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange,
|
||||||
|
}
|
||||||
|
|
||||||
|
plainChallenge = new String(decode.array(), decode.arrayOffset(), decode.limit(), charset);
|
||||||
|
- UndertowLogger.SECURITY_LOGGER.debugf("Found basic auth header %s (decoded using charset %s) in %s", plainChallenge, charset, exchange);
|
||||||
|
+ UndertowLogger.SECURITY_LOGGER.debugf("Found basic auth header (decoded using charset %s) in %s", charset, exchange);
|
||||||
|
} catch (IOException e) {
|
||||||
|
- UndertowLogger.SECURITY_LOGGER.debugf(e, "Failed to decode basic auth header %s in %s", base64Challenge, exchange);
|
||||||
|
+ UndertowLogger.SECURITY_LOGGER.debugf(e, "Failed to decode basic auth header in %s", exchange);
|
||||||
|
}
|
||||||
|
int colonPos;
|
||||||
|
if (plainChallenge != null && (colonPos = plainChallenge.indexOf(COLON)) > -1) {
|
||||||
@ -2,7 +2,7 @@
|
|||||||
%global namedversion %{version}%{?namedreltag}
|
%global namedversion %{version}%{?namedreltag}
|
||||||
Name: undertow
|
Name: undertow
|
||||||
Version: 1.4.0
|
Version: 1.4.0
|
||||||
Release: 9
|
Release: 10
|
||||||
Summary: Java web server using non-blocking IO
|
Summary: Java web server using non-blocking IO
|
||||||
License: ASL 2.0
|
License: ASL 2.0
|
||||||
URL: http://undertow.io/
|
URL: http://undertow.io/
|
||||||
@ -17,6 +17,11 @@ Patch5: CVE-2021-3690.patch
|
|||||||
Patch6: CVE-2023-1973.patch
|
Patch6: CVE-2023-1973.patch
|
||||||
Patch7: CVE-2023-5379.patch
|
Patch7: CVE-2023-5379.patch
|
||||||
Patch8: CVE-2024-4109.patch
|
Patch8: CVE-2024-4109.patch
|
||||||
|
Patch9: CVE-2017-12196-1.patch
|
||||||
|
Patch10: CVE-2017-12196-2.patch
|
||||||
|
Patch11: CVE-2019-10184-pre.patch
|
||||||
|
Patch12: CVE-2019-10184.patch
|
||||||
|
Patch13: CVE-2019-10212.patch
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
Epoch: 1
|
Epoch: 1
|
||||||
BuildRequires: maven-local mvn(junit:junit) mvn(org.eclipse.jetty.alpn:alpn-api)
|
BuildRequires: maven-local mvn(junit:junit) mvn(org.eclipse.jetty.alpn:alpn-api)
|
||||||
@ -78,6 +83,9 @@ export CXXFLAGS="${RPM_OPT_FLAGS}"
|
|||||||
%license LICENSE.txt
|
%license LICENSE.txt
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Mar 04 2025 yaoxin <1024769339@qq.com> - 1:1.4.0-10
|
||||||
|
- Fix CVE-2017-12196,CVE-2019-10184 and CVE-2019-10212
|
||||||
|
|
||||||
* Tue Dec 17 2024 liyajie <liyajie15@h-partners.com> - 1:1.4.0-9
|
* Tue Dec 17 2024 liyajie <liyajie15@h-partners.com> - 1:1.4.0-9
|
||||||
- Fix CVE-2024-4109
|
- Fix CVE-2024-4109
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user