mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 13:21:53 +01:00
[OAuth] Added capability for custom deserializer (#1891)
* Added capability for custom deserializer Closes #1888 Signed-off-by: clinique <gael@lhopital.org>
This commit is contained in:
parent
19daef5d09
commit
f7e03397fb
@ -35,6 +35,8 @@ import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
|
||||
/**
|
||||
* Implementation of OAuthClientService.
|
||||
*
|
||||
@ -49,6 +51,7 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Michael Bock - Initial contribution
|
||||
* @author Gary Tse - Initial contribution
|
||||
* @author Gaël L'hopital - Added capability for custom deserializer
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OAuthClientServiceImpl implements OAuthClientService {
|
||||
@ -150,7 +153,7 @@ public class OAuthClientServiceImpl implements OAuthClientService {
|
||||
throw new OAuthException("Missing client ID");
|
||||
}
|
||||
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory);
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
|
||||
return connector.getAuthorizationUrl(authorizationUrl, clientId, redirectURI, persistedParams.state,
|
||||
scopeToUse);
|
||||
}
|
||||
@ -204,7 +207,7 @@ public class OAuthClientServiceImpl implements OAuthClientService {
|
||||
throw new OAuthException("Missing client ID");
|
||||
}
|
||||
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory);
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
|
||||
AccessTokenResponse accessTokenResponse = connector.grantTypeAuthorizationCode(tokenUrl, authorizationCode,
|
||||
clientId, persistedParams.clientSecret, redirectURI,
|
||||
Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
|
||||
@ -236,7 +239,7 @@ public class OAuthClientServiceImpl implements OAuthClientService {
|
||||
throw new OAuthException("Missing token url");
|
||||
}
|
||||
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory);
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
|
||||
AccessTokenResponse accessTokenResponse = connector.grantTypePassword(tokenUrl, username, password,
|
||||
persistedParams.clientId, persistedParams.clientSecret, scope,
|
||||
Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
|
||||
@ -261,7 +264,7 @@ public class OAuthClientServiceImpl implements OAuthClientService {
|
||||
throw new OAuthException("Missing client ID");
|
||||
}
|
||||
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory);
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
|
||||
// depending on usage, cannot guarantee every parameter is not null at the beginning
|
||||
AccessTokenResponse accessTokenResponse = connector.grantTypeClientCredentials(tokenUrl, clientId,
|
||||
persistedParams.clientSecret, scope, Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
|
||||
@ -295,7 +298,7 @@ public class OAuthClientServiceImpl implements OAuthClientService {
|
||||
throw new OAuthException("tokenUrl is required but null");
|
||||
}
|
||||
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory);
|
||||
OAuthConnector connector = new OAuthConnector(httpClientFactory, persistedParams.deserializerClassName);
|
||||
AccessTokenResponse accessTokenResponse = connector.grantTypeRefreshToken(tokenUrl,
|
||||
lastAccessToken.getRefreshToken(), persistedParams.clientId, persistedParams.clientSecret,
|
||||
persistedParams.scope, Boolean.TRUE.equals(persistedParams.supportsBasicAuth));
|
||||
@ -395,4 +398,17 @@ public class OAuthClientServiceImpl implements OAuthClientService {
|
||||
private String createNewState() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends JsonDeserializer<?>> OAuthClientService withDeserializer(Class<T> deserializerClass) {
|
||||
OAuthClientServiceImpl clientService = new OAuthClientServiceImpl(handle, persistedParams.tokenExpiresInSeconds,
|
||||
httpClientFactory);
|
||||
persistedParams.deserializerClassName = deserializerClass.getName();
|
||||
clientService.persistedParams = persistedParams;
|
||||
clientService.storeHandler = storeHandler;
|
||||
|
||||
storeHandler.savePersistedParams(handle, clientService.persistedParams);
|
||||
|
||||
return clientService;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ package org.openhab.core.auth.oauth2client.internal;
|
||||
import static org.openhab.core.auth.oauth2client.internal.Keyword.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.AccessController;
|
||||
@ -65,9 +66,21 @@ public class OAuthConnector {
|
||||
private final Logger logger = LoggerFactory.getLogger(OAuthConnector.class);
|
||||
private final Gson gson;
|
||||
|
||||
public OAuthConnector(HttpClientFactory httpClientFactory) {
|
||||
public OAuthConnector(HttpClientFactory httpClientFactory, @Nullable String deserializerClassName) {
|
||||
this.httpClientFactory = httpClientFactory;
|
||||
gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
GsonBuilder gsonBuilder = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
|
||||
if (deserializerClassName != null) {
|
||||
try {
|
||||
Class<?> deserializerClass = Class.forName(deserializerClassName);
|
||||
gsonBuilder = gsonBuilder.registerTypeAdapter(AccessTokenResponse.class,
|
||||
deserializerClass.getConstructor().newInstance());
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException | NoSuchMethodException | SecurityException
|
||||
| ClassNotFoundException e) {
|
||||
logger.error("Unable to construct custom deserializer '{}'", deserializerClassName, e);
|
||||
}
|
||||
}
|
||||
gson = gsonBuilder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,7 +70,7 @@ public class OAuthFactoryImpl implements OAuthFactory {
|
||||
@Nullable Boolean supportsBasicAuth) {
|
||||
PersistedParams params = oAuthStoreHandler.loadPersistedParams(handle);
|
||||
PersistedParams newParams = new PersistedParams(handle, tokenUrl, authorizationUrl, clientId, clientSecret,
|
||||
scope, supportsBasicAuth, tokenExpiresInBuffer);
|
||||
scope, supportsBasicAuth, tokenExpiresInBuffer, null);
|
||||
OAuthClientService clientImpl = null;
|
||||
|
||||
// If parameters in storage and parameters are the same as arguments passed get the client from storage
|
||||
|
@ -20,6 +20,7 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
* @author Michael Bock - Initial contribution
|
||||
* @author Gary Tse - Initial contribution
|
||||
* @author Hilbrand Bouwkamp - Moved class to it's own file and added hashCode and equals methods
|
||||
* @author Gaël L'hopital - Added deserializerClassName
|
||||
*/
|
||||
class PersistedParams {
|
||||
String handle;
|
||||
@ -32,6 +33,8 @@ class PersistedParams {
|
||||
String state;
|
||||
String redirectUri;
|
||||
int tokenExpiresInSeconds = 60;
|
||||
@Nullable
|
||||
String deserializerClassName;
|
||||
|
||||
/**
|
||||
* Default constructor needed for json serialization.
|
||||
@ -56,9 +59,11 @@ class PersistedParams {
|
||||
* of the access tokens. This allows the access token to expire earlier than the
|
||||
* official stated expiry time; thus prevents the caller obtaining a valid token at the time of invoke,
|
||||
* only to find the token immediately expired.
|
||||
* @param deserializerClass (optional) if a specific deserializer is needed
|
||||
*/
|
||||
public PersistedParams(String handle, String tokenUrl, String authorizationUrl, String clientId,
|
||||
String clientSecret, String scope, Boolean supportsBasicAuth, int tokenExpiresInSeconds) {
|
||||
String clientSecret, String scope, Boolean supportsBasicAuth, int tokenExpiresInSeconds,
|
||||
@Nullable String deserializerClassName) {
|
||||
this.handle = handle;
|
||||
this.tokenUrl = tokenUrl;
|
||||
this.authorizationUrl = authorizationUrl;
|
||||
@ -67,6 +72,7 @@ class PersistedParams {
|
||||
this.scope = scope;
|
||||
this.supportsBasicAuth = supportsBasicAuth;
|
||||
this.tokenExpiresInSeconds = tokenExpiresInSeconds;
|
||||
this.deserializerClassName = deserializerClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -83,6 +89,7 @@ class PersistedParams {
|
||||
result = prime * result + ((supportsBasicAuth == null) ? 0 : supportsBasicAuth.hashCode());
|
||||
result = prime * result + tokenExpiresInSeconds;
|
||||
result = prime * result + ((tokenUrl == null) ? 0 : tokenUrl.hashCode());
|
||||
result = prime * result + ((deserializerClassName != null) ? deserializerClassName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -161,6 +168,14 @@ class PersistedParams {
|
||||
} else if (!tokenUrl.equals(other.tokenUrl)) {
|
||||
return false;
|
||||
}
|
||||
if (deserializerClassName == null) {
|
||||
if (other.deserializerClassName != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (deserializerClassName != null && !deserializerClassName.equals(other.deserializerClassName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ import java.io.IOException;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
|
||||
/**
|
||||
* This is the service factory to produce a OAuth2 service client that authenticates using OAUTH2.
|
||||
* This is a service factory pattern; the OAuthe2 service client is not shared between bundles.
|
||||
@ -77,6 +79,7 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
*
|
||||
* @author Gary Tse - Initial contribution
|
||||
* @author Hilbrand Bouwkamp - Added AccessTokenRefreshListener, fixed javadoc warnings
|
||||
* @author Gaël L'hopital - Added capability for custom deserializer
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface OAuthClientService extends AutoCloseable {
|
||||
@ -286,4 +289,12 @@ public interface OAuthClientService extends AutoCloseable {
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
boolean removeAccessTokenRefreshListener(AccessTokenRefreshListener listener);
|
||||
|
||||
/**
|
||||
* Adds a personalized deserializer to a given oauth service.
|
||||
*
|
||||
* @param deserializeClass the deserializer class that should be used to deserialize AccessTokenResponse
|
||||
* @return the oauth service
|
||||
*/
|
||||
<T extends JsonDeserializer<?>> OAuthClientService withDeserializer(Class<T> deserializerClass);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user