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.config;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.ArgumentMatchers.*;
17 import static org.mockito.Mockito.*;
18 import static org.openhab.binding.mielecloud.internal.util.ReflectionUtil.getPrivate;
20 import java.io.IOException;
21 import java.util.Objects;
22 import java.util.concurrent.ScheduledExecutorService;
23 import java.util.concurrent.ScheduledFuture;
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.junit.jupiter.api.BeforeEach;
28 import org.junit.jupiter.api.Test;
29 import org.mockito.ArgumentMatchers;
30 import org.openhab.binding.mielecloud.internal.MieleCloudBindingConstants;
31 import org.openhab.binding.mielecloud.internal.MieleCloudBindingTestConstants;
32 import org.openhab.binding.mielecloud.internal.auth.OAuthException;
33 import org.openhab.binding.mielecloud.internal.config.exception.NoOngoingAuthorizationException;
34 import org.openhab.binding.mielecloud.internal.config.exception.OngoingAuthorizationException;
35 import org.openhab.core.auth.client.oauth2.OAuthClientService;
36 import org.openhab.core.auth.client.oauth2.OAuthFactory;
37 import org.openhab.core.auth.client.oauth2.OAuthResponseException;
38 import org.openhab.core.thing.ThingUID;
41 * @author Björn Lange - Initial Contribution
44 public final class OAuthAuthorizationHandlerImplTest {
45 private static final String CLIENT_ID = "01234567-890a-bcde-f012-34567890abcd";
46 private static final String CLIENT_SECRET = "0123456789abcdefghijklmnopqrstiu";
47 private static final String REDIRECT_URL = "http://127.0.0.1:8080/mielecloud/result";
48 private static final String AUTH_CODE = "abcdef";
49 private static final ThingUID BRIDGE_UID = new ThingUID(MieleCloudBindingConstants.THING_TYPE_BRIDGE,
50 MieleCloudBindingTestConstants.BRIDGE_ID);
51 private static final String EMAIL = "openhab@openhab.org";
54 private OAuthClientService clientService;
56 private ScheduledFuture<?> timer;
58 private Runnable scheduledRunnable;
60 private OAuthAuthorizationHandler authorizationHandler;
62 private OAuthClientService getClientService() {
63 final OAuthClientService clientService = this.clientService;
64 assertNotNull(clientService);
65 return Objects.requireNonNull(clientService);
68 private ScheduledFuture<?> getTimer() {
69 final ScheduledFuture<?> timer = this.timer;
71 return Objects.requireNonNull(timer);
74 private Runnable getScheduledRunnable() {
75 final Runnable scheduledRunnable = this.scheduledRunnable;
76 assertNotNull(scheduledRunnable);
77 return Objects.requireNonNull(scheduledRunnable);
80 private OAuthAuthorizationHandler getAuthorizationHandler() {
81 final OAuthAuthorizationHandler authorizationHandler = this.authorizationHandler;
82 assertNotNull(authorizationHandler);
83 return Objects.requireNonNull(authorizationHandler);
88 OAuthClientService clientService = mock(OAuthClientService.class);
90 OAuthFactory oauthFactory = mock(OAuthFactory.class);
91 when(oauthFactory.createOAuthClientService(anyString(), anyString(), anyString(), anyString(), anyString(),
92 isNull(), any())).thenReturn(clientService);
94 ScheduledFuture<?> timer = mock(ScheduledFuture.class);
95 when(timer.isDone()).thenReturn(false);
97 ScheduledExecutorService scheduler = mock(ScheduledExecutorService.class);
98 when(scheduler.schedule(ArgumentMatchers.<Runnable> any(), anyLong(), any())).thenAnswer(invocation -> {
99 scheduledRunnable = invocation.getArgument(0);
103 OAuthAuthorizationHandler authorizationHandler = new OAuthAuthorizationHandlerImpl(oauthFactory, scheduler);
105 this.clientService = clientService;
107 this.scheduledRunnable = null;
108 this.authorizationHandler = authorizationHandler;
112 public void whenTheAuthorizationIsCompletedInTimeThenTheTimerIsCancelledAndAllResourcesAreCleanedUp()
115 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
116 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
119 getAuthorizationHandler().completeAuthorization("http://127.0.0.1:8080/mielecloud/result?code=abc&state=def");
122 assertNull(getPrivate(getAuthorizationHandler(), "timer"));
123 verify(getTimer()).cancel(false);
125 assertNull(getPrivate(getAuthorizationHandler(), "oauthClientService"));
126 assertNull(getPrivate(getAuthorizationHandler(), "bridgeUid"));
127 assertNull(getPrivate(getAuthorizationHandler(), "redirectUri"));
128 assertNull(getPrivate(getAuthorizationHandler(), "email"));
130 verify(getClientService()).extractAuthCodeFromAuthResponse(anyString());
131 verify(getClientService()).getAccessTokenResponseByAuthorizationCode(isNull(), anyString());
135 public void whenTheAuthorizationTimesOutThenTheOngoingAuthorizationIsCancelled() throws Exception {
137 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
138 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
141 getScheduledRunnable().run();
144 assertNull(getPrivate(getAuthorizationHandler(), "oauthClientService"));
145 assertNull(getPrivate(getAuthorizationHandler(), "bridgeUid"));
146 assertNull(getPrivate(getAuthorizationHandler(), "redirectUri"));
147 assertNull(getPrivate(getAuthorizationHandler(), "email"));
148 assertNull(getPrivate(getAuthorizationHandler(), "timer"));
149 verify(getTimer()).cancel(false);
153 public void whenTheAuthorizationCompletesAfterItTimedOutThenAnNoOngoingAuthorizationExceptionIsThrown()
156 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
157 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
159 getScheduledRunnable().run();
162 assertThrows(NoOngoingAuthorizationException.class, () -> {
163 getAuthorizationHandler()
164 .completeAuthorization("http://127.0.0.1:8080/mielecloud/result?code=abc&state=def");
169 public void whenASecondAuthorizationIsBegunWhileAnotherIsStillOngoingThenAnOngoingAuthorizationExceptionIsThrown() {
171 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
174 assertThrows(OngoingAuthorizationException.class, () -> {
175 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
180 public void whenNoAuthorizationIsOngoingAndTheAuthorizationUrlIsRequestedThenAnNoOngoingAuthorizationExceptionIsThrown() {
182 assertThrows(NoOngoingAuthorizationException.class, () -> {
183 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
188 public void whenGetAuthorizationUrlFromTheFrameworkFailsThenTheOngoingAuthorizationIsAborted()
189 throws org.openhab.core.auth.client.oauth2.OAuthException, IllegalArgumentException, IllegalAccessException,
190 NoSuchFieldException, SecurityException {
192 when(getClientService().getAuthorizationUrl(anyString(), isNull(), isNull()))
193 .thenThrow(new org.openhab.core.auth.client.oauth2.OAuthException());
195 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
198 assertThrows(OAuthException.class, () -> {
200 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
201 } catch (OAuthException e) {
202 assertNull(getPrivate(getAuthorizationHandler(), "timer"));
203 assertNull(getPrivate(getAuthorizationHandler(), "oauthClientService"));
204 assertNull(getPrivate(getAuthorizationHandler(), "bridgeUid"));
205 assertNull(getPrivate(getAuthorizationHandler(), "redirectUri"));
206 assertNull(getPrivate(getAuthorizationHandler(), "email"));
213 public void whenExtractingTheAuthCodeFromTheResponseFailsThenAnOAuthExceptionIsThrownAndAllResourcesAreCleanedUp()
216 when(getClientService().extractAuthCodeFromAuthResponse(anyString()))
217 .thenThrow(new org.openhab.core.auth.client.oauth2.OAuthException());
219 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
220 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
223 assertThrows(OAuthException.class, () -> {
225 getAuthorizationHandler()
226 .completeAuthorization("http://127.0.0.1:8080/mielecloud/result?code=abc&state=def");
227 } catch (OAuthException e) {
228 assertNull(getPrivate(getAuthorizationHandler(), "timer"));
229 assertNull(getPrivate(getAuthorizationHandler(), "oauthClientService"));
230 assertNull(getPrivate(getAuthorizationHandler(), "bridgeUid"));
231 assertNull(getPrivate(getAuthorizationHandler(), "email"));
232 assertNull(getPrivate(getAuthorizationHandler(), "redirectUri"));
239 public void whenRetrievingTheAccessTokenFailsDueToANetworkErrorThenAnOAuthExceptionIsThrownAndAllResourcesAreCleanedUp()
242 when(getClientService().extractAuthCodeFromAuthResponse(anyString())).thenReturn(AUTH_CODE);
243 when(getClientService().getAccessTokenResponseByAuthorizationCode(anyString(), anyString()))
244 .thenThrow(new IOException());
246 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
247 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
250 assertThrows(OAuthException.class, () -> {
252 getAuthorizationHandler()
253 .completeAuthorization("http://127.0.0.1:8080/mielecloud/result?code=abc&state=def");
254 } catch (OAuthException e) {
255 assertNull(getPrivate(getAuthorizationHandler(), "timer"));
256 assertNull(getPrivate(getAuthorizationHandler(), "oauthClientService"));
257 assertNull(getPrivate(getAuthorizationHandler(), "bridgeUid"));
258 assertNull(getPrivate(getAuthorizationHandler(), "email"));
259 assertNull(getPrivate(getAuthorizationHandler(), "redirectUri"));
266 public void whenRetrievingTheAccessTokenFailsDueToAnIllegalAnswerFromTheMieleServiceThenAnOAuthExceptionIsThrownAndAllResourcesAreCleanedUp()
269 when(getClientService().extractAuthCodeFromAuthResponse(anyString())).thenReturn(AUTH_CODE);
270 when(getClientService().getAccessTokenResponseByAuthorizationCode(anyString(), anyString()))
271 .thenThrow(new OAuthResponseException());
273 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
274 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
277 assertThrows(OAuthException.class, () -> {
279 getAuthorizationHandler()
280 .completeAuthorization("http://127.0.0.1:8080/mielecloud/result?code=abc&state=def");
281 } catch (OAuthException e) {
282 assertNull(getPrivate(getAuthorizationHandler(), "timer"));
283 assertNull(getPrivate(getAuthorizationHandler(), "oauthClientService"));
284 assertNull(getPrivate(getAuthorizationHandler(), "bridgeUid"));
285 assertNull(getPrivate(getAuthorizationHandler(), "email"));
286 assertNull(getPrivate(getAuthorizationHandler(), "redirectUri"));
293 public void whenRetrievingTheAccessTokenFailsWhileProcessingTheResponseThenAnOAuthExceptionIsThrownAndAllResourcesAreCleanedUp()
296 when(getClientService().extractAuthCodeFromAuthResponse(anyString())).thenReturn(AUTH_CODE);
297 when(getClientService().getAccessTokenResponseByAuthorizationCode(anyString(), anyString()))
298 .thenThrow(new org.openhab.core.auth.client.oauth2.OAuthException());
300 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
301 getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
304 assertThrows(OAuthException.class, () -> {
306 getAuthorizationHandler()
307 .completeAuthorization("http://127.0.0.1:8080/mielecloud/result?code=abc&state=def");
308 } catch (OAuthException e) {
309 assertNull(getPrivate(getAuthorizationHandler(), "timer"));
310 assertNull(getPrivate(getAuthorizationHandler(), "oauthClientService"));
311 assertNull(getPrivate(getAuthorizationHandler(), "bridgeUid"));
312 assertNull(getPrivate(getAuthorizationHandler(), "email"));
313 assertNull(getPrivate(getAuthorizationHandler(), "redirectUri"));
320 public void whenNoAuthorizationIsOngoingThenGetBridgeUidThrowsNoOngoingAuthorizationException() {
322 assertThrows(NoOngoingAuthorizationException.class, () -> {
323 getAuthorizationHandler().getBridgeUid();
328 public void whenNoAuthorizationIsOngoingThenGetEmailThrowsNoOngoingAuthorizationException() {
330 assertThrows(NoOngoingAuthorizationException.class, () -> {
331 getAuthorizationHandler().getEmail();
336 public void whenAnAuthorizationIsOngoingThenGetBridgeUidReturnsTheUidOfTheBridgeBeingAuthorized() {
338 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
341 ThingUID bridgeUid = getAuthorizationHandler().getBridgeUid();
344 assertEquals(BRIDGE_UID, bridgeUid);
348 public void whenAnAuthorizationIsOngoingThenGetEmailReturnsTheEmailBeingAuthorized() {
350 getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
353 String email = getAuthorizationHandler().getEmail();
356 assertEquals(EMAIL, email);