Skip to content

Commit

Permalink
Add Authentication
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Kittel <ckittel@gmx.de>
  • Loading branch information
EvilPingu committed Jan 3, 2024
1 parent 8a0361f commit f3f9fa5
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 5 deletions.
20 changes: 19 additions & 1 deletion bundles/org.openhab.binding.homematic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,22 @@ When the option "Restricted access" is used, some ports have to be added to the
2000;
2001;
2010;
8181;
8701;
9292;
```

Also the IP of the device running openHAB has to be set to the list of "IP addresses for restricted access".

Also under `Home page > Settings > Control panel` with the menu `Security` the option `Authentication` has to be disabled as the binding does not support the configuration of `username` and `password`for the XML-RPC API.
Also under `Home page > Settings > Control panel` with the menu `Security` the option `Authentication` has to be disabled if the option 'useAuthentication' is not set. This option may to be enabled
if the option 'useAuthentication' is set and BIN-RPC is not used. In this case a user and a password must be created. This can be done under `Home page > Settings > Control panel` with the menu `User management`. The new user should have the following configuration:

- User name - button for login: No
- Permission level: User
- Expert mode not visible: Yes
- Automatically confirm the device message: Yes

The user and password must then be entered in the settings 'userName' and 'password'.

If this is not done the binding will not be able to connect to the CCU and the CCU Thing will stay uninitialized and sets a timeout exception:

Expand Down Expand Up @@ -179,6 +188,15 @@ Due to the factory reset, the device will also be unpaired from the gateway, eve
If a large number of devices are connected to the gateway, the default buffersize of 2048 kB may be too small for communication with the gateway.
In this case, e.g. the discovery fails.
With this setting the buffer size can be adjusted. The value is specified in kB.

- **useAuthentication**
Username and password are send to the gateway to authenticate the access to the gateway.

- **username**
Username for Authentication to the gateway.

- **password**
Password for Authentication to the gateway.

The syntax for a bridge is:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project

Check failure on line 2 in bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/common/AuthenticationHandler.java

View workflow job for this annotation

GitHub Actions / Build (Java 17, ubuntu-22.04)

Header line doesn't match pattern ^ \* Copyright \(c\) 2010-2024 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.homematic.internal.common;

import java.net.URI;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Authentication;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.util.BasicAuthentication;

/**
* Handles the authentication to Homematic server.
*
* @author Christian Kittel
*/
@NonNullByDefault
public class AuthenticationHandler {

private final HomematicConfig config;
private final HttpClient httpClient;

public AuthenticationHandler(HomematicConfig config, HttpClient httpClient) {
this.config = config;
this.httpClient = httpClient;
}

/**
* Add or remove the basic auth credetials to the AuthenticationStore if needed.
*/
public synchronized void updateAuthenticationInformation(final URI uri) {
final AuthenticationStore authStore = httpClient.getAuthenticationStore();

Authentication findAuthentication = authStore.findAuthentication("Basic", uri, Authentication.ANY_REALM);

if (config.getUseAuthentication()) {
if (findAuthentication == null) {
if (config.getPassword() == null || config.getUserName() == null) {
throw new IllegalStateException("Username or password missing");
}
authStore.addAuthentication(new BasicAuthentication(uri, Authentication.ANY_REALM, config.getUserName(),
config.getPassword()));
}
} else if (findAuthentication != null) {
authStore.removeAuthentication(findAuthentication);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ public class HomematicConfig {
private HmGatewayInfo gatewayInfo;
private int callbackRegTimeout;

private boolean useAuthentication;
private String userName;
private String password;

/**
* Returns the Homematic gateway address.
*/
Expand Down Expand Up @@ -272,6 +276,48 @@ public int getRpcPort(HmChannel channel) {
return getRpcPort(channel.getDevice().getHmInterface());
}

/**
* Returns true if authorization for the gateway has to be used; otherwise false
*/
public boolean getUseAuthentication() {
return useAuthentication;
}

/**
* Sets if authorization for the gateway has to be used
*/
public void setUseAuthentication(Boolean useAuthentication) {
this.useAuthentication = useAuthentication;
}

/**
* Returns the user name for authorize against the gateway
*/
public String getUserName() {
return userName;
}

/**
* Sets the user name for authorize against the gateway
*/
public void setUserName(String userName) {
this.userName = userName;
}

/**
* Returns the password for authorize against the gateway
*/
public String getPassword() {
return password;
}

/**
* Sets the password for authorize against the gateway
*/
public void setPassword(String password) {
this.password = password;
}

/**
* Returns the Homematic gateway port of the interfaces.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
package org.openhab.binding.homematic.internal.communicator;

import static org.openhab.binding.homematic.internal.HomematicBindingConstants.*;
import static org.openhab.binding.homematic.internal.HomematicBindingConstants.GATEWAY_POOL_NAME;
import static org.openhab.binding.homematic.internal.misc.HomematicConstants.*;

import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
Expand All @@ -26,6 +28,7 @@
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpHeader;
import org.openhab.binding.homematic.internal.common.AuthenticationHandler;
import org.openhab.binding.homematic.internal.common.HomematicConfig;
import org.openhab.binding.homematic.internal.communicator.client.UnknownParameterSetException;
import org.openhab.binding.homematic.internal.communicator.client.UnknownRpcFailureException;
Expand Down Expand Up @@ -61,9 +64,16 @@ public class CcuGateway extends AbstractHomematicGateway {
private XStream xStream = new XStream(new StaxDriver());

protected CcuGateway(String id, HomematicConfig config, HomematicGatewayAdapter gatewayAdapter,
HttpClient httpClient) {
HttpClient httpClient) throws IOException {
super(id, config, gatewayAdapter, httpClient);

try {
new AuthenticationHandler(config, httpClient)
.updateAuthenticationInformation(new URI(config.getTclRegaUrl()));
} catch (URISyntaxException e) {
throw new IOException(e);
}

xStream.allowTypesByWildcard(new String[] { HmDevice.class.getPackageName() + ".**" });
xStream.setClassLoader(CcuGateway.class.getClassLoader());
xStream.autodetectAnnotations(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.BytesContentProvider;
import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.http.HttpHeader;
import org.openhab.binding.homematic.internal.common.AuthenticationHandler;
import org.openhab.binding.homematic.internal.common.HomematicConfig;
import org.openhab.binding.homematic.internal.communicator.message.RpcRequest;
import org.openhab.binding.homematic.internal.communicator.message.XmlRpcRequest;
Expand All @@ -43,10 +47,12 @@
public class XmlRpcClient extends RpcClient<String> {
private final Logger logger = LoggerFactory.getLogger(XmlRpcClient.class);
private HttpClient httpClient;
private @NonNull AuthenticationHandler authenticationHandler;

public XmlRpcClient(HomematicConfig config, HttpClient httpClient) throws IOException {
super(config);
this.httpClient = httpClient;
this.authenticationHandler = new AuthenticationHandler(config, httpClient);
}

@Override
Expand Down Expand Up @@ -103,8 +109,13 @@ private byte[] send(int port, RpcRequest<String> request) throws IOException {
if (port == config.getGroupPort()) {
url += "/groups";
}
Request req = httpClient.POST(url).content(content).timeout(config.getTimeout(), TimeUnit.SECONDS)
final URI uri = new URI(url);

authenticationHandler.updateAuthenticationInformation(uri);

Request req = httpClient.POST(uri).content(content).timeout(config.getTimeout(), TimeUnit.SECONDS)
.header(HttpHeader.CONTENT_TYPE, "text/xml;charset=" + config.getEncoding());

FutureResponseListener listener = new FutureResponseListener(req, config.getBufferSize() * 1024);
req.send(listener);
ContentResponse response = listener.get(config.getTimeout(), TimeUnit.SECONDS);
Expand All @@ -116,7 +127,8 @@ private byte[] send(int port, RpcRequest<String> request) throws IOException {
String result = new String(ret, config.getEncoding());
logger.trace("Client XmlRpcResponse (port {}):\n{}", port, result);
}
} catch (InterruptedException | ExecutionException | TimeoutException | IllegalArgumentException e) {
} catch (InterruptedException | ExecutionException | TimeoutException | IllegalArgumentException
| URISyntaxException e) {
throw new IOException(e);
}
return ret;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ thing-type.config.homematic.bridge.wiredPort.label = Wired Port
thing-type.config.homematic.bridge.wiredPort.description = The port number of the HS485 daemon
thing-type.config.homematic.bridge.xmlCallbackPort.label = XML-RPC Callback Port
thing-type.config.homematic.bridge.xmlCallbackPort.description = Callback port of the binding's XML-RPC server. If no value is specified, xmlCallbackPort starts with 9125 and counts up
thing-type.config.homematic.bridge.password.label = Password for accessing the gateway
thing-type.config.homematic.bridge.password.description = Password for accessing the gateway. Is required if the "useAuthentication" is true
thing-type.config.homematic.bridge.username.label = Username for accessing the gateway
thing-type.config.homematic.bridge.username.description = Username for accessing the gateway. Is required if the "useAuthentication" is true
thing-type.config.homematic.bridge.useAuthentication.label = Uses credentials for accessing the Homematic gateway
thing-type.config.homematic.bridge.useAuthentication.description = Credentials are used for accessing the Homematic gateway. If true 'username' and 'password' are required

# channel types

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ thing-type.config.homematic.bridge.wiredPort.label = Wired Port
thing-type.config.homematic.bridge.wiredPort.description = Die Portnummer des HS485-Dienstes
thing-type.config.homematic.bridge.xmlCallbackPort.label = XML-RPC Callback Port
thing-type.config.homematic.bridge.xmlCallbackPort.description = Callback-Port des XML-RPC-Servers. Wenn kein Wert angegeben ist, startet xmlCallbackPort mit 9125 und zählt hoch
thing-type.config.homematic.bridge.password.label = Password für Zugriff auf das Gateway
thing-type.config.homematic.bridge.password.description = Das Password welches für Zugriff auf das Gateway benutzt wird. Wird benötigt, wenn "useAuthentication" gesetzt ist
thing-type.config.homematic.bridge.username.label = Benutzername für Zugriff auf das Gateway
thing-type.config.homematic.bridge.username.description = Der Benutzername welcher für Zugriff auf das Gateway benutzt wird. Wird benötigt, wenn "useAuthentication" gesetzt ist
thing-type.config.homematic.bridge.useAuthentication.label = Nutzername/ Password für Zugriff auf Homematic gateway nutzen
thing-type.config.homematic.bridge.useAuthentication.description = Nutzername und Password werden benutzt, wenn auf das Homematic gateway zugegriffen wird. Wenn gesetzt müssen Nutzername und Passwort angegeben werden

# channel types

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,21 @@
<default>2048</default>
<advanced>true</advanced>
</parameter>
<parameter name="useAuthentication" type="boolean">
<label>Use authentication to access the gateway</label>
<description>If set to true, username and passwort is required.</description>
<advanced>true</advanced>
<default>false</default>
</parameter>
<parameter name="userName" type="text">
<label>User name for accessing the gateway</label>
<advanced>true</advanced>
</parameter>
<parameter name="password" type="text">
<label>Password for accessing the gateway</label>
<advanced>true</advanced>
<context>password</context>
</parameter>
</config-description>
</bridge-type>

Expand Down

0 comments on commit f3f9fa5

Please sign in to comment.