| `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.
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;
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,
return;
}
+ // check SSL handling and initialize client
if (config.ignoreSSLErrors) {
logger.info("Using the insecure client for thing '{}'.", thing.getUID());
httpClient = httpClientProvider.getInsecureClient();
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");
logger.debug("No authentication configured for thing '{}'", thing.getUID());
}
+ // create channels
thing.getChannels().forEach(this::createChannel);
updateStatus(ThingStatus.ONLINE);