View | Details | Raw Unified | Return to bug 57767
Collapse All | Expand All

(-)java/org/apache/tomcat/websocket/AuthenticationException.java (+25 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.tomcat.websocket;
18
19
public class AuthenticationException extends Exception {
20
21
    public AuthenticationException(String message) {
22
        super(message);
23
    }
24
25
}
(-)java/org/apache/tomcat/websocket/Authenticator.java (+51 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.tomcat.websocket;
18
19
import java.util.HashMap;
20
import java.util.Map;
21
import java.util.regex.Matcher;
22
import java.util.regex.Pattern;
23
24
public abstract class Authenticator {
25
    private static final Pattern pattern = Pattern
26
            .compile("(\\w+)\\s*=\\s*(\"([^\"]+)\"|([^,=\"]+))\\s*,?");
27
28
    public abstract String getAuthorization(String requestUri, String WWWAuthenticate,
29
            Map<String, Object> UserProperties) throws AuthenticationException;
30
31
    public abstract String getSchemeName();
32
33
    public Map<String, String> parseWWWAuthenticateHeader(String WWWAuthenticate) {
34
35
        Matcher m = pattern.matcher(WWWAuthenticate);
36
        Map<String, String> challenge = new HashMap();
37
38
        while (m.find()) {
39
            String key = m.group(1);
40
            String qtedValue = m.group(3);
41
            String value = m.group(4);
42
43
            challenge.put(key, qtedValue != null ? qtedValue : value);
44
45
        }
46
47
        return challenge;
48
49
    }
50
51
}
(-)java/org/apache/tomcat/websocket/AuthenticatorFactory.java (+59 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.tomcat.websocket;
18
19
import java.util.Iterator;
20
import java.util.ServiceLoader;
21
22
public class AuthenticatorFactory {
23
24
    public static Authenticator getAuthenticator(String authScheme) {
25
26
        Authenticator auth = null;
27
        switch (authScheme.toLowerCase()) {
28
29
        case BasicAuthenticator.schemeName:
30
            auth = new BasicAuthenticator();
31
            break;
32
33
        case DigestAuthenticator.schemeName:
34
            auth = new DigestAuthenticator();
35
            break;
36
37
        default:
38
            auth = loadAuthenticators(authScheme);
39
            break;
40
        }
41
42
        return auth;
43
44
    }
45
46
    private static Authenticator loadAuthenticators(String authScheme) {
47
        ServiceLoader<Authenticator> serviceLoader = ServiceLoader.load(Authenticator.class);
48
        Iterator<Authenticator> auths = serviceLoader.iterator();
49
50
        while (auths.hasNext()) {
51
            Authenticator auth = auths.next();
52
            if (auth.getSchemeName().equalsIgnoreCase(authScheme))
53
                return auth;
54
        }
55
56
        return null;
57
    }
58
59
}
(-)java/org/apache/tomcat/websocket/BasicAuthenticator.java (+63 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.tomcat.websocket;
18
19
import java.nio.charset.Charset;
20
import java.nio.charset.StandardCharsets;
21
import java.util.Base64;
22
import java.util.Map;
23
24
public class BasicAuthenticator extends Authenticator {
25
26
    public static final String schemeName = "basic";
27
    public static final String charsetparam = "charset";
28
29
    @Override
30
    public String getAuthorization(String requestUri, String WWWAuthenticate,
31
            Map<String, Object> userProperties) throws AuthenticationException {
32
33
        String userName = (String) userProperties.get(Constants.WS_AUTHENTICATION_USER_NAME);
34
        String password = (String) userProperties.get(Constants.WS_AUTHENTICATION_PASSWORD);
35
36
        if (userName == null || password == null) {
37
            throw new AuthenticationException(
38
                    "Failed to perform Basic authentication due to  missing user/password");
39
        }
40
41
        Map<String, String> wwwAuthenticate = parseWWWAuthenticateHeader(WWWAuthenticate);
42
43
        String userPass = userName + ":" + password;
44
        Charset charset;
45
46
        if (wwwAuthenticate.get(charsetparam) != null
47
                && wwwAuthenticate.get(charsetparam).equalsIgnoreCase("UTF-8")) {
48
            charset = StandardCharsets.UTF_8;
49
        } else {
50
            charset = StandardCharsets.ISO_8859_1;
51
        }
52
53
        String base64 = Base64.getEncoder().encodeToString(userPass.getBytes(charset));
54
55
        return " Basic " + base64;
56
    }
57
58
    @Override
59
    public String getSchemeName() {
60
        return schemeName;
61
    }
62
63
}
(-)java/org/apache/tomcat/websocket/Constants.java (+5 lines)
Lines 88-93 Link Here
88
    public static final String CONNECTION_HEADER_NAME = "Connection";
88
    public static final String CONNECTION_HEADER_NAME = "Connection";
89
    public static final String CONNECTION_HEADER_VALUE = "upgrade";
89
    public static final String CONNECTION_HEADER_VALUE = "upgrade";
90
    public static final String LOCATION_HEADER_NAME = "Location";
90
    public static final String LOCATION_HEADER_NAME = "Location";
91
    public static final String AUTHORIZATION_HEADER_NAME = "Authorization";
92
    public static final String WWW_AUTHENTICATE_HEADER_NAME = "WWW-Authenticate";
91
    public static final String WS_VERSION_HEADER_NAME = "Sec-WebSocket-Version";
93
    public static final String WS_VERSION_HEADER_NAME = "Sec-WebSocket-Version";
92
    public static final String WS_VERSION_HEADER_VALUE = "13";
94
    public static final String WS_VERSION_HEADER_VALUE = "13";
93
    public static final String WS_KEY_HEADER_NAME = "Sec-WebSocket-Key";
95
    public static final String WS_KEY_HEADER_NAME = "Sec-WebSocket-Key";
Lines 117-122 Link Here
117
            "org.apache.tomcat.websocket.DEFAULT_PROCESS_PERIOD", 10)
119
            "org.apache.tomcat.websocket.DEFAULT_PROCESS_PERIOD", 10)
118
            .intValue();
120
            .intValue();
119
121
122
    public static final String WS_AUTHENTICATION_USER_NAME = "org.apache.tomcat.websocket.WS_AUTHENTICATION_USER_NAME";
123
    public static final String WS_AUTHENTICATION_PASSWORD = "org.apache.tomcat.websocket.WS_AUTHENTICATION_PASSWORD";
124
120
    /* Configuration for extensions
125
    /* Configuration for extensions
121
     * Note: These options are primarily present to enable this implementation
126
     * Note: These options are primarily present to enable this implementation
122
     *       to pass compliance tests. They are expected to be removed once
127
     *       to pass compliance tests. They are expected to be removed once
(-)java/org/apache/tomcat/websocket/DigestAuthenticator.java (+149 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.tomcat.websocket;
18
19
import java.io.UnsupportedEncodingException;
20
import java.nio.charset.StandardCharsets;
21
import java.security.MessageDigest;
22
import java.security.NoSuchAlgorithmException;
23
import java.security.SecureRandom;
24
import java.util.Map;
25
26
import org.apache.tomcat.util.security.MD5Encoder;
27
28
public class DigestAuthenticator extends Authenticator {
29
30
    public static final String schemeName = "digest";
31
    private SecureRandom cnonceGenerator;
32
    private int nonceCount = 0;
33
    private long cNonce;
34
35
    @Override
36
    public String getAuthorization(String requestUri, String WWWAuthenticate,
37
            Map<String, Object> userProperties) throws AuthenticationException {
38
39
        String userName = (String) userProperties.get(Constants.WS_AUTHENTICATION_USER_NAME);
40
        String password = (String) userProperties.get(Constants.WS_AUTHENTICATION_PASSWORD);
41
42
        if (userName == null || password == null) {
43
            throw new AuthenticationException(
44
                    "Failed to perform Digest authentication due to  missing user/password");
45
        }
46
47
        Map<String, String> wwwAuthenticate = parseWWWAuthenticateHeader(WWWAuthenticate);
48
49
        String realm = wwwAuthenticate.get("realm");
50
        String nonce = wwwAuthenticate.get("nonce");
51
        String messageQop = wwwAuthenticate.get("qop");
52
        String algorithm = wwwAuthenticate.get("algorithm") == null ? "MD5"
53
                : wwwAuthenticate.get("algorithm");
54
        String opaque = wwwAuthenticate.get("opaque");
55
56
        StringBuilder challenge = new StringBuilder();
57
58
        if (!messageQop.isEmpty()) {
59
            if (cnonceGenerator == null) {
60
                cnonceGenerator = new SecureRandom();
61
            }
62
63
            cNonce = cnonceGenerator.nextLong();
64
            nonceCount++;
65
        }
66
67
        challenge.append("Digest ");
68
        challenge.append("username =\"" + userName + "\",");
69
        challenge.append("realm=\"" + realm + "\",");
70
        challenge.append("nonce=\"" + nonce + "\",");
71
        challenge.append("uri=\"" + requestUri + "\",");
72
73
        try {
74
            challenge.append("response=\"" + calculateRequestDigest(requestUri, userName, password,
75
                    realm, nonce, messageQop, algorithm) + "\",");
76
        }
77
78
        catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
79
            throw new AuthenticationException(
80
                    "Unable to generate request digest " + e.getMessage());
81
        }
82
83
        challenge.append("algorithm=" + algorithm + ",");
84
        challenge.append("opaque=\"" + opaque + "\",");
85
86
        if (!messageQop.isEmpty()) {
87
            challenge.append("qop=\"" + messageQop + "\"");
88
            challenge.append(",cnonce=\"" + cNonce + "\",");
89
            challenge.append("nc=" + String.format("%08X", nonceCount));
90
        }
91
92
        return challenge.toString();
93
94
    }
95
96
    private String calculateRequestDigest(String requestUri, String userName, String password,
97
            String realm, String nonce, String qop, String algorithm)
98
            throws UnsupportedEncodingException, NoSuchAlgorithmException {
99
100
        StringBuilder preDigest = new StringBuilder();
101
        String A1;
102
103
        if (algorithm.equalsIgnoreCase("MD5"))
104
            A1 = userName + ":" + realm + ":" + password;
105
106
        else
107
            A1 = encodeMD5(userName + ":" + realm + ":" + password) + ":" + nonce + ":" + cNonce;
108
109
        /*
110
         * If the "qop" value is "auth-int", then A2 is: A2 = Method ":"
111
         * digest-uri-value ":" H(entity-body) since we do not have an entity-body, A2 =
112
         * Method ":" digest-uri-value for auth and auth_int
113
         */
114
        String A2 = "GET:" + requestUri;
115
116
        preDigest.append(encodeMD5(A1));
117
        preDigest.append(":");
118
        preDigest.append(nonce);
119
120
        if (qop.toLowerCase().contains("auth")) {
121
            preDigest.append(":");
122
            preDigest.append(String.format("%08X", nonceCount));
123
            preDigest.append(":");
124
            preDigest.append(String.valueOf(cNonce));
125
            preDigest.append(":");
126
            preDigest.append(qop);
127
        }
128
129
        preDigest.append(":");
130
        preDigest.append(encodeMD5(A2));
131
132
        return encodeMD5(preDigest.toString());
133
134
    }
135
136
    private String encodeMD5(String value)
137
            throws UnsupportedEncodingException, NoSuchAlgorithmException {
138
        byte[] bytesOfMessage = value.getBytes(StandardCharsets.ISO_8859_1);
139
        MessageDigest md = MessageDigest.getInstance("MD5");
140
        byte[] thedigest = md.digest(bytesOfMessage);
141
142
        return MD5Encoder.encode(thedigest);
143
    }
144
145
    @Override
146
    public String getSchemeName() {
147
        return schemeName;
148
    }
149
}
(-)java/org/apache/tomcat/websocket/LocalStrings.properties (-1 / +4 lines)
Lines 137-140 Link Here
137
wsWebSocketContainer.sessionCloseFail=Session with ID [{0}] did not close cleanly
137
wsWebSocketContainer.sessionCloseFail=Session with ID [{0}] did not close cleanly
138
wsWebSocketContainer.sslEngineFail=Unable to create SSLEngine to support SSL/TLS connections
138
wsWebSocketContainer.sslEngineFail=Unable to create SSLEngine to support SSL/TLS connections
139
wsWebSocketContainer.missingLocationHeader=Failed to handle HTTP response code [{0}]. Missing Location header in response
139
wsWebSocketContainer.missingLocationHeader=Failed to handle HTTP response code [{0}]. Missing Location header in response
140
wsWebSocketContainer.redirectThreshold=Cyclic Location header [{0}] detected / reached max number of redirects [{1}] of max [{2}]
140
wsWebSocketContainer.redirectThreshold=Cyclic Location header [{0}] detected / reached max number of redirects [{1}] of max [{2}]
141
wsWebSocketContainer.unsupportedAuthScheme=Failed to handle HTTP response code [{0}]. Unsupported Authentication scheme [{1}] returned in response
142
wsWebSocketContainer.failedAuthentication=Failed to handle HTTP response code [{0}]. Authentication header was not accepted by server.
143
wsWebSocketContainer.missingWWWAuthenticateHeader=Failed to handle HTTP response code [{0}]. Missing WWW-Authenticate header in response
(-)java/org/apache/tomcat/websocket/WsWebSocketContainer.java (-13 / +63 lines)
Lines 256-268 Link Here
256
        }
256
        }
257
257
258
        // Create the initial HTTP request to open the WebSocket connection
258
        // Create the initial HTTP request to open the WebSocket connection
259
        Map<String,List<String>> reqHeaders = createRequestHeaders(host, port,
259
        Map<String, List<String>> reqHeaders = createRequestHeaders(host, port,
260
                clientEndpointConfiguration.getPreferredSubprotocols(),
260
                clientEndpointConfiguration);
261
                clientEndpointConfiguration.getExtensions());
261
        clientEndpointConfiguration.getConfigurator().beforeRequest(reqHeaders);
262
        clientEndpointConfiguration.getConfigurator().
262
        if (Constants.DEFAULT_ORIGIN_HEADER_VALUE != null
263
                beforeRequest(reqHeaders);
263
                && !reqHeaders.containsKey(Constants.ORIGIN_HEADER_NAME)) {
264
        if (Constants.DEFAULT_ORIGIN_HEADER_VALUE != null &&
265
                !reqHeaders.containsKey(Constants.ORIGIN_HEADER_NAME)) {
266
            List<String> originValues = new ArrayList<>(1);
264
            List<String> originValues = new ArrayList<>(1);
267
            originValues.add(Constants.DEFAULT_ORIGIN_HEADER_VALUE);
265
            originValues.add(Constants.DEFAULT_ORIGIN_HEADER_VALUE);
268
            reqHeaders.put(Constants.ORIGIN_HEADER_NAME, originValues);
266
            reqHeaders.put(Constants.ORIGIN_HEADER_NAME, originValues);
Lines 392-399 Link Here
392
                    return connectToServer(endpoint, clientEndpointConfiguration, redirectLocation);
390
                    return connectToServer(endpoint, clientEndpointConfiguration, redirectLocation);
393
391
394
                }
392
                }
395
                throw new DeploymentException(sm.getString("wsWebSocketContainer.invalidStatus",
393
396
                        Integer.toString(httpResponse.status)));
394
                else if (httpResponse.status == 401) {
395
396
                    if (userProperties.get(Constants.AUTHORIZATION_HEADER_NAME) != null) {
397
                        throw new DeploymentException(sm.getString(
398
                                "wsWebSocketContainer.failedAuthentication", httpResponse.status));
399
                    }
400
401
                    List<String> wwwAuthenticateHeaders = httpResponse.getHandshakeResponse()
402
                            .getHeaders().get(Constants.WWW_AUTHENTICATE_HEADER_NAME);
403
404
                    if (wwwAuthenticateHeaders == null || wwwAuthenticateHeaders.isEmpty() ||
405
                            wwwAuthenticateHeaders.get(0) == null || wwwAuthenticateHeaders.get(0).isEmpty()) {
406
                        throw new DeploymentException(sm.getString(
407
                                "wsWebSocketContainer.missingWWWAuthenticateHeader",
408
                                Integer.toString(httpResponse.status)));
409
                    }
410
411
                    String authScheme = wwwAuthenticateHeaders.get(0).split("\\s+", 2)[0];
412
                    String requestUri = new String(request.array(), StandardCharsets.ISO_8859_1)
413
                            .split("\\s", 3)[1];
414
415
                    Authenticator auth = AuthenticatorFactory.getAuthenticator(authScheme);
416
417
                    if (auth == null) {
418
                        throw new DeploymentException(
419
                                sm.getString("wsWebSocketContainer.unsupportedAuthScheme",
420
                                        httpResponse.status, authScheme));
421
                    }
422
423
                    userProperties.put(Constants.AUTHORIZATION_HEADER_NAME, auth.getAuthorization(
424
                            requestUri, wwwAuthenticateHeaders.get(0), userProperties));
425
426
                    return connectToServer(endpoint, clientEndpointConfiguration, path);
427
428
                }
429
430
                else {
431
                    throw new DeploymentException(sm.getString("wsWebSocketContainer.invalidStatus",
432
                            Integer.toString(httpResponse.status)));
433
                }
397
            }
434
            }
398
            HandshakeResponse handshakeResponse = httpResponse.getHandshakeResponse();
435
            HandshakeResponse handshakeResponse = httpResponse.getHandshakeResponse();
399
            clientEndpointConfiguration.getConfigurator().afterResponse(handshakeResponse);
436
            clientEndpointConfiguration.getConfigurator().afterResponse(handshakeResponse);
Lines 440-446 Link Here
440
477
441
            success = true;
478
            success = true;
442
        } catch (ExecutionException | InterruptedException | SSLException |
479
        } catch (ExecutionException | InterruptedException | SSLException |
443
                EOFException | TimeoutException | URISyntaxException e) {
480
                EOFException | TimeoutException | URISyntaxException | AuthenticationException e) {
444
            throw new DeploymentException(
481
            throw new DeploymentException(
445
                    sm.getString("wsWebSocketContainer.httpRequestFailed"), e);
482
                    sm.getString("wsWebSocketContainer.httpRequestFailed"), e);
446
        } finally {
483
        } finally {
Lines 447-452 Link Here
447
            if (!success) {
484
            if (!success) {
448
                channel.close();
485
                channel.close();
449
            }
486
            }
487
488
            if (redirectSet != null && !redirectSet.isEmpty()) {
489
                redirectSet.clear();
490
            }
450
        }
491
        }
451
492
452
        // Switch to WebSocket
493
        // Switch to WebSocket
Lines 588-598 Link Here
588
        return result;
629
        return result;
589
    }
630
    }
590
631
591
    private static Map<String,List<String>> createRequestHeaders(String host,
632
    private static Map<String, List<String>> createRequestHeaders(String host, int port,
592
            int port, List<String> subProtocols, List<Extension> extensions) {
633
            ClientEndpointConfig clientEndpointConfiguration) {
593
634
594
        Map<String,List<String>> headers = new HashMap<>();
635
        Map<String, List<String>> headers = new HashMap<>();
636
        List<Extension> extensions = clientEndpointConfiguration.getExtensions();
637
        List<String> subProtocols = clientEndpointConfiguration.getPreferredSubprotocols();
638
        Map<String, Object> userProperties = clientEndpointConfiguration.getUserProperties();
595
639
640
        if (userProperties.get(Constants.AUTHORIZATION_HEADER_NAME) != null) {
641
            List<String> authValues = new ArrayList<>(1);
642
            authValues.add((String) userProperties.get(Constants.AUTHORIZATION_HEADER_NAME));
643
            headers.put(Constants.AUTHORIZATION_HEADER_NAME, authValues);
644
        }
645
596
        // Host header
646
        // Host header
597
        List<String> hostValues = new ArrayList<>(1);
647
        List<String> hostValues = new ArrayList<>(1);
598
        if (port == -1) {
648
        if (port == -1) {
(-)test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java (-6 / +95 lines)
Lines 30-42 Link Here
30
import org.junit.Test;
30
import org.junit.Test;
31
31
32
import org.apache.catalina.Context;
32
import org.apache.catalina.Context;
33
import org.apache.catalina.authenticator.AuthenticatorBase;
33
import org.apache.catalina.servlets.DefaultServlet;
34
import org.apache.catalina.servlets.DefaultServlet;
34
import org.apache.catalina.startup.Tomcat;
35
import org.apache.catalina.startup.Tomcat;
36
import org.apache.tomcat.util.descriptor.web.LoginConfig;
37
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
38
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
35
import org.apache.tomcat.websocket.TesterMessageCountClient.BasicText;
39
import org.apache.tomcat.websocket.TesterMessageCountClient.BasicText;
36
import org.apache.tomcat.websocket.TesterMessageCountClient.TesterProgrammaticEndpoint;
40
import org.apache.tomcat.websocket.TesterMessageCountClient.TesterProgrammaticEndpoint;
37
41
38
public class TestWebSocketFrameClient extends WebSocketBaseTest {
42
public class TestWebSocketFrameClient extends WebSocketBaseTest {
39
43
44
    private static final String USER = "Aladdin";
45
    private static final String PWD = "open sesame";
46
    private static final String ROLE = "role";
47
    private static final String URI_PROTECTED = "/foo";
48
40
    @Test
49
    @Test
41
    public void testConnectToServerEndpoint() throws Exception {
50
    public void testConnectToServerEndpoint() throws Exception {
42
        Tomcat tomcat = getTomcatInstance();
51
        Tomcat tomcat = getTomcatInstance();
Lines 93-107 Link Here
93
102
94
        tomcat.start();
103
        tomcat.start();
95
104
96
        echoTester("");
105
        echoTester("",null);
97
        echoTester("/");
106
        echoTester("/",null);
98
        echoTester("/foo");
107
        echoTester("/foo",null);
99
        echoTester("/foo/");
108
        echoTester("/foo/",null);
100
    }
109
    }
101
110
102
    public void echoTester(String path) throws Exception {
111
    public void echoTester(String path, ClientEndpointConfig clientEndpointConfig)
112
            throws Exception {
103
        WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer();
113
        WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer();
104
        ClientEndpointConfig clientEndpointConfig = ClientEndpointConfig.Builder.create().build();
114
115
        if (clientEndpointConfig == null) {
116
            clientEndpointConfig = ClientEndpointConfig.Builder.create().build();
117
        }
105
        Session wsSession = wsContainer.connectToServer(TesterProgrammaticEndpoint.class,
118
        Session wsSession = wsContainer.connectToServer(TesterProgrammaticEndpoint.class,
106
                clientEndpointConfig, new URI("ws://localhost:" + getPort() + path));
119
                clientEndpointConfig, new URI("ws://localhost:" + getPort() + path));
107
        CountDownLatch latch = new CountDownLatch(1);
120
        CountDownLatch latch = new CountDownLatch(1);
Lines 120-123 Link Here
120
        wsSession.close();
133
        wsSession.close();
121
    }
134
    }
122
135
136
    @Test
137
    public void testConnectToBasicEndpoint() throws Exception {
138
139
        Tomcat tomcat = getTomcatInstance();
140
        Context ctx = tomcat.addContext(URI_PROTECTED, null);
141
        ctx.addApplicationListener(TesterEchoServer.Config.class.getName());
142
        Tomcat.addServlet(ctx, "default", new DefaultServlet());
143
        ctx.addServletMappingDecoded("/", "default");
144
145
        SecurityCollection collection = new SecurityCollection();
146
        collection.addPatternDecoded("/");
147
        String utf8User = "test";
148
        String utf8Pass = "123£";
149
150
        tomcat.addUser(utf8User, utf8Pass);
151
        tomcat.addRole(utf8User, ROLE);
152
153
        SecurityConstraint sc = new SecurityConstraint();
154
        sc.addAuthRole(ROLE);
155
        sc.addCollection(collection);
156
        ctx.addConstraint(sc);
157
158
        LoginConfig lc = new LoginConfig();
159
        lc.setAuthMethod("BASIC");
160
        ctx.setLoginConfig(lc);
161
162
        AuthenticatorBase basicAuthenticator = new org.apache.catalina.authenticator.BasicAuthenticator();
163
        ctx.getPipeline().addValve(basicAuthenticator);
164
165
        tomcat.start();
166
167
        ClientEndpointConfig clientEndpointConfig = ClientEndpointConfig.Builder.create().build();
168
        clientEndpointConfig.getUserProperties().put(Constants.WS_AUTHENTICATION_USER_NAME, utf8User);
169
        clientEndpointConfig.getUserProperties().put(Constants.WS_AUTHENTICATION_PASSWORD, utf8Pass);
170
171
        echoTester(URI_PROTECTED, clientEndpointConfig);
172
173
    }
174
175
    @Test
176
    public void testConnectToDigestEndpoint() throws Exception {
177
178
        Tomcat tomcat = getTomcatInstance();
179
        Context ctx = tomcat.addContext(URI_PROTECTED, null);
180
        ctx.addApplicationListener(TesterEchoServer.Config.class.getName());
181
        Tomcat.addServlet(ctx, "default", new DefaultServlet());
182
        ctx.addServletMappingDecoded("/", "default");
183
184
        SecurityCollection collection = new SecurityCollection();
185
        collection.addPatternDecoded("/*");
186
187
        tomcat.addUser(USER, PWD);
188
        tomcat.addRole(USER, ROLE);
189
190
        SecurityConstraint sc = new SecurityConstraint();
191
        sc.addAuthRole(ROLE);
192
        sc.addCollection(collection);
193
        ctx.addConstraint(sc);
194
195
        LoginConfig lc = new LoginConfig();
196
        lc.setAuthMethod("DIGEST");
197
        ctx.setLoginConfig(lc);
198
199
        AuthenticatorBase digestAuthenticator = new org.apache.catalina.authenticator.DigestAuthenticator();
200
        ctx.getPipeline().addValve(digestAuthenticator);
201
202
        tomcat.start();
203
204
        ClientEndpointConfig clientEndpointConfig = ClientEndpointConfig.Builder.create().build();
205
        clientEndpointConfig.getUserProperties().put(Constants.WS_AUTHENTICATION_USER_NAME, USER);
206
        clientEndpointConfig.getUserProperties().put(Constants.WS_AUTHENTICATION_PASSWORD,PWD);
207
208
        echoTester(URI_PROTECTED, clientEndpointConfig);
209
210
    }
211
123
}
212
}

Return to bug 57767