Getting client certificate in restlet

2019-08-29 00:54发布

问题:

I managed to implement an https restlet with bot client and server certificated. I can prove it works since if I call the server with an untrusted certification communication fails. Unfortunately I can't find the certificate of the client on the server. I'm using this code:

List<Certificate> certs = request.getClientInfo().getCertificates();

but list is empty. What I'm doing wrong?

EDIT:

version is Restlet-Framework/2.3m2

回答1:

The problem is related to the use of the default server implementation via com.sun.httpserver. The class org.restlet.engine.connector.HttpExchangeCall should return the certificates in the getCertificates() method, but it always returns null. This class is used in org.restlet.engine.connector.HttpsServerHelper which in turn is the helper for the Restlet framework when using the server implementation com.sun.httpserver.

To fix this, a couple of things are needed.
First, a new class HttpsExchangeCall:

package org.restlet.engine.connector;

import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.List;

import org.restlet.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpsExchange;

/**
 * The default {@link HttpExchangeCall} fails to extract certificates from the SSL connection.
 * This class implements {@link #getCertificates()} to extract certificates.
 */
@SuppressWarnings("restriction")
public class HttpsExchangeCall extends HttpExchangeCall {

    private static final Logger log = LoggerFactory.getLogger(HttpsExchangeCall.class);

    private final HttpsExchange sexchange;

    public HttpsExchangeCall(Server server, HttpExchange exchange) {
        this(server, exchange, true);
    }

    public HttpsExchangeCall(Server server, HttpExchange exchange, boolean confidential) {
        super(server, exchange, confidential);
        if (exchange instanceof HttpsExchange) {
            sexchange = (HttpsExchange) exchange;
        } else {
            sexchange = null;
        }
    }

    @Override
    public List<Certificate> getCertificates() {

        if (sexchange == null) {
            log.debug("Cannot extract peer certificates from unsecure connection.");
            return null;
        }
        Certificate[] certs = null;
        try {
            certs = sexchange.getSSLSession().getPeerCertificates();
            if (log.isDebugEnabled()) {
                log.debug("Found " + (certs == null ? "no" : Integer.toString(certs.length)) + " peer certificate(s).");
            }
        } catch (Exception e) {
            log.debug("Unable to find peer certificates - " + e);
        }
        List<Certificate> lcerts = null;
        if (certs != null) {
            lcerts = new ArrayList<Certificate>();
            for (int i = 0; i < certs.length; i++) {
                lcerts.add(certs[i]);
            }
        }
        return lcerts;
    }

}

Then a copy of HttpsServerHelper renamed to HttpsServerHelper2 with one line modified. Replace the line
HttpsServerHelper.this.handle(new HttpExchangeCall(getHelped(),
with the line:
HttpsServerHelper2.this.handle(new HttpsExchangeCall(getHelped(),

This helper needs to be registered:
Engine.getInstance().getRegisteredServers().add(new HttpsServerHelper2(null));
and creating a Server now becomes very explicit:

Component component = new Component();
Server server = new Server(
        (Context) null, Arrays.asList(Protocol.HTTPS),
        (String) null, Constants.PORT_TEST, component.getServers().getNext(), 
        HttpsServerHelper2.class.getName()
    );
component.getServers().add(server);

I'm hoping Restlet's own HttpExchangeCall will be updated to extract the certificates: it is a minor fix and saves a lot of unneeded code required to work around the issue.
In the mean time, you can find all the source code (using Restlet 2.3.4) and a working example in the restlet-clientcert Github project.



回答2:

This method should provide what you are looking for: request.getClientInfo().getCertificates() http://restlet.com/learn/javadocs/2.3/jse/api/org/restlet/data/ClientInfo.html

You can also retrieve the cipher suites



标签: ssl restlet