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

(-)java/org/apache/catalina/authenticator/AuthenticatorBase.java (-13 / +39 lines)
Lines 19-35 Link Here
19
package org.apache.catalina.authenticator;
19
package org.apache.catalina.authenticator;
20
20
21
21
22
import java.io.IOException;
23
import java.security.Principal;
24
import java.security.cert.X509Certificate;
25
import java.text.SimpleDateFormat;
26
import java.util.Date;
27
import java.util.Locale;
28
29
import javax.servlet.ServletException;
30
import javax.servlet.http.Cookie;
31
import javax.servlet.http.HttpServletResponse;
32
33
import org.apache.catalina.Authenticator;
22
import org.apache.catalina.Authenticator;
34
import org.apache.catalina.Container;
23
import org.apache.catalina.Container;
35
import org.apache.catalina.Context;
24
import org.apache.catalina.Context;
Lines 47-57 Link Here
47
import org.apache.catalina.util.DateTool;
36
import org.apache.catalina.util.DateTool;
48
import org.apache.catalina.util.SessionIdGenerator;
37
import org.apache.catalina.util.SessionIdGenerator;
49
import org.apache.catalina.valves.ValveBase;
38
import org.apache.catalina.valves.ValveBase;
39
import org.apache.coyote.ActionCode;
50
import org.apache.juli.logging.Log;
40
import org.apache.juli.logging.Log;
51
import org.apache.juli.logging.LogFactory;
41
import org.apache.juli.logging.LogFactory;
52
import org.apache.tomcat.util.res.StringManager;
42
import org.apache.tomcat.util.res.StringManager;
53
43
44
import javax.servlet.ServletException;
45
import javax.servlet.http.Cookie;
46
import javax.servlet.http.HttpServletResponse;
47
import java.io.IOException;
48
import java.security.Principal;
49
import java.security.cert.X509Certificate;
50
import java.text.SimpleDateFormat;
51
import java.util.Date;
52
import java.util.Locale;
54
53
54
55
/**
55
/**
56
 * Basic implementation of the <b>Valve</b> interface that enforces the
56
 * Basic implementation of the <b>Valve</b> interface that enforces the
57
 * <code>&lt;security-constraint&gt;</code> elements in the web application
57
 * <code>&lt;security-constraint&gt;</code> elements in the web application
Lines 561-568 Link Here
561
        }
561
        }
562
562
563
        if (!authRequired && context.getPreemptiveAuthentication()) {
563
        if (!authRequired && context.getPreemptiveAuthentication()) {
564
            X509Certificate[] certs = (X509Certificate[]) request.getAttribute(
564
            final X509Certificate[] certs = getRequestCertificates(request);
565
                    Globals.CERTIFICATES_ATTR);
566
            authRequired = certs != null && certs.length > 0;
565
            authRequired = certs != null && certs.length > 0;
567
        }
566
        }
568
567
Lines 614-620 Link Here
614
613
615
    // ------------------------------------------------------ Protected Methods
614
    // ------------------------------------------------------ Protected Methods
616
615
616
    /**
617
     * Look for the X509 certificate chain in the Request under the key
618
     * <code>javax.servlet.request.X509Certificate</code>.
619
     *
620
     * <p></p>If not found, try extracting
621
     * the certificate chain from the Coyote request and populate the Request so that we
622
     * can find it. This is required when using SSL with a Tomcat connector.</p>
623
     *
624
     * @param request   Request to be processed
625
     *
626
     * @return          The X509 certificate chain if found, <code>null</code> otherwise.
627
     */
628
    protected X509Certificate[] getRequestCertificates(final Request request) {
629
        X509Certificate certs[] = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR);
617
630
631
        if ((certs == null) || (certs.length < 1)) {
632
            try {
633
                request.getCoyoteRequest().action(ActionCode.REQ_SSL_CERTIFICATE, null);
634
635
            } catch (IllegalStateException ise) {
636
                // Request body was too large for save buffer
637
                return null;
638
            }
639
            certs = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR);
640
        }
641
        return certs;
642
    }
643
618
    /**
644
    /**
619
     * Associate the specified single sign on identifier with the
645
     * Associate the specified single sign on identifier with the
620
     * specified Session.
646
     * specified Session.
(-)java/org/apache/catalina/authenticator/SSLAuthenticator.java (-24 / +6 lines)
Lines 19-38 Link Here
19
package org.apache.catalina.authenticator;
19
package org.apache.catalina.authenticator;
20
20
21
21
22
import org.apache.catalina.connector.Request;
23
import org.apache.catalina.deploy.LoginConfig;
24
25
import javax.servlet.http.HttpServletRequest;
26
import javax.servlet.http.HttpServletResponse;
22
import java.io.IOException;
27
import java.io.IOException;
23
import java.security.Principal;
28
import java.security.Principal;
24
import java.security.cert.X509Certificate;
29
import java.security.cert.X509Certificate;
25
30
26
import javax.servlet.http.HttpServletRequest;
27
import javax.servlet.http.HttpServletResponse;
28
31
29
import org.apache.catalina.Globals;
30
import org.apache.catalina.connector.Request;
31
import org.apache.catalina.deploy.LoginConfig;
32
import org.apache.coyote.ActionCode;
33
32
34
35
36
/**
33
/**
37
 * An <b>Authenticator</b> and <b>Valve</b> implementation of authentication
34
 * An <b>Authenticator</b> and <b>Valve</b> implementation of authentication
38
 * that utilizes SSL certificates to identify client users.
35
 * that utilizes SSL certificates to identify client users.
Lines 129-150 Link Here
129
        if (containerLog.isDebugEnabled())
126
        if (containerLog.isDebugEnabled())
130
            containerLog.debug(" Looking up certificates");
127
            containerLog.debug(" Looking up certificates");
131
128
132
        X509Certificate certs[] = (X509Certificate[])
129
        final X509Certificate certs[] = getRequestCertificates(request);
133
            request.getAttribute(Globals.CERTIFICATES_ATTR);
134
        if ((certs == null) || (certs.length < 1)) {
130
        if ((certs == null) || (certs.length < 1)) {
135
            try {
136
                request.getCoyoteRequest().action
137
                                  (ActionCode.REQ_SSL_CERTIFICATE, null);
138
            } catch (IllegalStateException ise) {
139
                // Request body was too large for save buffer
140
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
141
                        sm.getString("authenticator.certificates"));
142
                return false;
143
            }
144
            certs = (X509Certificate[])
145
                request.getAttribute(Globals.CERTIFICATES_ATTR);
146
        }
147
        if ((certs == null) || (certs.length < 1)) {
148
            if (containerLog.isDebugEnabled())
131
            if (containerLog.isDebugEnabled())
149
                containerLog.debug("  No certificates included with this request");
132
                containerLog.debug("  No certificates included with this request");
150
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
133
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
Lines 169-175 Link Here
169
152
170
    }
153
    }
171
154
172
173
    @Override
155
    @Override
174
    protected String getAuthMethod() {
156
    protected String getAuthMethod() {
175
        return HttpServletRequest.CLIENT_CERT_AUTH;
157
        return HttpServletRequest.CLIENT_CERT_AUTH;
(-)test/org/apache/tomcat/util/net/TestClientCert.java (-9 / +73 lines)
Lines 16-32 Link Here
16
 */
16
 */
17
package org.apache.tomcat.util.net;
17
package org.apache.tomcat.util.net;
18
18
19
import org.apache.catalina.Context;
20
import org.apache.catalina.authenticator.AuthenticatorBase;
21
import org.apache.catalina.authenticator.SSLAuthenticator;
22
import org.apache.catalina.startup.TestTomcat;
23
import org.apache.catalina.startup.Tomcat;
24
import org.apache.catalina.startup.TomcatBaseTest;
25
import org.apache.tomcat.util.buf.ByteChunk;
26
import org.junit.Assume;
27
import org.junit.Test;
28
29
import javax.servlet.ServletException;
30
import javax.servlet.http.HttpServlet;
31
import javax.servlet.http.HttpServletRequest;
32
import javax.servlet.http.HttpServletResponse;
33
import java.io.IOException;
34
import java.io.PrintWriter;
19
import java.util.Arrays;
35
import java.util.Arrays;
20
36
21
import static org.junit.Assert.assertEquals;
37
import static org.junit.Assert.assertEquals;
22
38
23
import org.junit.Assume;
24
import org.junit.Test;
25
26
import org.apache.catalina.startup.Tomcat;
27
import org.apache.catalina.startup.TomcatBaseTest;
28
import org.apache.tomcat.util.buf.ByteChunk;
29
30
/**
39
/**
31
 * The keys and certificates used in this file are all available in svn and were
40
 * The keys and certificates used in this file are all available in svn and were
32
 * generated using a test CA the files for which are in the Tomcat PMC private
41
 * generated using a test CA the files for which are in the Tomcat PMC private
Lines 34-45 Link Here
34
 */
43
 */
35
public class TestClientCert extends TomcatBaseTest {
44
public class TestClientCert extends TomcatBaseTest {
36
45
46
    private static final String HTTPS_PREFIX = "https://localhost:";
47
    private static final String CONTEXT_PATH_SSL = "/ssl";
48
    private static final String URI_UNPROTECTED = "/unprotected";
49
    public static final String USERNAME = "CN=user1, C=US";
50
    public static final String TESTROLE = "testrole";
51
52
    private static final int SHORT_SESSION_TIMEOUT_MINS = 1;
53
54
    private Tomcat tomcat;
55
    private Context sslContext;
56
37
    @Test
57
    @Test
38
    public void testClientCertGet() throws Exception {
58
    public void testPreemptiveClientCert() throws Exception {
39
        Assume.assumeTrue("SSL renegotiation has to be supported for this test",
59
        Assume.assumeTrue("SSL renegotiation has to be supported for this test",
40
                TesterSupport.isRenegotiationSupported(getTomcatInstance()));
60
                TesterSupport.isRenegotiationSupported(getTomcatInstance()));
41
61
42
        // Unprotected resource
62
        // Unprotected resource
63
        ByteChunk res = getUrl(HTTPS_PREFIX + getPort() + CONTEXT_PATH_SSL + URI_UNPROTECTED);
64
        assertEquals("OK", res.toString());
65
66
    }
67
68
    @Test
69
    public void testBug56825() throws Exception {
70
        Assume.assumeTrue("SSL renegotiation has to be supported for this test",
71
                TesterSupport.isRenegotiationSupported(getTomcatInstance()));
72
73
        // Unprotected resource
43
        ByteChunk res =
74
        ByteChunk res =
44
                getUrl("https://localhost:" + getPort() + "/unprotected");
75
                getUrl("https://localhost:" + getPort() + "/unprotected");
45
        assertEquals("OK", res.toString());
76
        assertEquals("OK", res.toString());
Lines 103-115 Link Here
103
134
104
        super.setUp();
135
        super.setUp();
105
136
106
        Tomcat tomcat = getTomcatInstance();
137
        tomcat = getTomcatInstance();
107
138
108
        TesterSupport.configureClientCertContext(tomcat);
139
        TesterSupport.configureClientCertContext(tomcat);
109
140
141
        // add an SSL webapp with the SSLAuthenticator valve
142
        setupSslContext();
143
110
        // Start Tomcat
144
        // Start Tomcat
111
        tomcat.start();
145
        tomcat.start();
112
146
113
        TesterSupport.configureClientSsl();
147
        TesterSupport.configureClientSsl();
114
    }
148
    }
149
150
    private void setupSslContext() throws Exception {
151
        // Must have a real docBase for webapps - just use temp
152
        sslContext = tomcat.addContext(CONTEXT_PATH_SSL, System.getProperty("java.io.tmpdir"));
153
        sslContext.setSessionTimeout(SHORT_SESSION_TIMEOUT_MINS);
154
        sslContext.setPreemptiveAuthentication(true);
155
156
        // Add a servlet - the preemptive mode ensure the authentication will be done if a certificate
157
        // is available whatever the resource accessed is private or public
158
        // we don't need any servlet security configured here for this test
159
        Tomcat.addServlet(sslContext, "TesterServlet", new HttpServlet() {
160
            @Override
161
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
162
                // if the user has not been authenticated then it's going to fail
163
                resp.setContentType("text/plain");
164
                PrintWriter out = resp.getWriter();
165
                out.print(req.isUserInRole(TESTROLE) ? "OK" : "KO");
166
            }
167
        });
168
        sslContext.addServletMapping(URI_UNPROTECTED, "TesterServlet");
169
170
        // Configure the Realm at context level
171
        TestTomcat.MapRealm realm = new TestTomcat.MapRealm();
172
        realm.addUser(USERNAME, "not used for SSL");
173
        realm.addUserRole(USERNAME, TESTROLE);
174
        sslContext.setRealm(realm);
175
176
        AuthenticatorBase basicAuthenticator = new SSLAuthenticator();
177
        sslContext.getPipeline().addValve(basicAuthenticator);
178
    }
115
}
179
}

Return to bug 56825