Skip to content

Commit

Permalink
Add API to access SSL session (#10792)
Browse files Browse the repository at this point in the history
This is useful for e.g. the session ID.

Because I replaced the getCertificate implementation with this, this is already covered by tests.
  • Loading branch information
yawkat committed May 6, 2024
1 parent f3c28be commit 905467b
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 23 deletions.
Expand Up @@ -78,14 +78,13 @@
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
import java.security.cert.Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
Expand All @@ -106,8 +105,8 @@
final class HttpPipelineBuilder implements Closeable {
static final Supplier<AttributeKey<StreamPipeline>> STREAM_PIPELINE_ATTRIBUTE =
SupplierUtil.memoized(() -> AttributeKey.newInstance("stream-pipeline"));
static final Supplier<AttributeKey<Supplier<Certificate>>> CERTIFICATE_SUPPLIER_ATTRIBUTE =
SupplierUtil.memoized(() -> AttributeKey.newInstance("certificate-supplier"));
static final Supplier<AttributeKey<Supplier<SSLSession>>> SSL_SESSION_ATTRIBUTE =
SupplierUtil.memoized(() -> AttributeKey.newInstance("ssl-session"));

private static final Logger LOG = LoggerFactory.getLogger(HttpPipelineBuilder.class);

Expand Down Expand Up @@ -194,19 +193,8 @@ SslHandler makeNormal(ByteBufAllocator alloc) {
return sslHandler;
}

/**
* Create a supplier that looks up the peer cert of this connection ({@link #CERTIFICATE_SUPPLIER_ATTRIBUTE}).
*
* @return The supplier
*/
Supplier<Certificate> findPeerCert() {
return SupplierUtil.memoized(() -> {
try {
return (quicSslEngine == null ? sslHandler.engine() : quicSslEngine).getSession().getPeerCertificates()[0];
} catch (SSLPeerUnverifiedException ex) {
return null;
}
});
Supplier<SSLSession> findSslSession() {
return SupplierUtil.memoized(() -> (quicSslEngine == null ? sslHandler.engine() : quicSslEngine).getSession());
}

HttpPipelineBuilder pipelineBuilder() {
Expand Down Expand Up @@ -673,7 +661,7 @@ private void insertHttp2DownstreamHandlers() {
private void insertMicronautHandlers() {
channel.attr(STREAM_PIPELINE_ATTRIBUTE.get()).set(this);
if (sslHandler != null) {
channel.attr(CERTIFICATE_SUPPLIER_ATTRIBUTE.get()).set(sslHandler.findPeerCert());
channel.attr(SSL_SESSION_ATTRIBUTE.get()).set(sslHandler.findSslSession());
}

Optional<NettyServerWebSocketUpgradeHandler> webSocketUpgradeHandler = embeddedServices.getWebSocketUpgradeHandler(server);
Expand All @@ -699,7 +687,7 @@ void afterHttp2ServerHandlerSetUp() {
httpVersion = HttpVersion.HTTP_2_0;
channel.attr(STREAM_PIPELINE_ATTRIBUTE.get()).set(this);
if (sslHandler != null) {
channel.attr(CERTIFICATE_SUPPLIER_ATTRIBUTE.get()).set(sslHandler.findPeerCert());
channel.attr(SSL_SESSION_ATTRIBUTE.get()).set(sslHandler.findSslSession());
}
}

Expand Down
Expand Up @@ -91,11 +91,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLSession;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.security.cert.Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
Expand Down Expand Up @@ -397,8 +397,8 @@ public HttpRequest<T> setAttribute(CharSequence name, Object value) {
}

@Override
public Optional<Certificate> getCertificate() {
Supplier<Certificate> sup = channelHandlerContext.channel().attr(HttpPipelineBuilder.CERTIFICATE_SUPPLIER_ATTRIBUTE.get()).get();
public Optional<SSLSession> getSslSession() {
Supplier<SSLSession> sup = channelHandlerContext.channel().attr(HttpPipelineBuilder.SSL_SESSION_ATTRIBUTE.get()).get();
return sup == null ? Optional.empty() : Optional.ofNullable(sup.get());
}

Expand Down
25 changes: 24 additions & 1 deletion http/src/main/java/io/micronaut/http/HttpRequest.java
Expand Up @@ -19,6 +19,8 @@
import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.cookie.Cookies;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.Principal;
Expand Down Expand Up @@ -179,7 +181,28 @@ default Optional<Locale> getLocale() {
*/
@SuppressWarnings("deprecation")
default Optional<Certificate> getCertificate() {
return this.getAttribute(HttpAttributes.X509_CERTIFICATE, Certificate.class);
Optional<Certificate> attribute = this.getAttribute(HttpAttributes.X509_CERTIFICATE, Certificate.class);
if (attribute.isPresent()) {
return attribute;
}
Optional<SSLSession> session = getSslSession();
if (session.isPresent()) {
try {
return Optional.of(session.get().getPeerCertificates()[0]);
} catch (SSLPeerUnverifiedException e) {
// won't return unverified cert
}
}
return Optional.empty();
}

/**
* Get the SSL session used for the connection to the client, if available.
*
* @return The session
*/
default Optional<SSLSession> getSslSession() {
return Optional.empty();
}

/**
Expand Down
6 changes: 6 additions & 0 deletions http/src/main/java/io/micronaut/http/HttpRequestWrapper.java
Expand Up @@ -18,6 +18,7 @@
import io.micronaut.core.annotation.NonNull;
import io.micronaut.http.cookie.Cookies;

import javax.net.ssl.SSLSession;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.Principal;
Expand Down Expand Up @@ -84,6 +85,11 @@ public Optional<Certificate> getCertificate() {
return getDelegate().getCertificate();
}

@Override
public Optional<SSLSession> getSslSession() {
return getDelegate().getSslSession();
}

@Override
public Cookies getCookies() {
return getDelegate().getCookies();
Expand Down

0 comments on commit 905467b

Please sign in to comment.