diff --git a/http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java b/http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java index 185434e3afb..a89bfe1187b 100644 --- a/http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java +++ b/http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java @@ -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; @@ -106,8 +105,8 @@ final class HttpPipelineBuilder implements Closeable { static final Supplier> STREAM_PIPELINE_ATTRIBUTE = SupplierUtil.memoized(() -> AttributeKey.newInstance("stream-pipeline")); - static final Supplier>> CERTIFICATE_SUPPLIER_ATTRIBUTE = - SupplierUtil.memoized(() -> AttributeKey.newInstance("certificate-supplier")); + static final Supplier>> SSL_SESSION_ATTRIBUTE = + SupplierUtil.memoized(() -> AttributeKey.newInstance("ssl-session")); private static final Logger LOG = LoggerFactory.getLogger(HttpPipelineBuilder.class); @@ -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 findPeerCert() { - return SupplierUtil.memoized(() -> { - try { - return (quicSslEngine == null ? sslHandler.engine() : quicSslEngine).getSession().getPeerCertificates()[0]; - } catch (SSLPeerUnverifiedException ex) { - return null; - } - }); + Supplier findSslSession() { + return SupplierUtil.memoized(() -> (quicSslEngine == null ? sslHandler.engine() : quicSslEngine).getSession()); } HttpPipelineBuilder pipelineBuilder() { @@ -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 webSocketUpgradeHandler = embeddedServices.getWebSocketUpgradeHandler(server); @@ -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()); } } diff --git a/http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest.java b/http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest.java index fc2f049f102..f9e78de264b 100644 --- a/http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest.java +++ b/http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpRequest.java @@ -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; @@ -397,8 +397,8 @@ public HttpRequest setAttribute(CharSequence name, Object value) { } @Override - public Optional getCertificate() { - Supplier sup = channelHandlerContext.channel().attr(HttpPipelineBuilder.CERTIFICATE_SUPPLIER_ATTRIBUTE.get()).get(); + public Optional getSslSession() { + Supplier sup = channelHandlerContext.channel().attr(HttpPipelineBuilder.SSL_SESSION_ATTRIBUTE.get()).get(); return sup == null ? Optional.empty() : Optional.ofNullable(sup.get()); } diff --git a/http/src/main/java/io/micronaut/http/HttpRequest.java b/http/src/main/java/io/micronaut/http/HttpRequest.java index a684db8b243..9393658aff1 100644 --- a/http/src/main/java/io/micronaut/http/HttpRequest.java +++ b/http/src/main/java/io/micronaut/http/HttpRequest.java @@ -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; @@ -179,7 +181,28 @@ default Optional getLocale() { */ @SuppressWarnings("deprecation") default Optional getCertificate() { - return this.getAttribute(HttpAttributes.X509_CERTIFICATE, Certificate.class); + Optional attribute = this.getAttribute(HttpAttributes.X509_CERTIFICATE, Certificate.class); + if (attribute.isPresent()) { + return attribute; + } + Optional 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 getSslSession() { + return Optional.empty(); } /** diff --git a/http/src/main/java/io/micronaut/http/HttpRequestWrapper.java b/http/src/main/java/io/micronaut/http/HttpRequestWrapper.java index 2403f1363d6..fb90cc90772 100644 --- a/http/src/main/java/io/micronaut/http/HttpRequestWrapper.java +++ b/http/src/main/java/io/micronaut/http/HttpRequestWrapper.java @@ -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; @@ -84,6 +85,11 @@ public Optional getCertificate() { return getDelegate().getCertificate(); } + @Override + public Optional getSslSession() { + return getDelegate().getSslSession(); + } + @Override public Cookies getCookies() { return getDelegate().getCookies();