This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit ed7bc9110220bb620da4a16c599d4e6b5fb6bc97
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Sep 9 09:27:33 2022 +0100

    More refactoring in preparation for the BZ 62312 fix
---
 .../tomcat/websocket/AuthenticationType.java       | 61 +++++++++++++++
 java/org/apache/tomcat/websocket/Constants.java    |  3 +-
 .../tomcat/websocket/LocalStrings.properties       |  4 +-
 .../tomcat/websocket/WsWebSocketContainer.java     | 89 ++++++++++++----------
 4 files changed, 114 insertions(+), 43 deletions(-)

diff --git a/java/org/apache/tomcat/websocket/AuthenticationType.java 
b/java/org/apache/tomcat/websocket/AuthenticationType.java
new file mode 100644
index 0000000000..c3a9fa5736
--- /dev/null
+++ b/java/org/apache/tomcat/websocket/AuthenticationType.java
@@ -0,0 +1,61 @@
+/*
+ * 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
+ *
+ *     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 org.apache.tomcat.websocket;
+
+public enum AuthenticationType {
+
+    WWW(Constants.AUTHORIZATION_HEADER_NAME,
+            Constants.WWW_AUTHENTICATE_HEADER_NAME,
+            Constants.WS_AUTHENTICATION_USER_NAME,
+            Constants.WS_AUTHENTICATION_PASSWORD,
+            Constants.WS_AUTHENTICATION_REALM);
+
+    private final String authorizationHeaderName;
+    private final String authenticateHeaderName;
+    private final String userNameProperty;
+    private final String userPasswordProperty;
+    private final String userRealmProperty;
+
+    private AuthenticationType(String authorizationHeaderName, String 
authenticateHeaderName, String userNameProperty,
+            String userPasswordProperty, String userRealmProperty) {
+        this.authorizationHeaderName = authorizationHeaderName;
+        this.authenticateHeaderName = authenticateHeaderName;
+        this.userNameProperty = userNameProperty;
+        this.userPasswordProperty = userPasswordProperty;
+        this.userRealmProperty = userRealmProperty;
+    }
+
+    public String getAuthorizationHeaderName() {
+        return authorizationHeaderName;
+    }
+
+    public String getAuthenticateHeaderName() {
+        return authenticateHeaderName;
+    }
+
+    public String getUserNameProperty() {
+        return userNameProperty;
+    }
+
+    public String getUserPasswordProperty() {
+        return userPasswordProperty;
+    }
+
+    public String getUserRealmProperty() {
+        return userRealmProperty;
+    }
+}
diff --git a/java/org/apache/tomcat/websocket/Constants.java 
b/java/org/apache/tomcat/websocket/Constants.java
index b506694fe0..b2a843eba5 100644
--- a/java/org/apache/tomcat/websocket/Constants.java
+++ b/java/org/apache/tomcat/websocket/Constants.java
@@ -108,13 +108,14 @@ public class Constants {
     public static final String WS_PROTOCOL_HEADER_NAME = 
"Sec-WebSocket-Protocol";
     public static final String WS_EXTENSIONS_HEADER_NAME = 
"Sec-WebSocket-Extensions";
 
-    /// HTTP redirection status codes
+    // HTTP status codes
     public static final int MULTIPLE_CHOICES = 300;
     public static final int MOVED_PERMANENTLY = 301;
     public static final int FOUND = 302;
     public static final int SEE_OTHER = 303;
     public static final int USE_PROXY = 305;
     public static final int TEMPORARY_REDIRECT = 307;
+    public static final int UNAUTHORIZED = 401;
 
     // Configuration for Origin header in client
     static final String DEFAULT_ORIGIN_HEADER_VALUE =
diff --git a/java/org/apache/tomcat/websocket/LocalStrings.properties 
b/java/org/apache/tomcat/websocket/LocalStrings.properties
index 030d43b7fb..41b1e1efa2 100644
--- a/java/org/apache/tomcat/websocket/LocalStrings.properties
+++ b/java/org/apache/tomcat/websocket/LocalStrings.properties
@@ -139,7 +139,7 @@ wsWebSocketContainer.asynchronousSocketChannelFail=Unable 
to open a connection t
 wsWebSocketContainer.connect.entry=Connecting endpoint instance of type [{0}] 
to [{1}]
 wsWebSocketContainer.connect.write=Writing the HTTP upgrade request from 
buffer starting at [{0}] with a limit of [{1}] from local address [{2}]
 wsWebSocketContainer.defaultConfiguratorFail=Failed to create the default 
configurator
-wsWebSocketContainer.failedAuthentication=Failed to handle HTTP response code 
[{0}]. Authentication header was not accepted by server.
+wsWebSocketContainer.failedAuthentication=Failed to handle HTTP response code 
[{0}]. [{1}] header was not accepted by server.
 wsWebSocketContainer.httpRequestFailed=The HTTP request to initiate the 
WebSocket connection to [{0}] failed
 wsWebSocketContainer.invalidExtensionParameters=The server responded with 
extension parameters the client is unable to support
 wsWebSocketContainer.invalidHeader=Unable to parse HTTP header as no colon is 
present to delimit header name and header value in [{0}]. The header has been 
skipped.
@@ -147,8 +147,8 @@ wsWebSocketContainer.invalidStatus=The HTTP response from 
the server [{0}] did n
 wsWebSocketContainer.invalidSubProtocol=The WebSocket server returned multiple 
values for the Sec-WebSocket-Protocol header
 wsWebSocketContainer.maxBuffer=This implementation limits the maximum size of 
a buffer to Integer.MAX_VALUE
 wsWebSocketContainer.missingAnnotation=Cannot use POJO class [{0}] as it is 
not annotated with @ClientEndpoint
+wsWebSocketContainer.missingAuthenticateHeader=Failed to handle HTTP response 
code [{0}]. Missing [{1}] header in response
 wsWebSocketContainer.missingLocationHeader=Failed to handle HTTP response code 
[{0}]. Missing Location header in response
-wsWebSocketContainer.missingWWWAuthenticateHeader=Failed to handle HTTP 
response code [{0}]. Missing WWW-Authenticate header in response
 wsWebSocketContainer.pathNoHost=No host was specified in URI
 wsWebSocketContainer.pathWrongScheme=The scheme [{0}] is not supported. The 
supported schemes are ws and wss
 wsWebSocketContainer.proxyConnectFail=Failed to connect to the configured 
Proxy [{0}]. The HTTP response code was [{1}]
diff --git a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java 
b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
index 6b301aa086..571fe611c9 100644
--- a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
+++ b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
@@ -389,46 +389,9 @@ public class WsWebSocketContainer implements 
WebSocketContainer, BackgroundProce
                     return connectToServerRecursive(
                             clientEndpointHolder, clientEndpointConfiguration, 
redirectLocation, redirectSet);
 
-                }
-
-                else if (httpResponse.status == 401) {
-
-                    if 
(userProperties.get(Constants.AUTHORIZATION_HEADER_NAME) != null) {
-                        throw new DeploymentException(sm.getString(
-                                "wsWebSocketContainer.failedAuthentication",
-                                Integer.valueOf(httpResponse.status)));
-                    }
-
-                    List<String> wwwAuthenticateHeaders = 
httpResponse.getHandshakeResponse()
-                            
.getHeaders().get(Constants.WWW_AUTHENTICATE_HEADER_NAME);
-
-                    if (wwwAuthenticateHeaders == null || 
wwwAuthenticateHeaders.isEmpty() ||
-                            wwwAuthenticateHeaders.get(0) == null || 
wwwAuthenticateHeaders.get(0).isEmpty()) {
-                        throw new DeploymentException(sm.getString(
-                                
"wsWebSocketContainer.missingWWWAuthenticateHeader",
-                                Integer.toString(httpResponse.status)));
-                    }
-
-                    String authScheme = 
wwwAuthenticateHeaders.get(0).split("\\s+", 2)[0];
-                    String requestUri = new String(request.array(), 
StandardCharsets.ISO_8859_1)
-                            .split("\\s", 3)[1];
-
-                    Authenticator auth = 
AuthenticatorFactory.getAuthenticator(authScheme);
-
-                    if (auth == null) {
-                        throw new DeploymentException(
-                                
sm.getString("wsWebSocketContainer.unsupportedAuthScheme",
-                                        Integer.valueOf(httpResponse.status), 
authScheme));
-                    }
-
-                    userProperties.put(Constants.AUTHORIZATION_HEADER_NAME, 
auth.getAuthorization(
-                            requestUri, wwwAuthenticateHeaders.get(0),
-                            (String) 
userProperties.get(Constants.WS_AUTHENTICATION_USER_NAME),
-                            (String) 
userProperties.get(Constants.WS_AUTHENTICATION_PASSWORD),
-                            (String) 
userProperties.get(Constants.WS_AUTHENTICATION_REALM)));
-
-                    return connectToServerRecursive(
-                            clientEndpointHolder, clientEndpointConfiguration, 
path, redirectSet);
+                } else if (httpResponse.status == Constants.UNAUTHORIZED) {
+                    return 
processAuthenticationChallenge(clientEndpointHolder, 
clientEndpointConfiguration, path,
+                            redirectSet, userProperties, request, 
httpResponse, AuthenticationType.WWW);
 
                 } else {
                     throw new 
DeploymentException(sm.getString("wsWebSocketContainer.invalidStatus",
@@ -527,6 +490,52 @@ public class WsWebSocketContainer implements 
WebSocketContainer, BackgroundProce
     }
 
 
+    private Session processAuthenticationChallenge(ClientEndpointHolder 
clientEndpointHolder,
+            ClientEndpointConfig clientEndpointConfiguration, URI path, 
Set<URI> redirectSet,
+            Map<String,Object> userProperties, ByteBuffer request, 
HttpResponse httpResponse,
+            AuthenticationType authenticationType)
+            throws DeploymentException, AuthenticationException {
+
+        if 
(userProperties.get(authenticationType.getAuthorizationHeaderName()) != null) {
+            throw new DeploymentException(sm.getString(
+                    "wsWebSocketContainer.failedAuthentication",
+                    Integer.valueOf(httpResponse.status), 
authenticationType.getAuthorizationHeaderName()));
+        }
+
+        List<String> authenticateHeaders = 
httpResponse.getHandshakeResponse().getHeaders().get(
+                authenticationType.getAuthenticateHeaderName());
+
+        if (authenticateHeaders == null || authenticateHeaders.isEmpty() ||
+                authenticateHeaders.get(0) == null || 
authenticateHeaders.get(0).isEmpty()) {
+            throw new DeploymentException(sm.getString(
+                    "wsWebSocketContainer.missingAuthenticateHeader",
+                    Integer.toString(httpResponse.status), 
authenticationType.getAuthenticateHeaderName()));
+        }
+
+        String authScheme = authenticateHeaders.get(0).split("\\s+", 2)[0];
+
+        Authenticator auth = AuthenticatorFactory.getAuthenticator(authScheme);
+
+        if (auth == null) {
+            throw new DeploymentException(
+                    sm.getString("wsWebSocketContainer.unsupportedAuthScheme",
+                            Integer.valueOf(httpResponse.status), authScheme));
+        }
+
+        String requestUri = new String(request.array(), 
StandardCharsets.ISO_8859_1).split("\\s", 3)[1];
+
+        userProperties.put(authenticationType.getAuthorizationHeaderName(), 
auth.getAuthorization(
+                requestUri, authenticateHeaders.get(0),
+                (String) 
userProperties.get(authenticationType.getUserNameProperty()),
+                (String) 
userProperties.get(authenticationType.getUserPasswordProperty()),
+                (String) 
userProperties.get(authenticationType.getUserRealmProperty())));
+
+        return connectToServerRecursive(
+                clientEndpointHolder, clientEndpointConfiguration, path, 
redirectSet);
+    }
+
+
+
     private static void writeRequest(AsyncChannelWrapper channel, ByteBuffer 
request,
             long timeout) throws TimeoutException, InterruptedException, 
ExecutionException {
         int toWrite = request.limit();


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to