2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mielecloud.internal.auth;
15 import java.io.IOException;
16 import java.util.HashMap;
18 import java.util.Optional;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.core.auth.client.oauth2.AccessTokenRefreshListener;
23 import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
24 import org.openhab.core.auth.client.oauth2.OAuthClientService;
25 import org.openhab.core.auth.client.oauth2.OAuthFactory;
26 import org.openhab.core.auth.client.oauth2.OAuthResponseException;
27 import org.osgi.service.component.annotations.Activate;
28 import org.osgi.service.component.annotations.Component;
29 import org.osgi.service.component.annotations.Reference;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * Handles refreshing of OAuth2 tokens managed by the openHAB runtime.
36 * @author Björn Lange - Initial contribution
40 public final class OpenHabOAuthTokenRefresher implements OAuthTokenRefresher {
41 private final Logger logger = LoggerFactory.getLogger(OpenHabOAuthTokenRefresher.class);
43 private final OAuthFactory oauthFactory;
44 private Map<String, @Nullable AccessTokenRefreshListener> listenerByServiceHandle = new HashMap<>();
47 public OpenHabOAuthTokenRefresher(@Reference OAuthFactory oauthFactory) {
48 this.oauthFactory = oauthFactory;
52 public void setRefreshListener(OAuthTokenRefreshListener listener, String serviceHandle) {
53 final AccessTokenRefreshListener refreshListener = tokenResponse -> {
54 final String accessToken = tokenResponse.getAccessToken();
55 if (accessToken == null) {
56 // Fail without exception to ensure that the OAuthClientService notifies all listeners.
57 logger.warn("Ignoring access token response without access token.");
59 listener.onNewAccessToken(accessToken);
63 OAuthClientService clientService = getOAuthClientService(serviceHandle);
64 clientService.addAccessTokenRefreshListener(refreshListener);
65 listenerByServiceHandle.put(serviceHandle, refreshListener);
69 public void unsetRefreshListener(String serviceHandle) {
70 final AccessTokenRefreshListener refreshListener = listenerByServiceHandle.get(serviceHandle);
71 if (refreshListener != null) {
73 OAuthClientService clientService = getOAuthClientService(serviceHandle);
74 clientService.removeAccessTokenRefreshListener(refreshListener);
75 } catch (OAuthException e) {
76 logger.warn("Failed to remove refresh listener: OAuth client service is unavailable. Cause: {}",
80 listenerByServiceHandle.remove(serviceHandle);
84 public void refreshToken(String serviceHandle) {
85 if (listenerByServiceHandle.get(serviceHandle) == null) {
86 logger.warn("Token refreshing was requested but there is no token refresh listener registered!");
90 OAuthClientService clientService = getOAuthClientService(serviceHandle);
91 refreshAccessToken(clientService);
94 private OAuthClientService getOAuthClientService(String serviceHandle) {
95 final OAuthClientService clientService = oauthFactory.getOAuthClientService(serviceHandle);
96 if (clientService == null) {
97 throw new OAuthException("OAuth client service is not available.");
102 private void refreshAccessToken(OAuthClientService clientService) {
104 final AccessTokenResponse accessTokenResponse = clientService.refreshToken();
105 final String accessToken = accessTokenResponse.getAccessToken();
106 if (accessToken == null) {
107 throw new OAuthException("Access token is not available.");
109 } catch (org.openhab.core.auth.client.oauth2.OAuthException e) {
110 throw new OAuthException("An error occured during token refresh: " + e.getMessage(), e);
111 } catch (IOException e) {
112 throw new OAuthException("A network error occured during token refresh: " + e.getMessage(), e);
113 } catch (OAuthResponseException e) {
114 throw new OAuthException("Miele cloud service returned an illegal response: " + e.getMessage(), e);
119 public Optional<String> getAccessTokenFromStorage(String serviceHandle) {
121 AccessTokenResponse tokenResponse = getOAuthClientService(serviceHandle).getAccessTokenResponse();
122 if (tokenResponse == null) {
123 return Optional.empty();
125 return Optional.of(tokenResponse.getAccessToken());
127 } catch (OAuthException | org.openhab.core.auth.client.oauth2.OAuthException | IOException
128 | OAuthResponseException e) {
129 logger.debug("Cannot obtain access token from persistent storage.", e);
130 return Optional.empty();
135 public void removeTokensFromStorage(String serviceHandle) {
136 oauthFactory.deleteServiceAndAccessToken(serviceHandle);