Skip to content

Commit

Permalink
No need to cache CN header
Browse files Browse the repository at this point in the history
  • Loading branch information
danielkec committed Feb 2, 2024
1 parent fb95852 commit 6405f85
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022 Oracle and/or its affiliates.
* Copyright (c) 2017, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -105,7 +105,7 @@ static List<X509Certificate> loadCertificates(KeyStore keyStore) {
certs.add(cert);

if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) {
LOGGER.log(System.Logger.Level.DEBUG, "Added certificate under alis "
LOGGER.log(System.Logger.Level.DEBUG, "Added certificate under alias "
+ alias
+ " for "
+ cert
Expand Down
5 changes: 5 additions & 0 deletions common/socket/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,25 @@ public static TlsSocket client(SSLSocket delegate,

@Override
public PeerInfo remotePeer() {
if (remotePeer == null || renegotiated()) {
this.localPeer = null;
if (renegotiated()) {
remotePeer = null;
localPeer = null;
}

if (remotePeer == null) {
this.remotePeer = PeerInfoImpl.createRemote(this);
}
return this.remotePeer;
}

@Override
public PeerInfo localPeer() {
if (localPeer == null || renegotiated()) {
this.remotePeer = null;
if (renegotiated()) {
remotePeer = null;
localPeer = null;
}

if (localPeer == null) {
this.localPeer = PeerInfoImpl.createLocal(this);
}
return this.localPeer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.common.socket;

import java.security.Principal;
import java.util.Optional;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import org.junit.jupiter.api.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class TlsSocketTest {

private final SSLSocket sslSocket;
private final SSLSession sslSession1;
private final SSLSession sslSession2;

public TlsSocketTest() throws SSLPeerUnverifiedException {
sslSocket = mock(SSLSocket.class);
sslSession1 = mock(SSLSession.class);
sslSession2 = mock(SSLSession.class);

Principal principal1 = mock(Principal.class);
Principal principal2 = mock(Principal.class);

when(principal1.getName()).thenReturn("Frank");
when(principal2.getName()).thenReturn("Jack");

when(sslSession1.getId()).thenReturn(new byte[] {'a', 'b', 'c'});
when(sslSession2.getId()).thenReturn(new byte[] {'d', 'e', 'f'});

when(sslSession1.getPeerPrincipal()).thenReturn(principal1);
when(sslSession2.getPeerPrincipal()).thenReturn(principal2);
}

@Test
void renegotiationDetectionBySslSessionId() {
when(sslSocket.getSession()).thenReturn(sslSession1);
TlsSocket serverSocket = TlsSocket.server(sslSocket, "test1", "test2");

assertFalse(serverSocket.renegotiated());

// renegotiate
when(sslSocket.getSession()).thenReturn(sslSession2);

assertTrue(serverSocket.renegotiated());

// detection is not reentrant
assertFalse(serverSocket.renegotiated());
}

@Test
void lazyPeerInfo() {
when(sslSocket.getSession()).thenReturn(sslSession1);
TlsSocket serverSocket = TlsSocket.server(sslSocket, "test1", "test2");

assertPrincipal(serverSocket.remotePeer().tlsPrincipal(), "Frank");
assertPrincipal(serverSocket.remotePeer().tlsPrincipal(), "Frank");
}

@Test
void lazyPeerInfoRenegotiated() {
when(sslSocket.getSession()).thenReturn(sslSession1);
TlsSocket serverSocket = TlsSocket.server(sslSocket, "test1", "test2");

assertPrincipal(serverSocket.remotePeer().tlsPrincipal(), "Frank");
assertPrincipal(serverSocket.remotePeer().tlsPrincipal(), "Frank");

// renegotiate
when(sslSocket.getSession()).thenReturn(sslSession2);

assertPrincipal(serverSocket.remotePeer().tlsPrincipal(), "Jack");
assertPrincipal(serverSocket.remotePeer().tlsPrincipal(), "Jack");
}

private void assertPrincipal(Optional<Principal> act, String expectedName) {
assertTrue(act.isPresent());
assertThat(act.get().getName(), is(expectedName));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
* Copyright (c) 2023, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,9 +22,10 @@
import java.security.cert.X509Certificate;
import java.util.Objects;

import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;

class TlsReloadableX509KeyManager implements X509KeyManager, TlsReloadableComponent {
class TlsReloadableX509KeyManager extends X509ExtendedKeyManager implements TlsReloadableComponent {
private static final System.Logger LOGGER = System.getLogger(TlsReloadableX509KeyManager.class.getName());

private volatile X509KeyManager keyManager;
Expand Down
5 changes: 5 additions & 0 deletions webserver/tests/mtls/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,10 @@
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.logging</groupId>
<artifactId>helidon-logging-jul</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
6 changes: 3 additions & 3 deletions webserver/tests/mtls/src/main/resources/logging.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2022, 2023 Oracle and/or its affiliates.
# Copyright (c) 2022, 2024 Oracle and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -13,8 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
handlers=java.util.logging.ConsoleHandler
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n
handlers=io.helidon.logging.jul.HelidonConsoleHandler
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
# Global logging level. Can be overridden by specific loggers
.level=INFO

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.function.Supplier;
Expand All @@ -37,7 +36,6 @@
import io.helidon.http.DateTime;
import io.helidon.http.DirectHandler;
import io.helidon.http.DirectHandler.EventType;
import io.helidon.http.Header;
import io.helidon.http.HeaderNames;
import io.helidon.http.HeaderValues;
import io.helidon.http.HttpPrologue;
Expand Down Expand Up @@ -142,9 +140,6 @@ public void handle(Semaphore requestSemaphore) throws InterruptedException {
try {
// look for protocol data
ProxyProtocolData proxyProtocolData = ctx.proxyProtocolData().orElse(null);
Optional<Header> xHelidonCn = ctx.remotePeer().tlsCertificates()
.flatMap(TlsUtils::parseCn)
.map(name -> HeaderValues.create(X_HELIDON_CN, name));

// handle connection until an exception (or explicit connection close)
while (canRun) {
Expand All @@ -158,8 +153,9 @@ public void handle(Semaphore requestSemaphore) throws InterruptedException {
currentEntitySizeRead = 0;

WritableHeaders<?> headers = http1headers.readHeaders(prologue);
xHelidonCn.ifPresent(headers::set);

ctx.remotePeer().tlsCertificates()
.flatMap(TlsUtils::parseCn)
.ifPresent(name -> headers.set(X_HELIDON_CN, name));
recvListener.headers(ctx, headers);

// proxy protocol related headers X-Forwarded-For and X-Forwarded-Port
Expand Down

0 comments on commit 6405f85

Please sign in to comment.