Skip to content

Commit f7e0339

Browse files
authored
[OAuth] Added capability for custom deserializer (#1891)
* Added capability for custom deserializer Closes #1888 Signed-off-by: clinique <[email protected]>
1 parent 19daef5 commit f7e0339

File tree

5 files changed

+64
-9
lines changed

5 files changed

+64
-9
lines changed

bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthClientServiceImpl.java

+21-5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import org.slf4j.Logger;
3636
import org.slf4j.LoggerFactory;
3737

38+
import com.google.gson.JsonDeserializer;
39+
3840
/**
3941
* Implementation of OAuthClientService.
4042
*
@@ -49,6 +51,7 @@
4951
*
5052
* @author Michael Bock - Initial contribution
5153
* @author Gary Tse - Initial contribution
54+
* @author Gaël L'hopital - Added capability for custom deserializer
5255
*/
5356
@NonNullByDefault
5457
public class OAuthClientServiceImpl implements OAuthClientService {
@@ -150,7 +153,7 @@ public String getAuthorizationUrl(@Nullable String redirectURI, @Nullable String
150153
throw new OAuthException("Missing client ID");
151154
}
152155

153-
OAuthConnector connector = new OAuthConnector(httpClientFactory);
156+
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
154157
return connector.getAuthorizationUrl(authorizationUrl, clientId, redirectURI, persistedParams.state,
155158
scopeToUse);
156159
}
@@ -204,7 +207,7 @@ public AccessTokenResponse getAccessTokenResponseByAuthorizationCode(String auth
204207
throw new OAuthException("Missing client ID");
205208
}
206209

207-
OAuthConnector connector = new OAuthConnector(httpClientFactory);
210+
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
208211
AccessTokenResponse accessTokenResponse = connector.grantTypeAuthorizationCode(tokenUrl, authorizationCode,
209212
clientId, persistedParams.clientSecret, redirectURI,
210213
Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
@@ -236,7 +239,7 @@ public AccessTokenResponse getAccessTokenByResourceOwnerPasswordCredentials(Stri
236239
throw new OAuthException("Missing token url");
237240
}
238241

239-
OAuthConnector connector = new OAuthConnector(httpClientFactory);
242+
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
240243
AccessTokenResponse accessTokenResponse = connector.grantTypePassword(tokenUrl, username, password,
241244
persistedParams.clientId, persistedParams.clientSecret, scope,
242245
Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
@@ -261,7 +264,7 @@ public AccessTokenResponse getAccessTokenByClientCredentials(@Nullable String sc
261264
throw new OAuthException("Missing client ID");
262265
}
263266

264-
OAuthConnector connector = new OAuthConnector(httpClientFactory);
267+
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
265268
// depending on usage, cannot guarantee every parameter is not null at the beginning
266269
AccessTokenResponse accessTokenResponse = connector.grantTypeClientCredentials(tokenUrl, clientId,
267270
persistedParams.clientSecret, scope, Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
@@ -295,7 +298,7 @@ public AccessTokenResponse refreshToken() throws OAuthException, IOException, OA
295298
throw new OAuthException("tokenUrl is required but null");
296299
}
297300

298-
OAuthConnector connector = new OAuthConnector(httpClientFactory);
301+
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
299302
AccessTokenResponse accessTokenResponse = connector.grantTypeRefreshToken(tokenUrl,
300303
lastAccessToken.getRefreshToken(), persistedParams.clientId, persistedParams.clientSecret,
301304
persistedParams.scope, Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
@@ -395,4 +398,17 @@ public boolean removeAccessTokenRefreshListener(AccessTokenRefreshListener liste
395398
private String createNewState() {
396399
return UUID.randomUUID().toString();
397400
}
401+
402+
@Override
403+
public <T extends JsonDeserializer<?>> OAuthClientService withDeserializer(Class<T> deserializerClass) {
404+
OAuthClientServiceImpl clientService = new OAuthClientServiceImpl(handle, persistedParams.tokenExpiresInSeconds,
405+
httpClientFactory);
406+
persistedParams.deserializerClassName = deserializerClass.getName();
407+
clientService.persistedParams = persistedParams;
408+
clientService.storeHandler = storeHandler;
409+
410+
storeHandler.savePersistedParams(handle, clientService.persistedParams);
411+
412+
return clientService;
413+
}
398414
}

bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthConnector.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import static org.openhab.core.auth.oauth2client.internal.Keyword.*;
1616

1717
import java.io.IOException;
18+
import java.lang.reflect.InvocationTargetException;
1819
import java.net.URLEncoder;
1920
import java.nio.charset.StandardCharsets;
2021
import java.security.AccessController;
@@ -65,9 +66,21 @@ public class OAuthConnector {
6566
private final Logger logger = LoggerFactory.getLogger(OAuthConnector.class);
6667
private final Gson gson;
6768

68-
public OAuthConnector(HttpClientFactory httpClientFactory) {
69+
public OAuthConnector(HttpClientFactory httpClientFactory, @Nullable String deserializerClassName) {
6970
this.httpClientFactory = httpClientFactory;
70-
gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
71+
GsonBuilder gsonBuilder = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
72+
if (deserializerClassName != null) {
73+
try {
74+
Class<?> deserializerClass = Class.forName(deserializerClassName);
75+
gsonBuilder = gsonBuilder.registerTypeAdapter(AccessTokenResponse.class,
76+
deserializerClass.getConstructor().newInstance());
77+
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
78+
| InvocationTargetException | NoSuchMethodException | SecurityException
79+
| ClassNotFoundException e) {
80+
logger.error("Unable to construct custom deserializer '{}'", deserializerClassName, e);
81+
}
82+
}
83+
gson = gsonBuilder.create();
7184
}
7285

7386
/**

bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthFactoryImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public OAuthClientService createOAuthClientService(String handle, String tokenUr
7070
@Nullable Boolean supportsBasicAuth) {
7171
PersistedParams params = oAuthStoreHandler.loadPersistedParams(handle);
7272
PersistedParams newParams = new PersistedParams(handle, tokenUrl, authorizationUrl, clientId, clientSecret,
73-
scope, supportsBasicAuth, tokenExpiresInBuffer);
73+
scope, supportsBasicAuth, tokenExpiresInBuffer, null);
7474
OAuthClientService clientImpl = null;
7575

7676
// If parameters in storage and parameters are the same as arguments passed get the client from storage

bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/PersistedParams.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* @author Michael Bock - Initial contribution
2121
* @author Gary Tse - Initial contribution
2222
* @author Hilbrand Bouwkamp - Moved class to it's own file and added hashCode and equals methods
23+
* @author Gaël L'hopital - Added deserializerClassName
2324
*/
2425
class PersistedParams {
2526
String handle;
@@ -32,6 +33,8 @@ class PersistedParams {
3233
String state;
3334
String redirectUri;
3435
int tokenExpiresInSeconds = 60;
36+
@Nullable
37+
String deserializerClassName;
3538

3639
/**
3740
* Default constructor needed for json serialization.
@@ -56,9 +59,11 @@ public PersistedParams() {
5659
* of the access tokens. This allows the access token to expire earlier than the
5760
* official stated expiry time; thus prevents the caller obtaining a valid token at the time of invoke,
5861
* only to find the token immediately expired.
62+
* @param deserializerClass (optional) if a specific deserializer is needed
5963
*/
6064
public PersistedParams(String handle, String tokenUrl, String authorizationUrl, String clientId,
61-
String clientSecret, String scope, Boolean supportsBasicAuth, int tokenExpiresInSeconds) {
65+
String clientSecret, String scope, Boolean supportsBasicAuth, int tokenExpiresInSeconds,
66+
@Nullable String deserializerClassName) {
6267
this.handle = handle;
6368
this.tokenUrl = tokenUrl;
6469
this.authorizationUrl = authorizationUrl;
@@ -67,6 +72,7 @@ public PersistedParams(String handle, String tokenUrl, String authorizationUrl,
6772
this.scope = scope;
6873
this.supportsBasicAuth = supportsBasicAuth;
6974
this.tokenExpiresInSeconds = tokenExpiresInSeconds;
75+
this.deserializerClassName = deserializerClassName;
7076
}
7177

7278
@Override
@@ -83,6 +89,7 @@ public int hashCode() {
8389
result = prime * result + ((supportsBasicAuth == null) ? 0 : supportsBasicAuth.hashCode());
8490
result = prime * result + tokenExpiresInSeconds;
8591
result = prime * result + ((tokenUrl == null) ? 0 : tokenUrl.hashCode());
92+
result = prime * result + ((deserializerClassName != null) ? deserializerClassName.hashCode() : 0);
8693
return result;
8794
}
8895

@@ -161,6 +168,14 @@ public boolean equals(@Nullable Object obj) {
161168
} else if (!tokenUrl.equals(other.tokenUrl)) {
162169
return false;
163170
}
171+
if (deserializerClassName == null) {
172+
if (other.deserializerClassName != null) {
173+
return false;
174+
}
175+
} else if (deserializerClassName != null && !deserializerClassName.equals(other.deserializerClassName)) {
176+
return false;
177+
}
178+
164179
return true;
165180
}
166181
}

bundles/org.openhab.core/src/main/java/org/openhab/core/auth/client/oauth2/OAuthClientService.java

+11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import org.eclipse.jdt.annotation.NonNullByDefault;
1818
import org.eclipse.jdt.annotation.Nullable;
1919

20+
import com.google.gson.JsonDeserializer;
21+
2022
/**
2123
* This is the service factory to produce a OAuth2 service client that authenticates using OAUTH2.
2224
* This is a service factory pattern; the OAuthe2 service client is not shared between bundles.
@@ -77,6 +79,7 @@
7779
*
7880
* @author Gary Tse - Initial contribution
7981
* @author Hilbrand Bouwkamp - Added AccessTokenRefreshListener, fixed javadoc warnings
82+
* @author Gaël L'hopital - Added capability for custom deserializer
8083
*/
8184
@NonNullByDefault
8285
public interface OAuthClientService extends AutoCloseable {
@@ -286,4 +289,12 @@ AccessTokenResponse getAccessTokenByImplicit(@Nullable String redirectURI, @Null
286289
* @param listener the listener to remove
287290
*/
288291
boolean removeAccessTokenRefreshListener(AccessTokenRefreshListener listener);
292+
293+
/**
294+
* Adds a personalized deserializer to a given oauth service.
295+
*
296+
* @param deserializeClass the deserializer class that should be used to deserialize AccessTokenResponse
297+
* @return the oauth service
298+
*/
299+
<T extends JsonDeserializer<?>> OAuthClientService withDeserializer(Class<T> deserializerClass);
289300
}

0 commit comments

Comments
 (0)