Skip to content

Commit

Permalink
[ihc] Support for TLSv1.2 (openhab#10856)
Browse files Browse the repository at this point in the history
* [ihc] Support for TLSv1.2

So far IHC controller have supported only TLSv1. As TLSv1 is already
deprecated and upcoming IHC controller FW version will introduce support
for TLSv1.2.

This change introduce TLSv1.2 support for the binding. TLS version is
selectable to be backward compatible for older controller versions.

Communication error handling is also improved e.g. because of wrong
password or if Java environment doesn't support required TLS version.
When fatal communication error occurs, binding will not hammer
controller with retries as it need user actions.

Signed-off-by: Pauli Anttila <pauli.anttila@gmail.com>

* [ihc] Introduced auto mode and other improvements

Signed-off-by: Pauli Anttila <pauli.anttila@gmail.com>

* [ihc] introduced default constant

Signed-off-by: Pauli Anttila <pauli.anttila@gmail.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>
  • Loading branch information
paulianttila authored and lucacalcaterra committed Jul 26, 2021
1 parent 55fab95 commit 37759cf
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 73 deletions.
19 changes: 10 additions & 9 deletions bundles/org.openhab.binding.ihc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ This binding supports one ThingType: `controller`.

The `controller` Thing has the following configuration parameters:

| Parameter | Description | Required | Default value |
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------|----------|---------------|
| hostname | Network/IP address of the IHC / ELKO controller without https prefix, but can contain TCP port if default port is not used. | yes | |
| username | User name to login to the IHC / ELKO controller. | yes | |
| password | Password to login to the IHC / ELKO controller. | yes | |
| timeout | Timeout in milliseconds to communicate to IHC / ELKO controller. | no | 5000 |
| loadProjectFile | Load project file from controller. | no | true |
| createChannelsAutomatically | Create channels automatically from project file. Project file loading parameter should be enabled as well. | no | true |
| Parameter | Description | Required | Default value |
|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------|
| hostname | Network/IP address of the IHC / ELKO controller without https prefix, but can contain TCP port if default port is not used. | yes | |
| username | User name to login to the IHC / ELKO controller. | yes | |
| password | Password to login to the IHC / ELKO controller. | yes | |
| timeout | Timeout in milliseconds to communicate to IHC / ELKO controller. | no | 5000 |
| loadProjectFile | Load project file from controller. | no | true |
| createChannelsAutomatically | Create channels automatically from project file. Project file loading parameter should be enabled as well. | no | true |
| tlsVersion | TLS version used for controller communication. Choose `TLSv1` for older firmware versions and `TLSv1.2` for never versions (since fall 2021). `AUTO` mode try to recognize correct version. | no | TLSv1 |


## Channels
Expand Down Expand Up @@ -148,7 +149,7 @@ Will send TOGGLE (ON/OFF) command to Dimmer test item when short button press is
### example.things

```xtend
ihc:controller:elko [ hostname="192.168.1.2", username="openhab", password="secret", timeout=5000, loadProjectFile=true, createChannelsAutomatically=false ] {
ihc:controller:elko [ hostname="192.168.1.2", username="openhab", password="secret", timeout=5000, loadProjectFile=true, createChannelsAutomatically=false, tlsVersion="TLSv1" ] {
Channels:
Type switch : my_test_switch "My Test Switch" [ resourceId=3988827 ]
Type contact : my_test_contact "My Test Contact" [ resourceId=3988827 ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ public class IhcConfiguration {
public int timeout;
public boolean loadProjectFile;
public boolean createChannelsAutomatically;
public String tlsVersion;

@Override
public String toString() {
return "[" + "hostname=" + hostname + ", username=" + username + ", password=******" + ", timeout=" + timeout
+ ", loadProjectFile=" + loadProjectFile + ", createChannelsAutomatically="
+ createChannelsAutomatically + "]";
+ createChannelsAutomatically + ", tlsVersion=" + tlsVersion + "]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.openhab.binding.ihc.internal.ws.datatypes.WSTimeManagerSettings;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcFatalExecption;
import org.openhab.binding.ihc.internal.ws.projectfile.IhcEnumValue;
import org.openhab.binding.ihc.internal.ws.projectfile.ProjectFileUtils;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
Expand Down Expand Up @@ -534,7 +535,7 @@ private void connect() throws IhcExecption {
setConnectingState(true);
logger.debug("Connecting to IHC / ELKO LS controller [hostname='{}', username='{}'].", conf.hostname,
conf.username);
ihc = new IhcClient(conf.hostname, conf.username, conf.password, conf.timeout);
ihc = new IhcClient(conf.hostname, conf.username, conf.password, conf.timeout, conf.tlsVersion);
ihc.openConnection();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Initializing communication to the IHC / ELKO controller");
Expand Down Expand Up @@ -883,6 +884,11 @@ private void reconnectCheck() {
}
connect();
setReconnectRequest(false);
} catch (IhcFatalExecption e) {
logger.warn("Can't open connection to controller {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
setReconnectRequest(false);
return;
} catch (IhcExecption e) {
logger.debug("Can't open connection to controller {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.openhab.binding.ihc.internal.ws.datatypes.WSSystemInfo;
import org.openhab.binding.ihc.internal.ws.datatypes.WSTimeManagerSettings;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcFatalExecption;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcTlsExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.binding.ihc.internal.ws.services.IhcAirlinkManagementService;
Expand All @@ -60,6 +62,10 @@ public enum ConnectionState {
CONNECTED
}

public static final String TLS_VER_AUTO = "AUTO";
public static final String TLS_VER_V1 = "TLSv1";
public static final String TLS_VER_V1_2 = "TLSv1.2";

public static final String CONTROLLER_STATE_READY = "text.ctrl.state.ready";
public static final String CONTROLLER_STATE_INITIALIZE = "text.ctrl.state.initialize";

Expand Down Expand Up @@ -88,6 +94,7 @@ public enum ConnectionState {
private String username;
private String password;
private String host;
private String tlsVersion;

/** Timeout in milliseconds */
private int timeout;
Expand All @@ -96,14 +103,15 @@ public enum ConnectionState {
private List<IhcEventListener> eventListeners = new ArrayList<>();

public IhcClient(String host, String username, String password) {
this(host, username, password, 5000);
this(host, username, password, 5000, TLS_VER_V1);
}

public IhcClient(String host, String username, String password, int timeout) {
public IhcClient(String host, String username, String password, int timeout, String tlsVersion) {
this.host = host;
this.username = username;
this.password = password;
this.timeout = timeout;
this.tlsVersion = tlsVersion;
}

public synchronized ConnectionState getConnectionState() {
Expand Down Expand Up @@ -168,10 +176,23 @@ public void closeConnection() throws IhcExecption {
* @throws IhcExecption
*/
public void openConnection() throws IhcExecption {
logger.debug("Opening connection");
if (TLS_VER_AUTO.equalsIgnoreCase(tlsVersion)) {
try {
openConnection(TLS_VER_V1);
} catch (IhcTlsExecption e) {
logger.debug("Connection failed with TLS {}, trying with TLS {}", TLS_VER_V1, TLS_VER_V1_2);
openConnection(TLS_VER_V1_2);
}
} else {
openConnection(tlsVersion);
}
}

private void openConnection(String tlsVersion) throws IhcExecption {
logger.debug("Opening connection with TLS version {}", tlsVersion);

setConnectionState(ConnectionState.CONNECTING);
ihcConnectionPool = new IhcConnectionPool();
ihcConnectionPool = new IhcConnectionPool(tlsVersion);
authenticationService = new IhcAuthenticationService(host, timeout, ihcConnectionPool);
WSLoginResult loginResult = authenticationService.authenticate(username, password, "treeview");

Expand All @@ -181,18 +202,18 @@ public void openConnection() throws IhcExecption {
setConnectionState(ConnectionState.DISCONNECTED);

if (loginResult.isLoginFailedDueToAccountInvalid()) {
throw new IhcExecption("login failed because of invalid account");
throw new IhcFatalExecption("login failed because of invalid account");
}

if (loginResult.isLoginFailedDueToConnectionRestrictions()) {
throw new IhcExecption("login failed because of connection restrictions");
throw new IhcFatalExecption("login failed because of connection restrictions");
}

if (loginResult.isLoginFailedDueToInsufficientUserRights()) {
throw new IhcExecption("login failed because of insufficient user rights");
throw new IhcFatalExecption("login failed because of insufficient user rights");
}

throw new IhcExecption("login failed because of unknown reason");
throw new IhcFatalExecption("login failed because of unknown reason");
}

logger.debug("Connection successfully opened");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws.exeptions;

/**
* Exception for handling fatal communication errors to controller.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcFatalExecption extends IhcExecption {

private static final long serialVersionUID = -8107948791816894352L;

public IhcFatalExecption() {
}

public IhcFatalExecption(String message) {
super(message);
}

public IhcFatalExecption(String message, Throwable cause) {
super(message, cause);
}

public IhcFatalExecption(Throwable cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws.exeptions;

/**
* Exception for handling TLS communication errors to controller.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcTlsExecption extends IhcFatalExecption {

private static final long serialVersionUID = -1366186910684967044L;

public IhcTlsExecption() {
}

public IhcTlsExecption(String message) {
super(message);
}

public IhcTlsExecption(String message, Throwable cause) {
super(message, cause);
}

public IhcTlsExecption(Throwable cause) {
super(cause);
}
}
Loading

0 comments on commit 37759cf

Please sign in to comment.