Skip to content

Commit

Permalink
add support for passing extra fields to oauth token request (#3881)
Browse files Browse the repository at this point in the history
allows using oauth client for authentication with velux API https://github.com/nougad/velux-cli/blob/master/velux-protocol.md#initial-login

Signed-off-by: Jared Lyon <[email protected]>
  • Loading branch information
x1mc authored Dec 6, 2023
1 parent 075bcea commit 44b92db
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Instant>) (json, typeOfT, context) -> {
try {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down

0 comments on commit 44b92db

Please sign in to comment.