From 2ba191317709b89f69d13f2bcf95b6b04395b143 Mon Sep 17 00:00:00 2001 From: jameshall03885 Date: Mon, 23 Jun 2014 12:54:43 -0400 Subject: [PATCH] TLS support TLS is configured in 42-openflowplugin.xml (openflowplugin) Added tests for: - pipeline components - TLS classes - updated integration test Added new yang file: openflow-configuration.yang (contains generated classes for library configuration) Logging updated Change-Id: I5480b01760377db7de7791594a3b541338a1b43a Signed-off-by: jameshall03885 Signed-off-by: Michal Polkorab --- .../connection/ConnectionConfiguration.java | 18 +- .../api/connection/TlsConfiguration.java | 50 ++++ .../api/connection/TlsConfigurationImpl.java | 76 ++++++ .../src/main/yang/openflow-configuration.yang | 42 +++ .../connection/ConnectionAdapterFactory.java | 6 +- .../ConnectionAdapterFactoryImpl.java | 29 ++ .../SwitchConnectionProviderImpl.java | 25 +- .../protocol/impl/core/OFDecoder.java | 7 +- .../protocol/impl/core/OFFrameDecoder.java | 20 +- .../protocol/impl/core/OFVersionDetector.java | 9 +- .../core/PublishingChannelInitializer.java | 93 +++++-- .../PublishingChannelInitializerFactory.java | 77 ++++++ .../protocol/impl/core/SslContextFactory.java | 107 +++++--- .../protocol/impl/core/SslKeyStore.java | 46 +++- .../protocol/impl/core/TcpHandler.java | 88 +----- .../protocol/impl/core/TlsDetector.java | 107 -------- .../SwitchConnectionProviderModule.java | 37 ++- .../src/main/resources/ctlKeystore | Bin 0 -> 2254 bytes .../src/main/resources/ctlTrustStore | Bin 0 -> 957 bytes .../src/main/resources/key.raw | 258 ------------------ .../src/main/resources/selfSignedController | Bin 0 -> 1351 bytes .../src/main/resources/selfSignedSwitch | Bin 0 -> 1348 bytes ...nflow-switch-connection-provider-impl.yang | 30 +- .../core/DelegatingInboundHandlerTest.java | 72 +++++ .../protocol/impl/core/IdleHandlerTest.java | 110 ++++++++ .../protocol/impl/core/OFDecoderTest.java | 114 ++++++++ .../protocol/impl/core/OFEncoderTest.java | 101 +++++++ .../impl/core/OFFrameDecoderTest.java | 98 +++++-- .../impl/core/OFVersionDetectorTest.java | 35 +++ ...blishingChannelInitializerFactoryTest.java | 62 +++++ .../PublishingChannelInitializerTest.java | 171 ++++++++++++ .../impl/core/SslContextFactoryTest.java | 54 ++++ .../protocol/impl/core/SslKeyStoreTest.java | 65 +++++ .../impl/core/SslTrustManagerFactoryTest.java | 70 +++++ .../protocol/impl/core/TcpHandlerTest.java | 171 ++++++++++++ .../protocol/impl/core/TlsDetectorTest.java | 51 ---- .../impl/integration/IntegrationTest.java | 149 ---------- .../ConnectionConfigurationImpl.java} | 25 +- .../it/integration/IntegrationTest.java | 208 ++++++++++++++ .../{impl => it}/integration/MockPlugin.java | 42 +-- .../impl/clients/ClientSslContextFactory.java | 69 +++++ .../impl/clients/ClientSslKeyStore.java | 48 ++++ .../impl/clients/ClientSslTrustStore.java | 48 ++++ .../impl/clients/SimpleClientInitializer.java | 4 +- .../src/main/resources/selfSignedController | Bin 0 -> 1351 bytes .../src/main/resources/selfSignedSwitch | Bin 0 -> 1348 bytes 46 files changed, 2051 insertions(+), 841 deletions(-) create mode 100644 openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/TlsConfiguration.java create mode 100644 openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/TlsConfigurationImpl.java create mode 100644 openflow-protocol-api/src/main/yang/openflow-configuration.yang create mode 100644 openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactoryImpl.java create mode 100644 openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerFactory.java delete mode 100644 openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TlsDetector.java create mode 100644 openflow-protocol-impl/src/main/resources/ctlKeystore create mode 100644 openflow-protocol-impl/src/main/resources/ctlTrustStore delete mode 100644 openflow-protocol-impl/src/main/resources/key.raw create mode 100644 openflow-protocol-impl/src/main/resources/selfSignedController create mode 100644 openflow-protocol-impl/src/main/resources/selfSignedSwitch create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/DelegatingInboundHandlerTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/IdleHandlerTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoderTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoderTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerFactoryTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslContextFactoryTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslKeyStoreTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslTrustManagerFactoryTest.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TcpHandlerTest.java delete mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TlsDetectorTest.java delete mode 100644 openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/IntegrationTest.java rename openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/{impl/integration/TestingConnConfigImpl.java => it/integration/ConnectionConfigurationImpl.java} (69%) create mode 100644 openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/IntegrationTest.java rename openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/{impl => it}/integration/MockPlugin.java (85%) create mode 100644 simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslContextFactory.java create mode 100644 simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslKeyStore.java create mode 100644 simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslTrustStore.java create mode 100644 simple-client/src/main/resources/selfSignedController create mode 100644 simple-client/src/main/resources/selfSignedSwitch diff --git a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/ConnectionConfiguration.java b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/ConnectionConfiguration.java index c5ca795c..d877c0cc 100644 --- a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/ConnectionConfiguration.java +++ b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/ConnectionConfiguration.java @@ -20,19 +20,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.S * */ public interface ConnectionConfiguration { - - /** - * connection functionality support types - */ - public enum FEATURE_SUPPORT { - /** feature is not supported at all */ - NOT_SUPPORTED, - /** feature is supported */ - SUPPORTED, - /** feature is supported and has to be used by clients */ - REQUIRED - } - + /** * @return address to bind, if null, all available interfaces will be used */ @@ -49,9 +37,9 @@ public interface ConnectionConfiguration { public Object getTransferProtocol(); /** - * @return encryption feature support + * @return TLS configuration object */ - public FEATURE_SUPPORT getTlsSupport(); + public TlsConfiguration getTlsConfiguration(); /** * @return silence time (in milliseconds) - after this time {@link SwitchIdleEvent} message is sent upstream diff --git a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/TlsConfiguration.java b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/TlsConfiguration.java new file mode 100644 index 00000000..54298294 --- /dev/null +++ b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/TlsConfiguration.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.api.connection; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType; + + +/** + * @author michal.polkorab + * + */ +public interface TlsConfiguration { + + /** + * @return keystore location + */ + public String getTlsKeystore(); + + /** + * @return keystore type + */ + public KeystoreType getTlsKeystoreType(); + + /** + * @return truststore location + */ + public String getTlsTruststore(); + + /** + * @return truststore type + */ + public KeystoreType getTlsTruststoreType(); + + /** + * @return keystore path type (classpath or path) + */ + public PathType getTlsKeystorePathType(); + + /** + * @return truststore path type (classpath or path) + */ + public PathType getTlsTruststorePathType(); +} diff --git a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/TlsConfigurationImpl.java b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/TlsConfigurationImpl.java new file mode 100644 index 00000000..d0bafdd4 --- /dev/null +++ b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/TlsConfigurationImpl.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.api.connection; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType; + +/** + * @author michal.polkorab + * + */ +public class TlsConfigurationImpl implements TlsConfiguration { + + private KeystoreType trustStoreType; + private String trustStore; + private KeystoreType keyStoreType; + private String keyStore; + private PathType keystorePathType; + private PathType truststorePathType; + + /** + * Default constructor + * @param trustStoreType JKS or PKCS12 + * @param trustStore path to trustStore file + * @param trustStorePathType truststore path type (classpath or path) + * @param keyStoreType JKS or PKCS12 + * @param keyStore path to keyStore file + * @param keyStorePathType keystore path type (classpath or path) + */ + public TlsConfigurationImpl(KeystoreType trustStoreType, String trustStore, + PathType trustStorePathType, KeystoreType keyStoreType, + String keyStore, PathType keyStorePathType) { + this.trustStoreType = trustStoreType; + this.trustStore = trustStore; + this.truststorePathType = trustStorePathType; + this.keyStoreType = keyStoreType; + this.keyStore = keyStore; + this.keystorePathType = keyStorePathType; + } + + @Override + public KeystoreType getTlsTruststoreType() { + return trustStoreType; + } + + @Override + public String getTlsTruststore() { + return trustStore; + } + + @Override + public KeystoreType getTlsKeystoreType() { + return keyStoreType; + } + + @Override + public String getTlsKeystore() { + return keyStore; + } + + @Override + public PathType getTlsKeystorePathType() { + return keystorePathType; + } + + @Override + public PathType getTlsTruststorePathType() { + return truststorePathType; + } +} diff --git a/openflow-protocol-api/src/main/yang/openflow-configuration.yang b/openflow-protocol-api/src/main/yang/openflow-configuration.yang new file mode 100644 index 00000000..36b163cb --- /dev/null +++ b/openflow-protocol-api/src/main/yang/openflow-configuration.yang @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + + module openflow-configuration { + namespace "urn:opendaylight:openflow:config"; + prefix "of-config"; + + revision "2014-06-30" { + description "Library configuration classes"; + } + + typedef path-type { + type enumeration { + enum CLASSPATH { + value 0; + description "Keystore file is located on classpath."; + } + enum PATH { + value 1; + description "Keystore file is located on absolute or relative path."; + } + } + } + + typedef keystore-type { + type enumeration { + enum JKS { + value 0; + description "Keystore type - JKS."; + } + enum PKCS12 { + value 1; + description "Keystore type - PKCS12."; + } + } + } +} \ No newline at end of file diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactory.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactory.java index a3897e93..3070aba8 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactory.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactory.java @@ -15,14 +15,12 @@ import io.netty.channel.socket.SocketChannel; * @author mirehak * @author michal.polkorab */ -public abstract class ConnectionAdapterFactory { +public interface ConnectionAdapterFactory { /** * @param ch * @return connection adapter tcp-implementation */ - public static ConnectionFacade createConnectionFacade(SocketChannel ch) { - return new ConnectionAdapterImpl(ch); - } + public ConnectionFacade createConnectionFacade(SocketChannel ch) ; } diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactoryImpl.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactoryImpl.java new file mode 100644 index 00000000..fda222ce --- /dev/null +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactoryImpl.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + + +package org.opendaylight.openflowjava.protocol.impl.connection; + +import io.netty.channel.socket.SocketChannel; + +/** + * @author mirehak + * @author michal.polkorab + */ +public class ConnectionAdapterFactoryImpl implements ConnectionAdapterFactory { + + /** + * @param ch + * @return connection adapter tcp-implementation + */ + @Override + public ConnectionFacade createConnectionFacade(SocketChannel ch) { + return new ConnectionAdapterImpl(ch); + } + +} diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/SwitchConnectionProviderImpl.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/SwitchConnectionProviderImpl.java index e1dabb49..cd864bd4 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/SwitchConnectionProviderImpl.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/SwitchConnectionProviderImpl.java @@ -10,19 +10,19 @@ package org.opendaylight.openflowjava.protocol.impl.connection; import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration; -import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration.FEATURE_SUPPORT; import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler; -import org.opendaylight.openflowjava.protocol.api.extensibility.MessageTypeKey; -import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer; -import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistry; import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry; import org.opendaylight.openflowjava.protocol.api.extensibility.MessageCodeKey; +import org.opendaylight.openflowjava.protocol.api.extensibility.MessageTypeKey; import org.opendaylight.openflowjava.protocol.api.extensibility.OFGeneralDeserializer; +import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer; +import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistry; +import org.opendaylight.openflowjava.protocol.impl.core.PublishingChannelInitializerFactory; import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler; -import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory; -import org.opendaylight.openflowjava.protocol.impl.serialization.SerializerRegistryImpl; import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory; import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializerRegistryImpl; +import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory; +import org.opendaylight.openflowjava.protocol.impl.serialization.SerializerRegistryImpl; import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider; import org.opendaylight.yangtools.yang.binding.DataObject; import org.slf4j.Logger; @@ -112,12 +112,13 @@ public class SwitchConnectionProviderImpl implements SwitchConnectionProvider { private TcpHandler createAndConfigureServer() { LOGGER.debug("Configuring .."); TcpHandler server = new TcpHandler(connConfig.getAddress(), connConfig.getPort()); - server.setSwitchConnectionHandler(switchConnectionHandler); - server.setSwitchIdleTimeout(connConfig.getSwitchIdleTimeout()); - boolean tlsSupported = FEATURE_SUPPORT.REQUIRED.equals(connConfig.getTlsSupport()); - server.setEncryption(tlsSupported); - server.setSerializationFactory(serializationFactory); - server.setDeserializationFactory(deserializationFactory); + PublishingChannelInitializerFactory factory = new PublishingChannelInitializerFactory(); + factory.setSwitchConnectionHandler(switchConnectionHandler); + factory.setSwitchIdleTimeout(connConfig.getSwitchIdleTimeout()); + factory.setTlsConfig(connConfig.getTlsConfiguration()); + factory.setSerializationFactory(serializationFactory); + factory.setDeserializationFactory(deserializationFactory); + server.setChannelInitializer(factory.createPublishingChannelInitializer()); return server; } diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java index a1f9fb94..ee578046 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java @@ -38,10 +38,9 @@ public class OFDecoder extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, VersionMessageWrapper msg, List out) throws Exception { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("VersionMessageWrapper received"); - LOGGER.debug("<< " + ByteBufUtils.byteBufToHexString(msg.getMessageBuffer())); - } + LOGGER.debug("VersionMessageWrapper received"); + LOGGER.debug("<< " + ByteBufUtils.byteBufToHexString(msg.getMessageBuffer())); + DataObject dataObject = null; try { dataObject = deserializationFactory.deserialize(msg.getMessageBuffer(), diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoder.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoder.java index dab263a2..d074e93e 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoder.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoder.java @@ -15,6 +15,7 @@ import io.netty.handler.codec.ByteToMessageDecoder; import java.util.List; +import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade; import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,12 +30,16 @@ public class OFFrameDecoder extends ByteToMessageDecoder { public static final byte LENGTH_OF_HEADER = 8; private static final byte LENGTH_INDEX_IN_HEADER = 2; private static final Logger LOGGER = LoggerFactory.getLogger(OFFrameDecoder.class); + private ConnectionFacade connectionFacade; + private boolean started = false; /** * Constructor of class. + * @param connectionFacade */ - public OFFrameDecoder() { + public OFFrameDecoder(ConnectionFacade connectionFacade) { LOGGER.trace("Creating OFFrameDecoder"); + this.connectionFacade = connectionFacade; } @Override @@ -45,9 +50,14 @@ public class OFFrameDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext chc, ByteBuf bb, List list) throws Exception { + if (!started) { + connectionFacade.fireConnectionReadyNotification(); + started = true; + } int readableBytes = bb.readableBytes(); if (readableBytes < LENGTH_OF_HEADER) { - LOGGER.debug("skipping bb - too few data for header: " + readableBytes); + LOGGER.debug("skipping bytebuf - too few bytes for header: " + readableBytes + " < " + LENGTH_OF_HEADER ); + LOGGER.debug("bb: " + ByteBufUtils.byteBufToHexString(bb)); return; } @@ -55,11 +65,9 @@ public class OFFrameDecoder extends ByteToMessageDecoder { LOGGER.debug("length of actual message: {}", length); if (readableBytes < length) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("skipping bb - too few data for msg: " + + LOGGER.debug("skipping bytebuf - too few bytes for msg: " + readableBytes + " < " + length); - LOGGER.debug("bb: " + ByteBufUtils.byteBufToHexString(bb)); - } + LOGGER.debug("bytebuffer: " + ByteBufUtils.byteBufToHexString(bb)); return; } LOGGER.debug("OF Protocol message received, type:{}", bb.getByte(bb.readerIndex() + 1)); diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetector.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetector.java index 719965b9..2160a85e 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetector.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetector.java @@ -47,15 +47,12 @@ public class OFVersionDetector extends ByteToMessageDecoder { byte version = bb.readByte(); if ((version == OF13_VERSION_ID) || (version == OF10_VERSION_ID)) { LOGGER.debug("detected version: " + version); + ByteBuf messageBuffer = bb.slice(); + list.add(new VersionMessageWrapper(version, messageBuffer)); + messageBuffer.retain(); } else { LOGGER.warn("detected version: " + version + " - currently not supported"); - bb.skipBytes(bb.readableBytes()); - return; } - - ByteBuf messageBuffer = bb.slice(); - list.add(new VersionMessageWrapper(version, messageBuffer)); - messageBuffer.retain(); bb.skipBytes(bb.readableBytes()); } diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializer.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializer.java index cc245974..5d29e4be 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializer.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializer.java @@ -12,15 +12,19 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.socket.SocketChannel; +import io.netty.handler.ssl.SslHandler; import java.net.InetAddress; import java.util.Iterator; import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLEngine; + import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration; import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory; +import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactoryImpl; import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade; -import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler.COMPONENT_NAMES; import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory; import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory; import org.slf4j.Logger; @@ -32,22 +36,71 @@ import org.slf4j.LoggerFactory; */ public class PublishingChannelInitializer extends ChannelInitializer { + /** + * Enum used for storing names of used components (in pipeline). + */ + public static enum COMPONENT_NAMES { + + /** + * Detects switch idle state + */ + IDLE_HANDLER, + /** + * Detects TLS connections + */ + TLS_DETECTOR, + /** + * Component for handling TLS frames + */ + SSL_HANDLER, + /** + * Decodes incoming messages into message frames + */ + OF_FRAME_DECODER, + /** + * Detects version of incoming OpenFlow Protocol message + */ + OF_VERSION_DETECTOR, + /** + * Transforms OpenFlow Protocol byte messages into POJOs + */ + OF_DECODER, + /** + * Transforms POJOs into OpenFlow Protocol byte messages + */ + OF_ENCODER, + /** + * Delegates translated POJOs into MessageConsumer + */ + DELEGATING_INBOUND_HANDLER, + } + private static final Logger LOGGER = LoggerFactory .getLogger(PublishingChannelInitializer.class); private final DefaultChannelGroup allChannels; private SwitchConnectionHandler switchConnectionHandler; private long switchIdleTimeout; - private boolean encryption; private SerializationFactory serializationFactory; private DeserializationFactory deserializationFactory; + private ConnectionAdapterFactory connectionAdapterFactory; + private TlsConfiguration tlsConfiguration ; /** * default ctor */ public PublishingChannelInitializer() { - allChannels = new DefaultChannelGroup("netty-receiver", null); + this( new DefaultChannelGroup("netty-receiver", null), new ConnectionAdapterFactoryImpl() ); } + /** + * Testing Constructor + * + */ + protected PublishingChannelInitializer( DefaultChannelGroup channelGroup, ConnectionAdapterFactory connAdaptorFactory ) { + allChannels = channelGroup ; + connectionAdapterFactory = connAdaptorFactory ; + } + @Override protected void initChannel(final SocketChannel ch) { InetAddress switchAddress = ch.remoteAddress().getAddress(); @@ -63,19 +116,22 @@ public class PublishingChannelInitializer extends ChannelInitializer isOnlineFuture; - private final PublishingChannelInitializer channelInitializer; - - /** - * Enum used for storing names of used components (in pipeline). - */ - public static enum COMPONENT_NAMES { - - /** - * Detects switch idle state - */ - IDLE_HANDLER, - /** - * Detects TLS connections - */ - TLS_DETECTOR, - /** - * Component for handling TLS frames - */ - SSL_HANDLER, - /** - * Decodes incoming messages into message frames - */ - OF_FRAME_DECODER, - /** - * Detects version of incoming OpenFlow Protocol message - */ - OF_VERSION_DETECTOR, - /** - * Transforms OpenFlow Protocol byte messages into POJOs - */ - OF_DECODER, - /** - * Transforms POJOs into OpenFlow Protocol byte messages - */ - OF_ENCODER, - /** - * Delegates translated POJOs into MessageConsumer - */ - DELEGATING_INBOUND_HANDLER, - } - + private PublishingChannelInitializer channelInitializer; /** * Constructor of TCPHandler that listens on selected port. @@ -116,7 +73,6 @@ public class TcpHandler implements ServerFacade { public TcpHandler(final InetAddress address, final int port) { this.port = port; this.startupAddress = address; - channelInitializer = new PublishingChannelInitializer(); isOnlineFuture = SettableFuture.create(); } @@ -212,13 +168,6 @@ public class TcpHandler implements ServerFacade { return channelInitializer.size(); } - /** - * @return channelInitializer providing channels - */ - public PublishingChannelInitializer getChannelInitializer() { - return channelInitializer; - } - @Override public ListenableFuture getIsOnlineFuture() { return isOnlineFuture; @@ -239,39 +188,10 @@ public class TcpHandler implements ServerFacade { } /** - * @param switchConnectionHandler - */ - public void setSwitchConnectionHandler( - final SwitchConnectionHandler switchConnectionHandler) { - channelInitializer.setSwitchConnectionHandler(switchConnectionHandler); - } - - /** - * @param switchIdleTimeout in milliseconds - */ - public void setSwitchIdleTimeout(final long switchIdleTimeout) { - channelInitializer.setSwitchIdleTimeout(switchIdleTimeout); - } - - /** - * @param tlsSupported - */ - public void setEncryption(final boolean tlsSupported) { - channelInitializer.setEncryption(tlsSupported); - } - - /** - * @param sf serialization factory - */ - public void setSerializationFactory(final SerializationFactory sf) { - channelInitializer.setSerializationFactory(sf); - } - - /** - * @param factory + * @param channelInitializer */ - public void setDeserializationFactory(final DeserializationFactory factory) { - channelInitializer.setDeserializationFactory(factory); + public void setChannelInitializer(PublishingChannelInitializer channelInitializer) { + this.channelInitializer = channelInitializer; } } diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TlsDetector.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TlsDetector.java deleted file mode 100644 index 75ce2cc8..00000000 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TlsDetector.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.openflowjava.protocol.impl.core; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.ByteToMessageDecoder; -import io.netty.handler.ssl.SslHandler; - -import java.util.List; - -import javax.net.ssl.SSLEngine; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade; -import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler.COMPONENT_NAMES; -import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils; - -/** - * Class for detecting TLS encrypted connection. If TLS encrypted connection is detected, - * TLSDetector engages SSLHandler and OFFrameDecoder into pipeline else it engages only - * OFFrameDecoder. - * - * @author michal.polkorab - */ -public class TlsDetector extends ByteToMessageDecoder { - - private boolean detectSsl; - private static final Logger LOGGER = LoggerFactory - .getLogger(TlsDetector.class); - - private ConnectionFacade connectionFacade; - - /** - * Constructor of class - */ - public TlsDetector() { - LOGGER.trace("Creating TLS Detector"); - detectSsl = true; - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - LOGGER.warn("Unexpected exception from downstream.", - cause); - ctx.close(); - } - - private boolean isSsl(ByteBuf bb) { - if (detectSsl) { - LOGGER.trace("Testing connection for TLS"); - return SslHandler.isEncrypted(bb); - } - return false; - } - - private static void enableSsl(ChannelHandlerContext ctx) { - if (ctx.pipeline().get(COMPONENT_NAMES.SSL_HANDLER.name()) == null) { - LOGGER.trace("Engaging TLS handler"); - ChannelPipeline p = ctx.channel().pipeline(); - SSLEngine engine = SslContextFactory.getServerContext() - .createSSLEngine(); - engine.setUseClientMode(false); - p.addAfter(COMPONENT_NAMES.TLS_DETECTOR.name(), COMPONENT_NAMES.SSL_HANDLER.name(), - new SslHandler(engine)); - } - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf bb, - List list) throws Exception { - if (bb.readableBytes() < 5) { - return; - } - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(ByteBufUtils.byteBufToHexString(bb)); - } - if (isSsl(bb)) { - LOGGER.debug("Connection is encrypted"); - enableSsl(ctx); - } else { - LOGGER.debug("Connection is not encrypted"); - } - - if (connectionFacade != null) { - LOGGER.trace("Firing onConnectionReady notification"); - connectionFacade.fireConnectionReadyNotification(); - } - - ctx.pipeline().remove(COMPONENT_NAMES.TLS_DETECTOR.name()); - } - - /** - * @param connectionFacade the connectionFacade to set - */ - public void setConnectionFacade(ConnectionFacade connectionFacade) { - this.connectionFacade = connectionFacade; - } -} diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/_switch/connection/provider/impl/rev140328/SwitchConnectionProviderModule.java b/openflow-protocol-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/_switch/connection/provider/impl/rev140328/SwitchConnectionProviderModule.java index 6dbdef09..45fed553 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/_switch/connection/provider/impl/rev140328/SwitchConnectionProviderModule.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/_switch/connection/provider/impl/rev140328/SwitchConnectionProviderModule.java @@ -13,11 +13,15 @@ import java.net.InetAddress; import java.net.UnknownHostException; import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration; import org.opendaylight.openflowjava.protocol.impl.connection.SwitchConnectionProviderImpl; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Objects; + /** * */ @@ -65,13 +69,14 @@ public final class SwitchConnectionProviderModule extends org.opendaylight.yang. } /** - * @return + * @return instance configuration object * @throws UnknownHostException */ private ConnectionConfiguration createConnectionConfiguration() throws UnknownHostException { final InetAddress address = extractIpAddressBin(getAddress()); final Integer port = getPort(); final long switchIdleTimeout = getSwitchIdleTimeout(); + final Tls tlsConfig = getTls(); return new ConnectionConfiguration() { @Override @@ -88,9 +93,33 @@ public final class SwitchConnectionProviderModule extends org.opendaylight.yang. return null; } @Override - public FEATURE_SUPPORT getTlsSupport() { - // TODO Auto-generated method stub - return null; + public TlsConfiguration getTlsConfiguration() { + return new TlsConfiguration() { + @Override + public KeystoreType getTlsTruststoreType() { + return Objects.firstNonNull(tlsConfig.getTruststoreType(), null); + } + @Override + public String getTlsTruststore() { + return Objects.firstNonNull(tlsConfig.getTruststore(), null); + } + @Override + public KeystoreType getTlsKeystoreType() { + return Objects.firstNonNull(tlsConfig.getKeystoreType(), null); + } + @Override + public String getTlsKeystore() { + return Objects.firstNonNull(tlsConfig.getKeystore(), null); + } + @Override + public org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType getTlsKeystorePathType() { + return Objects.firstNonNull(tlsConfig.getKeystorePathType(), null); + } + @Override + public org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType getTlsTruststorePathType() { + return Objects.firstNonNull(tlsConfig.getTruststorePathType(), null); + } + }; } @Override public long getSwitchIdleTimeout() { diff --git a/openflow-protocol-impl/src/main/resources/ctlKeystore b/openflow-protocol-impl/src/main/resources/ctlKeystore new file mode 100644 index 0000000000000000000000000000000000000000..c7310975775cf0418464970fb3f0922901437077 GIT binary patch literal 2254 zcma)-cTkh*7RK`>0VGn5G!YDoQUsPS2?RqEh%{-kfD!2liPX@GG$C{mR1iTa0s)m? zlq>F~cMvIxARR=SEJ#~0AaHSaobk{5$C-JbbKaTvcb<9YoP(8v6$k_ZJqqBT0MJJ# zo$$x6Dj*OR0HnkBK`vH=3@ZQ!&O>VK$b z_R`hrv$J6bYr^W2H~F3Y=}YdOR5m zZ#5$6IgrDJOHUn?j{)}eHos1n&1wc;7L%8JHmt4!(>z zUYol{!>N~xilt?Dyh^`ft3yJ^0>!?LBogZm^KP?w; z$ITKRIPDpt*@OJ&pES4gJo4r|On;RK;ZsicQ`32H?cBi5} z7<&=J(dF;YnKKP&k%bE=}Y(u+~j21X01t*yC+6fmGoYDnP1{GBBli3JUr9$wC*zrI4N*0`29D)S8sP`5~Od+ZSh z6#ByC;(tjkC{&tR;Q{x+?G zyDo-#Y4G9xo>Vf9mZ=pzJSJ|BvS4JqtBca{h(b#hCNHC`1-o$*u`NfmvkPU2{+8Cl|0loH++YKk(1 zyU0dn2WV^tWj}UnY8lK~#Mo5d2h}KbjM|8p@2&2V8%y!HjI_hKMGMVORK9J3qCoU; zdj+|xNApqXhW;25;C3m#we@5m)Z=isQX_qf-MszI8big7;<&DepfpNx%Ou&W{Z0<( zG(iv5wf6N8rkY+>!Y8Mbdd-bp1j54rA*bvEk<8-n4|A^HiY`@=Tq>qw=&IB8d$HCF zW4^(osVhSR%C-I%Dv>v6oPA50JzppYqD!VT-}kIhLF8tnm1~|CS7K$gd9;|9c%YH> zGOj&ou$T9Jkg%f!HN(`ri9vpoM=;*;K+8)`->Do}YuBCas45vvGztK1aPuE_ zqF$P3!$!Cb3?R%T^PsP5^+jK){H2^l^}#6=nfvMM5pieu`sAC_xj=2O@t|5J(Oa zPYMm?Zx-O}OLqF1K91xdd(eEnJ>1+V-ed>#MNsX>Z5R?~a@7p=YY9crL=h<7zRpx< zvV$)LC4~Xe7?iPxKMD(?Fc@VlMp*$P4T=hIq7^_Kh)08p7&LhONGkp!!HBq@c>h1^ z8BpX0)Nv&LuPva+|I$#rj~>MQOD#k8bwfEjDm&sRBn%d>Acs-F;^h=DRJ#%d+2>(N1P8 z2&t|%IW z&0Zp^0Et(%G0aZ0Rw|{Ry?w~wxwLu(>oKdZmvUolGPQQo@`cfheQkcl&PzH;(lGS7 zbOE`}Gfm?Xx#7Kzjovh0J#?UOglEMOe(H; zgx|77)%RYcwLM>I)SQr0Nm{uboFTsXRbA7M*dd5+DdG%)8JpOZtzb^~!*54mjVlI? zy8rl+@7*dAJ3BLS=FI_^#dlNO_CPCWvqFhTNlc_^c305TQY`6hdycA4%TDqepdcN{ z)%?s?%|$vJ>yBplo$rqICv_6GPcnBrnWMVY!D5ozyLVn4;r3YEVuNFAtFs!l7TqP) z17}OT{4f+#OQJP1czCqMm{Sy-9Tl8Yi%K%nGLsWaQWZ3e3=EAF z{PN2bj13fwjI4}}tW1nF4dldm4NVM8jm!d9G}_)hK(_wz4rORao*HT4}m9Z1HCYw)QWfA(> zv2v!$r%2mH;vt74Q!kYt+qYuf-5-+=9;*yH&QvXXFst&_V?ZRk3!e|(#1Zb8?*bBk^;`g~ZBzdAYU zp~Smur<0B*Xk5Q(7Tx@7{`{Rq>RXkx{io}NPB?yewT6Di!if=Xj~?mSPql5?dQ`(p z`Pi1gkEiqgn_Zk*z3<|dbPnk|hocM3Kic_Q9Qkj?zs7S7XL;YM zMNh@`zNY5Lrv5j1m*IHDT4J|#u8q*mw@l2842;Mj1Wa7O5MpGA-KBVcr}pxFm+e#f z-zBa0Q8*y`t9{Dkzxi`lIft~~b=$K#@6zl*(_7Bx!=7>9o-Vn|?aEHnte z^oMJ;MClK2D-Fmp5Sxshd!8eD}UvHL#Tj$y^k~=jLs|K4yApHWoLT;^rM|tv(lgxjt)_R3^a-hx7S~qXeak0g z)|>s{-JT2g|L@rvC2vx8mT88(Z2RhMt0cmfzfC^9y{7YY&Q7tkO?GcSq_3@wxj8>) zMb1RFur<>{Se!F8rEWJdZ`dO6qvlc5Bu~p74}WVsX}+@2Ipb5s-HtWk`}MqTY`5C)Rg4>ypp2)oSf7mprl*D`44}9biY9pW48ex z8<#d4BMYMzlOQ7_D+5atW4Yvn%f|g`Cp1&TuWyQzzMQcv^XY+v%}dX%-6&Vdy42}Y zW&Md6=BGC+9-G9G-f{T*-v=}9R>p2pd60GZRFmngy_`j5xr*LNt4#OT)!F5VskSSe zdwe>u_~8G80l5sbjm7epvc_L;@i-Iw+^oUKvF`Kp-8T|FC(dQu?)x$?N}qQz--BbB zp09UpJ!5X-v_RzW*XC;t(I)m87b{L(`qp-Q|KDp@r>L;9zAgZA?x_I z9~(bO`MEFQVIThZiZQ_-Kd;Z$Hmz)N^9l zLmRQG?vR>ZjR%X@$!Tw1Ryr|naXt4hMbo5@zmuvMRjkh}`M7UI;DpW<&G#QhJ)O@s zsXHyMp*mDGh0(|Q-+50h=EfEVrp5*#kEWuH-;QN$_%rE%an3c{^`%DKGD@no-cR2x zX;KoCZg-e-@8r?{{SLNVFH{$#8NIn~*cY&fgDZWf;ntrHj~qBBW^9@D=Bz~iz*@?WHo-ph3UQE;v?Vjnn^Z3&ao!}p~`kPp`aVbeTkog-jGV z=kq^seAlyVjs?S^)VkbSU|_fHyj-E(HaWk5Kkjds!bbBM9(xy7N3467aZAQq?4-8b MR!6VGPUY390E5dNe*gdg literal 0 HcmV?d00001 diff --git a/openflow-protocol-impl/src/main/resources/selfSignedSwitch b/openflow-protocol-impl/src/main/resources/selfSignedSwitch new file mode 100644 index 0000000000000000000000000000000000000000..645ac44243d3a8af51fa012f7879d245d05c1054 GIT binary patch literal 1348 zcmezO_TO6u1_mY|W&~q_;?$h9;>`5C)Rf}#%#!2`poCk&^&f|T^aO(@#vTJcHZE;8 zMixdbCP79z z{vL2FH)cr72==#S)LUgc(PHjlri(wOALuim?f*=E<7+PNT*lcA@mu-6lmw(yh4<-L}h-Y&+z{I!>H?Z#{ZQ!{7(h^Pn5o=`((rK^)eF|8BY8l9%L)92pnUq z5qhQumJAHc$p%f#@jxuQfSHMriHXIvf&YmCHygWFo5wi|7G_okgT@9!ZUas>=1>+k zVWwbjLs0`^5QjsUC%+&yFD0=uCo?^x1SZUmU6>2IFgJE#W>jGVIdNV?69Y2?GebiI zBO`+-FxS$+1j-!@PHbY_0ZiyRuz+I(a^#sB8yWuA2RF)=3TX!2_nM>k=E?JKg4=^^ z-n%dyma}iz7O0l#8tb4G_&d_JH{#d+qhEI!d^66fYKrV-7ByE+kQ;?hjsY#V=I=4^0WMI{&xAO++ilu5aB4XiALW_Kd;kHysq{B zlM=J!+>0KJ$C*SKrY8jSiz;)U*)(Zq)1ucc+#e!jzJi?g{o#VvYqM?do!+xL#%xFU z&dMq4cmJ|_)$}vmhufCDDLpVUyl>Z)NdISr>;jDqTRg=Im0$R1hzV~$&uP?iV%b9* zv8wKnnqG|ui`U6%Z(de9F>i4__b)}$q>sOosu)$Q&n)@4Z$;pQ&K1q~A4WZ$&o-$$ zEv}(DR5gXs$NJxSPc7!gRtAtewrlO0Rieb17@)L6(p79twcpl?#C@I554~EPbX71u zXj7qobZC$7{mwmB+n?xVA1pbf{Ih^p{C3LK>~A|SvX(1(l`mOPwn4?{^H!~D%kwuU zp6UMdurtVJ$FDU{j@`=9tc{kvCOd)GtJS)vX7~U1e-GbY{(AC#)8lfpCs;3g|8BYJ zVnqXa16g32mgQp+V-fki@~qY6YpgvUy*{(v?mKM|ZLgw$k|UV)84ProL@H7mGR;I& zb1vSVr#Pp#c-;qWu?I{dz73Wqi_+Zp9Q~<%o^R5#J)YMMmR^YWQ7f+gl<8W)zE1Om KmC%%2<4FL78zvqA literal 0 HcmV?d00001 diff --git a/openflow-protocol-impl/src/main/yang/openflow-switch-connection-provider-impl.yang b/openflow-protocol-impl/src/main/yang/openflow-switch-connection-provider-impl.yang index ddd6ebd1..0abc830a 100644 --- a/openflow-protocol-impl/src/main/yang/openflow-switch-connection-provider-impl.yang +++ b/openflow-protocol-impl/src/main/yang/openflow-switch-connection-provider-impl.yang @@ -6,6 +6,7 @@ module openflow-switch-connection-provider-impl { import config {prefix config; revision-date 2013-04-05; } import openflow-switch-connection-provider {prefix openflow-switch-connection-provider; revision-date 2014-03-28; } import ietf-inet-types {prefix ietf-inet; revision-date 2010-09-24; } + import openflow-configuration {prefix of-config; revision-date 2014-06-30; } description "openflow-switch-connection-provider"; @@ -40,10 +41,31 @@ module openflow-switch-connection-provider-impl { type uint32; mandatory true; } - leaf tls-support { - description "tls support enabled (requires SSL-context / keystore)"; - type boolean; - default false; + container tls { + leaf keystore { + description "keystore location"; + type string; + } + leaf keystore-type { + description "keystore type (JKS or PKCS12)"; + type of-config:keystore-type; + } + leaf keystore-path-type { + description "keystore path type (classpath or path)"; + type of-config:path-type; + } + leaf truststore { + description "truststore location"; + type string; + } + leaf truststore-type { + description "truststore type (JKS or PKCS12)"; + type of-config:keystore-type; + } + leaf truststore-path-type { + description "truststore path type (classpath or path)"; + type of-config:path-type; + } } } } diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/DelegatingInboundHandlerTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/DelegatingInboundHandlerTest.java new file mode 100644 index 00000000..cc3d30c7 --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/DelegatingInboundHandlerTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import io.netty.channel.ChannelHandlerContext; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.openflowjava.protocol.impl.connection.MessageConsumer; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * @author jameshall + */ +public class DelegatingInboundHandlerTest { + + @Mock ChannelHandlerContext mockChHndlrCtx ; + @Mock MessageConsumer mockMsgConsumer ; + @Mock DataObject mockDataObject ; + + DelegatingInboundHandler dih ; + + /** + * Sets up test environment + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + dih = new DelegatingInboundHandler(mockMsgConsumer) ; + } + + /** + * + */ + @Test + public void testChannelReadSuccess() { + dih.channelRead(mockChHndlrCtx, mockDataObject) ; + + // Verify that the message buf was released... + verify( mockMsgConsumer, times(1)).consume(mockDataObject); + } + /** + * + */ + @Test + public void testChannelInactive() { + dih.channelInactive(mockChHndlrCtx); + + verify( mockMsgConsumer, times(1)).consume(any(DataObject.class)); + } + + /** + * ChannelUnregistered + */ + @Test + public void testChannelUnregistered() { + dih.channelUnregistered(mockChHndlrCtx); + + verify( mockMsgConsumer, times(1)).consume(any(DataObject.class)); + } +} diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/IdleHandlerTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/IdleHandlerTest.java new file mode 100644 index 00000000..aa08feb5 --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/IdleHandlerTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import io.netty.channel.ChannelHandlerContext; + +import java.util.concurrent.TimeUnit; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SwitchIdleEvent; + +/** + * + * @author jameshall + */ +public class IdleHandlerTest { + + @Mock ChannelHandlerContext mockChHndlrCtx ; + + IdleHandler idleHandler ; + + /** + * Sets up test environment + * + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + idleHandler = new IdleHandler(60L, TimeUnit.MINUTES ) ; + } + + /** + * Test message passing on channel read + */ + @Test + public void testChannelRead() { + try { + idleHandler.channelRead(mockChHndlrCtx, new Object() ); + } catch (Exception e) { + Assert.fail(); + } + + // Verify that a read was fired for the next handler ... + verify(mockChHndlrCtx, times(1)).fireChannelRead(any(SwitchIdleEvent.class)) ; + } + + /** + * Test channel read timeout + */ + @Test + public void testReadTimedOut() { + try { + idleHandler.readTimedOut( mockChHndlrCtx ); + } catch (Exception e) { + Assert.fail(); + } + + // Verify a read was fired for the next handler to process ... + verify(mockChHndlrCtx, times(1)).fireChannelRead(any(SwitchIdleEvent.class)) ; + } + + /** + * Test only one timeout notification + */ + @Test + public void testReadTimedOutNoOpNotFirst() { + try { + idleHandler.readTimedOut(mockChHndlrCtx); + idleHandler.readTimedOut(mockChHndlrCtx); + } catch (Exception e) { + Assert.fail(); + } + + // Verify that only one notification was sent to the next handler ... + verify(mockChHndlrCtx, times(1)).fireChannelRead(any(Object.class)) ; + } + + /** + * Test two timeout notifications + */ + @Test + public void testReadTimedOutTwice() { + try { + idleHandler.readTimedOut(mockChHndlrCtx); + verify(mockChHndlrCtx, times(1)).fireChannelRead(any(Object.class)) ; + + idleHandler.channelRead(mockChHndlrCtx, new String() ); + verify(mockChHndlrCtx, times(2)).fireChannelRead(any(Object.class)) ; + + idleHandler.readTimedOut(mockChHndlrCtx); + verify(mockChHndlrCtx, times(3)).fireChannelRead(any(Object.class)) ; + } catch (Exception e) { + Assert.fail(); + } + } + +} diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoderTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoderTest.java new file mode 100644 index 00000000..8337b792 --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoderTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyShort; +import static org.mockito.Mockito.when; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory; +import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * + * @author jameshall + */ +public class OFDecoderTest { + + @Mock ChannelHandlerContext mockChHndlrCtx ; + @Mock DeserializationFactory mockDeserializationFactory ; + @Mock DataObject mockDataObject ; + + OFDecoder ofDecoder ; + private ByteBuf writeObj; + private VersionMessageWrapper inMsg; + private List outList; + + /** + * Sets up test environment + * + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ofDecoder = new OFDecoder() ; + ofDecoder.setDeserializationFactory( mockDeserializationFactory ) ; + writeObj = ByteBufUtils.hexStringToByteBuf("16 03 01 00"); + inMsg = new VersionMessageWrapper( (short)8, writeObj ); + outList = new ArrayList<>(); + } + + /** + * + */ + @Test + public void testDecode() { + when(mockDeserializationFactory.deserialize( any(ByteBuf.class), anyShort() )).thenReturn(mockDataObject); + try { + ofDecoder.decode(mockChHndlrCtx, inMsg, outList); + } catch (Exception e) { + Assert.fail(); + } + + // Verify that the message buf was released... + assertEquals( mockDataObject, outList.get(0) ) ; + assertEquals( 0, writeObj.refCnt() ) ; + } + + /** + * + */ + @Test + public void testDecodeDeserializeException() { + when(mockDeserializationFactory.deserialize( any(ByteBuf.class), anyShort() )) + .thenThrow(new IllegalArgumentException()) ; + + try { + ofDecoder.decode(mockChHndlrCtx, inMsg, outList); + } catch (Exception e) { + System.out.println("a"); + Assert.fail(); + } + + // Verify that the message buf was released... + assertEquals( 0, outList.size() ) ; + assertEquals( 1, writeObj.refCnt() ) ; + } + + /** + * + */ + @Test + public void testDecodeDeserializeNull() { + when(mockDeserializationFactory.deserialize( any(ByteBuf.class), anyShort() )) + .thenReturn(null) ; + + try { + ofDecoder.decode(mockChHndlrCtx, inMsg, outList); + } catch (Exception e) { + Assert.fail(); + } + + // Verify that the message buf was released... + assertEquals( 0, outList.size() ) ; + assertEquals( 1, writeObj.refCnt() ) ; + } +} diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoderTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoderTest.java new file mode 100644 index 00000000..11d2098a --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoderTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyShort; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * + * @author jameshall + */ +public class OFEncoderTest { + + @Mock ChannelHandlerContext mockChHndlrCtx ; + @Mock SerializationFactory mockSerializationFactory ; + @Mock OfHeader mockMsg ; + @Mock ByteBuf mockOut ; + + OFEncoder ofEncoder = new OFEncoder() ; + + /** + * Sets up test environment + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ofEncoder = new OFEncoder() ; + ofEncoder.setSerializationFactory( mockSerializationFactory ) ; + } + + /** + * Test successful write (no clear) + */ + @Test + public void testEncodeSuccess() { + when(mockOut.readableBytes()).thenReturn(1); + try { + ofEncoder.encode(mockChHndlrCtx, mockMsg, mockOut); + } catch (Exception e) { + Assert.fail(); + } + + // Verify that the channel was flushed after the ByteBuf was retained. + verify(mockOut, times(0)).clear(); + } + + /** + * Test Bytebuf clearing after serialization failure + */ + @Test + public void testEncodeSerializationException() { + doThrow(new IllegalArgumentException()).when(mockSerializationFactory).messageToBuffer(anyShort(),any(ByteBuf.class), any(DataObject.class)); + try { + ofEncoder.encode(mockChHndlrCtx, mockMsg, mockOut); + } catch (Exception e) { + Assert.fail(); + } + + // Verify that the output message buf was cleared... + verify(mockOut, times(1)).clear(); + } + + /** + * Test no action on empty bytebuf + */ + @Test + public void testEncodeSerializesNoBytes() { + when(mockOut.readableBytes()).thenReturn(0); + try { + ofEncoder.encode(mockChHndlrCtx, mockMsg, mockOut); + } catch (Exception e) { + Assert.fail(); + } + + // Verify that the output message buf was cleared... + verify(mockOut, times(0)).clear(); + verify(mockChHndlrCtx, times(0)).writeAndFlush(mockOut); + verify(mockOut, times(0)).retain(); + } +} \ No newline at end of file diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoderTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoderTest.java index d758ab8f..786a0d88 100644 --- a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoderTest.java +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoderTest.java @@ -8,6 +8,7 @@ package org.opendaylight.openflowjava.protocol.impl.core; +import static org.junit.Assert.assertEquals; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; @@ -19,7 +20,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade; import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils; /** @@ -33,6 +36,8 @@ public class OFFrameDecoderTest { @Mock ChannelHandlerContext channelHandlerContext; + @Mock + ConnectionFacade connectionFacade; private OFFrameDecoder decoder; private List list = new ArrayList<>(); @@ -41,69 +46,104 @@ public class OFFrameDecoderTest { */ @Before public void setUp() { + MockitoAnnotations.initMocks(this); + decoder = new OFFrameDecoder(connectionFacade); list.clear(); - decoder = new OFFrameDecoder(); + } /** * Test of decoding * {@link OFFrameDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)} - * - * @throws Exception */ @Test - public void testDecode8BMessage() throws Exception { - decoder.decode(channelHandlerContext, - ByteBufUtils.hexStringToByteBuf("04 00 00 08 00 00 00 01"), - list); + public void testDecode8BMessage() { + try { + decoder.decode(channelHandlerContext, + ByteBufUtils.hexStringToByteBuf("04 00 00 08 00 00 00 01"), + list); + } catch (Exception e) { + Assert.fail(); + } + + assertEquals(8, ((ByteBuf) list.get(0)).readableBytes()); + } - Assert.assertEquals(8, ((ByteBuf) list.get(0)).readableBytes()); + /** + * Test of decoding + * {@link OFFrameDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)} + */ + @Test + public void testDecode16BMessage() { + ByteBuf byteBuffer = ByteBufUtils + .hexStringToByteBuf("04 00 00 10 00 00 00 00 00 00 00 00 00 00 00 42"); + try { + decoder.decode(channelHandlerContext, byteBuffer, list); + } catch (Exception e) { + Assert.fail(); + } + + assertEquals(16, ((ByteBuf) list.get(0)).readableBytes()); + assertEquals(0, byteBuffer.readableBytes()); } /** * Test of decoding * {@link OFFrameDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)} - * - * @throws Exception */ @Test - public void testDecode16BMessage() throws Exception { - decoder.decode(channelHandlerContext, - ByteBufUtils.hexStringToByteBuf("04 00 00 10 00 00 00 00 00 00 00 00 00 00 00 42"), - list); + public void testDecode5BIncompleteMessage() { + ByteBuf byteBuffer = ByteBufUtils.hexStringToByteBuf("04 00 00 08 00"); + try { + decoder.decode(channelHandlerContext, byteBuffer, list); + } catch (Exception e) { + Assert.fail(); + } - Assert.assertEquals(16, ((ByteBuf) list.get(0)).readableBytes()); + Assert.assertEquals("List is not empty", 0, list.size()); + assertEquals(5, byteBuffer.readableBytes()); } /** * Test of decoding * {@link OFFrameDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)} - * - * @throws Exception */ @Test - public void testDecodeIncompleteMessage() throws Exception { - decoder.decode(channelHandlerContext, - ByteBufUtils.hexStringToByteBuf("04 00 00 08 00"), - list); + public void testDecode16BIncompleteMessage() { + ByteBuf byteBuffer = ByteBufUtils + .hexStringToByteBuf("04 00 00 11 00 00 00 00 00 00 00 00 00 00 00 42"); + try { + decoder.decode(channelHandlerContext, byteBuffer, list); + } catch (Exception e) { + Assert.fail(); + } Assert.assertEquals("List is not empty", 0, list.size()); + assertEquals(16, byteBuffer.readableBytes()); } /** * Test of decoding * {@link OFFrameDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)} - * - * @throws Exception */ @Test - public void testDecodeCompleteAndPartialMessage() throws Exception { - decoder.decode(channelHandlerContext, - ByteBufUtils.hexStringToByteBuf("04 00 00 08 00 00 00 01 04 00 00 08 00"), - list); + public void testDecodeCompleteAndPartialMessage() { + ByteBuf byteBuffer = ByteBufUtils + .hexStringToByteBuf("04 00 00 08 00 00 00 01 04 00 00 08 00"); + try { + decoder.decode(channelHandlerContext, byteBuffer, list); + } catch (Exception e) { + Assert.fail(); + } Assert.assertEquals(8, ((ByteBuf) list.get(0)).readableBytes()); Assert.assertEquals(1, list.size()); + assertEquals(5, byteBuffer.readableBytes()); + + } + + @Test + public void testExceptionCaught() throws Exception { + decoder.exceptionCaught(channelHandlerContext, new Throwable()); } - -} \ No newline at end of file +} diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetectorTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetectorTest.java index fb3369bf..0f1d87d0 100644 --- a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetectorTest.java +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetectorTest.java @@ -8,12 +8,14 @@ package org.opendaylight.openflowjava.protocol.impl.core; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import java.util.ArrayList; import java.util.List; import org.junit.Assert; +import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -60,6 +62,39 @@ public class OFVersionDetectorTest { .getMessageBuffer().readableBytes()); } + /** + * Test of decode + * {@link OFVersionDetector#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) + * } + * @throws Exception + */ + @Test + public void testDecode10ProtocolMessage() throws Exception { + detector.decode(channelHandlerContext, + ByteBufUtils.hexStringToByteBuf("01 00 00 08 00 00 00 01"), + list); + + Assert.assertEquals(7, ((VersionMessageWrapper) list.get(0)) + .getMessageBuffer().readableBytes()); + } + + /** + * Test of decode + * {@link OFVersionDetector#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) + * } + * @throws Exception + */ + @Test + public void testDecodeEmptyProtocolMessage() throws Exception { + ByteBuf byteBuffer = ByteBufUtils.hexStringToByteBuf("01 00 00 08 00 00 00 01").skipBytes(8); + detector.decode(channelHandlerContext, + byteBuffer, + list); + + assertEquals( 0, byteBuffer.refCnt() ) ; + + } + /** * Test of decode * {@link OFVersionDetector#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerFactoryTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerFactoryTest.java new file mode 100644 index 00000000..c6ececd8 --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerFactoryTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfigurationImpl; +import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory; +import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType; + +/** + * + * @author jameshall + */ +public class PublishingChannelInitializerFactoryTest { + + TlsConfiguration tlsConfiguration ; + PublishingChannelInitializerFactory factory; + private final long switchIdleTimeOut = 60; + @Mock SwitchConnectionHandler switchConnectionHandler ; + @Mock SerializationFactory serializationFactory; + @Mock DeserializationFactory deserializationFactory ; + + /** + * Sets up test environment + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + factory = new PublishingChannelInitializerFactory(); + tlsConfiguration = new TlsConfigurationImpl(KeystoreType.JKS, "/ctlTrustStore", + PathType.CLASSPATH, KeystoreType.JKS, "/ctlKeystore", PathType.CLASSPATH); + factory.setDeserializationFactory(deserializationFactory); + factory.setSerializationFactory(serializationFactory); + factory.setSwitchConnectionHandler(switchConnectionHandler); + factory.setSwitchIdleTimeout(switchIdleTimeOut); + factory.setTlsConfig(tlsConfiguration); + } + + /** + * Test {@link PublishingChannelInitializer} creation + */ + @Test + public void testCreatePublishingChannelInitializer() { + PublishingChannelInitializer initializer = factory.createPublishingChannelInitializer() ; + assertNotNull( initializer ); + } +} \ No newline at end of file diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerTest.java new file mode 100644 index 00000000..55b13552 --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.group.DefaultChannelGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.ssl.SslHandler; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLEngine; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfigurationImpl; +import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory; +import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade; +import org.opendaylight.openflowjava.protocol.impl.core.PublishingChannelInitializer.COMPONENT_NAMES; +import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory; +import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow._switch.connection.provider.impl.rev140328.Tls; + +/** + * + * @author james.hall + */ +public class PublishingChannelInitializerTest { + + @Mock SocketChannel mockSocketCh ; + @Mock ChannelPipeline mockChPipeline ; + @Mock SwitchConnectionHandler mockSwConnHandler ; + @Mock ConnectionAdapterFactory mockConnAdaptorFactory; + @Mock DefaultChannelGroup mockChGrp ; + @Mock ConnectionFacade mockConnFacade ; + @Mock Tls mockTls ; + SSLEngine sslEngine ; + + @Mock SerializationFactory mockSerializationFactory ; + @Mock DeserializationFactory mockDeserializationFactory ; + + TlsConfiguration tlsConfiguration ; + InetSocketAddress inetSockAddr; + PublishingChannelInitializer pubChInitializer ; + + /** + * Sets up test environment + * @throws Exception + */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + pubChInitializer= new PublishingChannelInitializer(mockChGrp, mockConnAdaptorFactory) ; + pubChInitializer.setSerializationFactory(mockSerializationFactory); + pubChInitializer.setDeserializationFactory(mockDeserializationFactory); + pubChInitializer.setSwitchIdleTimeout(1) ; + pubChInitializer.getConnectionIterator() ; + + when( mockChGrp.size()).thenReturn(1) ; + pubChInitializer.setSwitchConnectionHandler( mockSwConnHandler ) ; + + inetSockAddr = new InetSocketAddress(InetAddress.getLocalHost(), 8675 ) ; + + when(mockConnAdaptorFactory.createConnectionFacade(mockSocketCh)) + .thenReturn(mockConnFacade); + when(mockSocketCh.remoteAddress()).thenReturn(inetSockAddr) ; + when(mockSocketCh.localAddress()).thenReturn(inetSockAddr) ; + when(mockSocketCh.remoteAddress()).thenReturn(inetSockAddr) ; + when(mockSwConnHandler.accept(eq(InetAddress.getLocalHost()))).thenReturn(true) ; + when(mockSocketCh.pipeline()).thenReturn(mockChPipeline) ; + + tlsConfiguration = new TlsConfigurationImpl(KeystoreType.JKS, "src/main/resources/selfSignedSwitch", PathType.PATH, + KeystoreType.JKS, "src/main/resources/selfSignedController", PathType.PATH); + } + + + /** + * Test channel initialization with encryption config set + */ + @Test + public void testinitChannelEncryptionSet() { + pubChInitializer.setTlsConfiguration(tlsConfiguration); + pubChInitializer.initChannel(mockSocketCh) ; + + verifyCommonHandlers(); + verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.SSL_HANDLER.name()),any(SslHandler.class)) ; + } + + /** + * Test channel initialization with null encryption config + */ + @Test + public void testinitChannelEncryptionSetNullTls() { + pubChInitializer.setTlsConfiguration(null); + pubChInitializer.initChannel(mockSocketCh) ; + + verifyCommonHandlers(); + verify(mockChPipeline, times(0)).addLast(eq(COMPONENT_NAMES.SSL_HANDLER.name()),any(SslHandler.class)) ; + } + + /** + * Test channel initialization without setting the encryption + */ + @Test + public void testinitChannelEncryptionNotSet() { + // Without encryption, only the common + pubChInitializer.initChannel(mockSocketCh) ; + + verifyCommonHandlers(); + } + + /** + * Test disconnect on new connection rejected + * @throws UnknownHostException + */ + @Test + public void testinitChannelNoEncryptionAcceptFails() throws UnknownHostException { + when(mockSwConnHandler.accept(eq(InetAddress.getLocalHost()))).thenReturn(false) ; + pubChInitializer.initChannel(mockSocketCh) ; + + verify(mockSocketCh, times(1)).disconnect(); + verify(mockChPipeline, times(0)) + .addLast( any(String.class), any(ChannelHandler.class) ) ; + } + + /** + * Test channel close on exception during initialization + */ + @Test + public void testExceptionThrown() { + doThrow(new IllegalArgumentException()).when(mockSocketCh).pipeline() ; + pubChInitializer.initChannel(mockSocketCh); + + verify( mockSocketCh, times(1)).close() ; + } + + /** + * All paths should install these six handlers: + */ + private void verifyCommonHandlers() { + verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.IDLE_HANDLER.name()),any(IdleHandler.class)) ; + verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_DECODER.name()),any(OFDecoder.class)) ; + verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_ENCODER.name()),any(OFEncoder.class)) ; + verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_FRAME_DECODER.name()),any(OFFrameDecoder.class)) ; + verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_VERSION_DETECTOR.name()),any(OFVersionDetector.class)) ; + verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.DELEGATING_INBOUND_HANDLER.name()),any(DelegatingInboundHandler.class)); + assertEquals(1, pubChInitializer.size()) ; + } +} diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslContextFactoryTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslContextFactoryTest.java new file mode 100644 index 00000000..2457fd33 --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslContextFactoryTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.junit.Assert.assertNotNull; + +import javax.net.ssl.SSLContext; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfigurationImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType; + +/** + * + * @author jameshall + */ +public class SslContextFactoryTest { + + SslContextFactory sslContextFactory; + TlsConfiguration tlsConfiguration ; + + /** + * Sets up test environment + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + tlsConfiguration = new TlsConfigurationImpl(KeystoreType.JKS, "src/main/resources/ctlTrustStore", + PathType.PATH, KeystoreType.JKS, "src/main/resources/ctlKeystore", PathType.PATH) ; + sslContextFactory = new SslContextFactory(tlsConfiguration); + } + + /** + * @throws Exception + */ + @Test + public void testGetServerContext() throws Exception { + SSLContext context = sslContextFactory.getServerContext() ; + + assertNotNull( context ); + } + +} + diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslKeyStoreTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslKeyStoreTest.java new file mode 100644 index 00000000..7c871bbd --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslKeyStoreTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.InputStream; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType; + +/** + * + * @author jameshall + */ +public class SslKeyStoreTest { + + /** + * Sets up test environment + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + /** + * Test keystore file access + * @throws Exception + */ + @Test + public void testAsInputStream() throws Exception { + InputStream inputStream = SslKeyStore.asInputStream("src/main/resources/key.bin", PathType.PATH); + assertNotNull( inputStream ); + inputStream.close(); + } + + /** + * Test certificate password retrieval + */ + @Test + public void testGetCertificatePassword() { + char[] password = SslKeyStore.getCertificatePassword(); + assertNotNull(password); + assertTrue (password.length>0) ; + } + + /** + * Test keystore password retrieval + */ + @Test + public void testGetKeyStorePassword() { + char[] password = SslKeyStore.getKeyStorePassword() ; + assertNotNull(password); + assertTrue (password.length>0) ; + } +} \ No newline at end of file diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslTrustManagerFactoryTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslTrustManagerFactoryTest.java new file mode 100644 index 00000000..23362840 --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/SslTrustManagerFactoryTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.security.cert.X509Certificate; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; + +/** + * + * @author jameshall + */ +public class SslTrustManagerFactoryTest { + + /** + * Sets up test environment + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + /** + * + */ + @Test + public void testGetTrustManagers() throws Exception { + TrustManager[] tmArray = SslTrustManagerFactory.getTrustManagers() ; + + assertNotNull( tmArray ); + for ( TrustManager tm : tmArray ) { + if ( tm.getClass() == X509TrustManager.class ) { + X509Certificate[] certsArray = ((X509TrustManager)tm).getAcceptedIssuers() ; + assertTrue( certsArray.length > 0 ) ; + + // Boolean caught = false; + // try { + // ((X509TrustManager)tm).checkClientTrusted( certsArray, TrustManagerFactory.getDefaultAlgorithm()) ; + // } catch (CertificateException ce) { + // caught = true ; + // } + // assertTrue( caught ) ; + // + // caught = false; + // try { + // ((X509TrustManager)tm).checkServerTrusted( certsArray, TrustManagerFactory.getDefaultAlgorithm()) ; + // } catch (CertificateException ce) { + // caught = true ; + // } + // assertTrue( caught ) ; + // } + } + } + } +} + diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TcpHandlerTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TcpHandlerTest.java new file mode 100644 index 00000000..7092922f --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TcpHandlerTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.core; + +import static org.junit.Assert.assertEquals; +import io.netty.channel.ChannelHandlerContext; + +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.concurrent.ExecutionException; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler; +import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory; +import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * + * @author jameshall + */ +public class TcpHandlerTest { + + private InetAddress serverAddress = InetAddress.getLoopbackAddress() ; + @Mock ChannelHandlerContext mockChHndlrCtx ; + @Mock PublishingChannelInitializer mockChannelInitializer; + @Mock SwitchConnectionHandler mockSwitchConnHndler ; + @Mock SerializationFactory mockSerializationFactory ; + @Mock DeserializationFactory mockDeserializationFactory ; + + TcpHandler tcpHandler ; + + /** + * Initialize mocks + */ + public TcpHandlerTest() { + MockitoAnnotations.initMocks(this); + } + + /** + * Test run with null address set + * @throws IOException + * @throws InterruptedException + * @throws ExecutionException + */ + @Test + public void testRunWithNullAddress() throws IOException, InterruptedException, ExecutionException { + + tcpHandler = new TcpHandler(null, 0); + tcpHandler.setChannelInitializer(mockChannelInitializer); + + assertEquals("failed to start server", true, startupServer()) ; + assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())) ; + shutdownServer(); + } + + /** + * Test run with address set + * @throws IOException + * @throws InterruptedException + * @throws ExecutionException + */ + @Test + public void testRunWithAddress() throws IOException, InterruptedException, ExecutionException { + + tcpHandler = new TcpHandler(serverAddress, 0); + tcpHandler.setChannelInitializer(mockChannelInitializer); + + assertEquals("failed to start server", true, startupServer()) ; + assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())) ; + shutdownServer(); + } + + /** + * Test run with encryption + * @throws InterruptedException + * @throws IOException + * @throws ExecutionException + */ + @Test + public void testRunWithEncryption () throws InterruptedException, IOException, ExecutionException { + int serverPort = 28001; + tcpHandler = new TcpHandler(serverAddress, serverPort); + tcpHandler.setChannelInitializer(mockChannelInitializer); + + assertEquals( "failed to start server", true, startupServer()) ; + assertEquals( "wrong connection count", 0, tcpHandler.getNumberOfConnections() ); + assertEquals( "wrong port", serverPort, tcpHandler.getPort() ); + assertEquals( "wrong address", serverAddress.getHostAddress(), tcpHandler.getAddress()) ; + + assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())) ; + + shutdownServer(); + } + + /** + * Test run on already used port + * @throws IOException + */ + @Test + public void testSocketAlreadyInUse() throws IOException { + int serverPort = 28001; + Socket firstBinder = new Socket(); + boolean exceptionThrown = false; + try { + firstBinder.bind(new InetSocketAddress(serverAddress, serverPort)); + } catch (Exception e) { + Assert.fail("Test precondition failed - not able to bind socket to port " + serverPort); + } + try { + tcpHandler = new TcpHandler(serverAddress, serverPort); + tcpHandler.setChannelInitializer(mockChannelInitializer); + tcpHandler.run(); + } catch (Exception e) { + if (e instanceof BindException) { + exceptionThrown = true; + } + } + firstBinder.close(); + Assert.assertTrue("Expected BindException has not been thrown", exceptionThrown == true); + } + + /** + * Trigger the server shutdown and wait 2 seconds for completion + */ + private void shutdownServer() throws InterruptedException, ExecutionException { + ListenableFuture shutdownRet = tcpHandler.shutdown() ; + while ( shutdownRet.isDone() != true ) + Thread.sleep(100) ; + assertEquals("shutdown failed", true, shutdownRet.get()); + } + + /** + * @throws InterruptedException + * @throws IOException + * @throws ExecutionException + */ + private Boolean startupServer() throws InterruptedException, IOException, ExecutionException { + ListenableFuture online = tcpHandler.getIsOnlineFuture(); + + (new Thread(tcpHandler)).start(); + int retry = 0; + while (online.isDone() != true && retry++ < 20) { + Thread.sleep(100); + } + return online.isDone() ; + } + /** + * @throws IOException + */ + private static Boolean clientConnection(int port) throws IOException { + // Connect, and disconnect + Socket socket = new Socket(InetAddress.getLoopbackAddress(), port ); + Boolean result = socket.isConnected(); + socket.close() ; + return result ; + } +} diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TlsDetectorTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TlsDetectorTest.java deleted file mode 100644 index 32685846..00000000 --- a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TlsDetectorTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.openflowjava.protocol.impl.core; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.embedded.EmbeddedChannel; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler.COMPONENT_NAMES; - -/** - * - * @author michal.polkorab - */ -public class TlsDetectorTest { - - private EmbeddedChannel embch; - - /** - * Sets up test environment - */ - @Before - public void setUp() { - TlsDetector tlsDetector = new TlsDetector(); - embch = new EmbeddedChannel(new DummyDecoder()); - embch.pipeline().addFirst(TcpHandler.COMPONENT_NAMES.TLS_DETECTOR.name(), tlsDetector); - } - - /** - * Test of decode {@link TlsDetector#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) } - * @throws Exception - */ - @Test - public void testDecodeNotEncryptedMessage() throws Exception { - byte[] msgs = new byte[]{0x04, 0x0, 0x0, 0x08, 0x0, 0x0, 0x0, 0x01}; - ByteBuf writeObj = embch.alloc().buffer(64); - writeObj.writeBytes(msgs); - embch.writeInbound(writeObj); - - Assert.assertNull(embch.pipeline().get(COMPONENT_NAMES.TLS_DETECTOR.name())); - Assert.assertNull(embch.pipeline().get(COMPONENT_NAMES.SSL_HANDLER.name())); - } -} \ No newline at end of file diff --git a/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/IntegrationTest.java b/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/IntegrationTest.java deleted file mode 100644 index 7cbae3f0..00000000 --- a/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/IntegrationTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.openflowjava.protocol.impl.integration; - -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration.FEATURE_SUPPORT; -import org.opendaylight.openflowjava.protocol.impl.clients.ClientEvent; -import org.opendaylight.openflowjava.protocol.impl.clients.ScenarioFactory; -import org.opendaylight.openflowjava.protocol.impl.clients.ScenarioHandler; -import org.opendaylight.openflowjava.protocol.impl.clients.SendEvent; -import org.opendaylight.openflowjava.protocol.impl.clients.SimpleClient; -import org.opendaylight.openflowjava.protocol.impl.clients.SleepEvent; -import org.opendaylight.openflowjava.protocol.impl.clients.WaitForMessageEvent; -import org.opendaylight.openflowjava.protocol.impl.connection.SwitchConnectionProviderImpl; -import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler; -import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author michal.polkorab - * @author timotej.kubas - */ -public class IntegrationTest { - - private static final Logger LOGGER = LoggerFactory - .getLogger(IntegrationTest.class); - private static int port; - private static final FEATURE_SUPPORT DEFAULT_TLS_SUPPORT = FEATURE_SUPPORT.NOT_SUPPORTED; - private static final int SWITCH_IDLE_TIMEOUT = 2000; - private static final long CONNECTION_TIMEOUT = 2000; - private InetAddress startupAddress; - private MockPlugin mockPlugin; - private SwitchConnectionProviderImpl scpimpl; - private TestingConnConfigImpl configs; - - /** - * @throws Exception - */ - @Before - public void setUp() throws Exception { - LOGGER.debug("\n\nstarting test -------------------------------"); - startupAddress = InetAddress.getLocalHost(); - mockPlugin = new MockPlugin(); - scpimpl = new SwitchConnectionProviderImpl(); - scpimpl.setSwitchConnectionHandler(mockPlugin); - configs = new TestingConnConfigImpl(startupAddress, 0, DEFAULT_TLS_SUPPORT, SWITCH_IDLE_TIMEOUT); - scpimpl.setConfiguration(configs); - scpimpl.startup().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); - TcpHandler server = (TcpHandler) scpimpl.getServerFacade(); - port = server.getPort(); - } - - /** - * @throws Exception - */ - @After - public void tearDown() throws Exception { - Thread.sleep(500); - } - - /** - * Library integration and communication test with handshake - * @throws Exception - */ - @Test - public void testHandshake() throws Exception { - int amountOfCLients = 1; - Stack scenario = ScenarioFactory.createHandshakeScenario(); - ScenarioHandler handler = new ScenarioHandler(scenario); - List clients = createAndStartClient(amountOfCLients, handler); - SimpleClient firstClient = clients.get(0); - firstClient.getScenarioDone().get(); - mockPlugin.shutdown(); - mockPlugin.getFinishedFuture().get(); - } - - /** - * Library integration and communication test with handshake + echo exchange - * @throws Exception - */ - @Test - public void testHandshakeAndEcho() throws Exception { - int amountOfCLients = 1; - Stack scenario = ScenarioFactory.createHandshakeScenario(); - scenario.add(0, new SleepEvent(100)); - scenario.add(0, new SendEvent(ByteBufUtils.hexStringToBytes("04 02 00 08 00 00 00 04"))); - scenario.add(0, new SleepEvent(100)); - scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04"))); - ScenarioHandler handler = new ScenarioHandler(scenario); - List clients = createAndStartClient(amountOfCLients, handler); - SimpleClient firstClient = clients.get(0); - firstClient.getScenarioDone().get(); - mockPlugin.shutdown(); - mockPlugin.getFinishedFuture().get(); - } - - /** - * Library integration and communication test (with virtual machine) - * @throws Exception - */ - //@Test - public void testCommunicationWithVM() throws Exception { - mockPlugin.getFinishedFuture().get(); - } - - /** - * @param amountOfCLients - * @return new clients up and running - * @throws ExecutionException if some client could not start - */ - private List createAndStartClient(int amountOfCLients, ScenarioHandler scenarioHandler) - throws ExecutionException { - List clientsHorde = new ArrayList<>(); - for (int i = 0; i < amountOfCLients; i++) { - LOGGER.debug("startup address in createclient: " + startupAddress.getHostAddress()); - SimpleClient sc = new SimpleClient(startupAddress.getHostAddress(), port); - sc.setSecuredClient(false); - sc.setScenarioHandler(scenarioHandler); - clientsHorde.add(sc); - sc.start(); - } - for (SimpleClient sc : clientsHorde) { - try { - sc.getIsOnlineFuture().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - throw new ExecutionException(e); - } - } - return clientsHorde; - } - -} diff --git a/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/TestingConnConfigImpl.java b/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/ConnectionConfigurationImpl.java similarity index 69% rename from openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/TestingConnConfigImpl.java rename to openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/ConnectionConfigurationImpl.java index 578001d4..17058269 100644 --- a/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/TestingConnConfigImpl.java +++ b/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/ConnectionConfigurationImpl.java @@ -6,35 +6,36 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.openflowjava.protocol.impl.integration; +package org.opendaylight.openflowjava.protocol.it.integration; import java.net.InetAddress; import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration; /** * @author michal.polkorab * */ -public class TestingConnConfigImpl implements ConnectionConfiguration { +public class ConnectionConfigurationImpl implements ConnectionConfiguration { private InetAddress address; private int port; private Object transferProtocol; - private FEATURE_SUPPORT tlsSupport; + private TlsConfiguration tlsConfig; private long switchIdleTimeout; /** - * Creates {@link TestingConnConfigImpl} + * Creates {@link ConnectionConfigurationImpl} * @param address * @param port - * @param tlsSupport + * @param tlsConfig * @param switchIdleTimeout */ - public TestingConnConfigImpl(InetAddress address, int port, FEATURE_SUPPORT tlsSupport, long switchIdleTimeout) { + public ConnectionConfigurationImpl(InetAddress address, int port, TlsConfiguration tlsConfig, long switchIdleTimeout) { this.address = address; this.port = port; - this.tlsSupport = tlsSupport; + this.tlsConfig = tlsConfig; this.switchIdleTimeout = switchIdleTimeout; } @@ -53,11 +54,6 @@ public class TestingConnConfigImpl implements ConnectionConfiguration { return transferProtocol; } - @Override - public FEATURE_SUPPORT getTlsSupport() { - return tlsSupport; - } - @Override public long getSwitchIdleTimeout() { return switchIdleTimeout; @@ -69,4 +65,9 @@ public class TestingConnConfigImpl implements ConnectionConfiguration { return null; } + @Override + public TlsConfiguration getTlsConfiguration() { + return tlsConfig; + } + } diff --git a/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/IntegrationTest.java b/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/IntegrationTest.java new file mode 100644 index 00000000..8a391dfa --- /dev/null +++ b/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/IntegrationTest.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.it.integration; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.Test; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration; +import org.opendaylight.openflowjava.protocol.api.connection.TlsConfigurationImpl; +import org.opendaylight.openflowjava.protocol.impl.clients.ClientEvent; +import org.opendaylight.openflowjava.protocol.impl.clients.ScenarioFactory; +import org.opendaylight.openflowjava.protocol.impl.clients.ScenarioHandler; +import org.opendaylight.openflowjava.protocol.impl.clients.SendEvent; +import org.opendaylight.openflowjava.protocol.impl.clients.SimpleClient; +import org.opendaylight.openflowjava.protocol.impl.clients.SleepEvent; +import org.opendaylight.openflowjava.protocol.impl.clients.WaitForMessageEvent; +import org.opendaylight.openflowjava.protocol.impl.connection.SwitchConnectionProviderImpl; +import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler; +import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author michal.polkorab + * @author timotej.kubas + */ +public class IntegrationTest { + + private static final Logger LOGGER = LoggerFactory + .getLogger(IntegrationTest.class); + + private static int port; + private TlsConfiguration tlsConfiguration ; + private static final int SWITCH_IDLE_TIMEOUT = 2000; + private static final long CONNECTION_TIMEOUT = 2000; + private InetAddress startupAddress; + private MockPlugin mockPlugin; + private SwitchConnectionProviderImpl switchConnectionProvider; + private ConnectionConfigurationImpl connConfig; + + /** + * @param secured true if an encrypted connection should be used + * @throws Exception + */ + public void setUp(boolean secured) throws Exception { + LOGGER.debug("\n starting test -------------------------------"); + + String currentDir = System.getProperty("user.dir"); + LOGGER.debug("Current dir using System:" +currentDir); + startupAddress = InetAddress.getLocalHost(); + if (secured) { + tlsConfiguration = new TlsConfigurationImpl(KeystoreType.JKS, + "../openflow-protocol-impl/src/main/resources/selfSignedSwitch", PathType.PATH, KeystoreType.JKS, + "../openflow-protocol-impl/src/main/resources/selfSignedController", PathType.PATH) ; + connConfig = new ConnectionConfigurationImpl(startupAddress, 0, tlsConfiguration, SWITCH_IDLE_TIMEOUT); + } else { + connConfig = new ConnectionConfigurationImpl(startupAddress, 0, null, SWITCH_IDLE_TIMEOUT); + } + mockPlugin = new MockPlugin(); + + switchConnectionProvider = new SwitchConnectionProviderImpl(); + switchConnectionProvider.setSwitchConnectionHandler(mockPlugin); + switchConnectionProvider.setConfiguration(connConfig); + switchConnectionProvider.startup().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); + TcpHandler tcpHandler = (TcpHandler) switchConnectionProvider.getServerFacade(); + port = tcpHandler.getPort(); + } + + /** + * @throws Exception + */ + @After + public void tearDown() throws Exception { + switchConnectionProvider.close(); + LOGGER.debug("\n ending test -------------------------------"); + + } + + /** + * Library integration and communication test with handshake + * @throws Exception + */ + @Test + public void testHandshake() throws Exception { + setUp(false); + int amountOfCLients = 1; + Stack scenario = ScenarioFactory.createHandshakeScenario(); + ScenarioHandler handler = new ScenarioHandler(scenario); + List clients = createAndStartClient(amountOfCLients, handler, false); + SimpleClient firstClient = clients.get(0); + firstClient.getScenarioDone().get(); + Thread.sleep(1000); + + LOGGER.debug("testHandshake() Finished") ; + } + + /** + * Library integration and communication test with handshake + * @throws Exception + */ + @Test + public void testTlsHandshake() throws Exception { + setUp(true); + int amountOfCLients = 1; + Stack scenario = ScenarioFactory.createHandshakeScenario(); + ScenarioHandler handler = new ScenarioHandler(scenario); + List clients = createAndStartClient(amountOfCLients, handler, true); + SimpleClient firstClient = clients.get(0); + firstClient.getScenarioDone().get(); + Thread.sleep(1000); + + LOGGER.debug("testTlsHandshake() Finished") ; + } + + /** + * Library integration and communication test with handshake + echo exchange + * @throws Exception + */ + @Test + public void testHandshakeAndEcho() throws Exception { + setUp(false); + int amountOfCLients = 1; + Stack scenario = ScenarioFactory.createHandshakeScenario(); + scenario.add(0, new SleepEvent(1000)); + scenario.add(0, new SendEvent(ByteBufUtils.hexStringToBytes("04 02 00 08 00 00 00 04"))); + scenario.add(0, new SleepEvent(1000)); + scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04"))); + ScenarioHandler handler = new ScenarioHandler(scenario); + List clients = createAndStartClient(amountOfCLients, handler, false); + SimpleClient firstClient = clients.get(0); + firstClient.getScenarioDone().get(); + + LOGGER.debug("testHandshakeAndEcho() Finished") ; + } + + /** + * Library integration and communication test with handshake + echo exchange + * @throws Exception + */ + @Test + public void testTlsHandshakeAndEcho() throws Exception { + setUp(true); + int amountOfCLients = 1; + Stack scenario = ScenarioFactory.createHandshakeScenario(); + scenario.add(0, new SleepEvent(1000)); + scenario.add(0, new SendEvent(ByteBufUtils.hexStringToBytes("04 02 00 08 00 00 00 04"))); + scenario.add(0, new SleepEvent(1000)); + scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04"))); + ScenarioHandler handler = new ScenarioHandler(scenario); + List clients = createAndStartClient(amountOfCLients, handler, true); + SimpleClient firstClient = clients.get(0); + firstClient.getScenarioDone().get(); + + LOGGER.debug("testTlsHandshakeAndEcho() Finished") ; + } + + /** + * Library integration and communication test (with virtual machine) + * @throws Exception + */ + //@Test + public void testCommunicationWithVM() throws Exception { + mockPlugin.getFinishedFuture().get(); + } + + /** + * @param amountOfCLients + * @param secured true if encrypted connection should be used + * @return new clients up and running + * @throws ExecutionException if some client could not start + */ + private List createAndStartClient(int amountOfCLients, ScenarioHandler scenarioHandler, + boolean secured) throws ExecutionException { + List clientsHorde = new ArrayList<>(); + for (int i = 0; i < amountOfCLients; i++) { + LOGGER.debug("startup address in createclient: " + startupAddress.getHostAddress()); + SimpleClient sc = new SimpleClient(startupAddress.getHostAddress(), port); + sc.setSecuredClient(secured); + sc.setScenarioHandler(scenarioHandler); + clientsHorde.add(sc); + sc.start(); + } + for (SimpleClient sc : clientsHorde) { + try { + sc.getIsOnlineFuture().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (Exception e) { + LOGGER.error("createAndStartClient: Something borked ... ", e.getMessage(), e); + throw new ExecutionException(e); + } + } + return clientsHorde; + } + +} diff --git a/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/MockPlugin.java b/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/MockPlugin.java similarity index 85% rename from openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/MockPlugin.java rename to openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/MockPlugin.java index e8834a98..b4f69bb0 100644 --- a/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/impl/integration/MockPlugin.java +++ b/openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/MockPlugin.java @@ -6,7 +6,7 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.openflowjava.protocol.impl.integration; +package org.opendaylight.openflowjava.protocol.it.integration; import java.net.InetAddress; import java.util.Arrays; @@ -52,7 +52,7 @@ public class MockPlugin implements OpenflowProtocolListener, SwitchConnectionHan SystemNotificationsListener, ConnectionReadyListener { protected static final Logger LOGGER = LoggerFactory.getLogger(MockPlugin.class); - protected ConnectionAdapter adapter; + protected volatile ConnectionAdapter adapter; private SettableFuture finishedFuture; private int idleCounter = 0; @@ -74,22 +74,25 @@ public class MockPlugin implements OpenflowProtocolListener, SwitchConnectionHan @Override public boolean accept(InetAddress switchAddress) { + LOGGER.debug("MockPlugin.accept(): " + switchAddress.toString()); + return true; } @Override public void onEchoRequestMessage(final EchoRequestMessage notification) { + LOGGER.debug("MockPlugin.onEchoRequestMessage() adapter: "+adapter); new Thread(new Runnable() { @Override public void run() { - LOGGER.debug("EchoRequest message received"); + LOGGER.debug("MockPlugin.onEchoRequestMessage().run() started adapter: "+adapter); EchoReplyInputBuilder replyBuilder = new EchoReplyInputBuilder(); replyBuilder.setVersion((short) 4); replyBuilder.setXid(notification.getXid()); EchoReplyInput echoReplyInput = replyBuilder.build(); adapter.echoReply(echoReplyInput); - LOGGER.debug("EchoReplyInput sent"); - LOGGER.debug("adapter: "+adapter); + LOGGER.debug("adapter.EchoReply(Input) sent : ", echoReplyInput.toString()); + LOGGER.debug("MockPlugin.onEchoRequestMessage().run() finished adapter: "+adapter); } }).start(); } @@ -117,7 +120,7 @@ public class MockPlugin implements OpenflowProtocolListener, SwitchConnectionHan new Thread(new Runnable() { @Override public void run() { - LOGGER.debug("Hello message received"); + LOGGER.debug("MockPlugin.onHelloMessage().run() Hello message received"); HelloInputBuilder hib = new HelloInputBuilder(); hib.setVersion((short) 4); hib.setXid(2L); @@ -127,21 +130,21 @@ public class MockPlugin implements OpenflowProtocolListener, SwitchConnectionHan new Thread(new Runnable() { @Override public void run() { - sendFeaturesReply(); + getSwitchFeatures(); } }).start(); - LOGGER.debug("adapter: "+adapter); } }).start(); + } - protected void sendFeaturesReply() { + protected void getSwitchFeatures() { GetFeaturesInputBuilder featuresBuilder = new GetFeaturesInputBuilder(); featuresBuilder.setVersion((short) 4); featuresBuilder.setXid(3L); GetFeaturesInput featuresInput = featuresBuilder.build(); try { - LOGGER.debug("Going to send featuresRequest"); + LOGGER.debug("Requesting features "); RpcResult rpcResult = adapter.getFeatures( featuresInput).get(2500, TimeUnit.MILLISECONDS); if (rpcResult.isSuccessful()) { @@ -154,23 +157,21 @@ public class MockPlugin implements OpenflowProtocolListener, SwitchConnectionHan + rpcError.getCause().getMessage(), rpcError.getCause()); } } catch (InterruptedException | ExecutionException | TimeoutException e) { - LOGGER.error(e.getMessage(), e); + LOGGER.error("getSwitchFeatures() exception caught: ", e.getMessage(), e); } - LOGGER.debug("After FeaturesReply message"); } protected void shutdown() { - LOGGER.debug("adapter: "+adapter); try { - LOGGER.debug("mockPlugin: "+System.identityHashCode(this)); + LOGGER.debug("MockPlugin.shutdown() sleeping 5... : "+System.identityHashCode(this)); Thread.sleep(500); if (adapter != null) { Future disconnect = adapter.disconnect(); disconnect.get(); - LOGGER.debug("Disconnected"); + LOGGER.debug("MockPlugin.shutdown() Disconnected"); } } catch (Exception e) { - LOGGER.error(e.getMessage(), e); + LOGGER.error("MockPlugin.shutdown() exception caught: ", e.getMessage(), e); } finishedFuture.set(null); } @@ -196,14 +197,13 @@ public class MockPlugin implements OpenflowProtocolListener, SwitchConnectionHan @Override public void onPortStatusMessage(PortStatusMessage notification) { - LOGGER.debug("PortStatus message received"); + LOGGER.debug("MockPlugin.onPortStatusMessage() message received"); } @Override public void onDisconnectEvent(DisconnectEvent notification) { - LOGGER.debug("disconnection ocured: "+notification.getInfo()); - LOGGER.debug("adapter: "+adapter); + LOGGER.debug("disconnection occured: "+notification.getInfo()); } /** @@ -215,7 +215,7 @@ public class MockPlugin implements OpenflowProtocolListener, SwitchConnectionHan @Override public void onSwitchIdleEvent(SwitchIdleEvent notification) { - LOGGER.debug("switch status: "+notification.getInfo()); + LOGGER.debug("MockPlugin.onSwitchIdleEvent() switch status: "+notification.getInfo()); idleCounter ++; } @@ -228,7 +228,7 @@ public class MockPlugin implements OpenflowProtocolListener, SwitchConnectionHan @Override public void onConnectionReady() { - LOGGER.debug("connection ready notification arrived"); + LOGGER.trace("MockPlugin().onConnectionReady()"); } diff --git a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslContextFactory.java b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslContextFactory.java new file mode 100644 index 00000000..c1199c1e --- /dev/null +++ b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslContextFactory.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.clients; + +import java.security.KeyStore; +import java.security.Security; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; + +/** + * Class for setting up TLS connection. + * + * @author michal.polkorab + */ +public final class ClientSslContextFactory { + + + // "TLS" - supports some version of TLS + // Use "TLSv1", "TLSv1.1", "TLSv1.2" for specific TLS version + private static final String PROTOCOL = "TLS"; + private static final SSLContext CLIENT_CONTEXT; + + static { + String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); + if (algorithm == null) { + algorithm = "SunX509"; + } + + SSLContext clientContext; + try { + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(ClientSslKeyStore.asInputStream(), + ClientSslKeyStore.getKeyStorePassword()); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); + kmf.init(ks, ClientSslKeyStore.getCertificatePassword()); + + KeyStore ts = KeyStore.getInstance("JKS"); + ts.load(ClientSslTrustStore.asInputStream(), + ClientSslTrustStore.getKeyStorePassword()); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); + tmf.init(ts); + + clientContext = SSLContext.getInstance(PROTOCOL); + clientContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + } catch (Exception e) { + throw new Error( + "Failed to initialize the client-side SSLContext", e); + } + + CLIENT_CONTEXT = clientContext; + } + + /** + * @return cliencontext + */ + public static SSLContext getClientContext() { + return CLIENT_CONTEXT; + } +} \ No newline at end of file diff --git a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslKeyStore.java b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslKeyStore.java new file mode 100644 index 00000000..279072fa --- /dev/null +++ b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslKeyStore.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.clients; + +import java.io.InputStream; + +/** + * Class for storing keys + * + * @author michal.polkorab + */ +public final class ClientSslKeyStore { + + private static final String filename = "/selfSignedSwitch"; + + /** + * InputStream instance of key + * + * @return key as InputStream + */ + public static InputStream asInputStream() { + InputStream in = ClientSslKeyStore.class.getResourceAsStream(filename); + if (in == null) { + throw new IllegalStateException("KeyStore file not found: " + filename); + } + return in; + } + + /** + * @return certificate password as char[] + */ + public static char[] getCertificatePassword() { + return "opendaylight".toCharArray(); + } + + /** + * @return KeyStore password as char[] + */ + public static char[] getKeyStorePassword() { + return "opendaylight".toCharArray(); + } +} \ No newline at end of file diff --git a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslTrustStore.java b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslTrustStore.java new file mode 100644 index 00000000..1379c8dd --- /dev/null +++ b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/ClientSslTrustStore.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowjava.protocol.impl.clients; + +import java.io.InputStream; + +/** + * Class for storing keys + * + * @author michal.polkorab + */ +public final class ClientSslTrustStore { + + private static final String filename = "/selfSignedController"; + + /** + * InputStream instance of key + * + * @return key as InputStream + */ + public static InputStream asInputStream() { + InputStream in = ClientSslTrustStore.class.getResourceAsStream(filename); + if (in == null) { + throw new IllegalStateException("KeyStore file not found: " + filename); + } + return in; + } + + /** + * @return certificate password as char[] + */ + public static char[] getCertificatePassword() { + return "opendaylight".toCharArray(); + } + + /** + * @return KeyStore password as char[] + */ + public static char[] getKeyStorePassword() { + return "opendaylight".toCharArray(); + } +} \ No newline at end of file diff --git a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/SimpleClientInitializer.java b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/SimpleClientInitializer.java index bd9a911b..d557c49b 100644 --- a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/SimpleClientInitializer.java +++ b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/SimpleClientInitializer.java @@ -16,8 +16,6 @@ import io.netty.handler.ssl.SslHandler; import javax.net.ssl.SSLEngine; -import org.opendaylight.openflowjava.protocol.impl.core.SslContextFactory; - import com.google.common.util.concurrent.SettableFuture; /** Initializes secured {@link SimpleClient} pipeline @@ -43,7 +41,7 @@ public class SimpleClientInitializer extends ChannelInitializer { public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (secured) { - SSLEngine engine = SslContextFactory.getClientContext() + SSLEngine engine = ClientSslContextFactory.getClientContext() .createSSLEngine(); engine.setUseClientMode(true); pipeline.addLast("ssl", new SslHandler(engine)); diff --git a/simple-client/src/main/resources/selfSignedController b/simple-client/src/main/resources/selfSignedController new file mode 100644 index 0000000000000000000000000000000000000000..9f4e421dad53beae6ce49b5354b57be87de93563 GIT binary patch literal 1351 zcmezO_TO6u1_mY|W&~rA;?$h9;>`5C)Rg4>ypp2)oSf7mprl*D`44}9biY9pW48ex z8<#d4BMYMzlOQ7_D+5atW4Yvn%f|g`Cp1&TuWyQzzMQcv^XY+v%}dX%-6&Vdy42}Y zW&Md6=BGC+9-G9G-f{T*-v=}9R>p2pd60GZRFmngy_`j5xr*LNt4#OT)!F5VskSSe zdwe>u_~8G80l5sbjm7epvc_L;@i-Iw+^oUKvF`Kp-8T|FC(dQu?)x$?N}qQz--BbB zp09UpJ!5X-v_RzW*XC;t(I)m87b{L(`qp-Q|KDp@r>L;9zAgZA?x_I z9~(bO`MEFQVIThZiZQ_-Kd;Z$Hmz)N^9l zLmRQG?vR>ZjR%X@$!Tw1Ryr|naXt4hMbo5@zmuvMRjkh}`M7UI;DpW<&G#QhJ)O@s zsXHyMp*mDGh0(|Q-+50h=EfEVrp5*#kEWuH-;QN$_%rE%an3c{^`%DKGD@no-cR2x zX;KoCZg-e-@8r?{{SLNVFH{$#8NIn~*cY&fgDZWf;ntrHj~qBBW^9@D=Bz~iz*@?WHo-ph3UQE;v?Vjnn^Z3&ao!}p~`kPp`aVbeTkog-jGV z=kq^seAlyVjs?S^)VkbSU|_fHyj-E(HaWk5Kkjds!bbBM9(xy7N3467aZAQq?4-8b MR!6VGPUY390E5dNe*gdg literal 0 HcmV?d00001 diff --git a/simple-client/src/main/resources/selfSignedSwitch b/simple-client/src/main/resources/selfSignedSwitch new file mode 100644 index 0000000000000000000000000000000000000000..645ac44243d3a8af51fa012f7879d245d05c1054 GIT binary patch literal 1348 zcmezO_TO6u1_mY|W&~q_;?$h9;>`5C)Rf}#%#!2`poCk&^&f|T^aO(@#vTJcHZE;8 zMixdbCP79z z{vL2FH)cr72==#S)LUgc(PHjlri(wOALuim?f*=E<7+PNT*lcA@mu-6lmw(yh4<-L}h-Y&+z{I!>H?Z#{ZQ!{7(h^Pn5o=`((rK^)eF|8BY8l9%L)92pnUq z5qhQumJAHc$p%f#@jxuQfSHMriHXIvf&YmCHygWFo5wi|7G_okgT@9!ZUas>=1>+k zVWwbjLs0`^5QjsUC%+&yFD0=uCo?^x1SZUmU6>2IFgJE#W>jGVIdNV?69Y2?GebiI zBO`+-FxS$+1j-!@PHbY_0ZiyRuz+I(a^#sB8yWuA2RF)=3TX!2_nM>k=E?JKg4=^^ z-n%dyma}iz7O0l#8tb4G_&d_JH{#d+qhEI!d^66fYKrV-7ByE+kQ;?hjsY#V=I=4^0WMI{&xAO++ilu5aB4XiALW_Kd;kHysq{B zlM=J!+>0KJ$C*SKrY8jSiz;)U*)(Zq)1ucc+#e!jzJi?g{o#VvYqM?do!+xL#%xFU z&dMq4cmJ|_)$}vmhufCDDLpVUyl>Z)NdISr>;jDqTRg=Im0$R1hzV~$&uP?iV%b9* zv8wKnnqG|ui`U6%Z(de9F>i4__b)}$q>sOosu)$Q&n)@4Z$;pQ&K1q~A4WZ$&o-$$ zEv}(DR5gXs$NJxSPc7!gRtAtewrlO0Rieb17@)L6(p79twcpl?#C@I554~EPbX71u zXj7qobZC$7{mwmB+n?xVA1pbf{Ih^p{C3LK>~A|SvX(1(l`mOPwn4?{^H!~D%kwuU zp6UMdurtVJ$FDU{j@`=9tc{kvCOd)GtJS)vX7~U1e-GbY{(AC#)8lfpCs;3g|8BYJ zVnqXa16g32mgQp+V-fki@~qY6YpgvUy*{(v?mKM|ZLgw$k|UV)84ProL@H7mGR;I& zb1vSVr#Pp#c-;qWu?I{dz73Wqi_+Zp9Q~<%o^R5#J)YMMmR^YWQ7f+gl<8W)zE1Om KmC%%2<4FL78zvqA literal 0 HcmV?d00001 -- 2.36.6