Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
guusdk committed Jun 27, 2023
1 parent 24961e4 commit b31e0bb
Show file tree
Hide file tree
Showing 10 changed files with 1,197 additions and 545 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
* @deprecated Old, pre NIO / MINA code. Should not be used as NIO offers better performance
*/
@Deprecated
class BlockingAcceptingMode extends SocketAcceptingMode {
public class BlockingAcceptingMode extends SocketAcceptingMode {

private static final Logger Log = LoggerFactory.getLogger(BlockingAcceptingMode.class);

private SocketReader reader;

protected BlockingAcceptingMode(int tcpPort, InetAddress bindInterface, boolean directTLS) throws IOException {
super(directTLS);
serverSocket = new ServerSocket(tcpPort, -1, bindInterface);
Expand All @@ -53,7 +55,7 @@ public void run() {
if (sock != null) {
Log.debug("Connect " + sock.toString());

SocketReader reader = createServerSocketReader( sock, false, true );
reader = createServerSocketReader( sock, false, true );
Thread thread = new Thread(reader, reader.getName());
thread.setDaemon(true);
thread.setPriority(Thread.NORM_PRIORITY);
Expand All @@ -71,4 +73,14 @@ public void run() {
}
}
}

/**
* The last socket reader that was created (if any).
*
* This is intended to be used for unit testing purposes only.
*/
public SocketReader getLastReader()
{
return reader;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ public class SocketAcceptThread extends Thread {
public SocketAcceptThread( int tcpPort, InetAddress bindInterface, boolean directTLS )
throws IOException {
super("Socket Listener at port " + tcpPort + ( directTLS ? " (direct TLS)" : ""));
this.tcpPort = tcpPort;
this.bindInterface = bindInterface;
this.directTLS = directTLS;

// Set the blocking reading mode to use
acceptingMode = new BlockingAcceptingMode(tcpPort, bindInterface, directTLS);
this.tcpPort = acceptingMode.serverSocket.getLocalPort();
}

/**
Expand Down Expand Up @@ -88,4 +88,13 @@ public void run() {
// We stopped accepting new connections so close the listener
shutdown();
}

/**
* The Socket Accepting Mode for this thread. This is exposed for unit testing purposes. It is unlikely that this
* should be used elsewhere.
*/
public SocketAcceptingMode getAcceptingMode()
{
return acceptingMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -520,4 +520,9 @@ abstract boolean createSession(String namespace) throws UnauthorizedException,
public String getExtraNamespaces() {
return null;
}

public LocalSession getSession()
{
return session;
}
}
9 changes: 5 additions & 4 deletions xmppserver/src/test/java/org/jivesoftware/Fixtures.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,14 @@ public static IQRouter mockIQRouter() {

public static SessionManager mockSessionManager() {
final SessionManager sessionManager = mock(SessionManager.class, withSettings().lenient());
when(sessionManager.nextStreamID()).thenReturn(new BasicStreamIDFactory().createStreamID());
return sessionManager;
}

public static ConnectionManagerImpl mockConnectionManager() {
final ConnectionManagerImpl connectionManagerImpl = mock(ConnectionManagerImpl.class, withSettings().lenient());
doReturn(mockConnectionListener()).when(connectionManagerImpl).getListener(any(ConnectionType.class), anyBoolean());
return connectionManagerImpl;
public static ConnectionManager mockConnectionManager() {
final ConnectionManager connectionManager = mock(ConnectionManagerImpl.class, withSettings().lenient());
doReturn(mockConnectionListener()).when(connectionManager).getListener(any(ConnectionType.class), anyBoolean());
return connectionManager;
}

public static ConnectionListener mockConnectionListener() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package org.jivesoftware.openfire.session;

import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.openfire.keystore.KeystoreTestUtils;

import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import java.net.Socket;
import java.security.KeyPair;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AbstractRemoteServerDummy
{
public static final String XMPP_DOMAIN = "remote-dummy.example.org";
public static final Duration SO_TIMEOUT = Duration.ofMillis(500);
protected boolean useExpiredEndEntityCertificate;
protected boolean useSelfSignedCertificate;
protected boolean disableDialback;
protected ServerSettings.EncryptionPolicy encryptionPolicy = ServerSettings.EncryptionPolicy.OPTIONAL;
protected KeystoreTestUtils.ResultHolder generatedPKIX;

/**
* Updates the TLS encryption policy that's observed by this server.
*/
public void setEncryptionPolicy(ServerSettings.EncryptionPolicy encryptionPolicy)
{
this.encryptionPolicy = encryptionPolicy;
}

/**
* When set to 'true', this instance will identify itself with a TLS certificate that is self-signed.
*
* Must be invoked before {@link #preparePKIX()} is invoked.
*
* @param useSelfSignedCertificate 'true' to use a self-signed certificate
*/
public void setUseSelfSignedCertificate(boolean useSelfSignedCertificate)
{
if (generatedPKIX != null) {
throw new IllegalStateException("Cannot change PKIX settings after PKIX has been prepared.");
}
this.useSelfSignedCertificate = useSelfSignedCertificate;
}

/**
* When set to 'true', this instance will identify itself with a TLS certificate that is expired (its 'notBefore'
* and 'notAfter' values define a period of validity that does not include the current date and time).
*
* Must be invoked before {@link #preparePKIX()} is invoked.
*
* @param useExpiredEndEntityCertificate 'true' to use an expired certificate
*/
public void setUseExpiredEndEntityCertificate(boolean useExpiredEndEntityCertificate)
{
if (generatedPKIX != null) {
throw new IllegalStateException("Cannot change PKIX settings after PKIX has been prepared.");
}
this.useExpiredEndEntityCertificate = useExpiredEndEntityCertificate;
}

/**
* When set to 'true', this instance will NOT advertise support for the Dialback authentication mechanism, and will
* reject Dialback authentication attempts.
*/
public void setDisableDialback(boolean disableDialback) {
this.disableDialback = disableDialback;
}

/**
* Generates KeyPairs and certificates that are used to identify this server using TLS.
*
* The data that is generated by this method can be configured by invoking methods such as
* {@link #setUseSelfSignedCertificate(boolean)} and
* {@link #setUseExpiredEndEntityCertificate(boolean)}. These must be invoked before invoking #preparePKIX
*/
public void preparePKIX() throws Exception
{
if (generatedPKIX != null) {
throw new IllegalStateException("PKIX already prepared.");
}

final String commonName = XMPP_DOMAIN;
if (useSelfSignedCertificate) {
generatedPKIX = useExpiredEndEntityCertificate ? KeystoreTestUtils.generateExpiredSelfSignedCertificate(commonName) : KeystoreTestUtils.generateSelfSignedCertificate(commonName);
} else {
generatedPKIX = useExpiredEndEntityCertificate ? KeystoreTestUtils.generateCertificateChainWithExpiredEndEntityCert(commonName) : KeystoreTestUtils.generateValidCertificateChain(commonName);
}
}

/**
* Returns the KeyPairs and certificates that are used to identify this server using TLS.
*
* @return TLS identification material for this server.
*/
public KeystoreTestUtils.ResultHolder getGeneratedPKIX() {
return generatedPKIX;
}

/**
* Parses text as an XML element.
*
* When the provided input is an element that is not closed, then a closing element is automatically generated. This
* helps to parse `stream` elements, that are closed only when the XMPP session ends.
*
* @param xml The data to parse
* @return an XML element
*/
public static Element parse(final String xml) throws DocumentException
{
String toParse = xml;

if (!xml.endsWith("/>")) {
Matcher matcher = Pattern.compile("[A-Za-z:]+").matcher(xml);
if (matcher.find()) {
final String fakeEndTag = "</" + matcher.group() + ">";
if (!xml.trim().endsWith(fakeEndTag)) {
toParse += fakeEndTag;
}
}
}

return DocumentHelper.parseText(toParse).getRootElement();
}

/**
* Creates a TrustManager that will blindly accept all certificates.
*/
public static TrustManager[] createTrustManagerThatTrustsAll()
{
// Create a trust manager that does not validate certificate chains
return new TrustManager[]{
new X509TrustManager()
{
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}

public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException
{
if (Instant.now().isAfter(certs[0].getNotAfter().toInstant()) || Instant.now().isBefore(certs[0].getNotBefore().toInstant())) {
throw new CertificateException("Peer certificate is expired.");
}
}

public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
if (Instant.now().isAfter(certs[0].getNotAfter().toInstant()) || Instant.now().isBefore(certs[0].getNotBefore().toInstant())) {
throw new CertificateException("Peer certificate is expired.");
}
}
}
};
}

/**
* Creates a KeyManager that identifies with the provided keyPair and certificate chain.
*/
public static KeyManager[] createKeyManager(final KeyPair keyPair, final X509Certificate... chain)
{
return new KeyManager[]{
new X509KeyManager()
{
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
throw new IllegalStateException("Should not be used.");
}

@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
throw new IllegalStateException("Should not be used.");
}

@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return new String[] { XMPP_DOMAIN };
}

@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return XMPP_DOMAIN;
}

@Override
public X509Certificate[] getCertificateChain(String alias) {
return chain;
}

@Override
public PrivateKey getPrivateKey(String alias) {
return keyPair.getPrivate();
}
}
};
}
}
Loading

0 comments on commit b31e0bb

Please sign in to comment.