diff --git a/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthClientServiceImpl.java b/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthClientServiceImpl.java index 1d8ce4cb125..4f80799db7b 100644 --- a/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthClientServiceImpl.java +++ b/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthClientServiceImpl.java @@ -25,6 +25,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.UrlEncoded; import org.openhab.core.auth.client.oauth2.AccessTokenRefreshListener; import org.openhab.core.auth.client.oauth2.AccessTokenResponse; @@ -73,6 +74,8 @@ public class OAuthClientServiceImpl implements OAuthClientService { private PersistedParams persistedParams = new PersistedParams(); + private @Nullable Fields extraAuthFields = null; + private volatile boolean closed = false; private OAuthClientServiceImpl(String handle, int tokenExpiresInSeconds, HttpClientFactory httpClientFactory, @@ -157,8 +160,8 @@ public String getAuthorizationUrl(@Nullable String redirectURI, @Nullable String } GsonBuilder gsonBuilder = this.gsonBuilder; - OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory) - : new OAuthConnector(httpClientFactory, gsonBuilder); + OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory, extraAuthFields) + : new OAuthConnector(httpClientFactory, extraAuthFields, gsonBuilder); return connector.getAuthorizationUrl(authorizationUrl, clientId, redirectURI, persistedParams.state, scopeToUse); } @@ -213,8 +216,8 @@ public AccessTokenResponse getAccessTokenResponseByAuthorizationCode(String auth } GsonBuilder gsonBuilder = this.gsonBuilder; - OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory) - : new OAuthConnector(httpClientFactory, gsonBuilder); + OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory, extraAuthFields) + : new OAuthConnector(httpClientFactory, extraAuthFields, gsonBuilder); AccessTokenResponse accessTokenResponse = connector.grantTypeAuthorizationCode(tokenUrl, authorizationCode, clientId, persistedParams.clientSecret, redirectURI, Boolean.TRUE.equals(persistedParams.supportsBasicAuth)); @@ -247,8 +250,8 @@ public AccessTokenResponse getAccessTokenByResourceOwnerPasswordCredentials(Stri } GsonBuilder gsonBuilder = this.gsonBuilder; - OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory) - : new OAuthConnector(httpClientFactory, gsonBuilder); + OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory, extraAuthFields) + : new OAuthConnector(httpClientFactory, extraAuthFields, gsonBuilder); AccessTokenResponse accessTokenResponse = connector.grantTypePassword(tokenUrl, username, password, persistedParams.clientId, persistedParams.clientSecret, scope, Boolean.TRUE.equals(persistedParams.supportsBasicAuth)); @@ -274,8 +277,8 @@ public AccessTokenResponse getAccessTokenByClientCredentials(@Nullable String sc } GsonBuilder gsonBuilder = this.gsonBuilder; - OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory) - : new OAuthConnector(httpClientFactory, gsonBuilder); + OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory, extraAuthFields) + : new OAuthConnector(httpClientFactory, extraAuthFields, gsonBuilder); // 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)); @@ -310,8 +313,8 @@ public AccessTokenResponse refreshToken() throws OAuthException, IOException, OA } GsonBuilder gsonBuilder = this.gsonBuilder; - OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory) - : new OAuthConnector(httpClientFactory, gsonBuilder); + OAuthConnector connector = gsonBuilder == null ? new OAuthConnector(httpClientFactory, extraAuthFields) + : new OAuthConnector(httpClientFactory, extraAuthFields, gsonBuilder); AccessTokenResponse accessTokenResponse = connector.grantTypeRefreshToken(tokenUrl, lastAccessToken.getRefreshToken(), persistedParams.clientId, persistedParams.clientSecret, persistedParams.scope, Boolean.TRUE.equals(persistedParams.supportsBasicAuth)); @@ -412,6 +415,19 @@ private String createNewState() { return UUID.randomUUID().toString(); } + /** + * Adds extra fields to include in the form data when doing the token request + * + * @param key The name of the key to add to the auth form + * @param value The value of the new auth form param + */ + public void addExtraAuthField(String key, String value) { + if (extraAuthFields == null) { + extraAuthFields = new Fields(); + } + extraAuthFields.add(key, value); + } + @Override public OAuthClientService withGsonBuilder(GsonBuilder gsonBuilder) { OAuthClientServiceImpl clientService = new OAuthClientServiceImpl(handle, persistedParams.tokenExpiresInSeconds, diff --git a/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthConnector.java b/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthConnector.java index 00d5a28d879..fd2d4fad1e5 100644 --- a/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthConnector.java +++ b/bundles/org.openhab.core.auth.oauth2client/src/main/java/org/openhab/core/auth/oauth2client/internal/OAuthConnector.java @@ -63,15 +63,26 @@ public class OAuthConnector { private final HttpClientFactory httpClientFactory; + private final @Nullable Fields extraFields; + private final Logger logger = LoggerFactory.getLogger(OAuthConnector.class); private final Gson gson; public OAuthConnector(HttpClientFactory httpClientFactory) { - this(httpClientFactory, new GsonBuilder()); + this(httpClientFactory, null, new GsonBuilder()); + } + + public OAuthConnector(HttpClientFactory httpClientFactory, @Nullable Fields extraFields) { + this(httpClientFactory, extraFields, new GsonBuilder()); } public OAuthConnector(HttpClientFactory httpClientFactory, GsonBuilder gsonBuilder) { + this(httpClientFactory, null, gsonBuilder); + } + + public OAuthConnector(HttpClientFactory httpClientFactory, @Nullable Fields extraFields, GsonBuilder gsonBuilder) { this.httpClientFactory = httpClientFactory; + this.extraFields = extraFields; gson = gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .registerTypeAdapter(Instant.class, (JsonDeserializer) (json, typeOfT, context) -> { try { @@ -291,6 +302,14 @@ private Fields initFields(String... parameters) { fields.add(parameters[i], parameters[i + 1]); } } + + if (extraFields != null) { + for (Fields.Field extra : extraFields) { + logger.debug("Oauth request (extra) parameter {}, value {}", extra.getName(), extra.getValue()); + fields.put(extra); + } + } + return fields; } @@ -326,11 +345,12 @@ private AccessTokenResponse doRequest(final String grantType, HttpClient httpCli throw new IOException("Exception in oauth communication, grant type " + grantType, e); } catch (JsonSyntaxException e) { throw new OAuthException(String.format( - "Unable to deserialize json into AccessTokenResponse/ OAuthResponseException. httpCode: %d json: %s", - statusCode, content), e); + "Unable to deserialize json into AccessTokenResponse/ OAuthResponseException. httpCode: %d json: %s: %s", + statusCode, content, e.getMessage()), e); } catch (Exception e) { // Dont know what exception it is, wrap it up and throw it out - throw new OAuthException("Exception in oauth communication, grant type " + grantType, e); + throw new OAuthException( + "Exception in oauth communication, grant type " + grantType + ": " + e.getMessage(), e); } } diff --git a/bundles/org.openhab.core/src/main/java/org/openhab/core/auth/client/oauth2/OAuthClientService.java b/bundles/org.openhab.core/src/main/java/org/openhab/core/auth/client/oauth2/OAuthClientService.java index 9cf6e0f02d5..54658993a43 100644 --- a/bundles/org.openhab.core/src/main/java/org/openhab/core/auth/client/oauth2/OAuthClientService.java +++ b/bundles/org.openhab.core/src/main/java/org/openhab/core/auth/client/oauth2/OAuthClientService.java @@ -294,6 +294,14 @@ AccessTokenResponse getAccessTokenByImplicit(@Nullable String redirectURI, @Null */ boolean removeAccessTokenRefreshListener(AccessTokenRefreshListener listener); + /** + * Adds extra fields to include in the form data when doing the token request + * + * @param key The name of the key to add to the auth form + * @param value The value of the new auth form param + */ + public void addExtraAuthField(String key, String value); + /** * Adds a custom GsonBuilder to be used with the OAuth service instance. *