From 25b3d84fe81856feac144a10a6a46fef12ed0918 Mon Sep 17 00:00:00 2001 From: Jacob Laursen Date: Mon, 12 Sep 2022 21:47:33 +0200 Subject: [PATCH] Fix access token serialization/deserialization Signed-off-by: Jacob Laursen --- .../pom.xml | 6 ++ .../internal/OAuthStoreHandlerImpl.java | 19 ++-- .../oauth2client/OAuthStoreHandlerTest.java | 98 +++++++++++++++++++ 3 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 bundles/org.openhab.core.auth.oauth2client/src/test/java/org/openhab/core/auth/oauth2client/OAuthStoreHandlerTest.java diff --git a/bundles/org.openhab.core.auth.oauth2client/pom.xml b/bundles/org.openhab.core.auth.oauth2client/pom.xml index 1efc99dc02c..91df5534ef0 100644 --- a/bundles/org.openhab.core.auth.oauth2client/pom.xml +++ b/bundles/org.openhab.core.auth.oauth2client/pom.xml @@ -25,6 +25,12 @@ org.openhab.core.io.net ${project.version} + + org.openhab.core.bundles + org.openhab.core.test + ${project.version} + test + diff --git a/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthStoreHandlerImpl.java b/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthStoreHandlerImpl.java index 6eb1b0075f7..cb6df490d15 100644 --- a/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthStoreHandlerImpl.java +++ b/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthStoreHandlerImpl.java @@ -15,7 +15,10 @@ import static org.openhab.core.auth.oauth2client.internal.StorageRecordType.*; import java.security.GeneralSecurityException; +import java.time.Instant; import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeParseException; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; @@ -236,13 +239,17 @@ private class StorageFacade implements AutoCloseable { public StorageFacade(Storage storage) { this.storage = storage; - // Add adapters for LocalDateTime + // Add adapters for Instant gson = new GsonBuilder() - .registerTypeAdapter(LocalDateTime.class, - (JsonDeserializer) (json, typeOfT, context) -> LocalDateTime - .parse(json.getAsString())) - .registerTypeAdapter(LocalDateTime.class, - (JsonSerializer) (date, type, + .registerTypeAdapter(Instant.class, (JsonDeserializer) (json, typeOfT, context) -> { + try { + return Instant.parse(json.getAsString()); + } catch (DateTimeParseException e) { + return LocalDateTime.parse(json.getAsString()).atZone(ZoneId.systemDefault()).toInstant(); + } + }) + .registerTypeAdapter(Instant.class, + (JsonSerializer) (date, type, jsonSerializationContext) -> new JsonPrimitive(date.toString())) .setPrettyPrinting().create(); } diff --git a/bundles/org.openhab.core.auth.oauth2client/src/test/java/org/openhab/core/auth/oauth2client/OAuthStoreHandlerTest.java b/bundles/org.openhab.core.auth.oauth2client/src/test/java/org/openhab/core/auth/oauth2client/OAuthStoreHandlerTest.java new file mode 100644 index 00000000000..39e7f30b915 --- /dev/null +++ b/bundles/org.openhab.core.auth.oauth2client/src/test/java/org/openhab/core/auth/oauth2client/OAuthStoreHandlerTest.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.auth.oauth2client; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.openhab.core.auth.client.oauth2.AccessTokenResponse; +import org.openhab.core.auth.oauth2client.internal.OAuthStoreHandlerImpl; +import org.openhab.core.auth.oauth2client.internal.StorageRecordType; +import org.openhab.core.storage.Storage; +import org.openhab.core.storage.StorageService; +import org.openhab.core.test.storage.VolatileStorage; + +/** + * The {@link OAuthStoreHandlerTest} contains tests for + * {@link org.openhab.core.auth.oauth2client.OAuthStoreHandlerImpl} + * + * @author Jacob Laursen - Initial contribution + */ +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +@NonNullByDefault +public class OAuthStoreHandlerTest { + private @Mock @NonNullByDefault({}) StorageService storageService; + + private static final String STORE_NAME = "StorageHandler.For.OAuthClientService"; + private @NonNullByDefault({}) Storage storage; + private @NonNullByDefault({}) OAuthStoreHandlerImpl storeHandler; + + @BeforeEach + public void initialize() throws IOException { + storage = new VolatileStorage<>(); + Mockito.doReturn(storage).when(storageService).getStorage(STORE_NAME); + storeHandler = new OAuthStoreHandlerImpl(storageService); + } + + @Test + public void loadAccessTokenResponseWhenCreatedOnIsLocalDateTime() throws GeneralSecurityException { + final String handle = "test"; + final String createdOn = "2022-08-14T21:21:05.568991"; + final Instant expected = LocalDateTime.parse(createdOn).atZone(ZoneId.systemDefault()).toInstant(); + + storage.put(StorageRecordType.ACCESS_TOKEN_RESPONSE.getKey(handle), getJsonforCreatedOn(createdOn)); + AccessTokenResponse response = storeHandler.loadAccessTokenResponse(handle); + + assertThat(response, is(notNullValue())); + if (response != null) { + assertThat(response.getCreatedOn(), is(expected)); + } + } + + @Test + public void loadAccessTokenResponseWhenCreatedOnIsInstant() throws GeneralSecurityException { + final String handle = "test"; + final String createdOn = "2022-08-14T19:21:05.568991Z"; + final Instant expected = Instant.parse(createdOn); + + storage.put(StorageRecordType.ACCESS_TOKEN_RESPONSE.getKey(handle), getJsonforCreatedOn(createdOn)); + AccessTokenResponse response = storeHandler.loadAccessTokenResponse(handle); + + assertThat(response, is(notNullValue())); + if (response != null) { + assertThat(response.getCreatedOn(), is(expected)); + } + } + + private String getJsonforCreatedOn(String createdOn) { + return "{\"accessToken\": \"x\", \"tokenType\": \"Bearer\", \"expiresIn\": 2592000, \"refreshToken\": \"x\", \"createdOn\": \"" + + createdOn + "\"}"; + } +}