mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 23:22:02 +01:00
[http] add pre-emptive basic authentication and fix header handling (#9584)
* add preemptive basic authentication Signed-off-by: Jan N. Klug <jan.n.klug@rub.de> * improve header handling Signed-off-by: Jan N. Klug <jan.n.klug@rub.de> * Update bundles/org.openhab.binding.http/README.md Co-authored-by: t2000 <t2000@users.noreply.github.com> Co-authored-by: t2000 <t2000@users.noreply.github.com>
This commit is contained in:
parent
1b5df97af5
commit
eaae9780ea
@ -18,14 +18,19 @@ It can be extended with different channels.
|
||||
| `delay` | no | 0 | Delay between two requests in ms (advanced parameter). |
|
||||
| `username` | yes | - | Username for authentication (advanced parameter). |
|
||||
| `password` | yes | - | Password for authentication (advanced parameter). |
|
||||
| `authMode` | no | BASIC | Authentication mode, `BASIC` or `DIGEST` (advanced parameter). |
|
||||
| `authMode` | no | BASIC | Authentication mode, `BASIC`, `BASIC_PREEMPTIVE` or `DIGEST` (advanced parameter). |
|
||||
| `commandMethod` | no | GET | Method used for sending commands `GET`, `PUT`, `POST`. |
|
||||
| `contentType` | yes | - | MIME content-type of the command requests. Only used for `PUT` and `POST`. |
|
||||
| `encoding` | yes | - | Encoding to be used if no encoding is found in responses (advanced parameter). |
|
||||
| `headers` | yes | - | Additional headers that are sent along with the request. Format is "header=value".|
|
||||
| `ignoreSSLErrors` | no | false | If set to true ignores invalid SSL certificate errors. This is potentially dangerous.|
|
||||
|
||||
*Note:* optional "no" means that you have to configure a value unless a default is provided and you are ok with that setting.
|
||||
*Note:* Optional "no" means that you have to configure a value unless a default is provided and you are ok with that setting.
|
||||
|
||||
*Note:* The `BASIC_PREEMPTIVE` mode adds basic authentication headers even if the server did not request authentication.
|
||||
This is dangerous and might be misused.
|
||||
The option exists to be able to authenticate when the server is not sending the proper 401/Unauthorized code.
|
||||
Authentication might fail if redirections are involved as headers are stripper prior to redirection.
|
||||
|
||||
*Note:* If you rate-limit requests by using the `delay` parameter you have to make sure that the time between two refreshes is larger than the time needed for one refresh cycle.
|
||||
|
||||
|
@ -14,10 +14,7 @@ package org.openhab.binding.http.internal;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
@ -85,7 +82,6 @@ public class HttpThingHandler extends BaseThingHandler {
|
||||
private final Map<String, RefreshingUrlCache> urlHandlers = new HashMap<>();
|
||||
private final Map<ChannelUID, ItemValueConverter> channels = new HashMap<>();
|
||||
private final Map<ChannelUID, String> channelUrls = new HashMap<>();
|
||||
private @Nullable Authentication authentication;
|
||||
|
||||
public HttpThingHandler(Thing thing, HttpClientProvider httpClientProvider,
|
||||
ValueTransformationProvider valueTransformationProvider,
|
||||
@ -139,6 +135,7 @@ public class HttpThingHandler extends BaseThingHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
// check SSL handling and initialize client
|
||||
if (config.ignoreSSLErrors) {
|
||||
logger.info("Using the insecure client for thing '{}'.", thing.getUID());
|
||||
httpClient = httpClientProvider.getInsecureClient();
|
||||
@ -158,29 +155,34 @@ public class HttpThingHandler extends BaseThingHandler {
|
||||
channelCount, thing.getUID(), config.delay, config.refresh);
|
||||
}
|
||||
|
||||
authentication = null;
|
||||
// remove empty headers
|
||||
config.headers.removeIf(String::isBlank);
|
||||
|
||||
// configure authentication
|
||||
if (!config.username.isEmpty()) {
|
||||
try {
|
||||
AuthenticationStore authStore = httpClient.getAuthenticationStore();
|
||||
URI uri = new URI(config.baseURL);
|
||||
switch (config.authMode) {
|
||||
case BASIC_PREEMPTIVE:
|
||||
config.headers.add("Authorization=Basic " + Base64.getEncoder()
|
||||
.encodeToString((config.username + ":" + config.password).getBytes()));
|
||||
logger.debug("Preemptive Basic Authentication configured for thing '{}'", thing.getUID());
|
||||
break;
|
||||
case BASIC:
|
||||
authentication = new BasicAuthentication(uri, Authentication.ANY_REALM, config.username,
|
||||
config.password);
|
||||
authStore.addAuthentication(new BasicAuthentication(uri, Authentication.ANY_REALM,
|
||||
config.username, config.password));
|
||||
logger.debug("Basic Authentication configured for thing '{}'", thing.getUID());
|
||||
break;
|
||||
case DIGEST:
|
||||
authentication = new DigestAuthentication(uri, Authentication.ANY_REALM, config.username,
|
||||
config.password);
|
||||
authStore.addAuthentication(new DigestAuthentication(uri, Authentication.ANY_REALM,
|
||||
config.username, config.password));
|
||||
logger.debug("Digest Authentication configured for thing '{}'", thing.getUID());
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown authentication method '{}' for thing '{}'", config.authMode,
|
||||
thing.getUID());
|
||||
}
|
||||
if (authentication != null) {
|
||||
AuthenticationStore authStore = httpClient.getAuthenticationStore();
|
||||
authStore.addAuthentication(authentication);
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"failed to create authentication: baseUrl is invalid");
|
||||
@ -189,6 +191,7 @@ public class HttpThingHandler extends BaseThingHandler {
|
||||
logger.debug("No authentication configured for thing '{}'", thing.getUID());
|
||||
}
|
||||
|
||||
// create channels
|
||||
thing.getChannels().forEach(this::createChannel);
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
@ -21,6 +21,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum HttpAuthMode {
|
||||
BASIC_PREEMPTIVE,
|
||||
BASIC,
|
||||
DIGEST
|
||||
}
|
||||
|
@ -12,8 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.http.internal.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@ -43,5 +42,6 @@ public class HttpThingConfig {
|
||||
|
||||
public boolean ignoreSSLErrors = false;
|
||||
|
||||
public List<String> headers = Collections.emptyList();
|
||||
// ArrayList is required as implementation because list may be modified later
|
||||
public ArrayList<String> headers = new ArrayList<>();
|
||||
}
|
||||
|
@ -52,6 +52,7 @@
|
||||
<label>Authentication Mode</label>
|
||||
<options>
|
||||
<option value="BASIC">Basic Authentication</option>
|
||||
<option value="BASIC_PREEMPTIVE">Preemptive Basic Authentication</option>
|
||||
<option value="DIGEST">Digest Authentication</option>
|
||||
</options>
|
||||
<default>BASIC</default>
|
||||
|
Loading…
Reference in New Issue
Block a user