]> git.basschouten.com Git - openhab-addons.git/blob
3f16d81ff5247daa4e1c38d2b2c54dce42234cfc
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.mielecloud.internal.config;
14
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;
19
20 import java.io.IOException;
21 import java.util.Objects;
22 import java.util.concurrent.ScheduledExecutorService;
23 import java.util.concurrent.ScheduledFuture;
24
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;
39
40 /**
41  * @author Björn Lange - Initial Contribution
42  */
43 @NonNullByDefault
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";
52
53     @Nullable
54     private OAuthClientService clientService;
55     @Nullable
56     private ScheduledFuture<?> timer;
57     @Nullable
58     private Runnable scheduledRunnable;
59     @Nullable
60     private OAuthAuthorizationHandler authorizationHandler;
61
62     private OAuthClientService getClientService() {
63         final OAuthClientService clientService = this.clientService;
64         assertNotNull(clientService);
65         return Objects.requireNonNull(clientService);
66     }
67
68     private ScheduledFuture<?> getTimer() {
69         final ScheduledFuture<?> timer = this.timer;
70         assertNotNull(timer);
71         return Objects.requireNonNull(timer);
72     }
73
74     private Runnable getScheduledRunnable() {
75         final Runnable scheduledRunnable = this.scheduledRunnable;
76         assertNotNull(scheduledRunnable);
77         return Objects.requireNonNull(scheduledRunnable);
78     }
79
80     private OAuthAuthorizationHandler getAuthorizationHandler() {
81         final OAuthAuthorizationHandler authorizationHandler = this.authorizationHandler;
82         assertNotNull(authorizationHandler);
83         return Objects.requireNonNull(authorizationHandler);
84     }
85
86     @BeforeEach
87     public void setUp() {
88         OAuthClientService clientService = mock(OAuthClientService.class);
89
90         OAuthFactory oauthFactory = mock(OAuthFactory.class);
91         when(oauthFactory.createOAuthClientService(anyString(), anyString(), anyString(), anyString(), anyString(),
92                 isNull(), any())).thenReturn(clientService);
93
94         ScheduledFuture<?> timer = mock(ScheduledFuture.class);
95         when(timer.isDone()).thenReturn(false);
96
97         ScheduledExecutorService scheduler = mock(ScheduledExecutorService.class);
98         when(scheduler.schedule(ArgumentMatchers.<Runnable> any(), anyLong(), any())).thenAnswer(invocation -> {
99             scheduledRunnable = invocation.getArgument(0);
100             return timer;
101         });
102
103         OAuthAuthorizationHandler authorizationHandler = new OAuthAuthorizationHandlerImpl(oauthFactory, scheduler);
104
105         this.clientService = clientService;
106         this.timer = timer;
107         this.scheduledRunnable = null;
108         this.authorizationHandler = authorizationHandler;
109     }
110
111     @Test
112     public void whenTheAuthorizationIsCompletedInTimeThenTheTimerIsCancelledAndAllResourcesAreCleanedUp()
113             throws Exception {
114         // given:
115         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
116         getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
117
118         // when:
119         getAuthorizationHandler().completeAuthorization("http://127.0.0.1:8080/mielecloud/result?code=abc&state=def");
120
121         // then:
122         assertNull(getPrivate(getAuthorizationHandler(), "timer"));
123         verify(getTimer()).cancel(false);
124
125         assertNull(getPrivate(getAuthorizationHandler(), "oauthClientService"));
126         assertNull(getPrivate(getAuthorizationHandler(), "bridgeUid"));
127         assertNull(getPrivate(getAuthorizationHandler(), "redirectUri"));
128         assertNull(getPrivate(getAuthorizationHandler(), "email"));
129
130         verify(getClientService()).extractAuthCodeFromAuthResponse(anyString());
131         verify(getClientService()).getAccessTokenResponseByAuthorizationCode(isNull(), anyString());
132     }
133
134     @Test
135     public void whenTheAuthorizationTimesOutThenTheOngoingAuthorizationIsCancelled() throws Exception {
136         // given:
137         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
138         getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
139
140         // when:
141         getScheduledRunnable().run();
142
143         // then:
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);
150     }
151
152     @Test
153     public void whenTheAuthorizationCompletesAfterItTimedOutThenAnNoOngoingAuthorizationExceptionIsThrown()
154             throws Exception {
155         // given:
156         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
157         getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
158
159         getScheduledRunnable().run();
160
161         // when:
162         assertThrows(NoOngoingAuthorizationException.class, () -> {
163             getAuthorizationHandler()
164                     .completeAuthorization("http://127.0.0.1:8080/mielecloud/result?code=abc&state=def");
165         });
166     }
167
168     @Test
169     public void whenASecondAuthorizationIsBegunWhileAnotherIsStillOngoingThenAnOngoingAuthorizationExceptionIsThrown() {
170         // given:
171         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
172
173         // when:
174         assertThrows(OngoingAuthorizationException.class, () -> {
175             getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
176         });
177     }
178
179     @Test
180     public void whenNoAuthorizationIsOngoingAndTheAuthorizationUrlIsRequestedThenAnNoOngoingAuthorizationExceptionIsThrown() {
181         // when:
182         assertThrows(NoOngoingAuthorizationException.class, () -> {
183             getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
184         });
185     }
186
187     @Test
188     public void whenGetAuthorizationUrlFromTheFrameworkFailsThenTheOngoingAuthorizationIsAborted()
189             throws org.openhab.core.auth.client.oauth2.OAuthException, IllegalArgumentException, IllegalAccessException,
190             NoSuchFieldException, SecurityException {
191         // given:
192         when(getClientService().getAuthorizationUrl(anyString(), isNull(), isNull()))
193                 .thenThrow(new org.openhab.core.auth.client.oauth2.OAuthException());
194
195         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
196
197         // when:
198         assertThrows(OAuthException.class, () -> {
199             try {
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"));
207                 throw e;
208             }
209         });
210     }
211
212     @Test
213     public void whenExtractingTheAuthCodeFromTheResponseFailsThenAnOAuthExceptionIsThrownAndAllResourcesAreCleanedUp()
214             throws Exception {
215         // given:
216         when(getClientService().extractAuthCodeFromAuthResponse(anyString()))
217                 .thenThrow(new org.openhab.core.auth.client.oauth2.OAuthException());
218
219         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
220         getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
221
222         // when:
223         assertThrows(OAuthException.class, () -> {
224             try {
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"));
233                 throw e;
234             }
235         });
236     }
237
238     @Test
239     public void whenRetrievingTheAccessTokenFailsDueToANetworkErrorThenAnOAuthExceptionIsThrownAndAllResourcesAreCleanedUp()
240             throws Exception {
241         // given:
242         when(getClientService().extractAuthCodeFromAuthResponse(anyString())).thenReturn(AUTH_CODE);
243         when(getClientService().getAccessTokenResponseByAuthorizationCode(anyString(), anyString()))
244                 .thenThrow(new IOException());
245
246         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
247         getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
248
249         // when:
250         assertThrows(OAuthException.class, () -> {
251             try {
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"));
260                 throw e;
261             }
262         });
263     }
264
265     @Test
266     public void whenRetrievingTheAccessTokenFailsDueToAnIllegalAnswerFromTheMieleServiceThenAnOAuthExceptionIsThrownAndAllResourcesAreCleanedUp()
267             throws Exception {
268         // given:
269         when(getClientService().extractAuthCodeFromAuthResponse(anyString())).thenReturn(AUTH_CODE);
270         when(getClientService().getAccessTokenResponseByAuthorizationCode(anyString(), anyString()))
271                 .thenThrow(new OAuthResponseException());
272
273         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
274         getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
275
276         // when:
277         assertThrows(OAuthException.class, () -> {
278             try {
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"));
287                 throw e;
288             }
289         });
290     }
291
292     @Test
293     public void whenRetrievingTheAccessTokenFailsWhileProcessingTheResponseThenAnOAuthExceptionIsThrownAndAllResourcesAreCleanedUp()
294             throws Exception {
295         // given:
296         when(getClientService().extractAuthCodeFromAuthResponse(anyString())).thenReturn(AUTH_CODE);
297         when(getClientService().getAccessTokenResponseByAuthorizationCode(anyString(), anyString()))
298                 .thenThrow(new org.openhab.core.auth.client.oauth2.OAuthException());
299
300         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
301         getAuthorizationHandler().getAuthorizationUrl(REDIRECT_URL);
302
303         // when:
304         assertThrows(OAuthException.class, () -> {
305             try {
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"));
314                 throw e;
315             }
316         });
317     }
318
319     @Test
320     public void whenNoAuthorizationIsOngoingThenGetBridgeUidThrowsNoOngoingAuthorizationException() {
321         // when:
322         assertThrows(NoOngoingAuthorizationException.class, () -> {
323             getAuthorizationHandler().getBridgeUid();
324         });
325     }
326
327     @Test
328     public void whenNoAuthorizationIsOngoingThenGetEmailThrowsNoOngoingAuthorizationException() {
329         // when:
330         assertThrows(NoOngoingAuthorizationException.class, () -> {
331             getAuthorizationHandler().getEmail();
332         });
333     }
334
335     @Test
336     public void whenAnAuthorizationIsOngoingThenGetBridgeUidReturnsTheUidOfTheBridgeBeingAuthorized() {
337         // given:
338         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
339
340         // when:
341         ThingUID bridgeUid = getAuthorizationHandler().getBridgeUid();
342
343         // then:
344         assertEquals(BRIDGE_UID, bridgeUid);
345     }
346
347     @Test
348     public void whenAnAuthorizationIsOngoingThenGetEmailReturnsTheEmailBeingAuthorized() {
349         // given:
350         getAuthorizationHandler().beginAuthorization(CLIENT_ID, CLIENT_SECRET, BRIDGE_UID, EMAIL);
351
352         // when:
353         String email = getAuthorizationHandler().getEmail();
354
355         // then:
356         assertEquals(EMAIL, email);
357     }
358 }